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