[prev in list] [next in list] [prev in thread] [next in thread] 

List:       apache-httpd-dev
Subject:    [PATCH] NT multiple services patch, revised
From:       Keith Wannamaker <krw () raleigh ! ibm ! com>
Date:       1999-03-29 15:27:44
[Download RAW message or body]

This revised patch enables multiple servers on NT by providing a clean way to
install, uninstall, and signal multiple services.

The following options were added or modified:

-n (name)   : Specify the name for the service to install or uninstall;
              forces this Apache to use config of service (name)
-k (signal) : Added signal "start"

If -n is not specified with -i or -u, Apache uses the default ("Apache").

When starting console Apache, if server is not specified,
Apache now searches for it in this order (step 1 is new):

1) ./SERVER_CONFIG_FILE
2) Registry:  HKEY_LOCAL_MACHINE/SOFTWARE/Apache Group/Apache
/[Version]/ServerRoot
3) /HTTPD_ROOT/SERVER_CONFIG_FILE

Command-line Apache can now signal services successfully by using a NULL NT ACL.

Keith Wannamaker
IBM IHS Development Team
RTP, NC  USA

--------------------------------------------------------------------------------
Users of the Apache webserver are hereby granted a non-exclusive, irrevocable,
world-wide, royalty-free, non-transferable license to use, execute, prepare
derivative works of, and distribute (internally and externally, and including
derivative works) the code accompanying this license as part of, and
integrated into the Apache webserver.  This code is provided "AS IS" WITHOUT
WARRANTY OF ANY KIND EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTY OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
AND ANY WARRANTY OF NON-INFRINGEMENT.  THE ENTIRE RISK ARISING OUT OF THE USE
OR PERFORMANCE OF THIS CODE REMAINS WITH USERS OF THE APACHE WEBSERVER.  The
owner of this code represents and warrants that it is legally entitled to
grant the above license.
["service.patch" (text/plain)]

--- main\http_main.apache.c	Thu Mar 18 02:12:36 1999
+++ main\http_main.c	Fri Mar 26 18:38:20 1999
@@ -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,54 @@
     return 0;
 }
 
+#ifdef WIN32
+/* To share the semaphores with other processes, we need a NULL ACL
+ * Code from MS KB Q106387
+ */
+
+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;
+}
+#endif
+
+void CleanNullACL( void *sa ) {
+#ifdef WIN32
+    if( sa ) {
+        LocalFree( ((PSECURITY_ATTRIBUTES)sa)->lpSecurityDescriptor);
+        LocalFree( sa );
+    }
+#endif
+}
+
 int master_main(int argc, char **argv)
 {
+#ifdef WIN32
+    // returns NULL if invalid (Win95?)
+    PSECURITY_ATTRIBUTES sa = GetNullACL();
+#else
+    void *sa = NULL;
+#endif
     int nchild = ap_daemons_to_start;
     event **ev;
     int *child;
@@ -5560,20 +5627,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 +5844,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 +5857,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 +5866,7 @@
     if (nread == 0) {
 	fclose(fp);
 	printf("PID file %s was empty\n", fname);
-	return;
+    return FALSE;
     }
     fclose(fp);
 
@@ -5812,11 +5882,38 @@
 	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
@@ -5829,41 +5926,36 @@
     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();
-
-    if ((s = strrchr(argv[0], '/')) != NULL) {
-	ap_server_argv0 = ++s;
-    }
-    else {
-	ap_server_argv0 = argv[0];
-    }
 
-    /* Get the serverroot from the registry, if it exists. This can be
-     * overridden by a command line -d argument.
+    /* Service application
+     * Configuration file in registry at:
+     * HKLM\System\CurrentControlSet\Services\[Svc name]\Parameters\ConfPath
      */
-    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);
+    if (isProcessService()) {
+        service_main(master_main, argc, argv);
+        clean_parent_exit(0);
     }
 
-    if (!*ap_server_root) {
-	ap_cpystrn(ap_server_root, HTTPD_ROOT, sizeof(ap_server_root));
+    /* Console application or a child process. */
+
+    if ((s = strrchr(argv[0], PATHSEPARATOR)) != NULL) {
+    ap_server_argv0 = ++s;
+    }
+    else {
+    ap_server_argv0 = argv[0];
     }
-    ap_cpystrn(ap_server_confname, SERVER_CONFIG_FILE, sizeof(ap_server_confname));
 
+    common_init();
     ap_setup_prelinked_modules();
+    ap_cpystrn(ap_server_confname, SERVER_CONFIG_FILE, sizeof(ap_server_confname));
 
-    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 +5982,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;
@@ -5908,9 +6005,11 @@
 #endif /* WIN32 */
 	case 'd':
 	    ap_cpystrn(ap_server_root, ap_os_canonical_filename(pconf, optarg), \
sizeof(ap_server_root)); +        conf_specified = 1;
 	    break;
 	case 'f':
 	    ap_cpystrn(ap_server_confname, ap_os_canonical_filename(pconf, optarg), \
sizeof(ap_server_confname)); +        conf_specified = 1;
 	    break;
 	case 'v':
 	    ap_set_version();
@@ -5934,49 +6033,85 @@
 	    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) {
+        if (!access(ap_server_confname, 0)) {
+            if(!GetCurrentDirectory(sizeof(ap_server_root),ap_server_root)) {
+                ap_log_error(APLOG_MARK,APLOG_WIN32ERROR, NULL,
+                "GetCurrentDirectory() failure");
+                return -1;
+            }
+        }
+        else {
+            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 (!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_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) {
-	printf("%s running...\n", ap_get_server_version());
+    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)
@@ -5993,10 +6128,8 @@
 	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 */
--- os\win32\service.apache.c	Sun May 10 17:18:46 1998
+++ os\win32\service.c	Fri Mar 26 18:43:38 1999
@@ -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;
@@ -207,17 +185,19 @@
     return(1);
 }
 
-
-void InstallService()
+void InstallService(char *service_name, char *conf)
 {
     SC_HANDLE   schService;
     SC_HANDLE   schSCManager;
 
     TCHAR szPath[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;
     }
 
@@ -233,8 +213,8 @@
     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
@@ -249,8 +229,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 +240,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 +260,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 +269,161 @@
         }
         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);
+    }
+
+}
+
+/* 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 */
 
 
--- os\win32\service.apache.h	Sun Jan 04 15:26:20 1998
+++ os\win32\service.h	Fri Mar 26 14:32:27 1999
@@ -3,11 +3,15 @@
 #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 */
--- os\win32\registry.apache.c	Tue Mar 23 02:12:54 1999
+++ os\win32\registry.c	Fri Mar 26 18:30:00 1999
@@ -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,27 @@
 	/* 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);
+	    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,7 +428,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;  
@@ -380,6 +439,23 @@
 }
 
 /*
+ * 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 +465,7 @@
 {
     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;
 }
--- os\win32\registry.apache.h	Tue Feb 24 11:37:26 1998
+++ os\win32\registry.h	Fri Mar 26 14:50:54 1999
@@ -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); +




[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic