From 1acac7a6b494db24f8f58e44dab7657b6de68742 Mon Sep 17 00:00:00 2001 From: Stefan Fritsch Date: Tue, 27 Dec 2011 19:42:13 +0100 Subject: Upstream tarball 2.2.6 --- server/NWGNUmakefile | 6 +- server/core.c | 2 +- server/log.c | 95 ++++++++++++++++++-------- server/main.c | 39 +++++++---- server/mpm/experimental/event/event.c | 10 ++- server/mpm/experimental/event/fdqueue.c | 3 +- server/mpm/netware/mpm_netware.c | 10 +++ server/mpm/prefork/prefork.c | 14 ++-- server/mpm/winnt/Win9xConHook.dsp | 12 ++++ server/mpm/winnt/mpm_winnt.c | 114 +++++++++++++++++++++----------- server/mpm/worker/fdqueue.c | 3 +- server/mpm/worker/worker.c | 10 ++- server/mpm_common.c | 72 ++++++++++++++++++++ server/request.c | 5 +- server/util.c | 7 +- 15 files changed, 291 insertions(+), 111 deletions(-) (limited to 'server') diff --git a/server/NWGNUmakefile b/server/NWGNUmakefile index f2f6da75..512adfdc 100644 --- a/server/NWGNUmakefile +++ b/server/NWGNUmakefile @@ -102,7 +102,7 @@ NLM_NAME = genchars # This is used by the link '-desc ' directive. # If left blank, NLM_NAME will be used. # -NLM_DESCRIPTION = Generate Test Characters +NLM_DESCRIPTION = Apache $(VERSION_STR) Generate Test Characters # # This is used by the '-threadname' directive. If left blank, @@ -112,9 +112,9 @@ NLM_THREAD_NAME = genchars # # If this is specified, it will override VERSION value in -# $(AP_WORK)\NWGNUNetWare.rul +# $(AP_WORK)\build\NWGNUenvironment.inc # -NLM_VERSION = 1,0,0 +NLM_VERSION = # # If this is specified, it will override the default of 64K diff --git a/server/core.c b/server/core.c index 69cd3dcb..b4aca33b 100644 --- a/server/core.c +++ b/server/core.c @@ -417,7 +417,7 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv) conf->etag_add = (conf->etag_add & (~ new->etag_remove)) | new->etag_add; conf->etag_remove = - (conf->opts_remove & (~ new->etag_add)) | new->etag_remove; + (conf->etag_remove & (~ new->etag_add)) | new->etag_remove; conf->etag_bits = (conf->etag_bits & (~ conf->etag_remove)) | conf->etag_add; } diff --git a/server/log.c b/server/log.c index c027f002..14b4fdc2 100644 --- a/server/log.c +++ b/server/log.c @@ -139,6 +139,8 @@ static const TRANS priorities[] = { {NULL, -1}, }; +static apr_pool_t *stderr_pool = NULL; + static apr_file_t *stderr_log = NULL; /* track pipe handles to close in child process */ @@ -151,7 +153,7 @@ static read_handle_t *read_handles; /* clear_handle_list() is called when plog is cleared; at that * point we need to forget about our old list of pipe read - * handles + * handles. We let the plog cleanups close the actual pipes. */ static apr_status_t clear_handle_list(void *v) { @@ -205,15 +207,36 @@ AP_DECLARE(apr_status_t) ap_replace_stderr_log(apr_pool_t *p, ap_server_argv0, fname); return rc; } - if ((rc = apr_file_open_stderr(&stderr_log, p)) == APR_SUCCESS) { + if (!stderr_pool) { + /* This is safe provided we revert it when we are finished. + * We don't manager the callers pool! + */ + stderr_pool = p; + } + if ((rc = apr_file_open_stderr(&stderr_log, stderr_pool)) + == APR_SUCCESS) { apr_file_flush(stderr_log); - if ((rc = apr_file_dup2(stderr_log, stderr_file, p)) == APR_SUCCESS) { + if ((rc = apr_file_dup2(stderr_log, stderr_file, stderr_pool)) + == APR_SUCCESS) { apr_file_close(stderr_file); + /* + * You might ponder why stderr_pool should survive? + * The trouble is, stderr_pool may have s_main->error_log, + * so we aren't in a position to destory stderr_pool until + * the next recycle. There's also an apparent bug which + * is not; if some folk decided to call this function before + * the core open error logs hook, this pool won't survive. + * Neither does the stderr logger, so this isn't a problem. + */ } } + /* Revert, see above */ + if (stderr_pool == p) + stderr_pool = NULL; + if (rc != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rc, NULL, - "unable to replace stderr with error_log"); + "unable to replace stderr with error log file"); } return rc; } @@ -250,18 +273,20 @@ static int log_child(apr_pool_t *p, const char *progname, APR_NO_PIPE, APR_NO_PIPE)) == APR_SUCCESS) && ((rc = apr_procattr_error_check_set(procattr, 1)) == APR_SUCCESS) - && ((rc = apr_procattr_child_errfn_set(procattr, log_child_errfn)) == APR_SUCCESS) - && (!dummy_stderr - || ((rc = apr_file_open_stdout(&errfile, p)) == APR_SUCCESS - && (rc = apr_procattr_child_err_set(procattr, - errfile, - errfile)) == APR_SUCCESS))) { + && ((rc = apr_procattr_child_errfn_set(procattr, log_child_errfn)) + == APR_SUCCESS)) { char **args; const char *pname; apr_tokenize_to_argv(progname, &args, p); pname = apr_pstrdup(p, args[0]); procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew)); + + if (dummy_stderr) { + if ((rc = apr_file_open_stdout(&errfile, p)) == APR_SUCCESS) + rc = apr_procattr_child_err_set(procattr, errfile, NULL); + } + rc = apr_proc_create(procnew, pname, (const char * const *)args, NULL, procattr, p); @@ -272,13 +297,6 @@ static int log_child(apr_pool_t *p, const char *progname, * close_handle_in_child() */ } - - /* apr_procattr_child_err_set dups errfile twice: close the - * remaining "parent-side" copy (apr_proc_create closes the - * other). */ - if (dummy_stderr) { - apr_file_close(procnew->err); - } } return rc; @@ -354,29 +372,54 @@ static int open_error_log(server_rec *s, int is_main, apr_pool_t *p) int ap_open_logs(apr_pool_t *pconf, apr_pool_t *p /* plog */, apr_pool_t *ptemp, server_rec *s_main) { - apr_status_t rc = APR_SUCCESS; + apr_pool_t *stderr_p; server_rec *virt, *q; int replace_stderr; - apr_file_t *errfile = NULL; + + /* Register to throw away the read_handles list when we + * cleanup plog. Upon fork() for the apache children, + * this read_handles list is closed so only the parent + * can relaunch a lost log child. These read handles + * are always closed on exec. + * We won't care what happens to our stderr log child + * between log phases, so we don't mind losing stderr's + * read_handle a little bit early. + */ apr_pool_cleanup_register(p, NULL, clear_handle_list, apr_pool_cleanup_null); - if (open_error_log(s_main, 1, p) != OK) { + + /* HERE we need a stdout log that outlives plog. + * We *presume* the parent of plog is a process + * or global pool which spans server restarts. + * Create our stderr_pool as a child of the plog's + * parent pool. + */ + apr_pool_create(&stderr_p, apr_pool_parent_get(p)); + apr_pool_tag(stderr_p, "stderr_pool"); + + if (open_error_log(s_main, 1, stderr_p) != OK) { return DONE; } replace_stderr = 1; if (s_main->error_log) { - /* replace stderr with this new log */ + apr_status_t rv; + + /* Replace existing stderr with new log. */ apr_file_flush(s_main->error_log); - if ((rc = apr_file_open_stderr(&errfile, p)) == APR_SUCCESS) { - rc = apr_file_dup2(errfile, s_main->error_log, p); - } - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rc, s_main, + rv = apr_file_dup2(stderr_log, s_main->error_log, stderr_p); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s_main, "unable to replace stderr with error_log"); } else { + /* We are done with stderr_pool, close it, killing + * the previous generation's stderr logger + */ + if (stderr_pool) + apr_pool_destroy(stderr_pool); + stderr_pool = stderr_p; replace_stderr = 0; } } diff --git a/server/main.c b/server/main.c index 29557f23..22c0b683 100644 --- a/server/main.c +++ b/server/main.c @@ -20,6 +20,7 @@ #include "apr_general.h" #include "apr_lib.h" #include "apr_md5.h" +#include "apr_time.h" #include "apr_version.h" #include "apu_version.h" @@ -261,20 +262,29 @@ static void destroy_and_exit_process(process_rec *process, exit(process_exit_value); } -static process_rec *create_process(int argc, const char * const *argv) +static process_rec *init_process(int *argc, const char * const * *argv) { process_rec *process; apr_pool_t *cntx; apr_status_t stat; + const char *failed = "apr_app_initialize()"; + + stat = apr_app_initialize(argc, argv, NULL); + if (stat == APR_SUCCESS) { + failed = "apr_pool_create()"; + stat = apr_pool_create(&cntx, NULL); + } - stat = apr_pool_create(&cntx, NULL); if (stat != APR_SUCCESS) { - /* XXX From the time that we took away the NULL pool->malloc mapping - * we have been unable to log here without segfaulting. + /* For all intents and purposes, this is impossibly unlikely, + * but APR doesn't exist yet, we can't use it for reporting + * these earliest two failures; */ - ap_log_error(APLOG_MARK, APLOG_ERR, stat, NULL, - "apr_pool_create() failed to create " - "initial context"); + char ctimebuff[APR_CTIME_LEN]; + apr_ctime(ctimebuff, apr_time_now()); + fprintf(stderr, "[%s] [crit] (%d) %s: %s failed " + "to initial context, exiting\n", + ctimebuff, stat, (*argv)[0], failed); apr_terminate(); exit(1); } @@ -282,14 +292,19 @@ static process_rec *create_process(int argc, const char * const *argv) apr_pool_tag(cntx, "process"); ap_open_stderr_log(cntx); + /* Now we have initialized apr and our logger, no more + * exceptional error reporting required for the lifetime + * of this server process. + */ + process = apr_palloc(cntx, sizeof(process_rec)); process->pool = cntx; apr_pool_create(&process->pconf, process->pool); apr_pool_tag(process->pconf, "pconf"); - process->argc = argc; - process->argv = argv; - process->short_name = apr_filepath_name_get(argv[0]); + process->argc = *argc; + process->argv = *argv; + process->short_name = apr_filepath_name_get((*argv)[0]); return process; } @@ -442,9 +457,7 @@ int main(int argc, const char * const argv[]) AP_MONCONTROL(0); /* turn off profiling of startup */ - apr_app_initialize(&argc, &argv, NULL); - - process = create_process(argc, argv); + process = init_process(&argc, &argv); pglobal = process->pool; pconf = process->pconf; ap_server_argv0 = process->short_name; diff --git a/server/mpm/experimental/event/event.c b/server/mpm/experimental/event/event.c index e105c25e..2a6913b3 100644 --- a/server/mpm/experimental/event/event.c +++ b/server/mpm/experimental/event/event.c @@ -1998,12 +1998,10 @@ int ap_mpm_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) active_children = 0; for (index = 0; index < ap_daemons_limit; ++index) { - if (MPM_CHILD_PID(index) != 0) { - if (kill(MPM_CHILD_PID(index), 0) == 0) { - active_children = 1; - /* Having just one child is enough to stay around */ - break; - } + if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) { + active_children = 1; + /* Having just one child is enough to stay around */ + break; } } } while (!shutdown_pending && active_children && diff --git a/server/mpm/experimental/event/fdqueue.c b/server/mpm/experimental/event/fdqueue.c index 51952ced..c0ef9bbb 100644 --- a/server/mpm/experimental/event/fdqueue.c +++ b/server/mpm/experimental/event/fdqueue.c @@ -65,8 +65,7 @@ apr_status_t ap_queue_info_create(fd_queue_info_t ** queue_info, apr_status_t rv; fd_queue_info_t *qi; - qi = apr_palloc(pool, sizeof(*qi)); - memset(qi, 0, sizeof(*qi)); + qi = apr_pcalloc(pool, sizeof(*qi)); rv = apr_thread_mutex_create(&qi->idlers_mutex, APR_THREAD_MUTEX_DEFAULT, pool); diff --git a/server/mpm/netware/mpm_netware.c b/server/mpm/netware/mpm_netware.c index a6f89633..a8d0952f 100644 --- a/server/mpm/netware/mpm_netware.c +++ b/server/mpm/netware/mpm_netware.c @@ -191,6 +191,14 @@ static void clean_child_exit(int code, int worker_num, apr_pool_t *ptrans, NXThreadExit((void*)&code); } +/* proper cleanup when returning from ap_mpm_run() */ +static void mpm_main_cleanup(void) +{ + if (pmain) { + apr_pool_destroy(pmain); + } +} + AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) { switch(query_code){ @@ -934,6 +942,7 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) apr_thread_yield(); } + mpm_main_cleanup(); return 1; } else { /* the only other way out is a restart */ @@ -956,6 +965,7 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) printf ("\nRestarting...\n"); } + mpm_main_cleanup(); return 0; } diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c index ba50581b..d3c93a63 100644 --- a/server/mpm/prefork/prefork.c +++ b/server/mpm/prefork/prefork.c @@ -1127,7 +1127,7 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) for (index = 0; index < ap_daemons_limit; ++index) { if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) { /* Ask each child to close its listeners. */ - kill(MPM_CHILD_PID(index), AP_SIG_GRACEFUL); + ap_mpm_safe_kill(MPM_CHILD_PID(index), AP_SIG_GRACEFUL); active_children++; } } @@ -1165,12 +1165,10 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) active_children = 0; for (index = 0; index < ap_daemons_limit; ++index) { - if (MPM_CHILD_PID(index) != 0) { - if (kill(MPM_CHILD_PID(index), 0) == 0) { - active_children = 1; - /* Having just one child is enough to stay around */ - break; - } + if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) { + active_children = 1; + /* Having just one child is enough to stay around */ + break; } } } while (!shutdown_pending && active_children && @@ -1222,7 +1220,7 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) * piped loggers, etc. They almost certainly won't handle * it gracefully. */ - kill(ap_scoreboard_image->parent[index].pid, AP_SIG_GRACEFUL); + ap_mpm_safe_kill(ap_scoreboard_image->parent[index].pid, AP_SIG_GRACEFUL); } } } diff --git a/server/mpm/winnt/Win9xConHook.dsp b/server/mpm/winnt/Win9xConHook.dsp index 77cbacfc..55bee020 100644 --- a/server/mpm/winnt/Win9xConHook.dsp +++ b/server/mpm/winnt/Win9xConHook.dsp @@ -54,6 +54,12 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /base:"0x1c0f0000" # ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /base:"0x1c0f0000" /opt:ref +# Begin Special Build Tool +TargetPath=.\Release\Win9xConHook.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool !ELSEIF "$(CFG)" == "Win9xConHook - Win32 Debug" @@ -80,6 +86,12 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /debug /base:"0x1c0f0000" # ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /debug /base:"0x1c0f0000" +# Begin Special Build Tool +TargetPath=.\Debug\Win9xConHook.dll +SOURCE="$(InputPath)" +PostBuild_Desc=Embed .manifest +PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2 +# End Special Build Tool !ENDIF diff --git a/server/mpm/winnt/mpm_winnt.c b/server/mpm/winnt/mpm_winnt.c index e55cbb46..4b37d741 100644 --- a/server/mpm/winnt/mpm_winnt.c +++ b/server/mpm/winnt/mpm_winnt.c @@ -66,7 +66,6 @@ static int thread_limit = DEFAULT_THREAD_LIMIT; static int first_thread_limit = 0; static int changed_limit_at_restart; int winnt_mpm_state = AP_MPMQ_STARTING; - /* ap_my_generation are used by the scoreboard code */ ap_generation_t volatile ap_my_generation=0; @@ -87,6 +86,12 @@ void child_main(apr_pool_t *pconf); extern apr_proc_mutex_t *start_mutex; extern HANDLE exit_event; +/* Only one of these, the pipe from our parent, ment only for + * one child worker's consumption (not to be inherited!) + * XXX: decorate this name for the trunk branch, was left simplified + * only to make the 2.2 patch trivial to read. + */ +static HANDLE pipe; /* Stub functions until this MPM supports the connection status API */ @@ -330,7 +335,6 @@ void get_handles_from_parent(server_rec *s, HANDLE *child_exit_event, apr_proc_mutex_t **child_start_mutex, apr_shm_t **scoreboard_shm) { - HANDLE pipe; HANDLE hScore; HANDLE ready_event; HANDLE os_start; @@ -338,7 +342,9 @@ void get_handles_from_parent(server_rec *s, HANDLE *child_exit_event, void *sb_shared; apr_status_t rv; - pipe = GetStdHandle(STD_INPUT_HANDLE); + /* *** We now do this was back in winnt_rewrite_args + * pipe = GetStdHandle(STD_INPUT_HANDLE); + */ if (!ReadFile(pipe, &ready_event, sizeof(HANDLE), &BytesRead, (LPOVERLAPPED) NULL) || (BytesRead != sizeof(HANDLE))) { @@ -493,7 +499,6 @@ static int send_handles_to_child(apr_pool_t *p, void get_listeners_from_parent(server_rec *s) { WSAPROTOCOL_INFO WSAProtocolInfo; - HANDLE pipe; ap_listen_rec *lr; DWORD BytesRead; int lcnt = 0; @@ -510,9 +515,10 @@ void get_listeners_from_parent(server_rec *s) /* Open the pipe to the parent process to receive the inherited socket * data. The sockets have been set to listening in the parent process. + * + * *** We now do this was back in winnt_rewrite_args + * pipe = GetStdHandle(STD_INPUT_HANDLE); */ - pipe = GetStdHandle(STD_INPUT_HANDLE); - for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) { if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO), &BytesRead, (LPOVERLAPPED) NULL)) { @@ -618,8 +624,6 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_ apr_status_t rv; apr_pool_t *ptemp; apr_procattr_t *attr; - apr_file_t *child_out; - apr_file_t *child_err; apr_proc_t new_child; HANDLE hExitEvent; HANDLE waitlist[2]; /* see waitlist_e */ @@ -674,36 +678,6 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_ return -1; } - /* Open a null handle to soak info from the child */ - if (((rv = apr_file_open(&child_out, "NUL", APR_READ | APR_WRITE, - APR_OS_DEFAULT, ptemp)) != APR_SUCCESS) - || ((rv = apr_procattr_child_out_set(attr, child_out, NULL)) - != APR_SUCCESS)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to connect child stdout to NUL."); - apr_pool_destroy(ptemp); - return -1; - } - - /* Connect the child's initial stderr to our main server error log - * or share our own stderr handle. - */ - if (ap_server_conf->error_log) { - child_err = ap_server_conf->error_log; - } - else { - rv = apr_file_open_stderr(&child_err, ptemp); - } - if (rv == APR_SUCCESS) { - if ((rv = apr_procattr_child_err_set(attr, child_err, NULL)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, - "Parent: Unable to connect child stderr."); - apr_pool_destroy(ptemp); - return -1; - } - } - /* Create the child_ready_event */ waitlist[waitlist_ready] = CreateEvent(NULL, TRUE, FALSE, NULL); if (!waitlist[waitlist_ready]) { @@ -802,6 +776,8 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_ return -1; } + apr_file_close(new_child.in); + *child_exit_event = hExitEvent; *child_proc = new_child.hproc; *child_pid = new_child.pid; @@ -1105,6 +1081,9 @@ void winnt_rewrite_args(process_rec *process) pid = getenv("AP_PARENT_PID"); if (pid) { + HANDLE filehand, newhand; + HANDLE hproc = GetCurrentProcess(); + /* This is the child */ my_pid = GetCurrentProcessId(); parent_pid = (DWORD) atol(pid); @@ -1112,6 +1091,36 @@ void winnt_rewrite_args(process_rec *process) /* Prevent holding open the (nonexistant) console */ ap_real_exit_code = 0; + /* The parent gave us stdin, we need to remember this + * handle, and no longer inherit it at our children + * (we can't slurp it up now, we just aren't ready yet). + */ + pipe = GetStdHandle(STD_INPUT_HANDLE); + + if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { + /* This doesn't work for 9x, but it's cleaner. */ + SetHandleInformation(pipe, HANDLE_FLAG_INHERIT, 0); + } + else if (DuplicateHandle(hproc, pipe, + hproc, &filehand, 0, FALSE, + DUPLICATE_SAME_ACCESS)) { + CloseHandle(pipe); + pipe = filehand; + } + + /* The parent gave us stdout of the NUL device, + * and expects us to suck up stdin of all of our + * shared handles and data from the parent. + * Don't infect child processes with our stdin + * handle, use another handle to NUL! + */ + if ((filehand = GetStdHandle(STD_OUTPUT_HANDLE)) + && DuplicateHandle(hproc, filehand, + hproc, &newhand, 0, + TRUE, DUPLICATE_SAME_ACCESS)) { + SetStdHandle(STD_INPUT_HANDLE, newhand); + } + /* The parent is responsible for providing the * COMPLETE ARGUMENTS REQUIRED to the child. * @@ -1258,6 +1267,8 @@ void winnt_rewrite_args(process_rec *process) */ if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { + apr_file_t *nullfile; + if (!errout) { mpm_nt_eventlog_stderr_open(service_name, process->pool); } @@ -1266,6 +1277,30 @@ void winnt_rewrite_args(process_rec *process) if (service_to_start_success == APR_SUCCESS) { service_set = APR_SUCCESS; } + + /* Open a null handle to soak stdout in this process. + * Windows service processes are missing any file handle + * usable for stdin/out/err. This was the cause of later + * trouble with invocations of apr_file_open_stdout() + */ + if ((rv = apr_file_open(&nullfile, "NUL", + APR_READ | APR_WRITE, APR_OS_DEFAULT, + process->pool)) == APR_SUCCESS) { + HANDLE hproc = GetCurrentProcess(); + HANDLE nullstdout = NULL; + HANDLE nullhandle; + + /* Duplicate the handle to be inherited by children */ + if ((apr_os_file_get(&nullhandle, nullfile) == APR_SUCCESS) + && DuplicateHandle(hproc, nullhandle, + hproc, &nullstdout, + 0, TRUE, DUPLICATE_SAME_ACCESS)) { + SetStdHandle(STD_OUTPUT_HANDLE, nullstdout); + } + + /* Close the original handle, we used the duplicate */ + apr_file_close(nullfile); + } } } @@ -1604,6 +1639,9 @@ static void winnt_child_init(apr_pool_t *pchild, struct server_rec *s) /* Set up the listeners */ get_listeners_from_parent(s); + /* Done reading from the parent, close that channel */ + CloseHandle(pipe); + ap_my_generation = ap_scoreboard_image->global->running_generation; } else { diff --git a/server/mpm/worker/fdqueue.c b/server/mpm/worker/fdqueue.c index 6b5485b3..8be7c9fa 100644 --- a/server/mpm/worker/fdqueue.c +++ b/server/mpm/worker/fdqueue.c @@ -58,8 +58,7 @@ apr_status_t ap_queue_info_create(fd_queue_info_t **queue_info, apr_status_t rv; fd_queue_info_t *qi; - qi = apr_palloc(pool, sizeof(*qi)); - memset(qi, 0, sizeof(*qi)); + qi = apr_pcalloc(pool, sizeof(*qi)); rv = apr_thread_mutex_create(&qi->idlers_mutex, APR_THREAD_MUTEX_DEFAULT, pool); diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c index a9d822f5..b6b9447b 100644 --- a/server/mpm/worker/worker.c +++ b/server/mpm/worker/worker.c @@ -1813,12 +1813,10 @@ int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) active_children = 0; for (index = 0; index < ap_daemons_limit; ++index) { - if (MPM_CHILD_PID(index) != 0) { - if (kill(MPM_CHILD_PID(index), 0) == 0) { - active_children = 1; - /* Having just one child is enough to stay around */ - break; - } + if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) { + active_children = 1; + /* Having just one child is enough to stay around */ + break; } } } while (!shutdown_pending && active_children && diff --git a/server/mpm_common.c b/server/mpm_common.c index 26a74891..f8063733 100644 --- a/server/mpm_common.c +++ b/server/mpm_common.c @@ -126,6 +126,11 @@ static int reclaim_one_pid(pid_t pid, action_t action) apr_proc_t proc; apr_status_t waitret; + /* Ensure pid sanity. */ + if (pid < 1) { + return 1; + } + proc.pid = pid; waitret = apr_proc_wait(&proc, NULL, NULL, APR_NOWAIT); if (waitret != APR_CHILD_NOTDONE) { @@ -305,6 +310,66 @@ void ap_relieve_child_processes(void) cur_extra = next; } } + +/* Before sending the signal to the pid this function verifies that + * the pid is a member of the current process group; either using + * apr_proc_wait(), where waitpid() guarantees to fail for non-child + * processes; or by using getpgid() directly, if available. */ +apr_status_t ap_mpm_safe_kill(pid_t pid, int sig) +{ +#ifndef HAVE_GETPGID + apr_proc_t proc; + apr_status_t rv; + apr_exit_why_e why; + int status; + + /* Ensure pid sanity */ + if (pid < 1) { + return APR_EINVAL; + } + + proc.pid = pid; + rv = apr_proc_wait(&proc, &status, &why, APR_NOWAIT); + if (rv == APR_CHILD_DONE) { +#ifdef AP_MPM_WANT_PROCESS_CHILD_STATUS + /* The child already died - log the termination status if + * necessary: */ + ap_process_child_status(&proc, why, status); +#endif + return APR_EINVAL; + } + else if (rv != APR_CHILD_NOTDONE) { + /* The child is already dead and reaped, or was a bogus pid - + * log this either way. */ + ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, ap_server_conf, + "cannot send signal %d to pid %ld (non-child or " + "already dead)", sig, (long)pid); + return APR_EINVAL; + } +#else + pid_t pg; + + /* Ensure pid sanity. */ + if (pid < 1) { + return APR_EINVAL; + } + + pg = getpgid(pid); + if (pg == -1) { + /* Process already dead... */ + return errno; + } + + if (pg != getpgrp()) { + ap_log_error(APLOG_MARK, APLOG_ALERT, 0, ap_server_conf, + "refusing to send signal %d to pid %ld outside " + "process group", sig, (long)pid); + return APR_EINVAL; + } +#endif + + return kill(pid, sig) ? errno : APR_SUCCESS; +} #endif /* AP_MPM_WANT_RECLAIM_CHILD_PROCESSES */ #ifdef AP_MPM_WANT_WAIT_OR_TIMEOUT @@ -1217,6 +1282,10 @@ apr_status_t ap_fatal_signal_setup(server_rec *s, apr_pool_t *in_pconf) if (sigaction(SIGILL, &sa, NULL) < 0) ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGILL)"); #endif +#ifdef SIGFPE + if (sigaction(SIGFPE, &sa, NULL) < 0) + ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGFPE)"); +#endif #else /* NO_USE_SIGACTION */ @@ -1233,6 +1302,9 @@ apr_status_t ap_fatal_signal_setup(server_rec *s, apr_pool_t *in_pconf) #ifdef SIGILL apr_signal(SIGILL, sig_coredump); #endif /* SIGILL */ +#ifdef SIGFPE + apr_signal(SIGFPE, sig_coredump); +#endif /* SIGFPE */ #endif /* NO_USE_SIGACTION */ diff --git a/server/request.c b/server/request.c index 1aff7304..92e91547 100644 --- a/server/request.c +++ b/server/request.c @@ -615,6 +615,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r) opts.add = this_dir->opts_add; opts.remove = this_dir->opts_remove; opts.override = this_dir->override; + opts.override_opts = this_dir->override_opts; /* Set aside path_info to merge back onto path_info later. * If r->filename is a directory, we must remerge the path_info, @@ -1741,9 +1742,9 @@ AP_DECLARE(request_rec *) ap_sub_req_lookup_dirent(const apr_finfo_t *dirent, /* ap_make_full_path overallocated the buffers * by one character to help us out here. */ - strcpy(rnew->filename + strlen(rnew->filename), "/"); + strcat(rnew->filename, "/"); if (!rnew->path_info || !*rnew->path_info) { - strcpy(rnew->uri + strlen(rnew->uri ), "/"); + strcat(rnew->uri, "/"); } } diff --git a/server/util.c b/server/util.c index 55ed076b..e1be3d18 100644 --- a/server/util.c +++ b/server/util.c @@ -2074,10 +2074,9 @@ AP_DECLARE(void) ap_content_type_tolower(char *str) if (semi) { *semi = '\0'; } - while (*str) { - *str = apr_tolower(*str); - ++str; - } + + ap_str_tolower(str); + if (semi) { *semi = ';'; } -- cgit v1.2.3