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