Here is another pass at it, starting with some of Justin's code but
trying to work out a more agreeable place for some of the function.
This puts the -k parsing in a rewrite_args hook (one for the Unix MPMs
is implemented in mpm_common.c) and puts the actual signalling code in
an optional function called from main() (again, one for the Unix MPMs
is implemented in mpm_common.c).

This patch concentrates on distributing the work to the right places.
It only implements "-k stop", it is only enabled for the prefork MPM
(easy to enable for other MPMs), and I didn't sort out the httpd help
text (gross).

Hopefully this won't break anybody, and it can be quickly filled in
with the necessary details.

Any comments/concerns?  There must be at least ten improvements to
this that different people can think of :)

Index: include/http_log.h
===================================================================
RCS file: /home/cvs/httpd-2.0/include/http_log.h,v
retrieving revision 1.36
diff -u -r1.36 http_log.h
--- include/http_log.h  17 May 2002 10:48:06 -0000      1.36
+++ include/http_log.h  22 May 2002 17:36:39 -0000
@@ -240,6 +240,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 22 May 2002 17:36:39 -0000
@@ -59,6 +59,8 @@
 #ifndef APACHE_HTTP_MAIN_H
 #define APACHE_HTTP_MAIN_H
 
+#include "apr_optional.h"
+
 /* AP_SERVER_BASEARGS is the command argument list parsed by http_main.c
  * in apr_getopt() format.  Use this for default'ing args that the MPM
  * can safely ignore and pass on from its rewrite_args() handler.
@@ -88,6 +90,8 @@
 /** An array of all -D defines on the command line.  This allows people to
  *  effect the server based on command line options */
 AP_DECLARE_DATA extern apr_array_header_t *ap_server_config_defines;
+
+APR_DECLARE_OPTIONAL_FN(int, ap_signal_server, (int *, apr_pool_t *));
 
 #ifdef __cplusplus
 }
Index: include/mpm_common.h
===================================================================
RCS file: /home/cvs/httpd-2.0/include/mpm_common.h,v
retrieving revision 1.36
diff -u -r1.36 mpm_common.h
--- include/mpm_common.h        29 Mar 2002 16:21:48 -0000      1.36
+++ include/mpm_common.h        22 May 2002 17:36:39 -0000
@@ -280,6 +280,11 @@
                                    const char *arg);
 #endif
 
+#ifdef AP_MPM_WANT_SIGNAL_SERVER
+int ap_signal_server(int *, apr_pool_t *);
+void ap_mpm_rewrite_args(process_rec *);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
Index: server/log.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/log.c,v
retrieving revision 1.120
diff -u -r1.120 log.c
--- server/log.c        17 May 2002 11:11:37 -0000      1.120
+++ server/log.c        22 May 2002 17:36:39 -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.129
diff -u -r1.129 main.c
--- server/main.c       21 May 2002 15:40:51 -0000      1.129
+++ server/main.c       22 May 2002 17:36:39 -0000
@@ -404,8 +404,9 @@
     apr_status_t rv;
     module **mod;
     const char *optarg;
+    APR_OPTIONAL_FN_TYPE(ap_signal_server) *signal_server;
 
-    AP_MONCONTROL(0); /* turn of profiling of startup */
+    AP_MONCONTROL(0); /* turn off profiling of startup */
 
     apr_app_initialize(&argc, &argv, NULL);
 
@@ -563,6 +564,15 @@
     if (configtestonly) {
         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "Syntax OK");
         destroy_and_exit_process(process, 0);
+    }
+
+    signal_server = APR_RETRIEVE_OPTIONAL_FN(ap_signal_server);
+    if (signal_server) {
+        int exit_status;
+
+        if (signal_server(&exit_status, pconf) != 0) {
+            destroy_and_exit_process(process, exit_status);
+        }
     }
 
     apr_pool_clear(plog);
Index: server/mpm_common.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm_common.c,v
retrieving revision 1.94
diff -u -r1.94 mpm_common.c
--- server/mpm_common.c 17 May 2002 11:11:37 -0000      1.94
+++ server/mpm_common.c 22 May 2002 17:36:39 -0000
@@ -73,6 +73,8 @@
 #include "apr_strings.h"
 #define APR_WANT_STRFUNC
 #include "apr_want.h"
+#include "apr_getopt.h"
+#include "apr_optional.h"
 
 #include "httpd.h"
 #include "http_config.h"
@@ -730,3 +732,87 @@
 }
 
 #endif
+
+#ifdef AP_MPM_WANT_SIGNAL_SERVER
+
+static const char *dash_k_arg;
+
+int ap_signal_server(int *exit_status, apr_pool_t *pconf)
+{
+    apr_status_t rv;
+    pid_t otherpid;
+
+    rv = ap_read_pid(pconf, ap_pid_fname, &otherpid);
+    if (rv != APR_SUCCESS && rv != APR_ENOENT) {
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, NULL,
+                     "Error retrieving pid file %s", ap_pid_fname);
+        *exit_status = 1;
+        return 1;
+    }
+
+    if (!strcmp(dash_k_arg, "stop")) {
+        if (rv != APR_SUCCESS) {
+            printf("httpd (no pid file) not running\n");
+        }
+        else {
+            kill(otherpid, SIGTERM);
+        }
+        *exit_status = 0;
+        return 1;
+    }
+    return 0;
+}
+
+void ap_mpm_rewrite_args(process_rec *process)
+{
+    apr_array_header_t *mpm_new_argv;
+    apr_status_t rv;
+    apr_getopt_t *opt;
+    char optbuf[3];
+    const char *optarg;
+    int fixed_args;
+
+    mpm_new_argv = apr_array_make(process->pool, process->argc,
+                                  sizeof(const char **));
+    *(const char **)apr_array_push(mpm_new_argv) = process->argv[0];
+    fixed_args = mpm_new_argv->nelts;
+    apr_getopt_init(&opt, process->pool, process->argc, process->argv);
+    opt->errfn = NULL;
+    optbuf[0] = '-';
+    while ((rv = apr_getopt(opt, "k:" AP_SERVER_BASEARGS,
+                            optbuf + 1, &optarg)) == APR_SUCCESS) {
+        switch(optbuf[1]) {
+        case 'k':
+            if (!dash_k_arg && !strcmp(optarg, "stop")) {
+                dash_k_arg = optarg;
+                break;
+            }
+        default:
+            *(const char **)apr_array_push(mpm_new_argv) =
+                apr_pstrdup(process->pool, optbuf);
+            if (optarg) {
+                *(const char **)apr_array_push(mpm_new_argv) = optarg;
+            }
+        }
+    }
+
+    /* back up to capture the bad argument */
+    if (rv == APR_BADCH || rv == APR_BADARG) {
+        opt->ind--;
+    }
+
+    while (opt->ind < opt->argc) {
+        *(const char **)apr_array_push(mpm_new_argv) =
+            apr_pstrdup(process->pool, opt->argv[opt->ind++]);
+    }
+
+    process->argc = mpm_new_argv->nelts;
+    process->argv = (const char * const *)mpm_new_argv->elts;
+
+    if (dash_k_arg) {
+        APR_REGISTER_OPTIONAL_FN(ap_signal_server);
+    }
+}
+
+#endif /* AP_MPM_WANT_SIGNAL_SERVER */
+
Index: server/mpm/prefork/mpm.h
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/prefork/mpm.h,v
retrieving revision 1.19
diff -u -r1.19 mpm.h
--- server/mpm/prefork/mpm.h    29 Mar 2002 16:15:33 -0000      1.19
+++ server/mpm/prefork/mpm.h    22 May 2002 17:36:39 -0000
@@ -77,6 +77,7 @@
 #define AP_MPM_WANT_SET_MAX_REQUESTS
 #define AP_MPM_WANT_SET_COREDUMPDIR
 #define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
+#define AP_MPM_WANT_SIGNAL_SERVER
 #define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
 
 #define AP_MPM_USES_POD 1
Index: server/mpm/prefork/prefork.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/prefork/prefork.c,v
retrieving revision 1.263
diff -u -r1.263 prefork.c
--- server/mpm/prefork/prefork.c        17 May 2002 11:11:39 -0000      1.263
+++ server/mpm/prefork/prefork.c        22 May 2002 17:36:39 -0000
@@ -1388,7 +1388,7 @@
 
 module AP_MODULE_DECLARE_DATA mpm_prefork_module = {
     MPM20_MODULE_STUFF,
-    NULL,                       /* hook to run before apache parses args */
+    ap_mpm_rewrite_args,        /* hook to run before apache parses args */
     NULL,                      /* create per-directory config structure */
     NULL,                      /* merge per-directory config structures */
     NULL,                      /* create per-server config structure */

-- 
Jeff Trawick | [EMAIL PROTECTED]
Born in Roswell... married an alien...

Reply via email to