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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2