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