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

  1 karl  1.6 //%2005////////////////////////////////////////////////////////////////////////
  2 tony  1.1 //
  3 karl  1.5 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
  4           // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
  5           // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
  6 karl  1.4 // IBM Corp.; EMC Corporation, The Open Group.
  7 karl  1.5 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
  8           // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
  9 karl  1.6 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 10           // EMC Corporation; VERITAS Software Corporation; The Open Group.
 11 tony  1.1 //
 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           // 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: Tony Fiorentino (fiorentino_tony@emc.com)
 31           //
 32 tony  1.1 //%/////////////////////////////////////////////////////////////////////////////
 33           #include <time.h>
 34           #include <stdio.h>
 35           #include <windows.h>
 36           #include <process.h>
 37           
 38           #include "service.h"
 39           
 40           //-------------------------------------------------------------------------
 41           // G L O B A L S
 42           //-------------------------------------------------------------------------
 43           int                    Service::g_argc                  = 0;
 44           char                 **Service::g_argv                  = NULL;
 45           char                  *Service::g_service_name          = NULL;
 46           char                  *Service::g_event_source          = NULL;
 47           DWORD                  Service::g_flags                 = 0;
 48           DWORD                  Service::g_current_state         = 0;
 49           SERVICE_STATUS_HANDLE  Service::g_service_status_handle = 0;
 50           SERVICE_MAIN_T         Service::g_service_main          = NULL;
 51           
 52           //-------------------------------------------------------------------------
 53 tony  1.1 // P U B L I C
 54           //-------------------------------------------------------------------------
 55           Service::Service(void)
 56           {
 57           }
 58           
 59           Service::Service(char *service_name)
 60           {
 61             g_service_name = service_name;
 62           }
 63           
 64           Service::Service(char *service_name, char *event_source)
 65           {
 66             g_event_source = event_source;
 67             g_service_name = service_name;
 68           }
 69           
 70           Service::~Service(void)
 71           {
 72           }
 73           
 74 tony  1.1 /*-------------------------------------------------------------------------*
 75            * Method: Install                                                         *
 76            *                                                                         *
 77            * Args:                                                                   *
 78            *   display_name                                                          *
 79            *     The service's display name (hopefully more descriptive, will show   *
 80            *     up in the Win32 Services MMC snapin as "Service Name").             *
 81            *                                                                         *
 82            *   exe_name:                                                             *
 83            *     The service's executable name (full path, please)                   *
 84            *                                                                         *
 85            *   flags:                                                                *
 86            *     Reserved.  Currently unused.                                        *
 87            *                                                                         *
 88            * Description:                                                            *
 89            *     This function creates the service.                                  *
 90            *                                                                         *
 91            * NOTE: If the process is successfully launched as a Win32 service, this  *
 92            *       function never returns, but calls exit() instead.                 *
 93            *-------------------------------------------------------------------------*/
 94           Service::ReturnCode
 95 tony  1.1 Service::Install(
 96             char  *display_name,
 97             char  *description,
 98             char  *exe_name)
 99           {
100             ReturnCode status = SERVICE_RETURN_SUCCESS;
101             SC_HANDLE sch;
102           
103             if (g_service_name == NULL || display_name == NULL || exe_name == NULL)
104               return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
105             else if ((sch = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL)
106               status = get_error(GetLastError(), "open");
107             else
108               {
109                 SC_HANDLE service = CreateService( 
110                   sch,                       // SCManager database 
111                   g_service_name,            // name of service 
112                   display_name,              // service name to display 
113                   SERVICE_ALL_ACCESS,        // desired access 
114                   SERVICE_WIN32_OWN_PROCESS, // service type 
115                   SERVICE_DEMAND_START,      // start type 
116 tony  1.1         SERVICE_ERROR_NORMAL,      // error control type 
117                   exe_name,                  // service's binary 
118                   NULL,                      // no load ordering group 
119                   NULL,                      // no tag identifier 
120                   NULL,                      // no dependencies 
121                   NULL,                      // LocalSystem account 
122                   NULL);                     // no password 
123            
124                 if (service == NULL) 
125                   {
126                     status = get_error(GetLastError(), "create");
127                     return status;
128                   }
129                 else 
130                   {
131                     change_service_description(service, description);
132                     CloseServiceHandle(service);
133                   }
134             
135                 CloseServiceHandle(sch);
136               }
137 tony  1.1 
138             return status;
139           }
140           
141           /*-------------------------------------------------------------------------*
142            * Method: Remove                                                          *
143            *                                                                         *
144            * Description:                                                            *
145            *     Removes the service.                                                *
146            *-------------------------------------------------------------------------*/
147           Service::ReturnCode
148           Service::Remove(void)
149           {
150             ReturnCode status = SERVICE_RETURN_SUCCESS;
151             SC_HANDLE sch;
152           
153             if (g_service_name == NULL)
154               return SERVICE_ERROR_NOT_FOUND; /* SERVICE_ERROR_NOT_FOUND */
155             else if ((sch = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL)
156               status = get_error(GetLastError(), "open");
157             else
158 tony  1.1     {
159                 SC_HANDLE service = OpenService(sch, g_service_name, DELETE);
160            
161                 if (service == NULL) 
162                   {
163                     status = get_error(GetLastError(), "open");
164                   }
165                 else 
166                   {
167                     if (!DeleteService(service))
168                       {
169                         status = get_error(GetLastError(), "remove");
170                       }
171           
172                     CloseServiceHandle(service);
173                   }
174             
175                 CloseServiceHandle(sch);
176               }
177           
178             return status;
179 tony  1.1 }
180           
181           /*-------------------------------------------------------------------------*
182            * Method: Start                                                           *
183            *                                                                         *
184            * Args:                                                                   *
185            *   wait_time:                                                            *
186            *     The user supplied wait (~1 second per QueryServiceStatus() attempt) *
187            *                                                                         *
188            * Description:                                                            *
189            *     Attempt to start the service.                                       *
190            *-------------------------------------------------------------------------*/
191           Service::ReturnCode
192           Service::Start(int wait_time)
193           {
194             ReturnCode      status = SERVICE_RETURN_SUCCESS;
195             SERVICE_STATUS  service_status;
196             SC_HANDLE       sch;
197           
198             if (g_service_name == NULL)
199               return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
200 tony  1.1   else if ((sch = OpenSCManager(NULL, NULL, GENERIC_READ)) == NULL)
201               status = get_error(GetLastError(), "open");
202             else
203               {
204                 SC_HANDLE service = OpenService(sch, g_service_name, SERVICE_START | SERVICE_QUERY_STATUS);
205            
206                 if (service == NULL) 
207                   status = get_error(GetLastError(), "open");
208 a.dunfey 1.7       else if (!StartService(service, g_argc, (const char **)g_argv))
209 tony     1.1         status = get_error(GetLastError(), "start");
210                    else 
211                      {
212                        int i, max = (wait_time > 0) ? wait_time : 5;
213              
214                        // Loop up to max times waiting for the service 
215                        // state to change to RUNNING
216              
217                        for (i = 0; i < max; i++)
218                          {
219                            if (!QueryServiceStatus(service, &service_status))
220                              {
221                                status = get_error(GetLastError(), "query");
222                                return status; // QUERY_FAIL
223                              }
224              
225                            if (service_status.dwCurrentState == SERVICE_RUNNING)
226                              break;
227              
228                            Sleep(1 * CLOCKS_PER_SEC);
229                          }
230 tony     1.1           
231                        status = (i < max) ? SERVICE_RETURN_SUCCESS : SERVICE_ERROR_REQUEST_TIMEOUT;
232              
233                        CloseServiceHandle(service);
234                      }
235               
236                    CloseServiceHandle(sch); 
237                  }
238              
239                return status;
240              } 
241              
242              /*-------------------------------------------------------------------------*
243               * Method: Stop                                                            *
244               *                                                                         *
245               * Args:                                                                   *
246               *   wait_time:                                                            *
247               *     The user supplied wait (~1 second per QueryServiceStatus() attempt) *
248               *                                                                         *
249               * Description:                                                            *
250               *     Attempt to stop the service.                                        *
251 tony     1.1  *-------------------------------------------------------------------------*/
252              Service::ReturnCode 
253              Service::Stop(int wait_time)
254              {
255                ReturnCode      status = SERVICE_RETURN_SUCCESS;
256                SERVICE_STATUS  service_status;
257                SC_HANDLE       sch;
258              
259                if (g_service_name == NULL)
260                  return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
261                else if ((sch = OpenSCManager(NULL, NULL, GENERIC_READ)) == NULL)
262                  status = get_error(GetLastError(), "open");
263               //   show_error("OpenSCMManager", "service", GetLastError());
264                else
265                  {
266                    SC_HANDLE service = OpenService(sch, g_service_name, SERVICE_STOP | SERVICE_QUERY_STATUS);
267               
268                    if (service == NULL) 
269                      status = get_error(GetLastError(), "open");
270                    else if (!ControlService(service, SERVICE_CONTROL_STOP, &service_status))
271                      status = get_error(GetLastError(), "stop");
272 tony     1.1       else 
273                      {
274                        int i, max = (wait_time > 0) ? wait_time : 5;
275              
276                        // Loop up to max times waiting for the service 
277                        // state to change to STOPPED
278              
279                        for (i = 0; i < max; i++)
280                          {
281                            if (!QueryServiceStatus(service, &service_status))
282                              {
283                                status = get_error(GetLastError(), "query");
284                                return status; // QUERY_FAIL
285                              }
286              
287                            if (service_status.dwCurrentState == SERVICE_STOPPED)
288                              break;
289              
290                            Sleep(1 * CLOCKS_PER_SEC);
291                          }
292                        
293 tony     1.1           status = (i < max) ? SERVICE_RETURN_SUCCESS : SERVICE_ERROR_REQUEST_TIMEOUT;
294              
295                        CloseServiceHandle(service);
296                      }
297               
298                    CloseServiceHandle(sch); 
299                  }
300              
301                return status;
302              }
303              
304              /*-------------------------------------------------------------------------*
305               * Method: Run                                                             *
306               *                                                                         *
307               * Args:                                                                   *
308               *   service_main:                                                         *
309               *     The user supplied service_main function (not to be confused with    *
310               *     real_service_main above)                                            *
311               *                                                                         *
312               *   flags:                                                                *
313               *     Reserved.  Currently unused.                                        *
314 tony     1.1  *                                                                         *
315               * Description:                                                            *
316               *     This function interacts with the SCM to run the current process     *
317               *     as a Win32 service.                                                 *
318               *                                                                         *
319               * NOTE: If the process is successfully launched as a Win32 service, this  *
320               *       function never returns, but calls exit() instead.                 *
321               *-------------------------------------------------------------------------*/
322              
323              Service::ReturnCode 
324              Service::Run(SERVICE_MAIN_T service_main, DWORD flags)
325              {
326                ReturnCode status = SERVICE_RETURN_SUCCESS;
327              
328                SERVICE_TABLE_ENTRY dispatchTable[] = 
329                { 
330                  { g_service_name, real_service_main },
331                  { NULL,         NULL              } 
332                };
333              
334                // Validate the arguments as best we can 
335 tony     1.1 
336                if (g_service_name == NULL || service_main == NULL)
337                  return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
338              
339                // Save parameters in global variables 
340              
341                g_flags        = flags;
342                g_service_main = service_main;
343              
344                // Kick off the service 
345              
346                if (!StartServiceCtrlDispatcher(dispatchTable))
347                  {
348                    status = get_error(GetLastError(), "start");
349                    return status; // FAIL
350                  }
351              
352 s.hills  1.2   // Don't call exit()
353                return status;
354 tony     1.1 }
355              
356              /*-------------------------------------------------------------------------*
357               * Method: GetState                                                        *
358               *                                                                         *
359               * Description:                                                            *
360               *     Returns the state of the service into "state".                      *
361               *-------------------------------------------------------------------------*/
362              Service::ReturnCode 
363              Service::GetState(State *state)
364              {
365                ReturnCode      status = SERVICE_RETURN_SUCCESS;
366                SERVICE_STATUS  service_status;
367                SC_HANDLE       sch;
368              
369                if (g_service_name == NULL)
370                  return SERVICE_ERROR_NOT_FOUND; // SERVICE_ERROR_NOT_FOUND
371                else if ((sch = OpenSCManager(NULL, NULL, GENERIC_READ)) == NULL)
372                  status = get_error(GetLastError(), "open");
373                else
374                  {
375 tony     1.1       SC_HANDLE service = OpenService(sch, g_service_name, SERVICE_QUERY_STATUS);
376               
377                    if (service == NULL) 
378                      status = get_error(GetLastError(), "open");
379                    else if (!QueryServiceStatus(service, &service_status))
380                      status = get_error(GetLastError(), "query");
381                    else
382                      {
383                        *state = get_state(service_status.dwCurrentState);
384                        CloseServiceHandle(service);
385                      }
386                
387                    CloseServiceHandle(sch);
388                  }
389              
390                return status;
391              }
392              
393              /*-------------------------------------------------------------------------*
394               * Method: LogEvent                                                        *
395               *                                                                         *
396 tony     1.1  * Args:                                                                   *
397               *   event_type:                                                           *
398               *     The Win32 event type. Valid event types are:                        *
399               *      EVENTLOG_SUCCESS          : Success event                          *
400               *      EVENTLOG_ERROR_TYPE       : Error event                            *
401               *      EVENTLOG_WARNING_TYPE     : Warning event                          *
402               *      EVENTLOG_INFORMATION_TYPE : Information event                      *
403               *      EVENTLOG_AUDIT_SUCCESS    : Success audit event                    *
404               *      EVENTLOG_AUDIT_FAILURE    : Failure audit event                    *
405               *                                                                         *
406               *   event_id:                                                             *
407               *     A fancy name for error code or error number.                        *
408               *                                                                         *
409               *   string:                                                               *
410               *     String to be logged or merged in with the error string in the       *
411               *     message DLL.                                                        *
412               *                                                                         *
413               * Description:                                                            *
414               *     This function provides a simple layer over the Win32 error logging  *
415               *     API's.                                                              *
416               *                                                                         *
417 tony     1.1  * Returns:                                                                *
418               *     true  if event was successfully logged                              *
419               *     false if the event could not be logged                              *
420               *-------------------------------------------------------------------------*/
421              bool
422              Service::LogEvent(WORD event_type, DWORD event_id, const char *string)
423              {
424                BOOL   status;
425                HANDLE h_event_source = RegisterEventSource(NULL, g_event_source);
426              
427                if (h_event_source == NULL)
428                  FALSE;
429              
430                status = ReportEvent (h_event_source, 
431                                      event_type, 
432                                      0, 
433                                      event_id, 
434                                      NULL, 
435                                      1, 
436                                      0, 
437                                      &string, 
438 tony     1.1                         NULL);
439              
440                DeregisterEventSource(h_event_source);
441              
442                return (status == TRUE) ? true : false;
443              }
444              
445              //-------------------------------------------------------------------------
446              // P R I V A T E
447              //-------------------------------------------------------------------------
448              /*-------------------------------------------------------------------------*
449               * Routine: real_service_main                                              *
450               *                                                                         *
451               * Args:                                                                   *
452               *   argc:                                                                 *
453               *     The number of arguments in the argv array                           *
454               *   argv:                                                                 *
455               *     An array of strings representing the command line arguments         *
456               *                                                                         *
457               * Description:                                                            *
458               *     This function is the real service main (as opposed to the user      *
459 tony     1.1  *     supplied service main, which is called service_main).               *
460               *                                                                         *
461               * Returns:                                                                *
462               *     nothing                                                             *
463               *-------------------------------------------------------------------------*/
464              void __stdcall
465              Service::real_service_main(DWORD argc, LPTSTR *argv)
466              {
467                // Let the SCM know we're alive and kicking
468              
469                report_status(SERVICE_START_PENDING, NO_ERROR, 0, 5000);
470              
471                // If the command line arguments include the string "-debug" then
472                // invoke the debugger
473              
474                if (check_args_for_string("-debug"))
475                  DebugBreak();
476              
477                // Save copy of argc and argc in global variables
478              
479                g_argc = argc;
480 tony     1.1   g_argv = argv;
481              
482                // Start service actions
483              
484                g_service_status_handle = RegisterServiceCtrlHandler (g_service_name, 
485                                                                      service_control_handler);
486              
487                if (g_service_status_handle == 0)
488                  {
489                    show_error("register", "Service Control Handler", GetLastError());
490                    report_status(SERVICE_STOPPED, NO_ERROR, 0, 5000);
491                    return;
492                  }
493              
494                // Change our state to RUNNING, then invoke the user supplied
495                // service_main function. After the user's service_main exits,
496                // change the service state to STOPPED.
497              
498                report_status(SERVICE_RUNNING, NO_ERROR, 0, 5000);
499                g_service_main(STARTUP_FLAG, argc, argv);
500                report_status(SERVICE_STOPPED, NO_ERROR, 0, 5000);
501 tony     1.1 
502                return;
503              }
504              
505              /*-------------------------------------------------------------------------*
506               * Routine: check_args_for_string                                          *
507               *                                                                         *
508               * Args:                                                                   *
509               *   string:                                                               *
510               *     The string to match.                                                *
511               *                                                                         *
512               * Description:                                                            *
513               *     This function iterates through the command line arguments searching *
514               *     for the string specified by the string parameter.                   *
515               *                                                                         *
516               * Returns:                                                                *
517               *     true  if the string was found                                       *
518               *     false if the string was not found                                   *
519               *-------------------------------------------------------------------------*/
520              bool
521              Service::check_args_for_string(char *string)
522 tony     1.1 {
523                int i;
524              
525                for (i = 1; i < g_argc; i++)
526                  {
527                    if (strcmp(g_argv[i], string) == 0)
528                      return true;
529                  }
530              
531                return false;
532              }
533              
534              /*-------------------------------------------------------------------------*
535               * Method: service_control_handler                                         *
536               *                                                                         *
537               * Args:                                                                   *
538               *   control:                                                              *
539               *     The control sent from the SCM telling us what action to take:       *
540               *     start, stop, pause, continue, etc.                                  *
541               *                                                                         *
542               * Description:                                                            *
543 tony     1.1  *     This function handles control messages sent from the SCM. Currently *
544               *     the only message that is handled differently is the STOP message,   *
545               *     which invokes the user's service main function passing to it the    *
546               *     SHUTDOWN_FLAG. The user is then responsible to perform all shutdown *
547               *     related tasks.                                                      *
548               *                                                                         *
549               * Returns:                                                                *
550               *     Nothing                                                             *
551               *-------------------------------------------------------------------------*/
552              
553              void WINAPI
554              Service::service_control_handler(DWORD control)
555              {
556                /* Currently, only the stop contol requires special handling */
557              
558                if (control == SERVICE_CONTROL_STOP)
559                  {
560                    report_status(SERVICE_STOP_PENDING, NO_ERROR, 0, 5000);
561                    g_service_main(SHUTDOWN_FLAG, g_argc, g_argv);
562                    return;
563                  }
564 tony     1.1 
565                /* For every other control, just send back our current state */
566              
567                report_status(g_current_state, NO_ERROR, 0, 5000);
568              }
569              
570              /*-------------------------------------------------------------------------*
571               * Method: report_status                                                   *
572               *                                                                         *
573               * Args:                                                                   *
574               *   current_state:                                                        *
575               *     The service's new state. May be any valid Win32 service state.      *
576               *                                                                         *
577               *   exit_code:                                                            *
578               *     This must be a Win32 exit code. If the server is exiting due to     *
579               *     an error returned from the Win32 API, then this is the place to     *
580               *     report the error status. Most of the time, this will be NO_ERROR.   *
581               *                                                                         *
582               *   check_point:                                                          *
583               *     An integer value that should start at zero and increment as each    *
584               *     discrete step within a phase is completed. For example, if startup  *
585 tony     1.1  *     consists of 3 steps, then the startup will issue its first check-   *
586               *     point of zero, then increment up through and including 2 as each    *
587               *     step is finished.                                                   *
588               *                                                                         *
589               *   wait_hint:                                                            *
590               *     Tells the SCM how long to expect to wait for the next status        *
591               *     update.                                                             *
592               *                                                                         *
593               * Description:                                                            *
594               *     This function provides an even higher level of abstraction over     *
595               *     the Win32 event logging API's.                                      *
596               *                                                                         *
597               * Returns:                                                                *
598               *     true  if the status was successfully reported                       *
599               *     false if the status could not be reported                           *
600               *-------------------------------------------------------------------------*/
601              bool
602              Service::report_status(
603                DWORD current_state, 
604                DWORD exit_code, 
605                DWORD check_point, 
606 tony     1.1   DWORD wait_hint)
607              {
608                SERVICE_STATUS current_status = 
609                {
610                  SERVICE_WIN32,
611                  current_state,
612                  SERVICE_CONTROL_INTERROGATE,
613                  exit_code,
614                  0,
615                  check_point,
616                  wait_hint
617                };
618              
619                /* Wait until we're started before we accept a stop control */
620              
621                if (current_state == SERVICE_RUNNING)
622                  current_status.dwControlsAccepted += SERVICE_ACCEPT_STOP;
623              
624                /* Save new state */
625              
626                g_current_state = current_state;
627 tony     1.1   
628                return (SetServiceStatus(g_service_status_handle, &current_status) == TRUE) ? true : false;
629              }
630              
631              /*-------------------------------------------------------------------------*
632               * Method: change_service_description                                      *
633               *                                                                         *
634               * Args:                                                                   *
635               *   service:                                                              *
636               *     Handle to the service                                               *
637               *                                                                         *
638               *   description:                                                          *
639               *     The service's description                                           *
640               *                                                                         *
641               * Description:                                                            *
642               *     This function sets the description for the service. The description *
643               *     text shows up in the Services mmc snapin. The description is added  *
644               *     as a benefit to users, but does not affect the service's operation. *
645               *     Therefore, if this function should fail for any reason, there is    *
646               *     no need to stop. That's why this function has no return value.      *
647               *                                                                         *
648 tony     1.1  * Returns:                                                                *
649               *     Nothing                                                             *
650               *                                                                         *
651               * Notes:                                                                  *
652               *     This function uses the ChangeServiceConfig2() API function which    *
653               *     first appeared in Windows2000. Therefore, this code checks the      *
654               *     OS version, before calling ChangeServiceConfig2().                  *
655               *-------------------------------------------------------------------------*/
656              void 
657              Service::change_service_description(SC_HANDLE service, char *description)
658              {
659                OSVERSIONINFO osvi;
660              
661                /* 
662                 *  Test for Windows 2000 or greater
663                 */ 
664                
665                osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
666              
667                if (GetVersionEx(&osvi) != 0                      && 
668                    osvi.dwPlatformId    == VER_PLATFORM_WIN32_NT && 
669 tony     1.1       osvi.dwMajorVersion  >= 5)
670                  {
671                    typedef BOOL (WINAPI *CHANGE_SERVICE_CONFIG2_T)(SC_HANDLE, DWORD, LPVOID);
672              
673                    HINSTANCE hdll = LoadLibrary("advapi32.dll");
674              
675                    if (hdll != NULL)
676                      {
677                        SERVICE_DESCRIPTION      sd;
678                        CHANGE_SERVICE_CONFIG2_T csc;
679              
680                        csc = (CHANGE_SERVICE_CONFIG2_T) GetProcAddress(hdll, "ChangeServiceConfig2A");
681              
682                        if (csc)
683                          {
684                            sd.lpDescription = description;
685                            csc(service, SERVICE_CONFIG_DESCRIPTION, &sd);
686                          }
687              
688                        FreeLibrary(hdll);
689                      }
690 tony     1.1     }
691              }
692              
693              /*-------------------------------------------------------------------------*
694               * Method: show_error                                                      *
695               *                                                                         *
696               * Args:                                                                   *
697               *   action:                                                               *
698               *     A single verb decribing the action going on when the error          *
699               *     occurred. For example, "opening", "creating", etc.                  *
700               *                                                                         *
701               *   object:                                                               *
702               *     Description of the object on which was action occurred. Examples    *
703               *     are "file", "service", etc.                                         *
704               *                                                                         *
705               *   hr:                                                                   *
706               *     The error status. Can be an hresult, or Win32 error status.         *
707               *                                                                         *
708               * Description:                                                            *
709               *     This function provides an even higher level of abstraction over     *
710               *     the Win32 event logging API's.                                      *
711 tony     1.1  *                                                                         *
712               * Returns:                                                                *
713               *     true  if event was successfully logged                              *
714               *     false if the event could not be logged                              *
715               *-------------------------------------------------------------------------*/
716              bool
717              Service::show_error(const char *action, const char *object, DWORD hr)
718              {
719                char console_title[_MAX_PATH] = {0};
720                char  txt[_MAX_PATH]          = "";
721                char  msg[_MAX_PATH]          = "";
722                DWORD nchars;
723              
724                nchars = FormatMessage(
725                  FORMAT_MESSAGE_FROM_SYSTEM,
726                  NULL,
727                  hr,
728                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
729                  msg,
730                  sizeof(msg),
731                  NULL);
732 tony     1.1 
733                if (nchars == 0) 
734                  sprintf(msg, "Unknown error code - %%X%x", hr);
735                else if (nchars > 1)
736                  {
737                    if (msg[nchars - 1] == '\n') msg[nchars - 1] = '\0';
738                    if (msg[nchars - 2] == '\r') msg[nchars - 2] = '\0';
739                  }
740              
741                sprintf(txt, "Failed to %s %s %s. Reason: %s", action, object, g_service_name, msg);
742              
743                // Running from a console window
744                // send courtesy message txt to stderr
745                if (GetConsoleTitle(console_title, _MAX_PATH) > 0)
746                  {
747 s.hills  1.3       PEGASUS_STD(cerr) << txt << PEGASUS_STD(endl);
748 tony     1.1     }
749              
750                return LogEvent(EVENTLOG_ERROR_TYPE, 1, txt);
751              }
752              
753              Service::State
754              Service::get_state(DWORD scm_state)
755              {
756                return (State)scm_state;
757              }
758              
759              Service::ReturnCode 
760              Service::get_error(DWORD error_status, const char *action)
761              {
762                switch (error_status)
763                  {
764                  /*
765                    // INFO: Could add cases to suppress error message.
766                    case ERROR_SERVICE_DOES_NOT_EXIST:
767                    case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:
768                      break;
769 tony     1.1     */
770                    case SERVICE_RETURN_SUCCESS:
771                      break;
772              
773                    default:
774                      show_error(action, "service", error_status); 
775                      break;
776                  }
777                return (ReturnCode)error_status;
778              }
779              

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2