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