Here's a starting point for someone else to pick up how to get httpd to honor -k [start|stop|graceful|restart] options.
I'm not going to finish it because: a) I'm not really sure what to do on Win32. b) What happens if an MPM decides it doesn't use a PID? (Perhaps this code needs to get moved to mpm_common.c, but then we'd have to reparse argv!) c) We may need to abstract out the kill func with APR. We can't use apr_proc_kill right now because we need a full apr_proc_t structure while we only know the PID. (no apr_os_proc_{set|get}) d) I don't have time. This works here for me on Unix-based platforms, but I'm afraid I can't take this one to its logical conclusion. So, if someone else is interested, here's a head start that might be useful. -- justin Index: include/http_log.h =================================================================== RCS file: /home/cvs/httpd-2.0/include/http_log.h,v retrieving revision 1.35 diff -u -r1.35 http_log.h --- include/http_log.h 22 Apr 2002 03:25:40 -0000 1.35 +++ include/http_log.h 17 May 2002 05:50:30 -0000 @@ -237,6 +237,14 @@ */ AP_DECLARE(void) ap_log_pid(apr_pool_t *p, const char *fname); +/** + * Retrieve the pid from a pidfile. + * @param p The pool to use for logging + * @param filename The name of the file containing the pid + * @param mypid Pointer to pid_t (valid only if return APR_SUCCESS) + */ +AP_DECLARE(apr_status_t) ap_read_pid(apr_pool_t *p, const char *filename, pid_t +*mypid); + typedef struct piped_log piped_log; /** Index: include/http_main.h =================================================================== RCS file: /home/cvs/httpd-2.0/include/http_main.h,v retrieving revision 1.23 diff -u -r1.23 http_main.h --- include/http_main.h 17 Apr 2002 16:36:27 -0000 1.23 +++ include/http_main.h 17 May 2002 05:50:30 -0000 @@ -63,7 +63,7 @@ * in apr_getopt() format. Use this for default'ing args that the MPM * can safely ignore and pass on from its rewrite_args() handler. */ -#define AP_SERVER_BASEARGS "C:c:D:d:E:e:f:vVlLth?X" +#define AP_SERVER_BASEARGS "C:c:D:d:E:e:f:k:vVlLth?X" #ifdef __cplusplus extern "C" { Index: server/log.c =================================================================== RCS file: /home/cvs/httpd-2.0/server/log.c,v retrieving revision 1.118 diff -u -r1.118 log.c --- server/log.c 22 Apr 2002 03:25:40 -0000 1.118 +++ server/log.c 17 May 2002 05:50:31 -0000 @@ -626,6 +626,55 @@ saved_pid = mypid; } +AP_DECLARE(apr_status_t) ap_read_pid(apr_pool_t *p, const char *filename, + pid_t *mypid) +{ + const int BUFFER_SIZE = sizeof(long) * 3 + 2; /* see apr_ltoa */ + apr_file_t *pid_file = NULL; + apr_status_t rv; + const char *fname; + char *buf, *endptr; + apr_size_t bytes_wanted, bytes_read; + + if (!filename) { + return APR_EGENERAL; + } + + fname = ap_server_root_relative(p, filename); + if (!fname) { + ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, APR_EBADPATH, + NULL, "Invalid PID file path %s, ignoring.", filename); + return APR_EGENERAL; + } + + rv = apr_file_open(&pid_file, fname, APR_READ, APR_OS_DEFAULT, p); + if (rv != APR_SUCCESS) { + return rv; + } + + bytes_wanted = BUFFER_SIZE; + endptr = buf = apr_palloc(p, BUFFER_SIZE); + do { + bytes_read = bytes_wanted; + rv = apr_file_read(pid_file, endptr, &bytes_read); + if (rv != APR_SUCCESS && rv != APR_EOF) { + return rv; + } + bytes_wanted -= bytes_read; + endptr += bytes_read; + } + while (bytes_wanted > 0 && rv != APR_EOF); + + *mypid = strtol(buf, &endptr, 10); + /* We only know for sure that the beginning part is the pid. */ + if (*buf == '\0' || *endptr != '\n') { + return APR_EGENERAL; + } + + apr_file_close(pid_file); + return APR_SUCCESS; +} + AP_DECLARE(void) ap_log_assert(const char *szExp, const char *szFile, int nLine) { Index: server/main.c =================================================================== RCS file: /home/cvs/httpd-2.0/server/main.c,v retrieving revision 1.127 diff -u -r1.127 main.c --- server/main.c 17 Apr 2002 16:36:28 -0000 1.127 +++ server/main.c 17 May 2002 05:50:32 -0000 @@ -77,6 +77,15 @@ #include "util_ebcdic.h" #include "ap_mpm.h" +typedef enum { + AP_NONE, + AP_START, + AP_STOP, + AP_RESTART, + AP_GRACEFUL +} ap_signaltype_e; +extern const char *ap_pid_fname; + /* WARNING: Win32 binds http_main.c dynamically to the server. Please place * extern functions and global data in another appropriate module. * @@ -301,11 +310,11 @@ ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " %s [-C \"directive\"] [-c \"directive\"]", pad); + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + " %s [-k start|restart|stop|graceful]", pad); #ifdef WIN32 ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " %s [-k start|restart|stop|shutdown]", pad); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " %s [-k install|config|uninstall] [-n service_name]", pad); #endif @@ -336,17 +345,21 @@ " -c \"directive\" : process directive after reading " "config files"); -#ifdef WIN32 - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " -n name : set service name and use its " - "ServerConfigFile"); ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -k start : tell Apache to start"); ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " -k restart : tell running Apache to do a graceful " + " -k restart : tell running Apache to do a graceless " + "restart"); + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + " -k graceful : tell running Apache to do a graceful " "restart"); ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -k stop|shutdown : tell running Apache to shutdown"); + +#ifdef WIN32 + ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, + " -n name : set service name and use its " + "ServerConfigFile"); ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -k install : install an Apache service"); ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, @@ -404,6 +417,7 @@ apr_status_t rv; module **mod; const char *optarg; + ap_signaltype_e sendsignal = AP_NONE; AP_MONCONTROL(0); /* turn of profiling of startup */ @@ -502,6 +516,25 @@ confname = optarg; break; + case 'k': + if (strcasecmp(optarg, "start") == 0) { + sendsignal = AP_START; + } + else if (strcasecmp(optarg, "stop") == 0 || + strcasecmp(optarg, "shutdown") == 0) { + sendsignal = AP_STOP; + } + else if (strcasecmp(optarg, "restart") == 0) { + sendsignal = AP_RESTART; + } + else if (strcasecmp(optarg, "graceful") == 0) { + sendsignal = AP_GRACEFUL; + } + else { + usage(process); + } + break; + case 'v': printf("Server version: %s\n", ap_get_server_version()); printf("Server built: %s\n", ap_get_server_built()); @@ -563,6 +596,36 @@ if (configtestonly) { ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Syntax OK\n"); + destroy_and_exit_process(process, 0); + } + + if (sendsignal != AP_NONE && sendsignal != AP_START) { + pid_t otherpid; + int desired_signal; + rv = ap_read_pid(pconf, ap_pid_fname, &otherpid); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, NULL, + "Error retrieving pid file\n"); + destroy_and_exit_process(process, 1); + } + + switch (sendsignal) { + case AP_STOP: + desired_signal = SIGTERM; + break; + case AP_RESTART: + desired_signal = SIGHUP; + break; + case AP_GRACEFUL: + desired_signal = AP_SIG_GRACEFUL; + break; + case AP_NONE: + case AP_START: + default: + /* Don't do anything. Just fall through. */ + break; + } + rv = kill(otherpid, desired_signal); destroy_and_exit_process(process, 0); }