stoddard    99/04/08 13:26:28

  Modified:    src/main http_main.c
               src/os/win32 registry.c registry.h service.c service.h
  Log:
  Win32 multiple services patch. Documentation to follow.
  Submitted by: Keith Wannamaker
  Reviewed by: Bill Stoddard, Ken Parzygnat
  
  Revision  Changes    Path
  1.428     +216 -66   apache-1.3/src/main/http_main.c
  
  Index: http_main.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/main/http_main.c,v
  retrieving revision 1.427
  retrieving revision 1.428
  diff -u -r1.427 -r1.428
  --- http_main.c       1999/03/17 23:05:43     1.427
  +++ http_main.c       1999/04/08 20:26:24     1.428
  @@ -180,6 +180,10 @@
   #ifdef WIN32
   #include "../os/win32/service.h"
   #include "../os/win32/registry.h"
  +#define DEFAULTSERVICENAME "Apache"
  +#define PATHSEPARATOR '\\'
  +#else
  +#define PATHSEPARATOR '/'
   #endif
   
   
  @@ -984,6 +988,9 @@
   #endif
       fprintf(stderr, "       %s [-C \"directive\"] [-c \"directive\"]\n", 
pad);
       fprintf(stderr, "       %s [-v] [-V] [-h] [-l] [-L] [-S] [-t]\n", pad);
  +#ifdef WIN32
  +    fprintf(stderr, "       %s [-n service] [-k signal] [-i] [-u]\n", pad);
  +#endif
       fprintf(stderr, "Options:\n");
   #ifdef SHARED_CORE
       fprintf(stderr, "  -R directory     : specify an alternate location for 
shared object files\n");
  @@ -1001,8 +1008,12 @@
       fprintf(stderr, "  -S               : show parsed settings (currently 
only vhost settings)\n");
       fprintf(stderr, "  -t               : run syntax test for configuration 
files only\n");
   #ifdef WIN32
  +    fprintf(stderr, "  -n name          : set service name and use its 
ServerConfigFile\n");
       fprintf(stderr, "  -k shutdown      : tell running Apache to 
shutdown\n");
       fprintf(stderr, "  -k restart       : tell running Apache to do a 
graceful restart\n");
  +    fprintf(stderr, "  -k start         : tell Apache to start\n");
  +    fprintf(stderr, "  -i               : install an Apache service\n");
  +    fprintf(stderr, "  -u               : uninstall an Apache service\n");
   #endif
       exit(1);
   }
  @@ -3465,7 +3476,7 @@
    * some of it is #ifdef'd but was duplicated before anyhow.  This stuff
    * is still a mess.
    */
  -static void common_init(void)
  +void common_init(void)
   {
       INIT_SIGLIST()
   #ifdef AUX3
  @@ -4485,7 +4496,7 @@
   
       common_init();
       
  -    if ((s = strrchr(argv[0], '/')) != NULL) {
  +    if ((s = strrchr(argv[0], PATHSEPARATOR)) != NULL) {
        ap_server_argv0 = ++s;
       }
       else {
  @@ -5434,7 +5445,13 @@
   {
       char buf[40], mod[200];
       int i, rv;
  -    char **pass_argv = (char **) alloca(sizeof(char *) * (argc + 3));
  +
  +#ifdef WIN32
  +#define NUMCHILDARGS  4
  +#else
  +#define NUMCHILDARGS  2
  +#endif
  +    char **pass_argv = (char **) alloca(sizeof(char *) * (argc + 
NUMCHILDARGS + 1));
       
       /* We need an event to tell the child process to kill itself when
        * the parent is doing a shutdown/restart. This will be named
  @@ -5456,10 +5473,14 @@
       pass_argv[0] = argv[0];
       pass_argv[1] = "-Z";
       pass_argv[2] = buf;
  +#ifdef WIN32
  +    pass_argv[3] = "-f";
  +    pass_argv[4] = ap_server_confname;
  +#endif
       for (i = 1; i < argc; i++) {
  -     pass_argv[i + 2] = argv[i];
  +        pass_argv[i + NUMCHILDARGS] = argv[i];
       }
  -    pass_argv[argc + 2] = NULL;
  +    pass_argv[argc + NUMCHILDARGS] = NULL;
   
       rv = GetModuleFileName(NULL, mod, sizeof(mod));
       if (rv == sizeof(mod)) {
  @@ -5533,8 +5554,47 @@
       return 0;
   }
   
  +/* To share the semaphores with other processes, we need a NULL ACL
  + * Code from MS KB Q106387
  + */
  +
  +static PSECURITY_ATTRIBUTES GetNullACL()
  +{
  +    PSECURITY_DESCRIPTOR pSD;
  +    PSECURITY_ATTRIBUTES sa;
  +
  +    sa  = (PSECURITY_ATTRIBUTES) LocalAlloc(LPTR, sizeof 
(SECURITY_ATTRIBUTES));
  +    pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, 
SECURITY_DESCRIPTOR_MIN_LENGTH);
  +    if (pSD == NULL || sa == NULL)
  +        return NULL;
  +    if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
  +        LocalFree( pSD );
  +        LocalFree( sa );
  +        return NULL;
  +    }
  +    if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE)) {
  +        LocalFree( pSD );
  +        LocalFree( sa );
  +        return NULL;
  +    }
  +    sa->nLength = sizeof(sa);
  +    sa->lpSecurityDescriptor = pSD;
  +    sa->bInheritHandle = TRUE;
  +    return sa;
  +}
  +
  +
  +static void CleanNullACL( void *sa ) {
  +    if( sa ) {
  +        LocalFree( ((PSECURITY_ATTRIBUTES)sa)->lpSecurityDescriptor);
  +        LocalFree( sa );
  +    }
  +}
  +
   int master_main(int argc, char **argv)
   {
  +    /* returns NULL if invalid (Win95?) */
  +    PSECURITY_ATTRIBUTES sa = GetNullACL();
       int nchild = ap_daemons_to_start;
       event **ev;
       int *child;
  @@ -5560,20 +5620,23 @@
                "ap%d", getpid());
       setup_signal_names(signal_prefix_string);
   
  -    signal_shutdown_event = CreateEvent(NULL, TRUE, FALSE, 
signal_shutdown_name);
  +    signal_shutdown_event = CreateEvent(sa, TRUE, FALSE, 
signal_shutdown_name);
       if (!signal_shutdown_event) {
        ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf,
                    "Cannot create shutdown event %s", signal_shutdown_name);
  +        CleanNullACL((void *)sa);
        exit(1);
       }
       APD2("master_main: created event %s", signal_shutdown_name);
  -    signal_restart_event = CreateEvent(NULL, TRUE, FALSE, 
signal_restart_name);
  +    signal_restart_event = CreateEvent(sa, TRUE, FALSE, signal_restart_name);
       if (!signal_restart_event) {
        CloseHandle(signal_shutdown_event);
        ap_log_error(APLOG_MARK, APLOG_EMERG|APLOG_WIN32ERROR, server_conf,
                    "Cannot create restart event %s", signal_restart_name);
  +        CleanNullACL((void *)sa);
        exit(1);
       }
  +    CleanNullACL((void *)sa);
       APD2("master_main: created event %s", signal_restart_name);
   
       start_mutex = ap_create_mutex(signal_prefix_string);
  @@ -5774,7 +5837,7 @@
    * either "shutdown" or "restart"
    */
   
  -void send_signal(pool *p, char *signal)
  +int send_signal(pool *p, char *signal)
   {
       char prefix[20];
       FILE *fp;
  @@ -5787,7 +5850,7 @@
       fp = fopen(fname, "r");
       if (!fp) {
        printf("Cannot read apache PID file %s\n", fname);
  -     return;
  +        return FALSE;
       }
       prefix[0] = 'a';
       prefix[1] = 'p';
  @@ -5796,7 +5859,7 @@
       if (nread == 0) {
        fclose(fp);
        printf("PID file %s was empty\n", fname);
  -     return;
  +        return FALSE;
       }
       fclose(fp);
   
  @@ -5812,13 +5875,40 @@
        ap_start_shutdown();
       else if (!strcasecmp(signal, "restart"))
        ap_start_restart(1);
  -    else
  +    else {
        printf("Unknown signal name \"%s\". Use either shutdown or restart.\n",
            signal);
  +        return FALSE;
  +    }
  +    return TRUE;
  +}
   
  -    return;
  +void post_parse_init()
  +{
  +    ap_set_version();
  +    ap_init_modules(pconf, server_conf);
  +    ap_suexec_enabled = init_suexec();
  +    version_locked++;
  +    ap_open_logs(server_conf, pconf);
  +    set_group_privs();
   }
   
  +int service_init()
  +{
  +    common_init();
  + 
  +    ap_cpystrn(ap_server_root, HTTPD_ROOT, sizeof(ap_server_root));
  +    if (ap_registry_get_service_conf(pconf, ap_server_confname, 
sizeof(ap_server_confname),
  +                                     ap_server_argv0))
  +        return FALSE;
  +
  +    ap_setup_prelinked_modules();
  +    server_conf = ap_read_config(pconf, ptrans, ap_server_confname);
  +    ap_log_pid(pconf, ap_pid_fname);
  +    post_parse_init();
  +    return TRUE;
  +}
  +
   #ifdef WIN32
   __declspec(dllexport)
        int apache_main(int argc, char *argv[])
  @@ -5829,41 +5919,45 @@
       int c;
       int child = 0;
       char *cp;
  -    int run_as_service = 1;
  +    char *s;
  +    char *service_name = NULL;
       int install = 0;
       int configtestonly = 0;
  +    int conf_specified = 0;
       char *signal_to_send = NULL;
  -    char *s;
  -    
  -    common_init();
  +    char cwd[MAX_STRING_LEN];
   
  -    if ((s = strrchr(argv[0], '/')) != NULL) {
  -     ap_server_argv0 = ++s;
  +    /* Service application
  +     * Configuration file in registry at:
  +     * HKLM\System\CurrentControlSet\Services\[Svc name]\Parameters\ConfPath
  +     */
  +    if (isProcessService()) {
  +        service_main(master_main, argc, argv);
  +        clean_parent_exit(0);
  +    }
  +
  +    /* Console application or a child process. */
  +
  +    if ((s = strrchr(argv[0], PATHSEPARATOR)) != NULL) {
  +        ap_server_argv0 = ++s;
       }
       else {
  -     ap_server_argv0 = argv[0];
  +        ap_server_argv0 = argv[0];
       }
   
  -    /* Get the serverroot from the registry, if it exists. This can be
  -     * overridden by a command line -d argument.
  -     */
  -    if (ap_registry_get_server_root(pconf, ap_server_root, 
sizeof(ap_server_root)) < 0) {
  -     /* The error has already been logged. Actually it won't have been,
  -      * because we haven't read the config files to find out where our 
  -      * error log is. But we can't just ignore the error since we might
  -      * end up using totally the wrong server root.
  -      */
  -     exit(1);
  -    }
  +    common_init();
  +    ap_setup_prelinked_modules();
   
  -    if (!*ap_server_root) {
  -     ap_cpystrn(ap_server_root, HTTPD_ROOT, sizeof(ap_server_root));
  +    if(!GetCurrentDirectory(sizeof(cwd),cwd)) {
  +       ap_log_error(APLOG_MARK,APLOG_WIN32ERROR, NULL,
  +       "GetCurrentDirectory() failure");
  +       return -1;
       }
  -    ap_cpystrn(ap_server_confname, SERVER_CONFIG_FILE, 
sizeof(ap_server_confname));
   
  -    ap_setup_prelinked_modules();
  +    ap_cpystrn(cwd, ap_os_canonical_filename(pcommands, cwd), sizeof(cwd));
  +    ap_cpystrn(ap_server_root, cwd, sizeof(ap_server_root));
   
  -    while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVlLZ:iusSthk:")) != -1) {
  +    while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVlLZ:iusSthk:n:")) != -1) {
           char **new;
        switch (c) {
        case 'c':
  @@ -5890,15 +5984,20 @@
            ap_assert(start_mutex);
            child = 1;
            break;
  +        case 'n':
  +            service_name = ap_pstrdup(pcommands, optarg);
  +            if (isValidService(optarg)) {
  +                ap_registry_get_service_conf(pconf, ap_server_confname, 
sizeof(ap_server_confname),
  +                                             optarg);
  +                conf_specified = 1;
  +            }
  +            break;
        case 'i':
            install = 1;
            break;
        case 'u':
            install = -1;
            break;
  -     case 's':
  -         run_as_service = 0;
  -         break;
        case 'S':
            ap_dump_settings = 1;
            break;
  @@ -5907,10 +6006,22 @@
            break;
   #endif /* WIN32 */
        case 'd':
  -         ap_cpystrn(ap_server_root, ap_os_canonical_filename(pconf, optarg), 
sizeof(ap_server_root));
  +            optarg = ap_os_canonical_filename(pcommands, optarg);
  +            if (!ap_os_is_path_absolute(optarg)) {
  +             optarg = ap_pstrcat(pcommands, cwd, optarg, NULL);
  +                ap_getparents(optarg);
  +            }
  +            if (optarg[strlen(optarg)-1] != '/')
  +                optarg = ap_pstrcat(pcommands, optarg, "/", NULL);
  +            ap_cpystrn(ap_server_root,
  +                       optarg,
  +                       sizeof(ap_server_root));
            break;
        case 'f':
  -         ap_cpystrn(ap_server_confname, ap_os_canonical_filename(pconf, 
optarg), sizeof(ap_server_confname));
  +            ap_cpystrn(ap_server_confname,
  +                       ap_os_canonical_filename(pcommands, optarg),
  +                       sizeof(ap_server_confname));
  +            conf_specified = 1;
            break;
        case 'v':
            ap_set_version();
  @@ -5934,49 +6045,89 @@
            configtestonly = 1;
            break;
        case 'h':
  -         usage(argv[0]);
  +         usage(ap_server_argv0);
        case '?':
  -         usage(argv[0]);
  -     }
  +         usage(ap_server_argv0);
  +        }   /* switch */
  +    }       /* while  */
  +
  +    /* ServerConfFile is found in this order:
  +     * (1) -f or -n
  +     * (2) [-d]/SERVER_CONFIG_FILE
  +     * (3) ./SERVER_CONFIG_FILE
  +     * (4) [Registry: HKLM\Software\[product]\ServerRoot]/SERVER_CONFIG_FILE
  +     * (5) /HTTPD_ROOT/SERVER_CONFIG_FILE
  +     */
  +
  +    if (!conf_specified) {
  +        ap_cpystrn(ap_server_confname, SERVER_CONFIG_FILE, 
sizeof(ap_server_confname));
  +        if (access(ap_server_root_relative(pcommands, ap_server_confname), 
0)) {
  +            ap_registry_get_server_root(pconf, ap_server_root, 
sizeof(ap_server_root));
  +            if (!*ap_server_root)
  +                ap_cpystrn(ap_server_root, HTTPD_ROOT, 
sizeof(ap_server_root));
  +            ap_cpystrn(ap_server_root, ap_os_canonical_filename(pcommands, 
ap_server_root),
  +                       sizeof(ap_server_root));
  +        }
  +    }
  +
  +    if (!ap_os_is_path_absolute(ap_server_confname)) {
  +        char *full_conf_path;
  +
  +        full_conf_path = ap_pstrcat(pcommands, ap_server_root, "/", 
ap_server_confname, NULL);
  +        full_conf_path = ap_os_canonical_filename(pcommands, full_conf_path);
  +        ap_cpystrn(ap_server_confname, full_conf_path, 
sizeof(ap_server_confname));
       }
  +    ap_getparents(ap_server_confname);
  +    ap_no2slash(ap_server_confname);
   
  -    if (!child && run_as_service) {
  -     service_cd();
  +#ifdef WIN32
  +    if (install) {
  +        if (!service_name)
  +            service_name = ap_pstrdup(pconf, DEFAULTSERVICENAME);
  +        if (install > 0) 
  +            InstallService(service_name, ap_server_root_relative(pcommands, 
ap_server_confname));
  +        else
  +            RemoveService(service_name);
  +        clean_parent_exit(0);
  +    }
  +    
  +    if (service_name && signal_to_send) {
  +        send_signal_to_service(service_name, signal_to_send);
  +        clean_parent_exit(0);
       }
   
  +    if (service_name && !conf_specified) {
  +        printf("Unknown service: %s\n", service_name);
  +        clean_parent_exit(0);
  +    }
  +#endif
       server_conf = ap_read_config(pconf, ptrans, ap_server_confname);
   
       if (configtestonly) {
  -        fprintf(stderr, "Syntax OK\n");
  -        exit(0);
  +        fprintf(stderr, "%s: Syntax OK\n", 
ap_server_root_relative(pcommands, ap_server_confname));
  +        clean_parent_exit(0);
       }
   
  -    if (signal_to_send) {
  -     send_signal(pconf, signal_to_send);
  -     exit(0);
  +    /* Treat -k start confpath as just -f confpath */
  +    if (signal_to_send && strcasecmp(signal_to_send, "start")) {
  +        send_signal(pconf, signal_to_send);
  +        clean_parent_exit(0);
       }
   
  -    if (!child && !ap_dump_settings && !install) {
  -     ap_log_pid(pconf, ap_pid_fname);
  +    if (!child && !ap_dump_settings) { 
  +        ap_log_pid(pconf, ap_pid_fname);
       }
  -    ap_set_version();
  -    ap_init_modules(pconf, server_conf);
  -    ap_suexec_enabled = init_suexec();
  -    version_locked++;
  -    if (!install) {
  -     ap_open_logs(server_conf, pconf);
  -    }
  -    set_group_privs();
  +
  +    post_parse_init();
   
   #ifdef OS2
       printf("%s running...\n", ap_get_server_version());
   #endif
   #ifdef WIN32
  -    if (!child && !install) {
  +    if (!child) {
        printf("%s running...\n", ap_get_server_version());
       }
   #endif
  -
       if (one_process && !exit_event)
        exit_event = create_event(0, 0, NULL);
       if (one_process && !start_mutex)
  @@ -5992,11 +6143,9 @@
        worker_main();
        ap_destroy_mutex(start_mutex);
        destroy_event(exit_event);
  -    }
  -    else {
  -     service_main(master_main, argc, argv,
  -                     "Apache", install, run_as_service);
       }
  +    else 
  +        master_main(argc, argv);
   
       clean_parent_exit(0);
       return 0;        /* purely to avoid a warning */
  @@ -6148,3 +6297,4 @@
   
   #endif /* ndef SHARED_CORE_BOOTSTRAP */
   
  +
  \ No newline at end of file
  
  
  
  1.19      +116 -39   apache-1.3/src/os/win32/registry.c
  
  Index: registry.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/os/win32/registry.c,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- registry.c        1999/03/23 00:36:46     1.18
  +++ registry.c        1999/04/08 20:26:26     1.19
  @@ -15,6 +15,16 @@
    * release to a development or beta version.
    */
   
  +/* To allow for multiple services, store the configuration file's full path
  + * under each service entry:
  + *
  + * HKLM\System\CurrentControlSet\Services\[service name]\Parameters\ConfPath
  + *
  + * The default configuration path (for console apache) is still stored:
  + * 
  + * HKLM\Software\[Vendor]\[Software]\[Version]\ServerRoot
  + */
  +
   #include <windows.h>
   #include <stdio.h>
   
  @@ -32,6 +42,9 @@
   
   #define REGKEY "SOFTWARE\\" VENDOR "\\" SOFTWARE "\\" VERSION
   
  +#define SERVICEKEYPRE  "System\\CurrentControlSet\\Services\\"
  +#define SERVICEKEYPOST "\\Parameters"
  +
   /*
    * The Windows API registry key functions don't set the last error
    * value (the windows equivalent of errno). So we need to set it
  @@ -79,7 +92,7 @@
    * message will be logged at priority "warning".
    */
   
  -static int ap_registry_get_key_int(pool *p, char *key, char *pBuffer, int 
nSizeBuffer, char **ppValue)
  +static int ap_registry_get_key_int(pool *p, char *key, char *name, char 
*pBuffer, int nSizeBuffer, char **ppValue)
   {
       long rv;
       HKEY hKey;
  @@ -88,19 +101,18 @@
       int retval;
   
       rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  -                   REGKEY,
  +                      key,
                      0,
                      KEY_READ,
                      &hKey);
   
       if (rv == ERROR_FILE_NOT_FOUND) {
        ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,NULL,
  -         "Registry does not contain key " REGKEY);
  +        "Registry does not contain key %s",key);
        return -1;
       }
       if (rv != ERROR_SUCCESS) {
  -     do_error(rv, "RegOpenKeyEx HKLM\\" REGKEY,
  -              NULL);
  +        do_error(rv, "RegOpenKeyEx HKLM\\%s",key);
        return -4;
       }
   
  @@ -110,7 +122,7 @@
         * buffer if the return value is ERROR_SUCCESS.
         */
        rv = RegQueryValueEx(hKey, 
  -                          key,               /* key name */
  +                          name,              /* key name */
                             NULL,              /* reserved */
                             NULL,              /* type */
                             NULL,              /* for value */
  @@ -139,7 +151,7 @@
       }
   
       rv = RegQueryValueEx(hKey, 
  -                      key,           /* key name */
  +                      name,          /* key name */
                         NULL,          /* reserved */
                         NULL,          /* type */
                         pValue,                /* for value */
  @@ -149,7 +161,7 @@
   
       if (rv == ERROR_FILE_NOT_FOUND) {
        ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,NULL,
  -         "Registry does not contain value " REGKEY "\\%s", key);
  +        "Registry does not contain value %s\\%s", key, name);
        retval = -1;
       }
       else if (rv == ERROR_MORE_DATA) {
  @@ -169,7 +181,7 @@
   
       rv = RegCloseKey(hKey);
       if (rv != ERROR_SUCCESS) {
  -     do_error(rv, "RegCloseKey HKLM\\" REGKEY, NULL);
  +    do_error(rv, "RegCloseKey HKLM\\%s", key);
        if (retval == 0) {
            /* Keep error status from RegQueryValueEx, if any */
            retval = -4;  
  @@ -191,7 +203,7 @@
   {
       int rv;
   
  -    rv = ap_registry_get_key_int(p, "ServerRoot", dir, size, NULL);
  +    rv = ap_registry_get_key_int(p, REGKEY, "ServerRoot", dir, size, NULL);
       if (rv < 0) {
        dir[0] = '\0';
       }
  @@ -199,10 +211,61 @@
       return (rv < -1) ? -1 : 0;
   }
   
  +char *ap_get_service_key(char *service_name)
  +{
  +    char *key = malloc(strlen(SERVICEKEYPRE) +
  +                       strlen(service_name) +
  +                       strlen(SERVICEKEYPOST) + 1);
  +
  +    sprintf(key,"%s%s%s", SERVICEKEYPRE, service_name, SERVICEKEYPOST);
  +
  +    return(key);
  +}
  +
  +int ap_registry_get_service_conf(pool *p, char *dir, int size, char 
*service_name)
  +{
  +    int rv;
  +    char *key = ap_get_service_key(service_name);
  +
  +    rv = ap_registry_get_key_int(p, key, "ConfPath", dir, size, NULL);
  +    if (rv < 0) {
  +    dir[0] = '\0';
  +    }
  +
  +    free(key);
  +    return (rv < -1) ? -1 : 0;
  +}
  +
   /**********************************************************************
    * The rest of this file deals with storing keys or values in the registry
    */
   
  +char *ap_registry_parse_key(int index, char *key)
  +{
  +    char *head = key, *skey;
  +    int i;
  +    
  +    if(!key)
  +        return(NULL);
  +
  +    for(i = 0; i <= index; i++)
  +    {
  +        if(key && key[0] == '\\')
  +            key++;
  +        if (!key)
  +            return(NULL);
  +        head = key;
  +        key = strchr(head, '\\');
  +    }
  +
  +    if(!key)
  +        return(strdup(head));
  +    *key = '\0';
  +    skey = strdup(head);
  +    *key = '\\';
  +    return(skey);
  +}
  +
   /*
    * ap_registry_create_apache_key() creates the Apache registry key
    * (HLKM\SOFTWARE\Apache Group\Apache\version, as defined at the start
  @@ -215,31 +278,25 @@
    * already have been logged.
    */
   
  -static int ap_registry_create_apache_key(void)
  +static int ap_registry_create_key(char *longkey)
   {
  -    static char *keys[] = 
  -    { "SOFTWARE",
  -     VENDOR,
  -     SOFTWARE,
  -     VERSION,
  -     NULL
  -    };
       int index;
       HKEY hKey;
       HKEY hKeyNext;
       int retval;
       int rv;
  +    char *key;
   
       hKey = HKEY_LOCAL_MACHINE;
       index = 0;
       retval = 0;
   
       /* Walk the tree, creating at each stage if necessary */
  -    while (keys[index]) {
  +    while (key=ap_registry_parse_key(index,longkey)) {
        int result;
   
        rv = RegCreateKeyEx(hKey,
  -                         keys[index], /* subkey */
  +                         key,         /* subkey */
                            0,           /* reserved */
                            NULL,        /* class */
                            REG_OPTION_NON_VOLATILE,
  @@ -248,7 +305,7 @@
                            &hKeyNext,
                            &result);
        if (rv != ERROR_SUCCESS) {
  -         do_error(rv, "RegCreateKeyEx(%s)", keys[index]);
  +         do_error(rv, "RegCreateKeyEx(%s)", longkey);
            retval = -4;
        }
   
  @@ -266,11 +323,12 @@
            break;
        }
   
  +    free(key);
        hKey = hKeyNext;
        index++;
       }
   
  -    if (keys[index] == NULL) {
  +    if (!key) {
        /* Close the final key we opened, if we walked the entire
         * tree
         */
  @@ -283,6 +341,8 @@
            }
        }
       }
  +    else
  +        free(key);
   
       return retval;
   }
  @@ -302,14 +362,14 @@
    * logged via aplog_error().
    */
   
  -static int ap_registry_store_key_int(char *key, DWORD type, void *value, int 
value_size)
  +static int ap_registry_store_key_int(char *key, char *name, DWORD type, void 
*value, int value_size)
   {
       long rv;
       HKEY hKey;
       int retval;
   
       rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  -                   REGKEY,
  +                   key,
                      0,
                      KEY_WRITE,
                      &hKey);
  @@ -317,7 +377,7 @@
       if (rv == ERROR_FILE_NOT_FOUND) {
        /* Key could not be opened -- try to create it 
         */
  -     if (ap_registry_create_apache_key() < 0) {
  +        if (ap_registry_create_key(key) < 0) {
            /* Creation failed (error already reported) */
            return -4;
        }
  @@ -325,28 +385,26 @@
        /* Now it has been created we should be able to open it
         */
        rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  -               REGKEY,
  +               key,
                  0,
                  KEY_WRITE,
                  &hKey);
   
        if (rv == ERROR_FILE_NOT_FOUND) {
  -         ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,NULL,
  -             "Registry does not contain key " REGKEY " after creation");
  -
  +            ap_log_error(APLOG_MARK,APLOG_WARNING|APLOG_NOERRNO,NULL,
  +                         "Registry does not contain key %s after 
creation",key);
            return -1;
        }
       }
   
       if (rv != ERROR_SUCCESS) {
  -     do_error(rv, "RegOpenKeyEx HKLM\\" REGKEY,
  -              NULL);
  -     return -4;
  +        do_error(rv, "RegOpenKeyEx HKLM\\%s", key);
  +        return -4;
       }
   
       /* Now set the value and data */
       rv = RegSetValueEx(hKey, 
  -                    key,     /* value key name */
  +                       name, /* value key name */
                       0,       /* reserved */
                       type,    /* type */
                       value,   /* value data */
  @@ -369,17 +427,34 @@
        */
       rv = RegCloseKey(hKey);
       if (rv != ERROR_SUCCESS) {
  -     do_error(rv, "RegCloseKey HKLM\\" REGKEY, NULL);
  -     if (retval == 0) {
  -         /* Keep error status from RegQueryValueEx, if any */
  -         retval = -4;  
  -     }
  +        do_error(rv, "RegCloseKey HKLM\\%s", key);
  +        if (retval == 0) {
  +            /* Keep error status from RegQueryValueEx, if any */
  +            retval = -4;  
  +        }
       }
   
       return retval;
   }
   
   /*
  + * Sets the service confpath value within the registry. Returns 0 on success
  + * or -1 on error. If -1 is return the error will already have been
  + * logged via aplog_error().
  + */
  +
  +int ap_registry_set_service_conf(char *conf, char *service_name)
  +{
  +    int rv;
  +    char *key = ap_get_service_key(service_name);
  +    
  +    rv = ap_registry_store_key_int(key, "ConfPath", REG_SZ, conf, 
strlen(conf)+1);
  +    free(key);
  +
  +    return rv < 0 ? -1: 0;
  +}
  +
  +/*
    * Sets the serverroot value within the registry. Returns 0 on success
    * or -1 on error. If -1 is return the error will already have been
    * logged via aplog_error().
  @@ -389,7 +464,9 @@
   {
       int rv;
   
  -    rv = ap_registry_store_key_int("ServerRoot", REG_SZ, dir, strlen(dir)+1);
  +    rv = ap_registry_store_key_int(REGKEY, "ServerRoot", REG_SZ, dir, 
strlen(dir)+1);
   
       return rv < 0 ? -1 : 0;
   }
  +
  +
  \ No newline at end of file
  
  
  
  1.2       +3 -0      apache-1.3/src/os/win32/registry.h
  
  Index: registry.h
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/os/win32/registry.h,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- registry.h        1998/02/24 11:37:25     1.1
  +++ registry.h        1999/04/08 20:26:26     1.2
  @@ -4,3 +4,6 @@
   
   extern int ap_registry_get_server_root(pool *p, char *dir, int size);
   extern int ap_registry_set_server_root(char *dir);
  +extern int ap_registry_get_service_conf(pool *p, char *dir, int size, char 
*service_name);
  +extern int ap_registry_set_service_conf(char *dir, char *service_name);
  +
  \ No newline at end of file
  
  
  
  1.12      +184 -69   apache-1.3/src/os/win32/service.c
  
  Index: service.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/os/win32/service.c,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- service.c 1998/05/10 16:18:45     1.11
  +++ service.c 1999/04/08 20:26:26     1.12
  @@ -26,59 +26,35 @@
       FILE *logFile;
   } globdat;
   
  -static void WINAPI service_main_fn(DWORD, char **);
  +static void WINAPI service_main_fn(DWORD, LPTSTR *);
   static void WINAPI service_ctrl(DWORD ctrlCode);
   static int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint);
  -static void InstallService();
  -static void RemoveService();
  +static int ap_start_service(SC_HANDLE);
  +static int ap_stop_service(SC_HANDLE);
   
  -
  -int service_main(int (*main_fn)(int, char **), int argc, char **argv,
  -                  char *service_name,
  -                  int install_flag, int run_as_service)
  +int service_main(int (*main_fn)(int, char **), int argc, char **argv )
   {
       SERVICE_TABLE_ENTRY dispatchTable[] =
       {
  -        { service_name, service_main_fn },
  +        { "", service_main_fn },
           { NULL, NULL }
       };
   
  -    globdat.name = service_name;
  +    globdat.main_fn = main_fn;
  +    globdat.stop_event = create_event(0, 0, "apache-signal");
  +    globdat.connected = 1;
   
  -    if(install_flag > 0)
  -    {
  -        InstallService();
  -        return(0);
  -    }
  -    else if(install_flag < 0)
  +    if(!StartServiceCtrlDispatcher(dispatchTable))
       {
  -        RemoveService();
  -        return(0);
  +        /* This is a genuine failure of the SCM. */
  +        ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  +        "Error starting service control dispatcher");
  +        return(globdat.exit_status);
       }
       else
       {
  -        globdat.main_fn = main_fn;
  -        globdat.stop_event = create_event(0, 0, "apache-signal");
  -     
  -        if(run_as_service)
  -        {
  -            globdat.connected = 1;
  -            if(!StartServiceCtrlDispatcher(dispatchTable))
  -            {
  -                return((*main_fn)(argc, argv));
  -            }
  -            else
  -            {
  -                return(globdat.exit_status);
  -            }
  -        }
  -        else
  -        {
  -            globdat.connected = 0;
  -            return((*main_fn)(argc, argv));
  -        }
  +        return(globdat.exit_status);
       }
  -
   }
   
   void service_cd()
  @@ -90,25 +66,27 @@
       chdir(buf);
   }
   
  -void __stdcall service_main_fn(DWORD argc, char **argv)
  +void __stdcall service_main_fn(DWORD argc, LPTSTR *argv)
   {
  -
  +    ap_server_argv0 = globdat.name = argv[0];
   
       if(!(globdat.hServiceStatus = RegisterServiceCtrlHandler( globdat.name, 
service_ctrl)))
       {
  -        globdat.exit_status = -1;
  +        ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  +        "Failure registering service handler");
           return;
       }
   
  -
       ReportStatusToSCMgr(
           SERVICE_START_PENDING, // service state
           NO_ERROR,              // exit code
           3000);                 // wait hint
  -
  -    globdat.exit_status = (*globdat.main_fn)( argc, argv );
  -
   
  +    service_cd();
  +    if( service_init() ) 
  +        /* Arguments are ok except for \! */
  +        globdat.exit_status = (*globdat.main_fn)( argc, argv );
  +    
       ReportStatusToSCMgr(SERVICE_STOPPED, NO_ERROR, 0);
   
       return;
  @@ -206,21 +184,26 @@
       }
       return(1);
   }
  -
   
  -void InstallService()
  +void InstallService(char *service_name, char *conf)
   {
       SC_HANDLE   schService;
       SC_HANDLE   schSCManager;
   
       TCHAR szPath[512];
  +    TCHAR szQuotedPath[512];
  +
  +    printf("Installing the %s service to use %s\n", service_name, conf);
   
       if (GetModuleFileName( NULL, szPath, 512 ) == 0)
       {
  -        exit(1);
  +        ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  +        "GetModuleFileName failed");
           return;
       }
   
  +    ap_snprintf(szQuotedPath, 512, "\"%s\"", szPath);
  +
       schSCManager = OpenSCManager(
                           NULL,                   // machine (NULL == local)
                           NULL,                   // database (NULL == default)
  @@ -233,13 +216,13 @@
       else {
           schService = CreateService(
               schSCManager,               // SCManager database
  -            globdat.name,        // name of service
  -            globdat.name, // name to display
  +            service_name,               // name of service
  +            service_name,               // name to display
               SERVICE_ALL_ACCESS,         // desired access
               SERVICE_WIN32_OWN_PROCESS,  // service type
               SERVICE_AUTO_START,       // start type
               SERVICE_ERROR_NORMAL,       // error control type
  -            szPath,                     // service's binary
  +            szQuotedPath,               // service's binary
               NULL,                       // no load ordering group
               NULL,                       // no tag identifier
               NULL,       // dependencies
  @@ -249,8 +232,9 @@
           if (schService) {
               CloseServiceHandle(schService);
   
  -         /* Now store the server_root in the registry */
  -         ap_registry_set_server_root(ap_server_root);
  +            /* Now store the server_root in the registry */
  +            if(!ap_registry_set_service_conf(conf, service_name))
  +                printf("The %s service has been installed successfully.\n", 
service_name );
           }
           else {
               ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL, 
  @@ -259,17 +243,16 @@
   
           CloseServiceHandle(schSCManager);
       }
  -
   }
   
   
  -
  -
  -void RemoveService()
  +void RemoveService(char *service_name)
   {
       SC_HANDLE   schService;
       SC_HANDLE   schSCManager;
   
  +    printf("Removing the %s service\n", service_name);
  +
       schSCManager = OpenSCManager(
                           NULL,                   // machine (NULL == local)
                           NULL,                   // database (NULL == default)
  @@ -280,7 +263,7 @@
           "OpenSCManager failed");
       }
       else {
  -        schService = OpenService(schSCManager, globdat.name, 
SERVICE_ALL_ACCESS);
  +        schService = OpenService(schSCManager, service_name, 
SERVICE_ALL_ACCESS);
   
           if (schService == NULL) {
               /* Could not open the service */
  @@ -289,28 +272,160 @@
           }
           else {
               /* try to stop the service */
  -            if (ControlService(schService, SERVICE_CONTROL_STOP, 
&globdat.ssStatus)) {
  -                Sleep(1000);
  -                while(QueryServiceStatus(schService, &globdat.ssStatus)) {
  -                    if(globdat.ssStatus.dwCurrentState == 
SERVICE_STOP_PENDING)
  -                        Sleep(1000);
  -                    else
  -                        break;
  -                }
  -            }
  +            ap_stop_service(schService);
   
               // now remove the service
               if (DeleteService(schService) == 0)
                ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
                    "DeleteService failed");
  +            else
  +                printf("The %s service has been removed successfully.\n", 
service_name );
               CloseServiceHandle(schService);
           }
  -
  +        /* SCM removes registry parameters  */
           CloseServiceHandle(schSCManager);
       }
   
   }
   
  -#endif /* WIN32 */
  +/* A hack to determine if we're running as a service without waiting for
  + * the SCM to fail; if AllocConsole succeeds, we're a service.
  + */
  +
  +BOOL isProcessService() {
  +    if( !AllocConsole() ) 
  +        return FALSE;
  +    FreeConsole();
  +    return TRUE;
  +}
  +
  +/* Determine is service_name is a valid service
  + */
  +
  +BOOL isValidService(char *service_name) {
  +    SC_HANDLE schSCM, schSVC;
  +    int Err;
  +
  +    if (!(schSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  +        ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  +        "OpenSCManager failed");
  +       return FALSE;
  +    }
  +
  +    if ((schSVC = OpenService(schSCM, service_name, SERVICE_ALL_ACCESS))) {
  +        CloseServiceHandle(schSVC);
  +        CloseServiceHandle(schSCM);
  +        return TRUE;
  +    }
  +
  +    Err = GetLastError();
  +    if (Err != ERROR_SERVICE_DOES_NOT_EXIST && Err != ERROR_INVALID_NAME)
  +        ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  +        "OpenService failed");
  +
  +    return FALSE;
  +}
  +
  +int send_signal_to_service(char *service_name, char *sig) {
  +    SC_HANDLE   schService;
  +    SC_HANDLE   schSCManager;
  +    int success = FALSE;
  +
  +    enum                        { start,      restart,      stop, unknown } 
action;
  +    static char *param[] =      { "start",    "restart",    "shutdown" };
  +    static char *participle[] = { "starting", "restarting", "stopping" };
  +    static char *past[]       = { "started",  "restarted",  "stopped"  };
  +
  +    for (action = start; action < unknown; action++)
  +        if (!strcasecmp(sig, param[action]))
  +            break;
  +
  +    if (action == unknown) {
  +        printf("signal must be start, restart, or shutdown\n");
  +        return FALSE;
  +    }
  +
  +    schSCManager = OpenSCManager(
  +                        NULL,                   // machine (NULL == local)
  +                        NULL,                   // database (NULL == default)
  +                        SC_MANAGER_ALL_ACCESS   // access required
  +                        );
  +    if (!schSCManager) {
  +        ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  +        "OpenSCManager failed");
  +    }
  +    else {
  +        schService = OpenService(schSCManager, service_name, 
SERVICE_ALL_ACCESS);
  +
  +        if (schService == NULL) {
  +            /* Could not open the service */
  +           ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  +            "OpenService failed");
  +        }
  +        else {
  +            if (!QueryServiceStatus(schService, &globdat.ssStatus))
  +                ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
  +                             "QueryService failed");
  +            else {
  +                if (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED && 
action == stop)
  +                    printf("The %s service is not started.\n", service_name);
  +                else if (globdat.ssStatus.dwCurrentState == SERVICE_RUNNING 
&& action == start)
  +                    printf("The %s service has already been started.\n", 
service_name);
  +                else {
  +                    printf("The %s service is %s.\n", service_name, 
participle[action]);
  +
  +                    if (action == stop || action == restart)
  +                        success = ap_stop_service(schService);
  +                    if (action == start || action == restart)
  +                        success = ap_start_service(schService);
  +                
  +                    if( success )
  +                        printf("The %s service has %s.\n", service_name, 
past[action]);
  +                    else
  +                        printf("Failed to %s the %s service.\n", sig, 
service_name );
  +                }
   
  +                CloseServiceHandle(schService);
  +            }
  +        }
  +        /* SCM removes registry parameters */
  +        CloseServiceHandle(schSCManager);
  +    }
  +    return success;
  +}
   
  +int ap_stop_service(SC_HANDLE schService)
  +{
  +    if (ControlService(schService, SERVICE_CONTROL_STOP, &globdat.ssStatus)) 
{
  +        Sleep(1000);
  +        while (QueryServiceStatus(schService, &globdat.ssStatus)) {
  +            if (globdat.ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
  +                Sleep(1000);
  +            else
  +                break;
  +        }
  +    }
  +    if (QueryServiceStatus(schService, &globdat.ssStatus))
  +        if (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED)
  +            return TRUE;
  +    return FALSE;
  +}
  +
  +int ap_start_service(SC_HANDLE schService) {
  +    if (StartService(schService, 0, NULL)) {
  +        Sleep(1000);
  +        while(QueryServiceStatus(schService, &globdat.ssStatus)) {
  +            if(globdat.ssStatus.dwCurrentState == SERVICE_START_PENDING)
  +                Sleep(1000);
  +            else
  +                break;
  +        }
  +    }
  +    if (QueryServiceStatus(schService, &globdat.ssStatus))
  +        if (globdat.ssStatus.dwCurrentState == SERVICE_RUNNING)
  +            return TRUE;
  +    return FALSE;
  +}
  +           
  +#endif /* WIN32 */
  +
  \ No newline at end of file
  
  
  
  1.3       +8 -3      apache-1.3/src/os/win32/service.h
  
  Index: service.h
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/os/win32/service.h,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- service.h 1998/01/04 15:26:20     1.2
  +++ service.h 1999/04/08 20:26:27     1.3
  @@ -3,11 +3,16 @@
   #define SERVICE_H
   
   #ifdef WIN32
  -int service_main(int (*main_fn)(int, char **), int argc, char **argv,
  -                  char *service_name,
  -                  int install_flag, int run_as_service);
  +int service_main(int (*main_fn)(int, char **), int argc, char **argv);
   void service_set_status(int status);
   void service_cd();
  +BOOL isProcessService();
  +BOOL isValidService(char *service_name);
  +void InstallService(char *service_name, char *conf);
  +void RemoveService(char *service_name);
  +int service_init();
  +int send_signal_to_service(char *service_name, char *sig);
   #endif /* WIN32 */
   
   #endif /* SERVICE_H */
  +
  \ No newline at end of file
  
  
  

Reply via email to