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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2