From: Jeff Trawick Date: Tue, 28 Jun 2005 11:59:21 +0000 (+0000) Subject: merge this fix from trunk: X-Git-Tag: 2.0.55~142 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=541584ddb86b91eab370972c170ccb185a9709d4;p=thirdparty%2Fapache%2Fhttpd.git merge this fix from trunk: Prevent hangs of child processes when writing to piped loggers at the time of graceful restart. PR: 26467 Reviewed by: jorton, pquerna git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.0.x@202161 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index d6b1de84ede..f205ee1920a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ Changes with Apache 2.0.55 + *) Prevent hangs of child processes when writing to piped loggers at + the time of graceful restart. PR 26467. [Jeff Trawick] + *) SECURITY: CAN-2005-1268 (cve.mitre.org) mod_ssl: Fix off-by-one overflow whilst printing CRL information at "LogLevel debug" which could be triggered if configured diff --git a/include/http_log.h b/include/http_log.h index 9b24f5844f1..93895f13c16 100644 --- a/include/http_log.h +++ b/include/http_log.h @@ -116,6 +116,20 @@ AP_DECLARE(apr_status_t) ap_replace_stderr_log(apr_pool_t *p, int ap_open_logs(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s_main); +#ifdef CORE_PRIVATE + +/** + * Perform special processing for piped loggers in MPM child + * processes. + * @param p Not used + * @param s Not used + * @tip ap_logs_child_init is not for use by modules; it is an + * internal core function + */ +void ap_logs_child_init(apr_pool_t *p, server_rec *s); + +#endif /* CORE_PRIVATE */ + /* * The three primary logging functions, ap_log_error, ap_log_rerror, and * ap_log_perror use a printf style format string to build the log message. diff --git a/server/core.c b/server/core.c index fbc1763ac71..d3ffd7ea0ae 100644 --- a/server/core.c +++ b/server/core.c @@ -4491,6 +4491,7 @@ static void register_hooks(apr_pool_t *p) ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST); ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST); ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST); + ap_hook_child_init(ap_logs_child_init,NULL,NULL,APR_HOOK_MIDDLE); ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST); /* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */ ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST); diff --git a/server/log.c b/server/log.c index 75b43e1e583..bfec7a30039 100644 --- a/server/log.c +++ b/server/log.c @@ -145,6 +145,45 @@ static const TRANS priorities[] = { static apr_file_t *stderr_log = NULL; +/* track pipe handles to close in child process */ +typedef struct read_handle_t { + struct read_handle_t *next; + apr_file_t *handle; +} read_handle_t; + +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 + */ +static apr_status_t clear_handle_list(void *v) +{ + read_handles = NULL; + return APR_SUCCESS; +} + +/* remember to close this handle in the child process */ +static void close_handle_in_child(apr_pool_t *p, apr_file_t *f) +{ + read_handle_t *new_handle; + + new_handle = apr_pcalloc(p, sizeof(read_handle_t)); + new_handle->next = read_handles; + new_handle->handle = f; + read_handles = new_handle; +} + +void ap_logs_child_init(apr_pool_t *p, server_rec *s) +{ + read_handle_t *cur = read_handles; + + while (cur) { + apr_file_close(cur->handle); + cur = cur->next; + } +} + AP_DECLARE(void) ap_open_stderr_log(apr_pool_t *p) { apr_file_open_stderr(&stderr_log, p); @@ -220,6 +259,9 @@ static int log_child(apr_pool_t *p, const char *progname, if (rc == APR_SUCCESS) { apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT); (*fpin) = procnew->in; + /* read handle to pipe not kept open, so no need to call + * close_handle_in_child() + */ } } @@ -296,6 +338,8 @@ int ap_open_logs(apr_pool_t *pconf, apr_pool_t *p /* plog */, int replace_stderr; apr_file_t *errfile = NULL; + apr_pool_cleanup_register(p, NULL, clear_handle_list, + apr_pool_cleanup_null); if (open_error_log(s_main, p) != OK) { return DONE; } @@ -756,6 +800,7 @@ static int piped_log_spawn(piped_log *pl) ap_piped_log_write_fd(pl) = procnew->in; apr_proc_other_child_register(procnew, piped_log_maintenance, pl, ap_piped_log_write_fd(pl), pl->p); + close_handle_in_child(pl->p, ap_piped_log_read_fd(pl)); } else { char buf[120];