(file) Return to ServerProcessWindows.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Service

  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                 }

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2