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);
}