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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2