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