"Fossies" - the Fresh Open Source Software Archive

Member "zebedee-2.5.3/service.c" (12 Apr 2001, 13750 Bytes) of package /linux/privat/old/zebedee-2.5.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "service.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2 ** This file is part of "zebedee"
    3 **
    4 ** Copyright 1999 by Neil Winton. All rights reserved.
    5 ** 
    6 ** This program is free software; you can redistribute it and/or modify
    7 ** it under the terms of the GNU General Public License as published by
    8 ** the Free Software Foundation; either version 2 of the License, or
    9 ** (at your option) any later version.
   10 **
   11 ** This program is distributed in the hope that it will be useful,
   12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 ** GNU General Public License for more details.
   15 **
   16 ** You should have received a copy of the GNU General Public License
   17 ** along with this program; if not, write to the Free Software
   18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   19 **
   20 ** $Id: service.c,v 1.1.1.1 2001/04/12 18:07:12 ndwinton Exp $
   21 **
   22 ** $Log: service.c,v $
   23 ** Revision 1.1.1.1  2001/04/12 18:07:12  ndwinton
   24 ** Imported source of Zebedee 2.2.1
   25 **
   26 ** Revision 1.2  2000/01/08 21:35:22  nwinton
   27 ** Version 1.3.0
   28 **
   29 ** Revision 1.1  1999/09/24 20:20:58  nwinton
   30 ** Cleanup of compiler warnings
   31 **
   32 ** Revision 1.0  1999/09/18 21:35:06  nwinton
   33 ** Initial revision
   34 **
   35 */
   36 
   37 #include <windows.h>
   38 #include <stdio.h>
   39 #include <stdlib.h>
   40 #include <process.h>
   41 
   42 char *service_c_rcsid = "$Id: service.c,v 1.1.1.1 2001/04/12 18:07:12 ndwinton Exp $";
   43 
   44 extern void message(unsigned short, int, char *, ...);
   45 
   46 #define MAX_BUF_SIZE    2048
   47 
   48 HANDLE          SvcFinishEvent = NULL;
   49 SERVICE_STATUS      SvcStatus;  /* Current status of service */
   50 SERVICE_STATUS_HANDLE   SvcStatusHandle;
   51 DWORD           SvcError;
   52 HANDLE          SvcThreadHandle = NULL;
   53 char            *SvcName = NULL;
   54 VOID            (*SvcFunction)(VOID *) = NULL;
   55 VOID            *SvcArg = NULL;
   56 
   57 DWORD   svcPlatform(void);
   58 VOID    svcRun(char *name, VOID (*function)(VOID *), VOID *arg);
   59 VOID    svcRun9X(char *name);
   60 VOID    svcRunNT(char *name);
   61 VOID    svcMain(DWORD argc, LPTSTR *argv);
   62 VOID    svcControl(DWORD ctrlCode);
   63 BOOL    svcReport(DWORD currentState, DWORD exitCode, DWORD checkPoint,
   64           DWORD waitHint);
   65 VOID    svcStop(LPTSTR msg);
   66 int svcInstall(char *name, char *configFile);
   67 int svcInstall9X(char *name, char *configFile);
   68 int svcInstallNT(char *name, char *configFile);
   69 int svcRemove(char *name);
   70 int svcRemove9X(char *name);
   71 int svcRemoveNT(char *name);
   72 
   73 
   74 DWORD
   75 svcPlatform(void)
   76 {
   77     OSVERSIONINFO info;
   78 
   79     info.dwOSVersionInfoSize = sizeof(info);
   80     if (!GetVersionEx(&info))
   81     {
   82     message(0, 0, "can't get OS version info");
   83     return 0;
   84     }
   85     return info.dwPlatformId;
   86 }
   87 
   88 VOID
   89 svcRun(char *name, VOID (*function)(VOID *), VOID *arg)
   90 {
   91     DWORD platform = svcPlatform();
   92 
   93     SvcName = name;
   94     SvcFunction = function;
   95     SvcArg = arg;
   96 
   97     switch (platform)
   98     {
   99     case VER_PLATFORM_WIN32_WINDOWS:
  100     svcRun9X(name);
  101     break;
  102 
  103     case VER_PLATFORM_WIN32_NT:
  104     svcRunNT(name);
  105     break;
  106 
  107     default:
  108     message(0, 0, "unsupported OS platform (type %d)", platform);
  109     break;
  110     }
  111 }
  112 
  113 VOID
  114 svcRunNT(char *name)
  115 {
  116     SERVICE_TABLE_ENTRY dispatchTable[] = {
  117         { TEXT(name), (LPSERVICE_MAIN_FUNCTION)svcMain },
  118         { NULL, NULL }
  119     };
  120 
  121     if (!StartServiceCtrlDispatcher(dispatchTable))
  122     {
  123         svcStop("StartServiceCtrlDispatcher failed");
  124     }
  125 }
  126 
  127 VOID
  128 svcRun9X(char *name)
  129 {
  130     HINSTANCE kernelDll;
  131     DWORD (*regFn)(void *, DWORD);
  132 
  133 
  134     /* Obtain a handle to the kernel library */
  135 
  136     if ((kernelDll = LoadLibrary("KERNEL32.DLL")) == NULL)
  137     {
  138     message(0, 0, "can't get handle to kernel library");
  139     return;
  140     }
  141 
  142     /* Find the address of the RegisterServiceProcess function */
  143 
  144     regFn = (DWORD (*)(void *, DWORD))GetProcAddress(kernelDll, "RegisterServiceProcess");
  145     if (regFn == NULL)
  146     {
  147     message(0, 0, "can't get the address of RegisterServiceProcess()");
  148     return;
  149     }
  150             
  151     /* Register this process with the OS as a service */
  152 
  153     if ((*regFn)(NULL, 1 /* RSP_SIMPLE_SERVICE */) == 0)
  154     {
  155     message(0, 0, "failed to register service process");
  156     exit(EXIT_FAILURE);
  157     }
  158 
  159     /* Run the main routine */
  160 
  161     (*SvcFunction)(SvcArg);
  162 
  163     /* Unregister the process */
  164 
  165     if ((*regFn)(NULL, 0 /* RSP_UNREGISTER_SERVICE */) == 0)
  166     {
  167     message(0, 0, "failed to unregister service process");
  168     exit(EXIT_FAILURE);
  169     }
  170 
  171     /* Free the kernel library */
  172 
  173     FreeLibrary(kernelDll);
  174 
  175     exit(EXIT_SUCCESS);
  176 }
  177 
  178 /*
  179 **  svcMain
  180 **
  181 ** This function starts the service worker thread proper. It then waits
  182 ** for the worker to terminate.
  183 **
  184 */
  185 
  186 VOID
  187 svcMain(DWORD argc, LPTSTR *argv)
  188 {
  189     DWORD   wait;
  190 
  191 
  192     /* Register the control handler */
  193 
  194     SvcStatusHandle = RegisterServiceCtrlHandler(TEXT(SvcName),
  195                          (LPHANDLER_FUNCTION)svcControl);
  196     if (!SvcStatusHandle)
  197     {
  198     message(0, 0, "failed to register service control handler");
  199     goto finish;
  200     }
  201 
  202     /* Initialise static service status values */
  203 
  204     SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  205     SvcStatus.dwServiceSpecificExitCode = 0;
  206 
  207     /* Report to SCM */
  208 
  209     if (!svcReport(SERVICE_START_PENDING,   /* Service state */
  210            NO_ERROR,            /* Exit code */
  211            1,               /* Checkpoint number */
  212            5000))           /* Wait hint -- 5 secs */
  213     {
  214     message(0, 0, "failed to report status to SCM");
  215     goto finish;
  216     }
  217 
  218     /*
  219     ** Create the "stop event" object. The arguments indicate a manually
  220     ** reset event whose initial state is unset.
  221     */
  222 
  223     if ((SvcFinishEvent = CreateEvent(NULL, 1, 0, NULL)) == NULL)
  224     {
  225     goto finish;
  226     }
  227 
  228     /* Report next checkpoint to SCM */
  229 
  230     if (!svcReport(SERVICE_START_PENDING, NO_ERROR, 2, 5000))
  231     {
  232     message(0, 0, "failed to report status to SCM");
  233     goto finish;
  234     }
  235 
  236     /* Start the worker thread */
  237 
  238     SvcThreadHandle = (HANDLE)_beginthread(SvcFunction, 65536, SvcArg);
  239     if (!SvcThreadHandle)
  240     {
  241     message(0, 0, "failed to create worker thread");
  242     goto finish;
  243     }
  244 
  245     /* Report all systems GO! */
  246 
  247     if (!svcReport(SERVICE_RUNNING, NO_ERROR, 0, 0))
  248     {
  249     message(0, 0, "failed to report status to SCM");
  250         goto finish;
  251     }
  252 
  253     /* Wait until SvcFinishEvent is set */
  254 
  255     wait = WaitForSingleObject(SvcFinishEvent, INFINITE);
  256 
  257 finish:
  258     if (SvcFinishEvent != NULL)
  259     {
  260     CloseHandle(SvcFinishEvent);
  261     }
  262 
  263     /* Report to SCM if possible */
  264 
  265     if (SvcStatusHandle != 0)
  266     {
  267     svcReport(SERVICE_STOPPED, SvcError, 0, 0);
  268     }
  269 
  270     return;
  271 }
  272 
  273 /*
  274 ** svcControl
  275 **
  276 ** Handle SCM service control requests
  277 */
  278 
  279 VOID
  280 svcControl(DWORD code)
  281 {
  282     DWORD  state = SERVICE_RUNNING;
  283  
  284 
  285     switch(code)
  286     {
  287     case SERVICE_CONTROL_PAUSE:
  288     if (SvcStatus.dwCurrentState == SERVICE_RUNNING)
  289     {
  290         SuspendThread(SvcThreadHandle);
  291         state = SERVICE_PAUSED;
  292     }
  293         break;
  294 
  295     case SERVICE_CONTROL_CONTINUE:
  296     if (SvcStatus.dwCurrentState == SERVICE_PAUSED)
  297     {
  298         ResumeThread(SvcThreadHandle);
  299         state = SERVICE_RUNNING;
  300     }
  301     break;
  302 
  303     case SERVICE_CONTROL_STOP:
  304     state = SERVICE_STOP_PENDING;
  305     svcReport(SERVICE_STOP_PENDING, NO_ERROR, 1, 5000);
  306     SetEvent(SvcFinishEvent);
  307     return;
  308 
  309     case SERVICE_CONTROL_INTERROGATE:
  310     break;
  311 
  312     default:
  313     break;
  314     }
  315 
  316     svcReport(state, NO_ERROR, 0, 0);
  317 }
  318 
  319 /*
  320 ** svcReport
  321 **
  322 ** Update the SCM with the current state of the service.
  323 */
  324 
  325 BOOL
  326 svcReport(DWORD currentState, DWORD exitCode, DWORD checkPoint, DWORD waitHint)
  327 {
  328     BOOL result;
  329 
  330     /* Disable control requests while starting */
  331 
  332     if (currentState == SERVICE_START_PENDING)
  333     {
  334     SvcStatus.dwControlsAccepted = 0;
  335     }
  336     else
  337     {
  338     SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  339                        SERVICE_ACCEPT_PAUSE_CONTINUE;
  340     }
  341 
  342     SvcStatus.dwCurrentState = currentState;
  343     SvcStatus.dwWin32ExitCode = exitCode;
  344     SvcStatus.dwCheckPoint = checkPoint;
  345     SvcStatus.dwWaitHint = waitHint;
  346 
  347     /* Make the report */
  348 
  349     if (!(result = SetServiceStatus(SvcStatusHandle, &SvcStatus)))
  350     {
  351     /* If there is an error then bail out */
  352     svcStop("SetServiceStatus failed!");
  353     }
  354 
  355     return result;
  356 }
  357 
  358 /*
  359 ** svcStop
  360 **
  361 ** Report an error and stop the service
  362 */
  363 
  364 VOID
  365 svcStop(LPTSTR msg)
  366 {
  367     SvcError = GetLastError();
  368 
  369     message(0, 0, "failed in Win32 service routines: code %#0x", SvcError);
  370 
  371     /* Signal the main routine to finish */
  372 
  373     SetEvent(SvcFinishEvent);
  374 }
  375 
  376 int
  377 svcInstall(char *name, char *configFile)
  378 {
  379     const char *runArg = "-Srun";
  380     char path[MAX_BUF_SIZE];
  381     char cmd[MAX_BUF_SIZE];
  382     const char *flag = "-f";
  383     const char *quote = "\"";
  384     DWORD platform = svcPlatform();
  385 
  386 
  387     if (configFile == NULL)
  388     {
  389     flag = "";
  390     quote = "";
  391     configFile = "";
  392     }
  393 
  394     /*
  395     ** Get the filename of the running executable. We need to leave
  396     ** space in the buffer for additional arguments, whitespace and
  397     ** quotes ...
  398     */
  399 
  400     if (GetModuleFileName(NULL, path,
  401               MAX_BUF_SIZE - (strlen(configFile) + 20)) == 0)
  402     {
  403     message(0, 0, "can't get executable path");
  404     return EXIT_FAILURE;
  405     }
  406 
  407     /*
  408     ** Build the command string. If a config file was specified
  409     ** this will be of the form:
  410     **
  411     **  "program path" -f "config file" -Srun
  412     */
  413 
  414     sprintf(cmd, "\"%s\" %s %s%s%s %s", path,
  415         flag, quote, configFile, quote, runArg);
  416 
  417     switch (platform)
  418     {
  419     case VER_PLATFORM_WIN32_WINDOWS:
  420     return svcInstall9X(name, cmd);
  421     break;
  422 
  423     case VER_PLATFORM_WIN32_NT:
  424     return svcInstallNT(name, cmd);
  425     break;
  426 
  427     default:
  428     message(0, 0, "unsupported OS platform (type %d)", platform);
  429     break;
  430     }
  431     return EXIT_FAILURE;
  432 }
  433 
  434 int
  435 svcInstallNT(char *name, char *cmd)
  436 {
  437     SC_HANDLE svcHandle;
  438     SC_HANDLE scmHandle;
  439 
  440 
  441     /* Open the local SCM database */
  442 
  443     if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL)
  444     {
  445     message(0, 0, "can't open SCM database");
  446     return EXIT_FAILURE;
  447     }
  448 
  449     /* Now create the service entry */
  450 
  451     svcHandle = CreateService(scmHandle,    /* SCM database handle */
  452                   name,     /* Name of service */
  453                   name,     /* Display name */
  454                   SERVICE_ALL_ACCESS,   /* Desired access */
  455                   SERVICE_WIN32_OWN_PROCESS,/* Run in own process */
  456                   SERVICE_AUTO_START,   /* Start during boot */
  457                   SERVICE_ERROR_NORMAL, /* Show message but continue boot */
  458                   cmd,      /* Program plus arguments */
  459                   NULL,     /* No load ordering group */
  460                   NULL,     /* No tag identifier */
  461                   NULL,     /* No dependencies */
  462                   NULL,     /* Use LocalSystem account */
  463                   NULL);        /* No password */
  464     CloseServiceHandle(scmHandle);
  465 
  466     if (svcHandle == NULL)
  467     {
  468     message(0, 0, "can't create service");
  469     return EXIT_FAILURE;
  470     }
  471 
  472     CloseServiceHandle(svcHandle);
  473 
  474     message(1, 0, "%s service installed to run '%s'", name, cmd);
  475 
  476     return EXIT_SUCCESS;
  477 }
  478 
  479 int
  480 svcInstall9X(char *name, char *cmd)
  481 {
  482     HKEY    runKey;
  483 
  484 
  485     /* Open RunServices registry key */
  486 
  487     if (RegCreateKey(HKEY_LOCAL_MACHINE,
  488              "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
  489              &runKey) != ERROR_SUCCESS)
  490     {
  491     message(0, 0, "can't locate registry key");
  492     return EXIT_FAILURE;
  493     }
  494 
  495     /* Add value for this service */
  496 
  497     if (RegSetValueEx(runKey, name, 0, REG_SZ, cmd, strlen(cmd) + 1) != ERROR_SUCCESS)
  498     {
  499     RegCloseKey(runKey);
  500     message(0, 0, "failed to add value to registry");
  501     return EXIT_FAILURE;
  502     }
  503 
  504     RegCloseKey(runKey);
  505 
  506     message(1, 0, "%s service installed to run '%s'", name, cmd);
  507 
  508     return EXIT_SUCCESS;
  509 }
  510 
  511 int
  512 svcRemove(char *name)
  513 {
  514     DWORD platform = svcPlatform();
  515 
  516 
  517     switch (platform)
  518     {
  519     case VER_PLATFORM_WIN32_WINDOWS:
  520     return svcRemove9X(name);
  521     break;
  522 
  523     case VER_PLATFORM_WIN32_NT:
  524     return svcRemoveNT(name);
  525     break;
  526 
  527     default:
  528     message(0, 0, "unsupported OS platform (type %d)", platform);
  529     break;
  530     }
  531 
  532     return EXIT_FAILURE;
  533 }
  534 
  535 int
  536 svcRemoveNT(char *name)
  537 {
  538     SC_HANDLE   svcHandle;
  539     SC_HANDLE   scmHandle;
  540     SERVICE_STATUS status;
  541     int     retStatus = EXIT_SUCCESS;
  542 
  543 
  544     /* Open the SCM */
  545 
  546     if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) != NULL)
  547     {
  548     svcHandle = OpenService(scmHandle, name, SERVICE_ALL_ACCESS);
  549 
  550     if (svcHandle != NULL)
  551     {
  552         /* Try to stop the service */
  553 
  554         if (ControlService(svcHandle, SERVICE_CONTROL_STOP, &status))
  555         {
  556         while (QueryServiceStatus(svcHandle, &status))
  557         {
  558             if (status.dwCurrentState == SERVICE_STOP_PENDING)
  559             {
  560             Sleep(1000);
  561             }
  562             else
  563             {
  564             break;
  565             }
  566         }
  567 
  568         if (status.dwCurrentState != SERVICE_STOPPED)
  569         {
  570             message(0, 0, "failed to stop the '%s' service", name);
  571             retStatus = EXIT_FAILURE;
  572         }
  573         }
  574 
  575         /* Now remove the service from the SCM */
  576 
  577         if (DeleteService(svcHandle))
  578         {
  579         message(1, 0, "successfully removed the '%s' service", name);
  580         }
  581         else
  582         {
  583         message(0, 0, "failed to remove the '%s' service", name);
  584         retStatus = EXIT_FAILURE;
  585         }
  586 
  587         CloseServiceHandle(svcHandle);
  588     }
  589     else
  590     {
  591         message(0, 0, "can't find the '%s' service", name);
  592         retStatus = EXIT_FAILURE;
  593     }
  594 
  595     CloseServiceHandle(scmHandle);
  596     }
  597     else
  598     {
  599     message(0, 0, "can't contact Service Control Manager");
  600     retStatus = EXIT_FAILURE;
  601     }
  602 
  603     return retStatus;
  604 }
  605 
  606 
  607 int
  608 svcRemove9X(char *name)
  609 {
  610     HKEY runKey;
  611     int status = EXIT_SUCCESS;
  612 
  613 
  614     /* Locate the RunServices registry entry */
  615 
  616     if (RegOpenKey(HKEY_LOCAL_MACHINE, 
  617            "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
  618            &runKey) != ERROR_SUCCESS)
  619     {
  620     message(0, 0, "can't find the RunServices registry key");
  621     status = EXIT_FAILURE;
  622     }
  623     else
  624     {
  625     /* Delete the key value for our service */
  626 
  627     if (RegDeleteValue(runKey, name) != ERROR_SUCCESS)
  628     {
  629         message(0, 0, "failed to delete registry RunServices entry for '%s'", name);
  630         status = EXIT_FAILURE;
  631     }
  632     else
  633     {
  634         message(1, 0, "successfully removed the '%s' service", name);
  635     }
  636 
  637     RegCloseKey(runKey);
  638     }
  639 
  640     return status;
  641 }