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