X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=server%2Fmpm_common.c;h=214c1be94f0fe2b8c6c0ab2e546c3c9db2db3d00;hb=aa21671e13767135f0ee3f88d6a3ff6d039e6534;hp=57c3c037ac53f6291e5804f4b2c84eee5fb6795f;hpb=b491e30b1c3b41a3de07979fee75b16582254eb4;p=apache diff --git a/server/mpm_common.c b/server/mpm_common.c index 57c3c037ac..214c1be94f 100644 --- a/server/mpm_common.c +++ b/server/mpm_common.c @@ -1,7 +1,7 @@ /* ==================================================================== * The Apache Software License, Version 1.1 * - * Copyright (c) 2000-2001 The Apache Software Foundation. All rights + * Copyright (c) 2000-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -71,9 +71,11 @@ #include "apr_thread_proc.h" #include "apr_signal.h" #include "apr_strings.h" -#include "apr_lock.h" #define APR_WANT_STRFUNC #include "apr_want.h" +#include "apr_getopt.h" +#include "apr_optional.h" +#include "apr_allocator.h" #include "httpd.h" #include "http_config.h" @@ -83,6 +85,7 @@ #include "mpm_common.h" #include "ap_mpm.h" #include "ap_listen.h" +#include "mpm_default.h" #ifdef AP_MPM_WANT_SET_SCOREBOARD #include "scoreboard.h" @@ -94,6 +97,9 @@ #ifdef HAVE_GRP_H #include #endif +#if APR_HAVE_UNISTD_H +#include +#endif #ifdef AP_MPM_WANT_RECLAIM_CHILD_PROCESSES void ap_reclaim_child_processes(int terminate) @@ -106,15 +112,14 @@ void ap_reclaim_child_processes(int terminate) int max_daemons; ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons); - MPM_SYNC_CHILD_TABLE(); for (tries = terminate ? 4 : 1; tries <= 9; ++tries) { /* don't want to hold up progress any more than * necessary, but we need to allow children a few moments to exit. * Set delay with an exponential backoff. */ - waittime = waittime * 4; apr_sleep(waittime); + waittime = waittime * 4; /* now see who is done */ not_dead_yet = 0; @@ -131,6 +136,7 @@ void ap_reclaim_child_processes(int terminate) MPM_NOTE_CHILD_KILLED(i); continue; } + ++not_dead_yet; switch (tries) { case 1: /* 16ms */ @@ -138,21 +144,25 @@ void ap_reclaim_child_processes(int terminate) case 3: /* 344ms */ case 4: /* 16ms */ break; + case 5: /* 82ms */ case 6: /* 344ms */ case 7: /* 1.4sec */ /* ok, now it's being annoying */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, - "child process %ld still did not exit, sending a SIGTERM", + "child process %ld still did not exit, " + "sending a SIGTERM", (long)pid); kill(pid, SIGTERM); break; + case 8: /* 6 sec */ /* die child scum */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, - "child process %ld still did not exit, sending a SIGKILL", + "child process %ld still did not exit, " + "sending a SIGKILL", (long)pid); #ifndef BEOS kill(pid, SIGKILL); @@ -166,22 +176,26 @@ void ap_reclaim_child_processes(int terminate) kill_thread(pid); #endif break; + case 9: /* 14 sec */ /* gave it our best shot, but alas... If this really * is a child we are trying to kill and it really hasn't * exited, we will likely fail to bind to the port * after the restart. */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "could not make child process %ld exit, " - "attempting to continue anyway", (long)pid); + "attempting to continue anyway", + (long)pid); break; } } + #if APR_HAS_OTHER_CHILD apr_proc_other_child_check(); #endif + if (!not_dead_yet) { /* nothing left to wait for */ break; @@ -207,19 +221,23 @@ void ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode, apr_proc_t *ret, if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) { wait_or_timeout_counter = 0; } + rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p); if (APR_STATUS_IS_EINTR(rv)) { ret->pid = -1; return; } + if (APR_STATUS_IS_CHILD_DONE(rv)) { return; } + #ifdef NEED_WAITPID if ((ret = reap_children(exitcode, status)) > 0) { return; } #endif + apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL); ret->pid = -1; return; @@ -230,21 +248,32 @@ void ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode, apr_proc_t *ret, int ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status) { int signum = status; - const char *sigdesc = apr_signal_get_description(signum); + const char *sigdesc = apr_signal_description_get(signum); /* Child died... if it died due to a fatal error, * we should simply bail out. The caller needs to * check for bad rc from us and exit, running any * appropriate cleanups. + * + * If the child died due to a resource shortage, + * the parent should limit the rate of forking */ - if ((APR_PROC_CHECK_EXIT(why)) && - (status == APEXIT_CHILDFATAL)) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, ap_server_conf, - "Child %" APR_OS_PROC_T_FMT - " returned a Fatal error..." APR_EOL_STR - "Apache is exiting!", - pid->pid); - return APEXIT_CHILDFATAL; + if (APR_PROC_CHECK_EXIT(why)) { + if (status == APEXIT_CHILDSICK) { + return status; + } + + if (status == APEXIT_CHILDFATAL) { + ap_log_error(APLOG_MARK, APLOG_ALERT, + 0, ap_server_conf, + "Child %" APR_PID_T_FMT + " returned a Fatal error..." APR_EOL_STR + "Apache is exiting!", + pid->pid); + return APEXIT_CHILDFATAL; + } + + return 0; } if (APR_PROC_CHECK_SIGNALED(why)) { @@ -254,9 +283,10 @@ int ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status) case AP_SIG_GRACEFUL: case SIGKILL: break; + default: if (APR_PROC_CHECK_CORE_DUMP(why)) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, "child pid %ld exit signal %s (%d), " "possible coredump in %s", @@ -264,7 +294,7 @@ int ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status) ap_coredump_dir); } else { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, "child pid %ld exit signal %s (%d)", (long)pid->pid, sigdesc, signum); @@ -275,7 +305,7 @@ int ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status) } #endif /* AP_MPM_WANT_PROCESS_CHILD_STATUS */ -#if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF) && !defined(WIN32) +#if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF) void ap_sock_disable_nagle(apr_socket_t *s) { /* The Nagle algorithm says that we should delay sending partial @@ -287,11 +317,11 @@ void ap_sock_disable_nagle(apr_socket_t *s) * * In spite of these problems, failure here is not a shooting offense. */ - apr_status_t status = apr_setsocketopt(s, APR_TCP_NODELAY, 1); + apr_status_t status = apr_socket_opt_set(s, APR_TCP_NODELAY, 1); if (status != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, status, ap_server_conf, - "setsockopt: (TCP_NODELAY)"); + "apr_socket_opt_set: (TCP_NODELAY)"); } } #endif @@ -305,9 +335,11 @@ AP_DECLARE(uid_t) ap_uname2id(const char *name) return (atoi(&name[1])); if (!(ent = getpwnam(name))) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "%s: bad user name %s", ap_server_argv0, name); + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "%s: bad user name %s", ap_server_argv0, name); exit(1); } + return (ent->pw_uid); } #endif @@ -321,8 +353,11 @@ AP_DECLARE(gid_t) ap_gname2id(const char *name) return (atoi(&name[1])); if (!(ent = getgrnam(name))) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "%s: bad group name %s", ap_server_argv0, name); exit(1); + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "%s: bad group name %s", ap_server_argv0, name); + exit(1); } + return (ent->gr_gid); } #endif @@ -342,14 +377,16 @@ int initgroups(const char *name, gid_t basegid) groups[index++] = basegid; - while (index < NGROUPS_MAX && ((g = getgrent()) != NULL)) + while (index < NGROUPS_MAX && ((g = getgrent()) != NULL)) { if (g->gr_gid != basegid) { char **names; - for (names = g->gr_mem; *names != NULL; ++names) + for (names = g->gr_mem; *names != NULL; ++names) { if (!strcmp(*names, name)) groups[index++] = g->gr_gid; + } } + } endgrent(); @@ -369,12 +406,17 @@ AP_DECLARE(apr_status_t) ap_mpm_pod_open(apr_pool_t *p, ap_pod_t **pod) if (rv != APR_SUCCESS) { return rv; } + apr_file_pipe_timeout_set((*pod)->pod_in, 0); (*pod)->p = p; - + apr_sockaddr_info_get(&(*pod)->sa, ap_listeners->bind_addr->hostname, APR_UNSPEC, ap_listeners->bind_addr->port, 0, p); + /* close these before exec. */ + apr_file_inherit_unset((*pod)->pod_in); + apr_file_inherit_unset((*pod)->pod_out); + return APR_SUCCESS; } @@ -389,9 +431,11 @@ AP_DECLARE(apr_status_t) ap_mpm_pod_check(ap_pod_t *pod) if ((rv == APR_SUCCESS) && (len == 1)) { return APR_SUCCESS; } + if (rv != APR_SUCCESS) { return rv; } + return AP_NORESTART; } @@ -408,7 +452,8 @@ AP_DECLARE(apr_status_t) ap_mpm_pod_close(ap_pod_t *pod) if (rv != APR_SUCCESS) { return rv; } - return rv; + + return APR_SUCCESS; } static apr_status_t pod_signal_internal(ap_pod_t *pod) @@ -417,13 +462,12 @@ static apr_status_t pod_signal_internal(ap_pod_t *pod) char char_of_death = '!'; apr_size_t one = 1; - do { - rv = apr_file_write(pod->pod_out, &char_of_death, &one); - } while (APR_STATUS_IS_EINTR(rv)); + rv = apr_file_write(pod->pod_out, &char_of_death, &one); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, "write pipe_of_death"); } + return rv; } @@ -432,50 +476,51 @@ static apr_status_t pod_signal_internal(ap_pod_t *pod) * socket, because it provides a alternate way to unblock an accept() when * the pod is used. */ - static apr_status_t dummy_connection(ap_pod_t *pod) { apr_status_t rv; apr_socket_t *sock; apr_pool_t *p; - + /* create a temporary pool for the socket. pconf stays around too long */ rv = apr_pool_create(&p, pod->p); if (rv != APR_SUCCESS) { return rv; } - - rv = apr_socket_create(&sock, pod->sa->family, SOCK_STREAM, p); + + rv = apr_socket_create(&sock, pod->sa->family, SOCK_STREAM, 0, p); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, "get socket to connect to listener"); return rv; } + /* on some platforms (e.g., FreeBSD), the kernel won't accept many * queued connections before it starts blocking local connects... * we need to keep from blocking too long and instead return an error, * because the MPM won't want to hold up a graceful restart for a * long time */ - rv = apr_setsocketopt(sock, APR_SO_TIMEOUT, 3 * APR_USEC_PER_SEC); + rv = apr_socket_timeout_set(sock, apr_time_from_sec(3)); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, "set timeout on socket to connect to listener"); + apr_socket_close(sock); return rv; } - - rv = apr_connect(sock, pod->sa); + + rv = apr_socket_connect(sock, pod->sa); if (rv != APR_SUCCESS) { int log_level = APLOG_WARNING; if (APR_STATUS_IS_TIMEUP(rv)) { - /* probably some server processes bailed out already and there - * is nobody around to call accept and clear out the kernel + /* probably some server processes bailed out already and there + * is nobody around to call accept and clear out the kernel * connection queue; usually this is not worth logging */ log_level = APLOG_DEBUG; } - + ap_log_error(APLOG_MARK, log_level, rv, ap_server_conf, "connect to listener"); } @@ -494,6 +539,7 @@ AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod) if (rv != APR_SUCCESS) { return rv; } + return dummy_connection(pod); } @@ -502,13 +548,21 @@ void ap_mpm_pod_killpg(ap_pod_t *pod, int num) int i; apr_status_t rv = APR_SUCCESS; + /* we don't write anything to the pod here... we assume + * that the would-be reader of the pod has another way to + * see that it is time to die once we wake it up + * + * writing lots of things to the pod at once is very + * problematic... we can fill the kernel pipe buffer and + * be blocked until somebody consumes some bytes or + * we hit a timeout... if we hit a timeout we can't just + * keep trying because maybe we'll never successfully + * write again... but then maybe we'll leave would-be + * readers stranded (a number of them could be tied up for + * a while serving time-consuming requests) + */ for (i = 0; i < num && rv == APR_SUCCESS; i++) { - rv = pod_signal_internal(pod); - } - if (rv == APR_SUCCESS) { - for (i = 0; i < num && rv == APR_SUCCESS; i++) { - rv = dummy_connection(pod); - } + rv = dummy_connection(pod); } } #endif /* #ifdef AP_MPM_USES_POD */ @@ -526,16 +580,17 @@ const char *ap_mpm_set_pidfile(cmd_parms *cmd, void *dummy, } if (cmd->server->is_virtual) { - return "PidFile directive not allowed in "; + return "PidFile directive not allowed in "; } + ap_pid_fname = arg; return NULL; } #endif #ifdef AP_MPM_WANT_SET_SCOREBOARD -AP_DECLARE(const char *) ap_mpm_set_scoreboard(cmd_parms *cmd, void *dummy, - const char *arg) +const char * ap_mpm_set_scoreboard(cmd_parms *cmd, void *dummy, + const char *arg) { const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { @@ -549,8 +604,9 @@ AP_DECLARE(const char *) ap_mpm_set_scoreboard(cmd_parms *cmd, void *dummy, #ifdef AP_MPM_WANT_SET_LOCKFILE const char *ap_lock_fname = NULL; -AP_DECLARE(const char *) ap_mpm_set_lockfile(cmd_parms *cmd, void *dummy, - const char *arg) + +const char *ap_mpm_set_lockfile(cmd_parms *cmd, void *dummy, + const char *arg) { const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { @@ -564,6 +620,7 @@ AP_DECLARE(const char *) ap_mpm_set_lockfile(cmd_parms *cmd, void *dummy, #ifdef AP_MPM_WANT_SET_MAX_REQUESTS int ap_max_requests_per_child = 0; + const char *ap_mpm_set_max_requests(cmd_parms *cmd, void *dummy, const char *arg) { @@ -580,9 +637,12 @@ const char *ap_mpm_set_max_requests(cmd_parms *cmd, void *dummy, #ifdef AP_MPM_WANT_SET_COREDUMPDIR char ap_coredump_dir[MAX_STRING_LEN]; +int ap_coredumpdir_configured; + const char *ap_mpm_set_coredumpdir(cmd_parms *cmd, void *dummy, const char *arg) { + apr_status_t rv; apr_finfo_t finfo; const char *fname; const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); @@ -591,21 +651,49 @@ const char *ap_mpm_set_coredumpdir(cmd_parms *cmd, void *dummy, } fname = ap_server_root_relative(cmd->pool, arg); - if ((apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) - || (finfo.filetype != APR_DIR)) { - return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, - " does not exist or is not a directory", NULL); + if (!fname) { + return apr_pstrcat(cmd->pool, "Invalid CoreDumpDirectory path ", + arg, NULL); + } + if ((rv = apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool)) != APR_SUCCESS) { + return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, + " does not exist", NULL); + } + if (finfo.filetype != APR_DIR) { + return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, + " is not a directory", NULL); } apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir)); + ap_coredumpdir_configured = 1; return NULL; } #endif #ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH -apr_lockmech_e_np ap_accept_lock_mech = APR_LOCK_DEFAULT; +apr_lockmech_e ap_accept_lock_mech = APR_LOCK_DEFAULT; + +const char ap_valid_accept_mutex_string[] = + "Valid accept mutexes for this platform and MPM are: default" +#if APR_HAS_FLOCK_SERIALIZE + ", flock" +#endif +#if APR_HAS_FCNTL_SERIALIZE + ", fcntl" +#endif +#if APR_HAS_SYSVSEM_SERIALIZE && !defined(PERCHILD_MPM) + ", sysvsem" +#endif +#if APR_HAS_POSIXSEM_SERIALIZE + ", posixsem" +#endif +#if APR_HAS_PROC_PTHREAD_SERIALIZE + ", pthread" +#endif + "."; + AP_DECLARE(const char *) ap_mpm_set_accept_lock_mech(cmd_parms *cmd, - void *dummy, - const char *arg) + void *dummy, + const char *arg) { const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); if (err != NULL) { @@ -625,6 +713,7 @@ AP_DECLARE(const char *) ap_mpm_set_accept_lock_mech(cmd_parms *cmd, ap_accept_lock_mech = APR_LOCK_FCNTL; } #endif + /* perchild can't use SysV sems because the permissions on the accept * mutex can't be set to allow all processes to use the mutex and * at the same time keep all users from being able to dink with the @@ -635,28 +724,290 @@ AP_DECLARE(const char *) ap_mpm_set_accept_lock_mech(cmd_parms *cmd, ap_accept_lock_mech = APR_LOCK_SYSVSEM; } #endif +#if APR_HAS_POSIXSEM_SERIALIZE + else if (!strcasecmp(arg, "posixsem")) { + ap_accept_lock_mech = APR_LOCK_POSIXSEM; + } +#endif #if APR_HAS_PROC_PTHREAD_SERIALIZE else if (!strcasecmp(arg, "pthread")) { ap_accept_lock_mech = APR_LOCK_PROC_PTHREAD; } #endif else { - return apr_pstrcat(cmd->pool, arg, " is an invalid mutex mechanism; valid " - "ones for this platform and MPM are: default" -#if APR_HAS_FLOCK_SERIALIZE - ", flock" -#endif -#if APR_HAS_FCNTL_SERIALIZE - ", fcntl" -#endif -#if APR_HAS_SYSVSEM_SERIALIZE && !defined(PERCHILD_MPM) - ", sysvsem" -#endif -#if APR_HAS_PROC_PTHREAD_SERIALIZE - ", pthread" + return apr_pstrcat(cmd->pool, arg, " is an invalid mutex mechanism; ", + ap_valid_accept_mutex_string, NULL); + } + return NULL; +} + #endif - , NULL); + +#ifdef AP_MPM_WANT_SIGNAL_SERVER + +static const char *dash_k_arg; + +static int send_signal(pid_t pid, int sig) +{ + if (kill(pid, sig) < 0) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, errno, NULL, + "sending signal to server"); + return 1; + } + return 0; +} + +int ap_signal_server(int *exit_status, apr_pool_t *pconf) +{ + apr_status_t rv; + pid_t otherpid; + int running = 0; + int have_pid_file = 0; + const char *status; + + *exit_status = 0; + + rv = ap_read_pid(pconf, ap_pid_fname, &otherpid); + if (rv != APR_SUCCESS) { + if (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; + } + status = "httpd (no pid file) not running"; + } + else { + have_pid_file = 1; + if (kill(otherpid, 0) == 0) { + running = 1; + status = apr_psprintf(pconf, + "httpd (pid %" APR_PID_T_FMT ") already " + "running", otherpid); + } + else { + status = apr_psprintf(pconf, + "httpd (pid %" APR_PID_T_FMT "?) not running", + otherpid); + } + } + + if (!strcmp(dash_k_arg, "start")) { + if (running) { + printf("%s\n", status); + return 1; + } + } + + if (!strcmp(dash_k_arg, "stop")) { + if (!running) { + printf("%s\n", status); + } + else { + send_signal(otherpid, SIGTERM); + } + return 1; + } + + if (!strcmp(dash_k_arg, "restart")) { + if (!running) { + printf("httpd not running, trying to start\n"); + } + else { + *exit_status = send_signal(otherpid, SIGHUP); + return 1; + } + } + + if (!strcmp(dash_k_arg, "graceful")) { + if (!running) { + printf("httpd not running, trying to start\n"); + } + else { + *exit_status = send_signal(otherpid, SIGUSR1); + 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] = '-'; + /* option char returned by apr_getopt() will be stored in optbuf[1] */ + optbuf[2] = '\0'; + while ((rv = apr_getopt(opt, "k:" AP_SERVER_BASEARGS, + optbuf + 1, &optarg)) == APR_SUCCESS) { + switch(optbuf[1]) { + case 'k': + if (!dash_k_arg) { + if (!strcmp(optarg, "start") || !strcmp(optarg, "stop") || + !strcmp(optarg, "restart") || !strcmp(optarg, "graceful")) { + 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 */ + +#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE +apr_uint32_t ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; + +const char *ap_mpm_set_max_mem_free(cmd_parms *cmd, void *dummy, + const char *arg) +{ + long value; + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + return err; + } + + value = strtol(arg, NULL, 0); + if (value < 0 || errno == ERANGE) + return apr_pstrcat(cmd->pool, "Invalid MaxMemFree value: ", + arg, NULL); + + ap_max_mem_free = (apr_uint32_t)value * 1024; + return NULL; } + +#endif /* AP_MPM_WANT_SET_MAX_MEM_FREE */ + +#ifdef AP_MPM_WANT_FATAL_SIGNAL_HANDLER + +static pid_t parent_pid, my_pid; +apr_pool_t *pconf; + +/* handle all varieties of core dumping signals */ +static void sig_coredump(int sig) +{ + apr_filepath_set(ap_coredump_dir, pconf); + apr_signal(sig, SIG_DFL); + if (my_pid == parent_pid) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, + 0, ap_server_conf, + "seg fault or similar nasty error detected " + "in the parent process"); + /* XXX we can probably add some rudimentary cleanup code here, + * like getting rid of the pid file. If any additional bad stuff + * happens, we are protected from recursive errors taking down the + * system since this function is no longer the signal handler GLA + */ + } + kill(getpid(), sig); + /* At this point we've got sig blocked, because we're still inside + * the signal handler. When we leave the signal handler it will + * be unblocked, and we'll take the signal... and coredump or whatever + * is appropriate for this particular Unix. In addition the parent + * will see the real signal we received -- whereas if we called + * abort() here, the parent would only see SIGABRT. + */ +} + +apr_status_t ap_fatal_signal_child_setup(server_rec *s) +{ + my_pid = getpid(); + return APR_SUCCESS; +} + +apr_status_t ap_fatal_signal_setup(server_rec *s, apr_pool_t *in_pconf) +{ +#ifndef NO_USE_SIGACTION + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + +#if defined(SA_ONESHOT) + sa.sa_flags = SA_ONESHOT; +#elif defined(SA_RESETHAND) + sa.sa_flags = SA_RESETHAND; +#else + sa.sa_flags = 0; #endif + + sa.sa_handler = sig_coredump; + if (sigaction(SIGSEGV, &sa, NULL) < 0) + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGSEGV)"); +#ifdef SIGBUS + if (sigaction(SIGBUS, &sa, NULL) < 0) + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGBUS)"); +#endif +#ifdef SIGABORT + if (sigaction(SIGABORT, &sa, NULL) < 0) + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGABORT)"); +#endif +#ifdef SIGABRT + if (sigaction(SIGABRT, &sa, NULL) < 0) + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGABRT)"); +#endif +#ifdef SIGILL + if (sigaction(SIGILL, &sa, NULL) < 0) + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGILL)"); +#endif + +#else /* NO_USE_SIGACTION */ + + apr_signal(SIGSEGV, sig_coredump); +#ifdef SIGBUS + apr_signal(SIGBUS, sig_coredump); +#endif /* SIGBUS */ +#ifdef SIGABORT + apr_signal(SIGABORT, sig_coredump); +#endif /* SIGABORT */ +#ifdef SIGABRT + apr_signal(SIGABRT, sig_coredump); +#endif /* SIGABRT */ +#ifdef SIGILL + apr_signal(SIGILL, sig_coredump); +#endif /* SIGILL */ + +#endif /* NO_USE_SIGACTION */ + + pconf = in_pconf; + parent_pid = my_pid = getpid(); + + return APR_SUCCESS; +} + +#endif /* AP_MPM_WANT_FATAL_SIGNAL_HANDLER */