diff options
Diffstat (limited to 'server/log.c')
-rw-r--r-- | server/log.c | 95 |
1 files changed, 69 insertions, 26 deletions
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; } } |