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

Reply via email to