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