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 //%/////////////////////////////////////////////////////////////////////////////
33
34 h.sterling 1.1 #include <windows.h>
35 #include <process.h> /* _beginthread, _endthread */
36 #include <tchar.h>
37 #include <direct.h>
|
38 kumpf 1.7 #include <Pegasus/Common/MessageLoader.h>
39 #include <Pegasus/Common/Thread.h>
|
40 h.sterling 1.1 #include <Pegasus/Server/CIMServer.h>
|
41 kumpf 1.8 #include <Service/ServerRunStatus.h>
|
42 h.sterling 1.1
43 #include "Service.cpp"
44
45 PEGASUS_USING_PEGASUS;
46 PEGASUS_USING_STD;
47
48 //-------------------------------------------------------------------------
49 // GLOBALS
50 //-------------------------------------------------------------------------
51 static Mutex _cimserverLock;
52 static ServerProcess* _server_proc = 0;
53 static bool _shutdown = false;
54 static Service pegasus_service;
55 static HANDLE pegasus_service_event = NULL;
56 static LPCSTR g_cimservice_key = TEXT("SYSTEM\\CurrentControlSet\\Services\\%s");
57 static LPCSTR g_cimservice_home = TEXT("home");
58 static int g_argc = 0;
59 static char **g_argv = 0;
60
61 // Constants representing the command line options.
62 static const char OPTION_INSTALL[] = "install";
63 h.sterling 1.1 static const char OPTION_REMOVE[] = "remove";
64 static const char OPTION_START[] = "start";
65 static const char OPTION_STOP[] = "stop";
66
67 //-------------------------------------------------------------------------
68 // PROTOTYPES
69 //-------------------------------------------------------------------------
70 int cimserver_windows_main(int flag, int argc, char **argv);
71 static bool _getRegInfo(const char *lpchKeyword, char *lpchRetValue);
72 static bool _setRegInfo(const char *lpchKeyword, const char *lpchValue);
73
74 //-------------------------------------------------------------------------
75 // NO-OPs for windows platform
76 //-------------------------------------------------------------------------
77 int ServerProcess::cimserver_fork(void) { return(0); }
78 void ServerProcess::notify_parent(int id) { return; }
79 void cimserver_exitRC(int rc) {}
80 int ServerProcess::cimserver_initialize(void) { return 0; }
81 int ServerProcess::cimserver_wait(void) { return 0; }
82
83
84 h.sterling 1.1 //-------------------------------------------------------------------------
85 // Helper for platform specific handling
86 //-------------------------------------------------------------------------
87
88 ServerProcess::ServerProcess()
89 {
90 //be sure to call cimserver_set_process right after instantiating this in order for everything to work
91 }
92
93 ServerProcess::~ServerProcess()
94 {
95 }
96
97 void ServerProcess::cimserver_set_process(void* p)
98 {
99 AutoMutex am( _cimserverLock );
100 _server_proc = static_cast<ServerProcess *>(p);
101 if(_server_proc && _shutdown)
102 _server_proc->cimserver_stop();
103
104 pegasus_service = Service(getProcessName());
105 h.sterling 1.1 }
106
107 void signal_shutdown()
108 {
109 AutoMutex am( _cimserverLock );
110 _shutdown = true;
111 if( _server_proc )
112 _server_proc->cimserver_stop();
113 }
114
115 //-------------------------------------------------------------------------
116 // Run main server asynchronously
117 //-------------------------------------------------------------------------
118 static unsigned __stdcall cimserver_windows_thread( void* parm )
119 {
120 int argc = 0;
|
121 kumpf 1.5 int rc = _server_proc->cimserver_run( g_argc, g_argv, false, false );
|
122 h.sterling 1.1 SetEvent(pegasus_service_event);
123 _endthreadex( rc );
124 return rc;
125 }
126
127 //-------------------------------------------------------------------------
128 // Windows NT Service Control Code
129 //-------------------------------------------------------------------------
130
131 //-------------------------------------------------------------------------
132 // START/STOP handler
133 //-------------------------------------------------------------------------
134 int cimserver_windows_main(int flag, int argc, char *argv[])
135 {
136 switch( flag )
137 {
138 case Service::STARTUP_FLAG:
139 {
140 //
141 // Start up main run in a separate thread and wait for it to finish.
142 //
143 h.sterling 1.1
144 unsigned threadid = 0;
145 g_argc = argc;
146 g_argv = argv;
147 HANDLE hThread = (HANDLE)_beginthreadex( NULL, 0, cimserver_windows_thread, NULL, 0, &threadid );
148 if( hThread == NULL )
149 return 1;
150
151 WaitForSingleObject( pegasus_service_event, INFINITE );
152
153 //
154 // Shutdown the cimserver.
155 //
156
157 signal_shutdown();
158
159 //
160 // Make sure we upate the SCM that our stop is pending.
161 // Wait for the main run thread to exit.
162 //
163
164 h.sterling 1.1 DWORD dwCheckPoint = 1; // service code should have already started at 0
165
166 while( WaitForSingleObject( hThread, 3000 ) == WAIT_TIMEOUT )
167 {
168 pegasus_service.report_status(
169 SERVICE_STOP_PENDING, NO_ERROR, dwCheckPoint++, 5000 );
170 }
171
172 CloseHandle( hThread );
173
174 break;
175 }
176 case Service::SHUTDOWN_FLAG:
177 SetEvent(pegasus_service_event);
178 break;
179
180 default:
181 break;
182 }
183
184 return 0;
185 h.sterling 1.1 }
186
187
188 //-------------------------------------------------------------------------
189 // INSTALL
190 //-------------------------------------------------------------------------
191 bool cimserver_install_nt_service(char *service_name)
192 {
193 Service::ReturnCode status = Service::SERVICE_RETURN_SUCCESS;
194 char filename[_MAX_PATH] = {0};
195 char displayname[_MAX_PATH] = {0};
196 char descriptionname[_MAX_PATH] = {0};
197
198 // If service name is specified, override default
199 if (service_name == NULL)
200 {
201 strcpy(displayname, _server_proc->getExtendedName());
202 }
203 else
204 {
205 pegasus_service.SetServiceName(service_name);
206 h.sterling 1.1 sprintf(displayname, "%s - %s", _server_proc->getExtendedName(), service_name);
207 }
208
209 strcpy(descriptionname, _server_proc->getDescription());
210
|
211 joyce.j 1.3 if(0 != GetModuleFileName(NULL, filename, sizeof(filename)))
212 {
213 status = pegasus_service.Install(displayname, descriptionname, filename);
|
214 h.sterling 1.1
|
215 joyce.j 1.3 // Upon success, set home in registry
216 if (status == Service::SERVICE_RETURN_SUCCESS)
217 {
|
218 h.sterling 1.1 char pegasus_homepath[_MAX_PATH];
219 System::extract_file_path(filename, pegasus_homepath);
220 pegasus_homepath[strlen(pegasus_homepath)-1] = '\0';
221 strcpy(filename, pegasus_homepath);
222 System::extract_file_path(filename, pegasus_homepath);
223 pegasus_homepath[strlen(pegasus_homepath)-1] = '\0';
224 _setRegInfo(g_cimservice_home, pegasus_homepath);
|
225 joyce.j 1.3 }
226 }
227 else
228 {
229 status = (Service::ReturnCode) GetLastError();
230 }
|
231 h.sterling 1.1 return (status == Service::SERVICE_RETURN_SUCCESS) ? true : false;
232 }
233
234 //-------------------------------------------------------------------------
235 // REMOVE
236 //-------------------------------------------------------------------------
237 bool cimserver_remove_nt_service(char *service_name)
238 {
239 Service::ReturnCode status = Service::SERVICE_RETURN_SUCCESS;
240
241 // If service name is specified, override default
242 if (service_name != NULL)
243 {
244 pegasus_service.SetServiceName(service_name);
245 }
246
247 status = pegasus_service.Remove();
248
249 return (status == Service::SERVICE_RETURN_SUCCESS) ? true : false;
250 }
251
252 h.sterling 1.1 //-------------------------------------------------------------------------
253 // START
254 //-------------------------------------------------------------------------
255 bool cimserver_start_nt_service(char *service_name, int num_args, char **service_args)
256 {
257 Service::ReturnCode status = Service::SERVICE_RETURN_SUCCESS;
258
259 // If service name is specified, override default
260 if (service_name != NULL)
261 {
262 pegasus_service.SetServiceName(service_name);
263 }
264
265 if(num_args > 0 && service_args != NULL)
266 {
267 pegasus_service.SetServiceArgs(num_args, service_args);
268 }
269
270 status = pegasus_service.Start(5);
271
272 return (status == Service::SERVICE_RETURN_SUCCESS) ? true : false;
273 h.sterling 1.1 }
274
275 //-------------------------------------------------------------------------
276 // STOP
277 //-------------------------------------------------------------------------
278 bool cimserver_stop_nt_service(char *service_name)
279 {
280 Service::ReturnCode status = Service::SERVICE_RETURN_SUCCESS;
281
282 // If service name is specified, override default
283 if (service_name != NULL)
284 {
285 pegasus_service.SetServiceName(service_name);
286 }
287
288 status = pegasus_service.Stop(5);
289
290 return (status == Service::SERVICE_RETURN_SUCCESS) ? true : false;
291 }
292
293 //-------------------------------------------------------------------------
294 h.sterling 1.1 // HELPER Utilities
295 //-------------------------------------------------------------------------
296 static bool _getRegInfo(const char *lpchKeyword, char *lpchRetValue)
297 {
298 HKEY hKey;
299 DWORD dw = _MAX_PATH;
300 char subKey[_MAX_PATH] = {0};
301
302 sprintf(subKey, g_cimservice_key, pegasus_service.GetServiceName());
303
304 if ((RegOpenKeyEx(HKEY_LOCAL_MACHINE,
305 subKey,
306 0,
307 KEY_READ,
308 &hKey)) != ERROR_SUCCESS)
309 {
310 return false;
311 }
312
313 if ((RegQueryValueEx(hKey,
314 lpchKeyword,
315 h.sterling 1.1 NULL,
316 NULL,
317 (LPBYTE)lpchRetValue,
318 &dw)) != ERROR_SUCCESS)
319 {
320 RegCloseKey(hKey);
321 return false;
322 }
323
324 RegCloseKey(hKey);
325
326 return true;
327 }
328
329 static bool _setRegInfo(const char *lpchKeyword, const char *lpchValue)
330 {
331 HKEY hKey;
332 DWORD dw = _MAX_PATH;
333 char home_key[_MAX_PATH] = {0};
334 char subKey[_MAX_PATH] = {0};
335
336 h.sterling 1.1 if (lpchKeyword == NULL || lpchValue == NULL)
337 return false;
338
339 sprintf(subKey, g_cimservice_key, pegasus_service.GetServiceName());
340
341 if ((RegCreateKeyEx (HKEY_LOCAL_MACHINE,
342 subKey,
343 0,
344 NULL,
345 0,
346 KEY_ALL_ACCESS,
347 NULL,
348 &hKey,
349 NULL) != ERROR_SUCCESS))
350 {
351 return false;
352 }
353
354 if ((RegSetValueEx(hKey,
355 lpchKeyword,
356 0,
357 h.sterling 1.1 REG_SZ,
358 (CONST BYTE *)lpchValue,
359 (DWORD)(strlen(lpchValue)+1))) != ERROR_SUCCESS)
360 {
361 RegCloseKey(hKey);
362 return false;
363 }
364
365 RegCloseKey(hKey);
366
367 return true;
368 }
369
370 //void ServerProcess::setHome(const String& home)
371 String ServerProcess::getHome(void)
372 {
|
373 kumpf 1.7 String home;
|
374 h.sterling 1.1
375 // Determine the absolute path to the running program
376 char exe_pathname[_MAX_PATH] = {0};
377 char home_pathname[_MAX_PATH] = {0};
|
378 joyce.j 1.3 if(0 != GetModuleFileName(NULL, exe_pathname, sizeof(exe_pathname)))
379 {
|
380 h.sterling 1.1
|
381 joyce.j 1.3 // Pegasus home search rules:
382 // - look in registry (if set)
383 // - if not found, look in PEGASUS_HOME (if set)
384 // - if not found, use exe directory minus one level
385
386 bool found_reg = _getRegInfo("home", home_pathname);
387 if (found_reg == true)
388 {
389 // Make sure home matches
390 String current_home(home_pathname);
391 String current_exe(exe_pathname);
392 current_home.toLower();
393 current_exe.toLower();
394
395 Uint32 pos = current_exe.find(current_home);
396 if (pos != PEG_NOT_FOUND)
397 {
398 home = home_pathname;
399 }
400 else
401 {
402 joyce.j 1.3 found_reg = false;
403 }
404 }
405 if (found_reg == false)
406 {
407 const char* tmp = getenv("PEGASUS_HOME");
408 if (tmp)
409 {
410 home = tmp;
411 }
412 else
413 {
414 // ASSUMPTION: At a minimum, the cimserver program is running
415 // from a "bin" directory
416 home = FileSystem::extractFilePath(exe_pathname);
417 home.remove(home.size()-1, 1);
418 home = FileSystem::extractFilePath(home);
419 home.remove(home.size()-1, 1);
420 }
421 }
422 }
|
423 h.sterling 1.1 return home;
424 }
425
426 //
427 // Our console control handler
428 //
429
430 static BOOL WINAPI ControlHandler( DWORD dwCtrlType )
431 {
432 switch( dwCtrlType )
433 {
434 case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
435 case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
436 {
437 signal_shutdown();
438 return TRUE;
439 }
440 }
441 return FALSE;
442 }
443
444 h.sterling 1.1 //
445 // Platform specific run
446 //
447
|
448 kumpf 1.4 int ServerProcess::platform_run(
449 int argc,
450 char** argv,
451 Boolean shutdownOption,
452 Boolean debugOutputOption)
|
453 h.sterling 1.1 {
454 //
455 // Check for my command line options
456 //
457
458 for( int i = 1; i < argc; )
459 {
460 const char* arg = argv[i];
461
462 // Check for -option
463 if (*arg == '-')
464 {
465 // Get the option
466 const char* option = arg + 1;
467
468 if (strcmp(option, OPTION_INSTALL) == 0)
469 {
470 //
471 // Install as a NT service
472 //
473 char *opt_arg = NULL;
474 h.sterling 1.1 if (i+1 < argc)
475 {
476 opt_arg = argv[i+1];
477
478 }
479 if(cimserver_install_nt_service(opt_arg))
480 {
481 //l10n
482 //cout << "\nPegasus installed as NT Service";
483 MessageLoaderParms parms(
484 "src.Server.cimserver.INSTALLED_NT_SERVICE",
485 "\nPegasus installed as a Windows service");
486 cout << MessageLoader::getMessage(parms) << endl;
487 exit(0);
488 }
489 else
490 {
491 exit(0);
492 }
493 }
494 else if (strcmp(option, OPTION_REMOVE) == 0)
495 h.sterling 1.1 {
496 //
497 // Remove Pegasus as an NT service
498 //
499 char *opt_arg = NULL;
500 if (i+1 < argc)
501 {
502 opt_arg = argv[i+1];
503 }
504 if(cimserver_remove_nt_service(opt_arg))
505 {
506 //l10n
507 //cout << "\nPegasus removed as NT Service";
508 MessageLoaderParms parms(
509 "src.Server.cimserver.REMOVED_NT_SERVICE",
510 "\nPegasus removed as a Windows service");
511 cout << MessageLoader::getMessage(parms) << endl;
512 exit(0);
513 }
514 else
515 {
516 h.sterling 1.1 exit(0);
517 }
518
519 }
520 else if (strcmp(option, OPTION_START) == 0)
521 {
522 //
523 // Start as a NT service
524 //
525 char *opt_arg = NULL;
526 int num_args = 0;
527 if (i+1 < argc)
528 {
529 opt_arg = argv[i+1];
530 num_args = argc - 3;
531 }
532 else
533 {
534 num_args = argc - 2;
535 }
536
537 h.sterling 1.1 char **service_args = &argv[1];
538 if(cimserver_start_nt_service(opt_arg, num_args, service_args))
539 {
540 //l10n
541 //cout << "\nPegasus started as NT Service";
542 MessageLoaderParms parms(
543 "src.Server.cimserver.STARTED_NT_SERVICE",
544 "\nPegasus started as a Windows service");
545 cout << MessageLoader::getMessage(parms) << endl;
546 exit(0);
547 }
548 else
549 {
550 exit(0);
551 }
552 }
553 else if (strcmp(option, OPTION_STOP) == 0)
554 {
555 //
556 // Stop as a NT service
557 //
558 h.sterling 1.1 char *opt_arg = NULL;
559 if (i+1 < argc)
560 {
561 opt_arg = argv[i+1];
562 }
563 if(cimserver_stop_nt_service(opt_arg))
564 {
565 //l10n
566 //cout << "\nPegasus stopped as NT Service";
567 MessageLoaderParms parms(
568 "src.Server.cimserver.STOPPED_NT_SERVICE",
569 "\nPegasus stopped as a Windows service");
570 cout << MessageLoader::getMessage(parms) << endl;
571 exit(0);
572 }
573 else
574 {
575 exit(0);
576 }
577 }
578 else
579 h.sterling 1.1 i++;
580 }
581 else
582 i++;
583 }
584
585 //
586 // Signal ourself as running
587 //
588
|
589 kumpf 1.8 // NOTE: This object must persist for the life of the server process
590 ServerRunStatus serverRunStatus(getProcessName(), getPIDFileName());
591
592 if (!shutdownOption)
593 {
|
594 dave.sudlik 1.9 serverRunStatus.setServerRunning();
|
595 kumpf 1.8 }
|
596 h.sterling 1.1
597 //
598 // Check if already running
599 //
600 // Hmm, when starting as a service, should we do this here (before
601 // starting the control dispatcher)? If we do then the SCM reports
602 // a dumb message to the user. If we don't, and it in the serviceProc
603 // then the service will start up then die silently.
604 //
605
|
606 kumpf 1.8 if (!shutdownOption && serverRunStatus.isServerRunning())
|
607 h.sterling 1.1 {
608 MessageLoaderParms parms(
609 "src.Server.cimserver.UNABLE_TO_START_SERVER_ALREADY_RUNNING",
610 "Unable to start CIMServer.\nCIMServer is already running." );
611 Logger::put(
612 Logger::ERROR_LOG, "CIMServer", Logger::SEVERE,
613 MessageLoader::getMessage(parms) );
614 PEGASUS_STD(cerr) << MessageLoader::getMessage(parms) << PEGASUS_STD(endl);
615 return 1;
616 }
617
618 //
619 // Check if running from a console window. If so then just run
620 // as a console process.
621 //
622
623 char console_title[ _MAX_PATH ] = {0};
624 if( GetConsoleTitle( console_title, _MAX_PATH ) > 0 )
625 {
626 SetConsoleCtrlHandler( ControlHandler, TRUE );
627
|
628 kumpf 1.4 return cimserver_run(argc, argv, shutdownOption, debugOutputOption);
|
629 h.sterling 1.1 }
630
631 //
632 // Run as a service
633 //
634
635 pegasus_service_event = CreateEvent( NULL, FALSE, FALSE, NULL );
636
637 Service::ReturnCode status;
638 status = pegasus_service.Run( cimserver_windows_main );
639
640 if( status != Service::SERVICE_RETURN_SUCCESS )
641 {
642 // todo: put into localized messages when messages unfreezes.
643 Logger::put_l(
644 Logger::ERROR_LOG, "CIMServer", Logger::SEVERE,
645 "src.Server.cimserver_windows.LISTENING_ON_HTTP_PORT",
646 "Error during service run: code = $0.", status );
647 return 1;
648 }
649
650 h.sterling 1.1 return 0;
651 }
|