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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2