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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2