1 h.sterling 1.1 //%2005////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
6 // IBM Corp.; EMC Corporation, The Open Group.
7 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
9 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining a copy
13 // of this software and associated documentation files (the "Software"), to
14 // deal in the Software without restriction, including without limitation the
15 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
16 // sell copies of the Software, and to permit persons to whom the Software is
17 // furnished to do so, subject to the following conditions:
18 //
19 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
20 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
21 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
22 h.sterling 1.1 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
23 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 //==============================================================================
29 //
30 // Author: Mike Day (mdday@us.ibm.com)
31 //
32 // Modified By: Mary Hinton (m.hinton@verizon.net)
33 // Sushma Fernandes (sushma_fernandes@hp.com)
34 // Yi Zhou, Hewlett-Packard Company (yi_zhou@hp.com)
35 // Tony Fiorentino (fiorentino_tony@emc.com)
36 // Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
37 // Steve Hills (steve.hills@ncr.com)
|
38 joyce.j 1.3 // Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) - Bug#2032, 2031
|
39 h.sterling 1.1 //
40 //%/////////////////////////////////////////////////////////////////////////////
41
42 #include <windows.h>
43 #include <process.h> /* _beginthread, _endthread */
44 #include <tchar.h>
45 #include <direct.h>
46 #include <Pegasus/Common/MessageLoader.h> //l10n
47 #include <Pegasus/Common/Thread.h> // l10n
48 #include <Pegasus/Server/CIMServer.h>
49
50 #include "Service.cpp"
51
52 PEGASUS_USING_PEGASUS;
53 PEGASUS_USING_STD;
54
55 static const char* _ALREADY_RUNNING_NAME = 0;
56
57 //-------------------------------------------------------------------------
58 // GLOBALS
59 //-------------------------------------------------------------------------
60 h.sterling 1.1 static Mutex _cimserverLock;
61 static ServerProcess* _server_proc = 0;
62 static bool _shutdown = false;
63 static Service pegasus_service;
64 static HANDLE pegasus_service_event = NULL;
65 static LPCSTR g_cimservice_key = TEXT("SYSTEM\\CurrentControlSet\\Services\\%s");
66 static LPCSTR g_cimservice_home = TEXT("home");
67 static int g_argc = 0;
68 static char **g_argv = 0;
69
70 // Constants representing the command line options.
71 static const char OPTION_INSTALL[] = "install";
72 static const char OPTION_REMOVE[] = "remove";
73 static const char OPTION_START[] = "start";
74 static const char OPTION_STOP[] = "stop";
75
76 //-------------------------------------------------------------------------
77 // PROTOTYPES
78 //-------------------------------------------------------------------------
79 int cimserver_windows_main(int flag, int argc, char **argv);
80 static bool _getRegInfo(const char *lpchKeyword, char *lpchRetValue);
81 h.sterling 1.1 static bool _setRegInfo(const char *lpchKeyword, const char *lpchValue);
82
83 //-------------------------------------------------------------------------
84 // NO-OPs for windows platform
85 //-------------------------------------------------------------------------
86 int ServerProcess::cimserver_fork(void) { return(0); }
87 void ServerProcess::notify_parent(int id) { return; }
88 long ServerProcess::get_server_pid(void) { return 0; }
|
89 h.sterling 1.2 void ServerProcess::set_parent_pid(int pid) {}
|
90 h.sterling 1.1 int ServerProcess::get_proc(int pid) { return 0; }
91 int ServerProcess::cimserver_kill(int id) { return(0); }
92 void cimserver_exitRC(int rc) {}
93 int ServerProcess::cimserver_initialize(void) { return 0; }
94 int ServerProcess::cimserver_wait(void) { return 0; }
95
96
97 //-------------------------------------------------------------------------
98 // Helper for platform specific handling
99 //-------------------------------------------------------------------------
100
101 ServerProcess::ServerProcess()
102 {
103 //be sure to call cimserver_set_process right after instantiating this in order for everything to work
104 }
105
106 ServerProcess::~ServerProcess()
107 {
108 }
109
110 void ServerProcess::cimserver_set_process(void* p)
111 h.sterling 1.1 {
112 AutoMutex am( _cimserverLock );
113 _server_proc = static_cast<ServerProcess *>(p);
114 if(_server_proc && _shutdown)
115 _server_proc->cimserver_stop();
116
117 pegasus_service = Service(getProcessName());
118 _ALREADY_RUNNING_NAME = getProcessName();
119 }
120
121 void signal_shutdown()
122 {
123 AutoMutex am( _cimserverLock );
124 _shutdown = true;
125 if( _server_proc )
126 _server_proc->cimserver_stop();
127 }
128
129 //-------------------------------------------------------------------------
130 // Run main server asynchronously
131 //-------------------------------------------------------------------------
132 h.sterling 1.1 static unsigned __stdcall cimserver_windows_thread( void* parm )
133 {
134 int argc = 0;
|
135 kumpf 1.5 int rc = _server_proc->cimserver_run( g_argc, g_argv, false, false );
|
136 h.sterling 1.1 SetEvent(pegasus_service_event);
137 _endthreadex( rc );
138 return rc;
139 }
140
141 //-------------------------------------------------------------------------
142 // Windows NT Service Control Code
143 //-------------------------------------------------------------------------
144
145 //-------------------------------------------------------------------------
146 // START/STOP handler
147 //-------------------------------------------------------------------------
148 int cimserver_windows_main(int flag, int argc, char *argv[])
149 {
150 switch( flag )
151 {
152 case Service::STARTUP_FLAG:
153 {
154 //
155 // Start up main run in a separate thread and wait for it to finish.
156 //
157 h.sterling 1.1
158 unsigned threadid = 0;
159 g_argc = argc;
160 g_argv = argv;
161 HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, cimserver_windows_thread, NULL, 0, &threadid );
162 if( hThread == NULL )
163 return 1;
164
165 WaitForSingleObject( pegasus_service_event, INFINITE );
166
167 //
168 // Shutdown the cimserver.
169 //
170
171 signal_shutdown();
172
173 //
174 // Make sure we upate the SCM that our stop is pending.
175 // Wait for the main run thread to exit.
176 //
177
178 h.sterling 1.1 DWORD dwCheckPoint = 1; // service code should have already started at 0
179
180 while( WaitForSingleObject( hThread, 3000 ) == WAIT_TIMEOUT )
181 {
182 pegasus_service.report_status(
183 SERVICE_STOP_PENDING, NO_ERROR, dwCheckPoint++, 5000 );
184 }
185
186 CloseHandle( hThread );
187
188 break;
189 }
190 case Service::SHUTDOWN_FLAG:
191 SetEvent(pegasus_service_event);
192 break;
193
194 default:
195 break;
196 }
197
198 return 0;
199 h.sterling 1.1 }
200
201 //-------------------------------------------------------------------------
202 // IS RUNNING?
203 //-------------------------------------------------------------------------
204
205 class AlreadyRunning
206 {
207 public:
208 AlreadyRunning(): alreadyRunning( true ), event( NULL )
209 {
210 }
211 ~AlreadyRunning()
212 {
213 if( event != NULL )
214 CloseHandle( event );
215 }
216
217 void Init()
218 {
219 if( event == NULL )
220 h.sterling 1.1 {
221 event = CreateEvent( NULL, TRUE, TRUE, _ALREADY_RUNNING_NAME );
222 if( event != NULL && GetLastError() != ERROR_ALREADY_EXISTS )
223 alreadyRunning = false;
224 }
225 }
226
227 bool IsAlreadyRunning()
228 {
229 return alreadyRunning;
230 }
231
232 bool alreadyRunning;
233 HANDLE event;
234 };
235
236 AlreadyRunning _alreadyRunning;
237
238
239 Boolean ServerProcess::isCIMServerRunning(void)
240 {
241 h.sterling 1.1 //Service::State state;
242 //pegasus_service.GetState(&state);
243 //return (state == Service::SERVICE_STATE_RUNNING) ? true : false;
244
245 // We do it this way so this will work when run as a
246 // console process and a Windows service.
247 AlreadyRunning ar;
248 ar.Init();
249 return ar.IsAlreadyRunning();
250 }
251
252 //-------------------------------------------------------------------------
253 // INSTALL
254 //-------------------------------------------------------------------------
255 bool cimserver_install_nt_service(char *service_name)
256 {
257 Service::ReturnCode status = Service::SERVICE_RETURN_SUCCESS;
258 char filename[_MAX_PATH] = {0};
259 char displayname[_MAX_PATH] = {0};
260 char descriptionname[_MAX_PATH] = {0};
261
262 h.sterling 1.1 // If service name is specified, override default
263 if (service_name == NULL)
264 {
265 strcpy(displayname, _server_proc->getExtendedName());
266 }
267 else
268 {
269 pegasus_service.SetServiceName(service_name);
270 sprintf(displayname, "%s - %s", _server_proc->getExtendedName(), service_name);
271 }
272
273 strcpy(descriptionname, _server_proc->getDescription());
274
|
275 joyce.j 1.3 if(0 != GetModuleFileName(NULL, filename, sizeof(filename)))
276 {
277 status = pegasus_service.Install(displayname, descriptionname, filename);
|
278 h.sterling 1.1
|
279 joyce.j 1.3 // Upon success, set home in registry
280 if (status == Service::SERVICE_RETURN_SUCCESS)
281 {
|
282 h.sterling 1.1 char pegasus_homepath[_MAX_PATH];
283 System::extract_file_path(filename, pegasus_homepath);
284 pegasus_homepath[strlen(pegasus_homepath)-1] = '\0';
285 strcpy(filename, pegasus_homepath);
286 System::extract_file_path(filename, pegasus_homepath);
287 pegasus_homepath[strlen(pegasus_homepath)-1] = '\0';
288 _setRegInfo(g_cimservice_home, pegasus_homepath);
|
289 joyce.j 1.3 }
290 }
291 else
292 {
293 status = (Service::ReturnCode) GetLastError();
294 }
|
295 h.sterling 1.1 return (status == Service::SERVICE_RETURN_SUCCESS) ? true : false;
296 }
297
298 //-------------------------------------------------------------------------
299 // REMOVE
300 //-------------------------------------------------------------------------
301 bool cimserver_remove_nt_service(char *service_name)
302 {
303 Service::ReturnCode status = Service::SERVICE_RETURN_SUCCESS;
304
305 // If service name is specified, override default
306 if (service_name != NULL)
307 {
308 pegasus_service.SetServiceName(service_name);
309 }
310
311 status = pegasus_service.Remove();
312
313 return (status == Service::SERVICE_RETURN_SUCCESS) ? true : false;
314 }
315
316 h.sterling 1.1 //-------------------------------------------------------------------------
317 // START
318 //-------------------------------------------------------------------------
319 bool cimserver_start_nt_service(char *service_name, int num_args, char **service_args)
320 {
321 Service::ReturnCode status = Service::SERVICE_RETURN_SUCCESS;
322
323 // If service name is specified, override default
324 if (service_name != NULL)
325 {
326 pegasus_service.SetServiceName(service_name);
327 }
328
329 if(num_args > 0 && service_args != NULL)
330 {
331 pegasus_service.SetServiceArgs(num_args, service_args);
332 }
333
334 status = pegasus_service.Start(5);
335
336 return (status == Service::SERVICE_RETURN_SUCCESS) ? true : false;
337 h.sterling 1.1 }
338
339 //-------------------------------------------------------------------------
340 // STOP
341 //-------------------------------------------------------------------------
342 bool cimserver_stop_nt_service(char *service_name)
343 {
344 Service::ReturnCode status = Service::SERVICE_RETURN_SUCCESS;
345
346 // If service name is specified, override default
347 if (service_name != NULL)
348 {
349 pegasus_service.SetServiceName(service_name);
350 }
351
352 status = pegasus_service.Stop(5);
353
354 return (status == Service::SERVICE_RETURN_SUCCESS) ? true : false;
355 }
356
357 //-------------------------------------------------------------------------
358 h.sterling 1.1 // HELPER Utilities
359 //-------------------------------------------------------------------------
360 static bool _getRegInfo(const char *lpchKeyword, char *lpchRetValue)
361 {
362 HKEY hKey;
363 DWORD dw = _MAX_PATH;
364 char subKey[_MAX_PATH] = {0};
365
366 sprintf(subKey, g_cimservice_key, pegasus_service.GetServiceName());
367
368 if ((RegOpenKeyEx(HKEY_LOCAL_MACHINE,
369 subKey,
370 0,
371 KEY_READ,
372 &hKey)) != ERROR_SUCCESS)
373 {
374 return false;
375 }
376
377 if ((RegQueryValueEx(hKey,
378 lpchKeyword,
379 h.sterling 1.1 NULL,
380 NULL,
381 (LPBYTE)lpchRetValue,
382 &dw)) != ERROR_SUCCESS)
383 {
384 RegCloseKey(hKey);
385 return false;
386 }
387
388 RegCloseKey(hKey);
389
390 return true;
391 }
392
393 static bool _setRegInfo(const char *lpchKeyword, const char *lpchValue)
394 {
395 HKEY hKey;
396 DWORD dw = _MAX_PATH;
397 char home_key[_MAX_PATH] = {0};
398 char subKey[_MAX_PATH] = {0};
399
400 h.sterling 1.1 if (lpchKeyword == NULL || lpchValue == NULL)
401 return false;
402
403 sprintf(subKey, g_cimservice_key, pegasus_service.GetServiceName());
404
405 if ((RegCreateKeyEx (HKEY_LOCAL_MACHINE,
406 subKey,
407 0,
408 NULL,
409 0,
410 KEY_ALL_ACCESS,
411 NULL,
412 &hKey,
413 NULL) != ERROR_SUCCESS))
414 {
415 return false;
416 }
417
418 if ((RegSetValueEx(hKey,
419 lpchKeyword,
420 0,
421 h.sterling 1.1 REG_SZ,
422 (CONST BYTE *)lpchValue,
423 (DWORD)(strlen(lpchValue)+1))) != ERROR_SUCCESS)
424 {
425 RegCloseKey(hKey);
426 return false;
427 }
428
429 RegCloseKey(hKey);
430
431 return true;
432 }
433
434 //void ServerProcess::setHome(const String& home)
435 String ServerProcess::getHome(void)
436 {
437 String home = String::EMPTY;
438
439 // Determine the absolute path to the running program
440 char exe_pathname[_MAX_PATH] = {0};
441 char home_pathname[_MAX_PATH] = {0};
|
442 joyce.j 1.3 if(0 != GetModuleFileName(NULL, exe_pathname, sizeof(exe_pathname)))
443 {
|
444 h.sterling 1.1
|
445 joyce.j 1.3 // Pegasus home search rules:
446 // - look in registry (if set)
447 // - if not found, look in PEGASUS_HOME (if set)
448 // - if not found, use exe directory minus one level
449
450 bool found_reg = _getRegInfo("home", home_pathname);
451 if (found_reg == true)
452 {
453 // Make sure home matches
454 String current_home(home_pathname);
455 String current_exe(exe_pathname);
456 current_home.toLower();
457 current_exe.toLower();
458
459 Uint32 pos = current_exe.find(current_home);
460 if (pos != PEG_NOT_FOUND)
461 {
462 home = home_pathname;
463 }
464 else
465 {
466 joyce.j 1.3 found_reg = false;
467 }
468 }
469 if (found_reg == false)
470 {
471 const char* tmp = getenv("PEGASUS_HOME");
472 if (tmp)
473 {
474 home = tmp;
475 }
476 else
477 {
478 // ASSUMPTION: At a minimum, the cimserver program is running
479 // from a "bin" directory
480 home = FileSystem::extractFilePath(exe_pathname);
481 home.remove(home.size()-1, 1);
482 home = FileSystem::extractFilePath(home);
483 home.remove(home.size()-1, 1);
484 }
485 }
486 }
|
487 h.sterling 1.1 return home;
488 }
489
490 //
491 // Our console control handler
492 //
493
494 static BOOL WINAPI ControlHandler( DWORD dwCtrlType )
495 {
496 switch( dwCtrlType )
497 {
498 case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
499 case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
500 {
501 signal_shutdown();
502 return TRUE;
503 }
504 }
505 return FALSE;
506 }
507
508 h.sterling 1.1 //
509 // Platform specific run
510 //
511
|
512 kumpf 1.4 int ServerProcess::platform_run(
513 int argc,
514 char** argv,
515 Boolean shutdownOption,
516 Boolean debugOutputOption)
|
517 h.sterling 1.1 {
518 //
519 // Check for my command line options
520 //
521
522 for( int i = 1; i < argc; )
523 {
524 const char* arg = argv[i];
525
526 // Check for -option
527 if (*arg == '-')
528 {
529 // Get the option
530 const char* option = arg + 1;
531
532 if (strcmp(option, OPTION_INSTALL) == 0)
533 {
534 //
535 // Install as a NT service
536 //
537 char *opt_arg = NULL;
538 h.sterling 1.1 if (i+1 < argc)
539 {
540 opt_arg = argv[i+1];
541
542 }
543 if(cimserver_install_nt_service(opt_arg))
544 {
545 //l10n
546 //cout << "\nPegasus installed as NT Service";
547 MessageLoaderParms parms(
548 "src.Server.cimserver.INSTALLED_NT_SERVICE",
549 "\nPegasus installed as a Windows service");
550 cout << MessageLoader::getMessage(parms) << endl;
551 exit(0);
552 }
553 else
554 {
555 exit(0);
556 }
557 }
558 else if (strcmp(option, OPTION_REMOVE) == 0)
559 h.sterling 1.1 {
560 //
561 // Remove Pegasus as an NT service
562 //
563 char *opt_arg = NULL;
564 if (i+1 < argc)
565 {
566 opt_arg = argv[i+1];
567 }
568 if(cimserver_remove_nt_service(opt_arg))
569 {
570 //l10n
571 //cout << "\nPegasus removed as NT Service";
572 MessageLoaderParms parms(
573 "src.Server.cimserver.REMOVED_NT_SERVICE",
574 "\nPegasus removed as a Windows service");
575 cout << MessageLoader::getMessage(parms) << endl;
576 exit(0);
577 }
578 else
579 {
580 h.sterling 1.1 exit(0);
581 }
582
583 }
584 else if (strcmp(option, OPTION_START) == 0)
585 {
586 //
587 // Start as a NT service
588 //
589 char *opt_arg = NULL;
590 int num_args = 0;
591 if (i+1 < argc)
592 {
593 opt_arg = argv[i+1];
594 num_args = argc - 3;
595 }
596 else
597 {
598 num_args = argc - 2;
599 }
600
601 h.sterling 1.1 char **service_args = &argv[1];
602 if(cimserver_start_nt_service(opt_arg, num_args, service_args))
603 {
604 //l10n
605 //cout << "\nPegasus started as NT Service";
606 MessageLoaderParms parms(
607 "src.Server.cimserver.STARTED_NT_SERVICE",
608 "\nPegasus started as a Windows service");
609 cout << MessageLoader::getMessage(parms) << endl;
610 exit(0);
611 }
612 else
613 {
614 exit(0);
615 }
616 }
617 else if (strcmp(option, OPTION_STOP) == 0)
618 {
619 //
620 // Stop as a NT service
621 //
622 h.sterling 1.1 char *opt_arg = NULL;
623 if (i+1 < argc)
624 {
625 opt_arg = argv[i+1];
626 }
627 if(cimserver_stop_nt_service(opt_arg))
628 {
629 //l10n
630 //cout << "\nPegasus stopped as NT Service";
631 MessageLoaderParms parms(
632 "src.Server.cimserver.STOPPED_NT_SERVICE",
633 "\nPegasus stopped as a Windows service");
634 cout << MessageLoader::getMessage(parms) << endl;
635 exit(0);
636 }
637 else
638 {
639 exit(0);
640 }
641 }
642 else
643 h.sterling 1.1 i++;
644 }
645 else
646 i++;
647 }
648
649 //
650 // Signal ourself as running
651 //
652
653 if( !shutdownOption )
654 _alreadyRunning.Init();
655
656 //
657 // Check if already running
658 //
659 // Hmm, when starting as a service, should we do this here (before
660 // starting the control dispatcher)? If we do then the SCM reports
661 // a dumb message to the user. If we don't, and it in the serviceProc
662 // then the service will start up then die silently.
663 //
664 h.sterling 1.1
665 if( !shutdownOption && _alreadyRunning.IsAlreadyRunning() )
666 {
667 MessageLoaderParms parms(
668 "src.Server.cimserver.UNABLE_TO_START_SERVER_ALREADY_RUNNING",
669 "Unable to start CIMServer.\nCIMServer is already running." );
670 Logger::put(
671 Logger::ERROR_LOG, "CIMServer", Logger::SEVERE,
672 MessageLoader::getMessage(parms) );
673 PEGASUS_STD(cerr) << MessageLoader::getMessage(parms) << PEGASUS_STD(endl);
674 return 1;
675 }
676
677 //
678 // Check if running from a console window. If so then just run
679 // as a console process.
680 //
681
682 char console_title[ _MAX_PATH ] = {0};
683 if( GetConsoleTitle( console_title, _MAX_PATH ) > 0 )
684 {
685 h.sterling 1.1 SetConsoleCtrlHandler( ControlHandler, TRUE );
686
|
687 kumpf 1.4 return cimserver_run(argc, argv, shutdownOption, debugOutputOption);
|
688 h.sterling 1.1 }
689
690 //
691 // Run as a service
692 //
693
694 pegasus_service_event = CreateEvent( NULL, FALSE, FALSE, NULL );
695
696 Service::ReturnCode status;
697 status = pegasus_service.Run( cimserver_windows_main );
698
699 if( status != Service::SERVICE_RETURN_SUCCESS )
700 {
701 // todo: put into localized messages when messages unfreezes.
702 Logger::put_l(
703 Logger::ERROR_LOG, "CIMServer", Logger::SEVERE,
704 "src.Server.cimserver_windows.LISTENING_ON_HTTP_PORT",
705 "Error during service run: code = $0.", status );
706 return 1;
707 }
708
709 h.sterling 1.1 return 0;
710 }
|