diff options
Diffstat (limited to 'rubbos/app/httpd-2.0.64/server/log.c')
-rw-r--r-- | rubbos/app/httpd-2.0.64/server/log.c | 1084 |
1 files changed, 0 insertions, 1084 deletions
diff --git a/rubbos/app/httpd-2.0.64/server/log.c b/rubbos/app/httpd-2.0.64/server/log.c deleted file mode 100644 index 9ab706dd..00000000 --- a/rubbos/app/httpd-2.0.64/server/log.c +++ /dev/null @@ -1,1084 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * http_log.c: Dealing with the logs and errors - * - * Rob McCool - * - */ - -#include "apr.h" -#include "apr_general.h" /* for signal stuff */ -#include "apr_strings.h" -#include "apr_errno.h" -#include "apr_thread_proc.h" -#include "apr_lib.h" -#include "apr_signal.h" - -#define APR_WANT_STDIO -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_STDARG_H -#include <stdarg.h> -#endif -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_main.h" -#include "util_time.h" -#include "ap_mpm.h" - -#ifndef APR_LARGEFILE -#define APR_LARGEFILE 0 -#endif - -typedef struct { - char *t_name; - int t_val; -} TRANS; - -APR_HOOK_STRUCT( - APR_HOOK_LINK(error_log) -) - -int AP_DECLARE_DATA ap_default_loglevel = DEFAULT_LOGLEVEL; - -#ifdef HAVE_SYSLOG - -static const TRANS facilities[] = { - {"auth", LOG_AUTH}, -#ifdef LOG_AUTHPRIV - {"authpriv",LOG_AUTHPRIV}, -#endif -#ifdef LOG_CRON - {"cron", LOG_CRON}, -#endif -#ifdef LOG_DAEMON - {"daemon", LOG_DAEMON}, -#endif -#ifdef LOG_FTP - {"ftp", LOG_FTP}, -#endif -#ifdef LOG_KERN - {"kern", LOG_KERN}, -#endif -#ifdef LOG_LPR - {"lpr", LOG_LPR}, -#endif -#ifdef LOG_MAIL - {"mail", LOG_MAIL}, -#endif -#ifdef LOG_NEWS - {"news", LOG_NEWS}, -#endif -#ifdef LOG_SYSLOG - {"syslog", LOG_SYSLOG}, -#endif -#ifdef LOG_USER - {"user", LOG_USER}, -#endif -#ifdef LOG_UUCP - {"uucp", LOG_UUCP}, -#endif -#ifdef LOG_LOCAL0 - {"local0", LOG_LOCAL0}, -#endif -#ifdef LOG_LOCAL1 - {"local1", LOG_LOCAL1}, -#endif -#ifdef LOG_LOCAL2 - {"local2", LOG_LOCAL2}, -#endif -#ifdef LOG_LOCAL3 - {"local3", LOG_LOCAL3}, -#endif -#ifdef LOG_LOCAL4 - {"local4", LOG_LOCAL4}, -#endif -#ifdef LOG_LOCAL5 - {"local5", LOG_LOCAL5}, -#endif -#ifdef LOG_LOCAL6 - {"local6", LOG_LOCAL6}, -#endif -#ifdef LOG_LOCAL7 - {"local7", LOG_LOCAL7}, -#endif - {NULL, -1}, -}; -#endif - -static const TRANS priorities[] = { - {"emerg", APLOG_EMERG}, - {"alert", APLOG_ALERT}, - {"crit", APLOG_CRIT}, - {"error", APLOG_ERR}, - {"warn", APLOG_WARNING}, - {"notice", APLOG_NOTICE}, - {"info", APLOG_INFO}, - {"debug", APLOG_DEBUG}, - {NULL, -1}, -}; - -static apr_pool_t *stderr_pool = NULL; - -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. We let the plog cleanups close the actual pipes. - */ -static apr_status_t clear_handle_list(void *v) -{ - read_handles = NULL; - return APR_SUCCESS; -} - -/* remember to close this handle in the child process - * - * On Win32 this makes zero sense, because we don't - * take the parent process's child procs. - * If the win32 parent instead passed each and every - * logger write handle from itself down to the child, - * and the parent manages all aspects of keeping the - * reliable pipe log children alive, this would still - * make no sense :) Cripple it on Win32. - */ -static void close_handle_in_child(apr_pool_t *p, apr_file_t *f) -{ -#ifndef WIN32 - 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; -#endif -} - -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); -} - -AP_DECLARE(apr_status_t) ap_replace_stderr_log(apr_pool_t *p, - const char *fname) -{ - apr_file_t *stderr_file; - apr_status_t rc; - char *filename = ap_server_root_relative(p, fname); - if (!filename) { - ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, - APR_EBADPATH, NULL, "Invalid -E error log file %s", - fname); - return APR_EBADPATH; - } - if ((rc = apr_file_open(&stderr_file, filename, - APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE, - APR_OS_DEFAULT, p)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL, - "%s: could not open error log file %s.", - ap_server_argv0, fname); - return rc; - } - 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, 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 file"); - } - return rc; -} - -static void log_child_errfn(apr_pool_t *pool, apr_status_t err, - const char *description) -{ - ap_log_error(APLOG_MARK, APLOG_ERR, err, NULL, - "%s", description); -} - -/* Create a child process running PROGNAME with a pipe connected to - * the childs stdin. The write-end of the pipe will be placed in - * *FPIN on successful return. If dummy_stderr is non-zero, the - * stderr for the child will be the same as the stdout of the parent. - * Otherwise the child will inherit the stderr from the parent. */ -static int log_child(apr_pool_t *p, const char *progname, - apr_file_t **fpin, int dummy_stderr) -{ - /* Child process code for 'ErrorLog "|..."'; - * may want a common framework for this, since I expect it will - * be common for other foo-loggers to want this sort of thing... - */ - apr_status_t rc; - apr_procattr_t *procattr; - apr_proc_t *procnew; - apr_file_t *outfile, *errfile; - - if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS) - && ((rc = apr_procattr_io_set(procattr, - APR_FULL_BLOCK, - 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)) { - 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 ((rc = apr_file_open_stdout(&outfile, p)) == APR_SUCCESS) { - rc = apr_procattr_child_out_set(procattr, outfile, NULL); - if (dummy_stderr) - rc = apr_procattr_child_err_set(procattr, outfile, NULL); - else if ((rc = apr_file_open_stderr(&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); - - 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() - */ - } - } - - return rc; -} - -/* Open the error log for the given server_rec. If IS_MAIN is - * non-zero, s is the main server. */ -static int open_error_log(server_rec *s, int is_main, apr_pool_t *p) -{ - const char *fname; - int rc; - - if (*s->error_fname == '|') { - apr_file_t *dummy = NULL; - - /* Spawn a new child logger. If this is the main server_rec, - * the new child must use a dummy stderr since the current - * stderr might be a pipe to the old logger. Otherwise, the - * child inherits the parents stderr. */ - rc = log_child(p, s->error_fname + 1, &dummy, is_main); - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL, - "Couldn't start ErrorLog process"); - return DONE; - } - - s->error_log = dummy; - } - -#ifdef HAVE_SYSLOG - else if (!strncasecmp(s->error_fname, "syslog", 6)) { - if ((fname = strchr(s->error_fname, ':'))) { - const TRANS *fac; - - fname++; - for (fac = facilities; fac->t_name; fac++) { - if (!strcasecmp(fname, fac->t_name)) { - openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID, - fac->t_val); - s->error_log = NULL; - return OK; - } - } - } - else { - openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID, LOG_LOCAL7); - } - - s->error_log = NULL; - } -#endif - else { - fname = ap_server_root_relative(p, s->error_fname); - if (!fname) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EBADPATH, NULL, - "%s: Invalid error log path %s.", - ap_server_argv0, s->error_fname); - return DONE; - } - if ((rc = apr_file_open(&s->error_log, fname, - APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE, - APR_OS_DEFAULT, p)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL, - "%s: could not open error log file %s.", - ap_server_argv0, fname); - return DONE; - } - } - - return OK; -} - -int ap_open_logs(apr_pool_t *pconf, apr_pool_t *p /* plog */, - apr_pool_t *ptemp, server_rec *s_main) -{ - apr_pool_t *stderr_p; - server_rec *virt, *q; - int replace_stderr; - - - /* 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); - - /* 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) { - apr_status_t rv; - - /* Replace existing stderr with new log. */ - apr_file_flush(s_main->error_log); - 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; - /* - * Now that we have dup'ed s_main->error_log to stderr_log - * close it and set s_main->error_log to stderr_log. This avoids - * this fd being inherited by the next piped logger who would - * keep open the writing end of the pipe that this one uses - * as stdin. This in turn would prevent the piped logger from - * exiting. - */ - apr_file_close(s_main->error_log); - s_main->error_log = stderr_log; - } - } - /* note that stderr may still need to be replaced with something - * because it points to the old error log, or back to the tty - * of the submitter. - * XXX: This is BS - /dev/null is non-portable - */ - if (replace_stderr && freopen("/dev/null", "w", stderr) == NULL) { - ap_log_error(APLOG_MARK, APLOG_CRIT, errno, s_main, - "unable to replace stderr with /dev/null"); - } - - for (virt = s_main->next; virt; virt = virt->next) { - if (virt->error_fname) { - for (q=s_main; q != virt; q = q->next) { - if (q->error_fname != NULL - && strcmp(q->error_fname, virt->error_fname) == 0) { - break; - } - } - - if (q == virt) { - if (open_error_log(virt, 0, p) != OK) { - return DONE; - } - } - else { - virt->error_log = q->error_log; - } - } - else { - virt->error_log = s_main->error_log; - } - } - return OK; -} - -AP_DECLARE(void) ap_error_log2stderr(server_rec *s) { - apr_file_t *errfile = NULL; - - apr_file_open_stderr(&errfile, s->process->pool); - if (s->error_log != NULL) { - apr_file_dup2(s->error_log, errfile, s->process->pool); - } -} - -static void log_error_core(const char *file, int line, int level, - apr_status_t status, const server_rec *s, - const conn_rec *c, - const request_rec *r, apr_pool_t *pool, - const char *fmt, va_list args) -{ - char errstr[MAX_STRING_LEN]; -#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED - char scratch[MAX_STRING_LEN]; -#endif - apr_size_t len, errstrlen; - apr_file_t *logf = NULL; - const char *referer; - int level_and_mask = level & APLOG_LEVELMASK; - - if (r && r->connection) { - c = r->connection; - } - - if (s == NULL) { - /* - * If we are doing stderr logging (startup), don't log messages that are - * above the default server log level unless it is a startup/shutdown - * notice - */ - if ((level_and_mask != APLOG_NOTICE) - && (level_and_mask > ap_default_loglevel)) { - return; - } - - logf = stderr_log; - } - else if (s->error_log) { - /* - * If we are doing normal logging, don't log messages that are - * above the server log level unless it is a startup/shutdown notice - */ - if ((level_and_mask != APLOG_NOTICE) - && (level_and_mask > s->loglevel)) { - return; - } - - logf = s->error_log; - } -#ifdef TPF - else if (tpf_child) { - /* - * If we are doing normal logging, don't log messages that are - * above the server log level unless it is a startup/shutdown notice - */ - if ((level_and_mask != APLOG_NOTICE) - && (level_and_mask > s->loglevel)) { - return; - } - - logf = stderr; - } -#endif /* TPF */ - else { - /* - * If we are doing syslog logging, don't log messages that are - * above the server log level (including a startup/shutdown notice) - */ - if (level_and_mask > s->loglevel) { - return; - } - } - - if (logf && ((level & APLOG_STARTUP) != APLOG_STARTUP)) { - errstr[0] = '['; - ap_recent_ctime(errstr + 1, apr_time_now()); - errstr[1 + APR_CTIME_LEN - 1] = ']'; - errstr[1 + APR_CTIME_LEN ] = ' '; - len = 1 + APR_CTIME_LEN + 1; - } else { - len = 0; - } - - if ((level & APLOG_STARTUP) != APLOG_STARTUP) { - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - "[%s] ", priorities[level_and_mask].t_name); - } - -#ifndef TPF - if (file && level_and_mask == APLOG_DEBUG) { -#if defined(_OSD_POSIX) || defined(WIN32) || defined(__MVS__) - char tmp[256]; - char *e = strrchr(file, '/'); -#ifdef WIN32 - if (!e) { - e = strrchr(file, '\\'); - } -#endif - - /* In OSD/POSIX, the compiler returns for __FILE__ - * a string like: __FILE__="*POSIX(/usr/include/stdio.h)" - * (it even returns an absolute path for sources in - * the current directory). Here we try to strip this - * down to the basename. - */ - if (e != NULL && e[1] != '\0') { - apr_snprintf(tmp, sizeof(tmp), "%s", &e[1]); - e = &tmp[strlen(tmp)-1]; - if (*e == ')') { - *e = '\0'; - } - file = tmp; - } -#else /* _OSD_POSIX || WIN32 */ - const char *p; - /* On Unix, __FILE__ may be an absolute path in a - * VPATH build. */ - if (file[0] == '/' && (p = ap_strrchr_c(file, '/')) != NULL) { - file = p + 1; - } -#endif /*_OSD_POSIX || WIN32 */ - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - "%s(%d): ", file, line); - } -#endif /* TPF */ - - if (c) { - /* XXX: TODO: add a method of selecting whether logged client - * addresses are in dotted quad or resolved form... dotted - * quad is the most secure, which is why I'm implementing it - * first. -djg - */ - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - "[client %s] ", c->remote_ip); - } - if (status != 0) { - if (status < APR_OS_START_EAIERR) { - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - "(%d)", status); - } - else if (status < APR_OS_START_SYSERR) { - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - "(EAI %d)", status - APR_OS_START_EAIERR); - } - else if (status < 100000 + APR_OS_START_SYSERR) { - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - "(OS %d)", status - APR_OS_START_SYSERR); - } - else { - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - "(os 0x%08x)", status - APR_OS_START_SYSERR); - } - apr_strerror(status, errstr + len, MAX_STRING_LEN - len); - len += strlen(errstr + len); - if (MAX_STRING_LEN - len > 2) { - errstr[len++] = ':'; - errstr[len++] = ' '; - errstr[len] = '\0'; - } - } - - errstrlen = len; -#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED - if (apr_vsnprintf(scratch, MAX_STRING_LEN - len, fmt, args)) { - len += ap_escape_errorlog_item(errstr + len, scratch, - MAX_STRING_LEN - len); - } -#else - len += apr_vsnprintf(errstr + len, MAX_STRING_LEN - len, fmt, args); -#endif - - if ( r && (referer = apr_table_get(r->headers_in, "Referer")) -#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED - && ap_escape_errorlog_item(scratch, referer, MAX_STRING_LEN - len) -#endif - ) { - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - ", referer: %s", -#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED - scratch -#else - referer -#endif - ); - } - - /* NULL if we are logging to syslog */ - if (logf) { - /* Truncate for the terminator (as apr_snprintf does) */ - if (len > MAX_STRING_LEN - sizeof(APR_EOL_STR)) { - len = MAX_STRING_LEN - sizeof(APR_EOL_STR); - } - strcpy(errstr + len, APR_EOL_STR); - apr_file_puts(errstr, logf); - apr_file_flush(logf); - } -#ifdef HAVE_SYSLOG - else { - syslog(level_and_mask, "%s", errstr); - } -#endif - - ap_run_error_log(file, line, level, status, s, r, pool, errstr + errstrlen); -} - -AP_DECLARE(void) ap_log_error(const char *file, int line, int level, - apr_status_t status, const server_rec *s, - const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - log_error_core(file, line, level, status, s, NULL, NULL, NULL, fmt, args); - va_end(args); -} - -AP_DECLARE(void) ap_log_perror(const char *file, int line, int level, - apr_status_t status, apr_pool_t *p, - const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - log_error_core(file, line, level, status, NULL, NULL, NULL, p, fmt, args); - va_end(args); -} - -AP_DECLARE(void) ap_log_rerror(const char *file, int line, int level, - apr_status_t status, const request_rec *r, - const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - log_error_core(file, line, level, status, r->server, NULL, r, NULL, fmt, - args); - - /* - * IF APLOG_TOCLIENT is set, - * AND the error level is 'warning' or more severe, - * AND there isn't already error text associated with this request, - * THEN make the message text available to ErrorDocument and - * other error processors. - */ - va_end(args); - va_start(args,fmt); - if ((level & APLOG_TOCLIENT) - && ((level & APLOG_LEVELMASK) <= APLOG_WARNING) - && (apr_table_get(r->notes, "error-notes") == NULL)) { - apr_table_setn(r->notes, "error-notes", - ap_escape_html(r->pool, apr_pvsprintf(r->pool, fmt, - args))); - } - va_end(args); -} - -AP_DECLARE(void) ap_log_cerror(const char *file, int line, int level, - apr_status_t status, const conn_rec *c, - const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - log_error_core(file, line, level, status, c->base_server, c, NULL, NULL, - fmt, args); - va_end(args); -} - -AP_DECLARE(void) ap_log_pid(apr_pool_t *p, const char *filename) -{ - apr_file_t *pid_file = NULL; - apr_finfo_t finfo; - static pid_t saved_pid = -1; - pid_t mypid; - apr_status_t rv; - const char *fname; - - if (!filename) { - return; - } - - 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; - } - - mypid = getpid(); - if (mypid != saved_pid - && apr_stat(&finfo, fname, APR_FINFO_MTIME, p) == APR_SUCCESS) { - /* AP_SIG_GRACEFUL and HUP call this on each restart. - * Only warn on first time through for this pid. - * - * XXX: Could just write first time through too, although - * that may screw up scripts written to do something - * based on the last modification time of the pid file. - */ - ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, p, - apr_psprintf(p, "pid file %s overwritten -- Unclean " - "shutdown of previous Apache run?", - fname)); - } - - if ((rv = apr_file_open(&pid_file, fname, - APR_WRITE | APR_CREATE | APR_TRUNCATE, - APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD, p)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, - "could not create %s", fname); - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, - "%s: could not log pid to file %s", - ap_server_argv0, fname); - exit(1); - } - apr_file_printf(pid_file, "%ld" APR_EOL_STR, (long)mypid); - apr_file_close(pid_file); - saved_pid = mypid; -} - -AP_DECLARE(apr_status_t) ap_read_pid(apr_pool_t *p, const char *filename, - pid_t *mypid) -{ - const apr_size_t 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_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; - } - - /* Ensure null-termination, so that strtol doesn't go crazy. */ - buf = apr_palloc(p, BUFFER_SIZE); - buf[BUFFER_SIZE - 1] = '\0'; - - rv = apr_file_read_full(pid_file, buf, BUFFER_SIZE - 1, &bytes_read); - if (rv != APR_SUCCESS && rv != APR_EOF) { - return rv; - } - - /* If we fill the buffer, we're probably reading a corrupt pid file. - * To be nice, let's also ensure the first char is a digit. */ - if (bytes_read == BUFFER_SIZE - 1 || !apr_isdigit(*buf)) { - return APR_EGENERAL; - } - - *mypid = strtol(buf, &endptr, 10); - - apr_file_close(pid_file); - return APR_SUCCESS; -} - -AP_DECLARE(void) ap_log_assert(const char *szExp, const char *szFile, - int nLine) -{ - char time_str[APR_CTIME_LEN]; - - apr_ctime(time_str, apr_time_now()); - ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL, - "[%s] file %s, line %d, assertion \"%s\" failed", - time_str, szFile, nLine, szExp); -#if defined(WIN32) - DebugBreak(); -#else - /* unix assert does an abort leading to a core dump */ - abort(); -#endif -} - -/* piped log support */ - -#ifdef AP_HAVE_RELIABLE_PIPED_LOGS -/* forward declaration */ -static void piped_log_maintenance(int reason, void *data, apr_wait_t status); - -/* Spawn the piped logger process pl->program. */ -static apr_status_t piped_log_spawn(piped_log *pl) -{ - apr_procattr_t *procattr; - apr_proc_t *procnew = NULL; - apr_status_t status; - - if (((status = apr_procattr_create(&procattr, pl->p)) != APR_SUCCESS) || - ((status = apr_procattr_child_in_set(procattr, - ap_piped_log_read_fd(pl), - ap_piped_log_write_fd(pl))) - != APR_SUCCESS) || - ((status = apr_procattr_child_errfn_set(procattr, log_child_errfn)) - != APR_SUCCESS) || - ((status = apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS)) { - char buf[120]; - /* Something bad happened, give up and go away. */ - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "piped_log_spawn: unable to setup child process '%s': %s", - pl->program, apr_strerror(status, buf, sizeof(buf))); - } - else { - char **args; - const char *pname; - apr_file_t *outfile, *errfile; - - if ((status = apr_file_open_stdout(&outfile, pl->p)) == APR_SUCCESS) - status = apr_procattr_child_out_set(procattr, outfile, NULL); - if ((status = apr_file_open_stderr(&errfile, pl->p)) == APR_SUCCESS) - status = apr_procattr_child_err_set(procattr, errfile, NULL); - - apr_tokenize_to_argv(pl->program, &args, pl->p); - pname = apr_pstrdup(pl->p, args[0]); - procnew = apr_pcalloc(pl->p, sizeof(apr_proc_t)); - status = apr_proc_create(procnew, pname, (const char * const *) args, - NULL, procattr, pl->p); - - if (status == APR_SUCCESS) { - pl->pid = procnew; - /* procnew->in was dup2'd from ap_piped_log_write_fd(pl); - * since the original fd is still valid, close the copy to - * avoid a leak. */ - apr_file_close(procnew->in); - procnew->in = NULL; - 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]; - /* Something bad happened, give up and go away. */ - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "unable to start piped log program '%s': %s", - pl->program, apr_strerror(status, buf, sizeof(buf))); - } - } - - return status; -} - - -static void piped_log_maintenance(int reason, void *data, apr_wait_t status) -{ - piped_log *pl = data; - apr_status_t stats; - int mpm_state; - - switch (reason) { - case APR_OC_REASON_DEATH: - case APR_OC_REASON_LOST: - pl->pid = NULL; /* in case we don't get it going again, this - * tells other logic not to try to kill it - */ - apr_proc_other_child_unregister(pl); - stats = ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state); - if (stats != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "can't query MPM state; not restarting " - "piped log program '%s'", - pl->program); - } - else if (mpm_state != AP_MPMQ_STOPPING) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "piped log program '%s' failed unexpectedly", - pl->program); - if ((stats = piped_log_spawn(pl)) != APR_SUCCESS) { - /* what can we do? This could be the error log we're having - * problems opening up... */ - char buf[120]; - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "piped_log_maintenance: unable to respawn '%s': %s", - pl->program, apr_strerror(stats, buf, sizeof(buf))); - } - } - break; - - case APR_OC_REASON_UNWRITABLE: - /* We should not kill off the pipe here, since it may only be full. - * If it really is locked, we should kill it off manually. */ - break; - - case APR_OC_REASON_RESTART: - if (pl->pid != NULL) { - apr_proc_kill(pl->pid, SIGTERM); - pl->pid = NULL; - } - break; - - case APR_OC_REASON_UNREGISTER: - break; - } -} - - -static apr_status_t piped_log_cleanup_for_exec(void *data) -{ - piped_log *pl = data; - - apr_file_close(ap_piped_log_read_fd(pl)); - apr_file_close(ap_piped_log_write_fd(pl)); - return APR_SUCCESS; -} - - -static apr_status_t piped_log_cleanup(void *data) -{ - piped_log *pl = data; - - if (pl->pid != NULL) { - apr_proc_kill(pl->pid, SIGTERM); - } - return piped_log_cleanup_for_exec(data); -} - - -AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program) -{ - piped_log *pl; - - pl = apr_palloc(p, sizeof (*pl)); - pl->p = p; - pl->program = apr_pstrdup(p, program); - pl->pid = NULL; - if (apr_file_pipe_create(&ap_piped_log_read_fd(pl), - &ap_piped_log_write_fd(pl), p) != APR_SUCCESS) { - return NULL; - } - apr_pool_cleanup_register(p, pl, piped_log_cleanup, - piped_log_cleanup_for_exec); - if (piped_log_spawn(pl) != APR_SUCCESS) { - apr_pool_cleanup_kill(p, pl, piped_log_cleanup); - apr_file_close(ap_piped_log_read_fd(pl)); - apr_file_close(ap_piped_log_write_fd(pl)); - return NULL; - } - return pl; -} - -#else /* !AP_HAVE_RELIABLE_PIPED_LOGS */ - -static apr_status_t piped_log_cleanup(void *data) -{ - piped_log *pl = data; - - apr_file_close(ap_piped_log_write_fd(pl)); - return APR_SUCCESS; -} - -AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program) -{ - piped_log *pl; - apr_file_t *dummy = NULL; - int rc; - - rc = log_child(p, program, &dummy, 0); - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL, - "Couldn't start piped log process"); - return NULL; - } - - pl = apr_palloc(p, sizeof (*pl)); - pl->p = p; - ap_piped_log_read_fd(pl) = NULL; - ap_piped_log_write_fd(pl) = dummy; - apr_pool_cleanup_register(p, pl, piped_log_cleanup, piped_log_cleanup); - - return pl; -} - -#endif - -AP_DECLARE(void) ap_close_piped_log(piped_log *pl) -{ - apr_pool_cleanup_run(pl->p, pl, piped_log_cleanup); -} - -AP_IMPLEMENT_HOOK_VOID(error_log, - (const char *file, int line, int level, - apr_status_t status, const server_rec *s, - const request_rec *r, apr_pool_t *pool, - const char *errstr), (file, line, level, - status, s, r, pool, errstr)) - |