1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * http_log.c: Dealing with the logs and errors
19 *
20 * Rob McCool
21 *
22 */
23
24#include "apr.h"
25#include "apr_general.h"        /* for signal stuff */
26#include "apr_strings.h"
27#include "apr_errno.h"
28#include "apr_thread_proc.h"
29#include "apr_lib.h"
30#include "apr_signal.h"
31
32#define APR_WANT_STDIO
33#define APR_WANT_STRFUNC
34#include "apr_want.h"
35
36#if APR_HAVE_STDARG_H
37#include <stdarg.h>
38#endif
39#if APR_HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42
43#define CORE_PRIVATE
44
45#include "ap_config.h"
46#include "httpd.h"
47#include "http_config.h"
48#include "http_core.h"
49#include "http_log.h"
50#include "http_main.h"
51#include "util_time.h"
52#include "ap_mpm.h"
53
54typedef struct {
55    char    *t_name;
56    int      t_val;
57} TRANS;
58
59APR_HOOK_STRUCT(
60    APR_HOOK_LINK(error_log)
61)
62
63int AP_DECLARE_DATA ap_default_loglevel = DEFAULT_LOGLEVEL;
64
65#ifdef HAVE_SYSLOG
66
67static const TRANS facilities[] = {
68    {"auth",    LOG_AUTH},
69#ifdef LOG_AUTHPRIV
70    {"authpriv",LOG_AUTHPRIV},
71#endif
72#ifdef LOG_CRON
73    {"cron",    LOG_CRON},
74#endif
75#ifdef LOG_DAEMON
76    {"daemon",  LOG_DAEMON},
77#endif
78#ifdef LOG_FTP
79    {"ftp", LOG_FTP},
80#endif
81#ifdef LOG_KERN
82    {"kern",    LOG_KERN},
83#endif
84#ifdef LOG_LPR
85    {"lpr", LOG_LPR},
86#endif
87#ifdef LOG_MAIL
88    {"mail",    LOG_MAIL},
89#endif
90#ifdef LOG_NEWS
91    {"news",    LOG_NEWS},
92#endif
93#ifdef LOG_SYSLOG
94    {"syslog",  LOG_SYSLOG},
95#endif
96#ifdef LOG_USER
97    {"user",    LOG_USER},
98#endif
99#ifdef LOG_UUCP
100    {"uucp",    LOG_UUCP},
101#endif
102#ifdef LOG_LOCAL0
103    {"local0",  LOG_LOCAL0},
104#endif
105#ifdef LOG_LOCAL1
106    {"local1",  LOG_LOCAL1},
107#endif
108#ifdef LOG_LOCAL2
109    {"local2",  LOG_LOCAL2},
110#endif
111#ifdef LOG_LOCAL3
112    {"local3",  LOG_LOCAL3},
113#endif
114#ifdef LOG_LOCAL4
115    {"local4",  LOG_LOCAL4},
116#endif
117#ifdef LOG_LOCAL5
118    {"local5",  LOG_LOCAL5},
119#endif
120#ifdef LOG_LOCAL6
121    {"local6",  LOG_LOCAL6},
122#endif
123#ifdef LOG_LOCAL7
124    {"local7",  LOG_LOCAL7},
125#endif
126    {NULL,      -1},
127};
128#endif
129
130static const TRANS priorities[] = {
131    {"emerg",   APLOG_EMERG},
132    {"alert",   APLOG_ALERT},
133    {"crit",    APLOG_CRIT},
134    {"error",   APLOG_ERR},
135    {"warn",    APLOG_WARNING},
136    {"notice",  APLOG_NOTICE},
137    {"info",    APLOG_INFO},
138    {"debug",   APLOG_DEBUG},
139    {NULL,      -1},
140};
141
142static apr_pool_t *stderr_pool = NULL;
143
144static apr_file_t *stderr_log = NULL;
145
146/* track pipe handles to close in child process */
147typedef struct read_handle_t {
148    struct read_handle_t *next;
149    apr_file_t *handle;
150} read_handle_t;
151
152static read_handle_t *read_handles;
153
154/* clear_handle_list() is called when plog is cleared; at that
155 * point we need to forget about our old list of pipe read
156 * handles.  We let the plog cleanups close the actual pipes.
157 */
158static apr_status_t clear_handle_list(void *v)
159{
160    read_handles = NULL;
161    return APR_SUCCESS;
162}
163
164/* remember to close this handle in the child process
165 *
166 * On Win32 this makes zero sense, because we don't
167 * take the parent process's child procs.
168 * If the win32 parent instead passed each and every
169 * logger write handle from itself down to the child,
170 * and the parent manages all aspects of keeping the
171 * reliable pipe log children alive, this would still
172 * make no sense :)  Cripple it on Win32.
173 */
174static void close_handle_in_child(apr_pool_t *p, apr_file_t *f)
175{
176#ifndef WIN32
177    read_handle_t *new_handle;
178
179    new_handle = apr_pcalloc(p, sizeof(read_handle_t));
180    new_handle->next = read_handles;
181    new_handle->handle = f;
182    read_handles = new_handle;
183#endif
184}
185
186void ap_logs_child_init(apr_pool_t *p, server_rec *s)
187{
188    read_handle_t *cur = read_handles;
189
190    while (cur) {
191        apr_file_close(cur->handle);
192        cur = cur->next;
193    }
194}
195
196AP_DECLARE(void) ap_open_stderr_log(apr_pool_t *p)
197{
198    apr_file_open_stderr(&stderr_log, p);
199}
200
201AP_DECLARE(apr_status_t) ap_replace_stderr_log(apr_pool_t *p,
202                                               const char *fname)
203{
204    apr_file_t *stderr_file;
205    apr_status_t rc;
206    char *filename = ap_server_root_relative(p, fname);
207    if (!filename) {
208        ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT,
209                     APR_EBADPATH, NULL, "Invalid -E error log file %s",
210                     fname);
211        return APR_EBADPATH;
212    }
213    if ((rc = apr_file_open(&stderr_file, filename,
214                            APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
215                            APR_OS_DEFAULT, p)) != APR_SUCCESS) {
216        ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
217                     "%s: could not open error log file %s.",
218                     ap_server_argv0, fname);
219        return rc;
220    }
221    if (!stderr_pool) {
222        /* This is safe provided we revert it when we are finished.
223         * We don't manager the callers pool!
224         */
225        stderr_pool = p;
226    }
227    if ((rc = apr_file_open_stderr(&stderr_log, stderr_pool))
228            == APR_SUCCESS) {
229        apr_file_flush(stderr_log);
230        if ((rc = apr_file_dup2(stderr_log, stderr_file, stderr_pool))
231                == APR_SUCCESS) {
232            apr_file_close(stderr_file);
233            /*
234             * You might ponder why stderr_pool should survive?
235             * The trouble is, stderr_pool may have s_main->error_log,
236             * so we aren't in a position to destory stderr_pool until
237             * the next recycle.  There's also an apparent bug which
238             * is not; if some folk decided to call this function before
239             * the core open error logs hook, this pool won't survive.
240             * Neither does the stderr logger, so this isn't a problem.
241             */
242        }
243    }
244    /* Revert, see above */
245    if (stderr_pool == p)
246        stderr_pool = NULL;
247
248    if (rc != APR_SUCCESS) {
249        ap_log_error(APLOG_MARK, APLOG_CRIT, rc, NULL,
250                     "unable to replace stderr with error log file");
251    }
252    return rc;
253}
254
255static void log_child_errfn(apr_pool_t *pool, apr_status_t err,
256                            const char *description)
257{
258    ap_log_error(APLOG_MARK, APLOG_ERR, err, NULL,
259                 "%s", description);
260}
261
262/* Create a child process running PROGNAME with a pipe connected to
263 * the childs stdin.  The write-end of the pipe will be placed in
264 * *FPIN on successful return.  If dummy_stderr is non-zero, the
265 * stderr for the child will be the same as the stdout of the parent.
266 * Otherwise the child will inherit the stderr from the parent. */
267static int log_child(apr_pool_t *p, const char *progname,
268                     apr_file_t **fpin, apr_cmdtype_e cmdtype,
269                     int dummy_stderr)
270{
271    /* Child process code for 'ErrorLog "|..."';
272     * may want a common framework for this, since I expect it will
273     * be common for other foo-loggers to want this sort of thing...
274     */
275    apr_status_t rc;
276    apr_procattr_t *procattr;
277    apr_proc_t *procnew;
278    apr_file_t *outfile, *errfile;
279
280    if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS)
281        && ((rc = apr_procattr_cmdtype_set(procattr, cmdtype)) == APR_SUCCESS)
282        && ((rc = apr_procattr_io_set(procattr,
283                                      APR_FULL_BLOCK,
284                                      APR_NO_PIPE,
285                                      APR_NO_PIPE)) == APR_SUCCESS)
286        && ((rc = apr_procattr_error_check_set(procattr, 1)) == APR_SUCCESS)
287        && ((rc = apr_procattr_child_errfn_set(procattr, log_child_errfn))
288                == APR_SUCCESS)) {
289        char **args;
290        const char *pname;
291
292        apr_tokenize_to_argv(progname, &args, p);
293        pname = apr_pstrdup(p, args[0]);
294        procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew));
295
296        if ((rc = apr_file_open_stdout(&outfile, p)) == APR_SUCCESS) {
297            rc = apr_procattr_child_out_set(procattr, outfile, NULL);
298            if (dummy_stderr)
299                rc = apr_procattr_child_err_set(procattr, outfile, NULL);
300            else if ((rc = apr_file_open_stderr(&errfile, p)) == APR_SUCCESS)
301                rc = apr_procattr_child_err_set(procattr, errfile, NULL);
302        }
303
304        rc = apr_proc_create(procnew, pname, (const char * const *)args,
305                             NULL, procattr, p);
306
307        if (rc == APR_SUCCESS) {
308            apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
309            (*fpin) = procnew->in;
310            /* read handle to pipe not kept open, so no need to call
311             * close_handle_in_child()
312             */
313        }
314    }
315
316    return rc;
317}
318
319/* Open the error log for the given server_rec.  If IS_MAIN is
320 * non-zero, s is the main server. */
321static int open_error_log(server_rec *s, int is_main, apr_pool_t *p)
322{
323    const char *fname;
324    int rc;
325
326    if (*s->error_fname == '|') {
327        apr_file_t *dummy = NULL;
328        apr_cmdtype_e cmdtype = APR_SHELLCMD_ENV;
329        fname = s->error_fname + 1;
330
331        /* In 2.4 favor PROGRAM_ENV, accept "||prog" syntax for compatibility
332         * and "|$cmd" to override the default.
333         * Any 2.2 backport would continue to favor SHELLCMD_ENV so there
334         * accept "||prog" to override, and "|$cmd" to ease conversion.
335         */
336        if (*fname == '|') {
337            cmdtype = APR_PROGRAM_ENV;
338            ++fname;
339        }
340        if (*fname == '$')
341            ++fname;
342
343        /* Spawn a new child logger.  If this is the main server_rec,
344         * the new child must use a dummy stderr since the current
345         * stderr might be a pipe to the old logger.  Otherwise, the
346         * child inherits the parents stderr. */
347        rc = log_child(p, fname, &dummy, cmdtype, is_main);
348        if (rc != APR_SUCCESS) {
349            ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
350                         "Couldn't start ErrorLog process");
351            return DONE;
352        }
353
354        s->error_log = dummy;
355    }
356
357#ifdef HAVE_SYSLOG
358    else if (!strncasecmp(s->error_fname, "syslog", 6)) {
359        if ((fname = strchr(s->error_fname, ':'))) {
360            const TRANS *fac;
361
362            fname++;
363            for (fac = facilities; fac->t_name; fac++) {
364                if (!strcasecmp(fname, fac->t_name)) {
365                    openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID,
366                            fac->t_val);
367                    s->error_log = NULL;
368                    return OK;
369                }
370            }
371        }
372        else {
373            openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID, LOG_LOCAL7);
374        }
375
376        s->error_log = NULL;
377    }
378#endif
379    else {
380        fname = ap_server_root_relative(p, s->error_fname);
381        if (!fname) {
382            ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EBADPATH, NULL,
383                         "%s: Invalid error log path %s.",
384                         ap_server_argv0, s->error_fname);
385            return DONE;
386        }
387        if ((rc = apr_file_open(&s->error_log, fname,
388                               APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
389                               APR_OS_DEFAULT, p)) != APR_SUCCESS) {
390            ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
391                         "%s: could not open error log file %s.",
392                         ap_server_argv0, fname);
393            return DONE;
394        }
395    }
396
397    return OK;
398}
399
400int ap_open_logs(apr_pool_t *pconf, apr_pool_t *p /* plog */,
401                 apr_pool_t *ptemp, server_rec *s_main)
402{
403    apr_pool_t *stderr_p;
404    server_rec *virt, *q;
405    int replace_stderr;
406
407
408    /* Register to throw away the read_handles list when we
409     * cleanup plog.  Upon fork() for the apache children,
410     * this read_handles list is closed so only the parent
411     * can relaunch a lost log child.  These read handles
412     * are always closed on exec.
413     * We won't care what happens to our stderr log child
414     * between log phases, so we don't mind losing stderr's
415     * read_handle a little bit early.
416     */
417    apr_pool_cleanup_register(p, NULL, clear_handle_list,
418                              apr_pool_cleanup_null);
419
420    /* HERE we need a stdout log that outlives plog.
421     * We *presume* the parent of plog is a process
422     * or global pool which spans server restarts.
423     * Create our stderr_pool as a child of the plog's
424     * parent pool.
425     */
426    apr_pool_create(&stderr_p, apr_pool_parent_get(p));
427    apr_pool_tag(stderr_p, "stderr_pool");
428
429    if (open_error_log(s_main, 1, stderr_p) != OK) {
430        return DONE;
431    }
432
433    replace_stderr = 1;
434    if (s_main->error_log) {
435        apr_status_t rv;
436
437        /* Replace existing stderr with new log. */
438        apr_file_flush(s_main->error_log);
439        rv = apr_file_dup2(stderr_log, s_main->error_log, stderr_p);
440        if (rv != APR_SUCCESS) {
441            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s_main,
442                         "unable to replace stderr with error_log");
443        }
444        else {
445            /* We are done with stderr_pool, close it, killing
446             * the previous generation's stderr logger
447             */
448            if (stderr_pool)
449                apr_pool_destroy(stderr_pool);
450            stderr_pool = stderr_p;
451            replace_stderr = 0;
452            /*
453             * Now that we have dup'ed s_main->error_log to stderr_log
454             * close it and set s_main->error_log to stderr_log. This avoids
455             * this fd being inherited by the next piped logger who would
456             * keep open the writing end of the pipe that this one uses
457             * as stdin. This in turn would prevent the piped logger from
458             * exiting.
459             */
460             apr_file_close(s_main->error_log);
461             s_main->error_log = stderr_log;
462        }
463    }
464    /* note that stderr may still need to be replaced with something
465     * because it points to the old error log, or back to the tty
466     * of the submitter.
467     * XXX: This is BS - /dev/null is non-portable
468     */
469    if (replace_stderr && freopen("/dev/null", "w", stderr) == NULL) {
470        ap_log_error(APLOG_MARK, APLOG_CRIT, errno, s_main,
471                     "unable to replace stderr with /dev/null");
472    }
473
474    for (virt = s_main->next; virt; virt = virt->next) {
475        if (virt->error_fname) {
476            for (q=s_main; q != virt; q = q->next) {
477                if (q->error_fname != NULL
478                    && strcmp(q->error_fname, virt->error_fname) == 0) {
479                    break;
480                }
481            }
482
483            if (q == virt) {
484                if (open_error_log(virt, 0, p) != OK) {
485                    return DONE;
486                }
487            }
488            else {
489                virt->error_log = q->error_log;
490            }
491        }
492        else {
493            virt->error_log = s_main->error_log;
494        }
495    }
496    return OK;
497}
498
499AP_DECLARE(void) ap_error_log2stderr(server_rec *s) {
500    apr_file_t *errfile = NULL;
501
502    apr_file_open_stderr(&errfile, s->process->pool);
503    if (s->error_log != NULL) {
504        apr_file_dup2(s->error_log, errfile, s->process->pool);
505    }
506}
507
508static void log_error_core(const char *file, int line, int level,
509                           apr_status_t status, const server_rec *s,
510                           const conn_rec *c,
511                           const request_rec *r, apr_pool_t *pool,
512                           const char *fmt, va_list args)
513{
514    char errstr[MAX_STRING_LEN];
515#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
516    char scratch[MAX_STRING_LEN];
517#endif
518    apr_size_t len, errstrlen;
519    apr_file_t *logf = NULL;
520    const char *referer;
521    int level_and_mask = level & APLOG_LEVELMASK;
522
523    if (r && r->connection) {
524        c = r->connection;
525    }
526
527    if (s == NULL) {
528        /*
529         * If we are doing stderr logging (startup), don't log messages that are
530         * above the default server log level unless it is a startup/shutdown
531         * notice
532         */
533        if ((level_and_mask != APLOG_NOTICE)
534            && (level_and_mask > ap_default_loglevel)) {
535            return;
536        }
537
538        logf = stderr_log;
539    }
540    else if (s->error_log) {
541        /*
542         * If we are doing normal logging, don't log messages that are
543         * above the server log level unless it is a startup/shutdown notice
544         */
545        if ((level_and_mask != APLOG_NOTICE)
546            && (level_and_mask > s->loglevel)) {
547            return;
548        }
549
550        logf = s->error_log;
551    }
552#ifdef TPF
553    else if (tpf_child) {
554        /*
555         * If we are doing normal logging, don't log messages that are
556         * above the server log level unless it is a startup/shutdown notice
557         */
558        if ((level_and_mask != APLOG_NOTICE)
559            && (level_and_mask > s->loglevel)) {
560            return;
561        }
562
563        logf = stderr;
564    }
565#endif /* TPF */
566    else {
567        /*
568         * If we are doing syslog logging, don't log messages that are
569         * above the server log level (including a startup/shutdown notice)
570         */
571        if (level_and_mask > s->loglevel) {
572            return;
573        }
574    }
575
576    if (logf && ((level & APLOG_STARTUP) != APLOG_STARTUP)) {
577        errstr[0] = '[';
578        ap_recent_ctime(errstr + 1, apr_time_now());
579        errstr[1 + APR_CTIME_LEN - 1] = ']';
580        errstr[1 + APR_CTIME_LEN    ] = ' ';
581        len = 1 + APR_CTIME_LEN + 1;
582    } else {
583        len = 0;
584    }
585
586    if ((level & APLOG_STARTUP) != APLOG_STARTUP) {
587        len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
588                            "[%s] ", priorities[level_and_mask].t_name);
589    }
590
591#ifndef TPF
592    if (file && level_and_mask == APLOG_DEBUG) {
593#if defined(_OSD_POSIX) || defined(WIN32) || defined(__MVS__)
594        char tmp[256];
595        char *e = strrchr(file, '/');
596#ifdef WIN32
597        if (!e) {
598            e = strrchr(file, '\\');
599        }
600#endif
601
602        /* In OSD/POSIX, the compiler returns for __FILE__
603         * a string like: __FILE__="*POSIX(/usr/include/stdio.h)"
604         * (it even returns an absolute path for sources in
605         * the current directory). Here we try to strip this
606         * down to the basename.
607         */
608        if (e != NULL && e[1] != '\0') {
609            apr_snprintf(tmp, sizeof(tmp), "%s", &e[1]);
610            e = &tmp[strlen(tmp)-1];
611            if (*e == ')') {
612                *e = '\0';
613            }
614            file = tmp;
615        }
616#else /* _OSD_POSIX || WIN32 */
617        const char *p;
618        /* On Unix, __FILE__ may be an absolute path in a
619         * VPATH build. */
620        if (file[0] == '/' && (p = ap_strrchr_c(file, '/')) != NULL) {
621            file = p + 1;
622        }
623#endif /*_OSD_POSIX || WIN32 */
624        len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
625                            "%s(%d): ", file, line);
626    }
627#endif /* TPF */
628
629    if (c) {
630        /* XXX: TODO: add a method of selecting whether logged client
631         * addresses are in dotted quad or resolved form... dotted
632         * quad is the most secure, which is why I'm implementing it
633         * first. -djg
634         */
635        len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
636                            "[client %s] ", c->remote_ip);
637    }
638    if (status != 0) {
639        if (status < APR_OS_START_EAIERR) {
640            len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
641                                "(%d)", status);
642        }
643        else if (status < APR_OS_START_SYSERR) {
644            len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
645                                "(EAI %d)", status - APR_OS_START_EAIERR);
646        }
647        else if (status < 100000 + APR_OS_START_SYSERR) {
648            len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
649                                "(OS %d)", status - APR_OS_START_SYSERR);
650        }
651        else {
652            len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
653                                "(os 0x%08x)", status - APR_OS_START_SYSERR);
654        }
655        apr_strerror(status, errstr + len, MAX_STRING_LEN - len);
656        len += strlen(errstr + len);
657        if (MAX_STRING_LEN - len > 2) {
658            errstr[len++] = ':';
659            errstr[len++] = ' ';
660            errstr[len] = '\0';
661        }
662    }
663
664    errstrlen = len;
665#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
666    if (apr_vsnprintf(scratch, MAX_STRING_LEN - len, fmt, args)) {
667        len += ap_escape_errorlog_item(errstr + len, scratch,
668                                       MAX_STRING_LEN - len);
669    }
670#else
671    len += apr_vsnprintf(errstr + len, MAX_STRING_LEN - len, fmt, args);
672#endif
673
674    if (   r && (referer = apr_table_get(r->headers_in, "Referer"))
675#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
676        && ap_escape_errorlog_item(scratch, referer, MAX_STRING_LEN - len)
677#endif
678        ) {
679        len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
680                            ", referer: %s",
681#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
682                            scratch
683#else
684                            referer
685#endif
686                            );
687    }
688
689    /* NULL if we are logging to syslog */
690    if (logf) {
691        /* Truncate for the terminator (as apr_snprintf does) */
692        if (len > MAX_STRING_LEN - sizeof(APR_EOL_STR)) {
693            len = MAX_STRING_LEN - sizeof(APR_EOL_STR);
694        }
695        strcpy(errstr + len, APR_EOL_STR);
696        apr_file_puts(errstr, logf);
697        apr_file_flush(logf);
698    }
699#ifdef HAVE_SYSLOG
700    else {
701        syslog(level_and_mask, "%s", errstr);
702    }
703#endif
704
705    ap_run_error_log(file, line, level, status, s, r, pool, errstr + errstrlen);
706}
707
708AP_DECLARE(void) ap_log_error(const char *file, int line, int level,
709                              apr_status_t status, const server_rec *s,
710                              const char *fmt, ...)
711{
712    va_list args;
713
714    va_start(args, fmt);
715    log_error_core(file, line, level, status, s, NULL, NULL, NULL, fmt, args);
716    va_end(args);
717}
718
719AP_DECLARE(void) ap_log_perror(const char *file, int line, int level,
720                               apr_status_t status, apr_pool_t *p,
721                               const char *fmt, ...)
722{
723    va_list args;
724
725    va_start(args, fmt);
726    log_error_core(file, line, level, status, NULL, NULL, NULL, p, fmt, args);
727    va_end(args);
728}
729
730AP_DECLARE(void) ap_log_rerror(const char *file, int line, int level,
731                               apr_status_t status, const request_rec *r,
732                               const char *fmt, ...)
733{
734    va_list args;
735
736    va_start(args, fmt);
737    log_error_core(file, line, level, status, r->server, NULL, r, NULL, fmt,
738                   args);
739
740    /*
741     * IF APLOG_TOCLIENT is set,
742     * AND the error level is 'warning' or more severe,
743     * AND there isn't already error text associated with this request,
744     * THEN make the message text available to ErrorDocument and
745     * other error processors.
746     */
747    va_end(args);
748    va_start(args,fmt);
749    if ((level & APLOG_TOCLIENT)
750        && ((level & APLOG_LEVELMASK) <= APLOG_WARNING)
751        && (apr_table_get(r->notes, "error-notes") == NULL)) {
752        apr_table_setn(r->notes, "error-notes",
753                       ap_escape_html(r->pool, apr_pvsprintf(r->pool, fmt,
754                                                             args)));
755    }
756    va_end(args);
757}
758
759AP_DECLARE(void) ap_log_cerror(const char *file, int line, int level,
760                               apr_status_t status, const conn_rec *c,
761                               const char *fmt, ...)
762{
763    va_list args;
764
765    va_start(args, fmt);
766    log_error_core(file, line, level, status, c->base_server, c, NULL, NULL,
767                   fmt, args);
768    va_end(args);
769}
770
771AP_DECLARE(void) ap_log_pid(apr_pool_t *p, const char *filename)
772{
773    apr_file_t *pid_file = NULL;
774    apr_finfo_t finfo;
775    static pid_t saved_pid = -1;
776    pid_t mypid;
777    apr_status_t rv;
778    const char *fname;
779
780    if (!filename) {
781        return;
782    }
783
784    fname = ap_server_root_relative(p, filename);
785    if (!fname) {
786        ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, APR_EBADPATH,
787                     NULL, "Invalid PID file path %s, ignoring.", filename);
788        return;
789    }
790
791    mypid = getpid();
792    if (mypid != saved_pid
793        && apr_stat(&finfo, fname, APR_FINFO_MTIME, p) == APR_SUCCESS) {
794        /* AP_SIG_GRACEFUL and HUP call this on each restart.
795         * Only warn on first time through for this pid.
796         *
797         * XXX: Could just write first time through too, although
798         *      that may screw up scripts written to do something
799         *      based on the last modification time of the pid file.
800         */
801        ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, p,
802                      "pid file %s overwritten -- Unclean "
803                      "shutdown of previous Apache run?",
804                      fname);
805    }
806
807    if ((rv = apr_file_open(&pid_file, fname,
808                            APR_WRITE | APR_CREATE | APR_TRUNCATE,
809                            APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD, p))
810        != APR_SUCCESS) {
811        ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL,
812                     "could not create %s", fname);
813        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
814                     "%s: could not log pid to file %s",
815                     ap_server_argv0, fname);
816        exit(1);
817    }
818    apr_file_printf(pid_file, "%ld" APR_EOL_STR, (long)mypid);
819    apr_file_close(pid_file);
820    saved_pid = mypid;
821}
822
823AP_DECLARE(apr_status_t) ap_read_pid(apr_pool_t *p, const char *filename,
824                                     pid_t *mypid)
825{
826    const apr_size_t BUFFER_SIZE = sizeof(long) * 3 + 2; /* see apr_ltoa */
827    apr_file_t *pid_file = NULL;
828    apr_status_t rv;
829    const char *fname;
830    char *buf, *endptr;
831    apr_size_t bytes_read;
832
833    if (!filename) {
834        return APR_EGENERAL;
835    }
836
837    fname = ap_server_root_relative(p, filename);
838    if (!fname) {
839        ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, APR_EBADPATH,
840                     NULL, "Invalid PID file path %s, ignoring.", filename);
841        return APR_EGENERAL;
842    }
843
844    rv = apr_file_open(&pid_file, fname, APR_READ, APR_OS_DEFAULT, p);
845    if (rv != APR_SUCCESS) {
846        return rv;
847    }
848
849    buf = apr_palloc(p, BUFFER_SIZE);
850
851    rv = apr_file_read_full(pid_file, buf, BUFFER_SIZE - 1, &bytes_read);
852    if (rv != APR_SUCCESS && rv != APR_EOF) {
853        return rv;
854    }
855
856    /* If we fill the buffer, we're probably reading a corrupt pid file.
857     * To be nice, let's also ensure the first char is a digit. */
858    if (bytes_read == 0 || bytes_read == BUFFER_SIZE - 1 || !apr_isdigit(*buf)) {
859        return APR_EGENERAL;
860    }
861
862    buf[bytes_read] = '\0';
863    *mypid = strtol(buf, &endptr, 10);
864
865    apr_file_close(pid_file);
866    return APR_SUCCESS;
867}
868
869AP_DECLARE(void) ap_log_assert(const char *szExp, const char *szFile,
870                               int nLine)
871{
872    char time_str[APR_CTIME_LEN];
873
874    apr_ctime(time_str, apr_time_now());
875    ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL,
876                 "[%s] file %s, line %d, assertion \"%s\" failed",
877                 time_str, szFile, nLine, szExp);
878#if defined(WIN32)
879    DebugBreak();
880#else
881    /* unix assert does an abort leading to a core dump */
882    abort();
883#endif
884}
885
886/* piped log support */
887
888#ifdef AP_HAVE_RELIABLE_PIPED_LOGS
889/* forward declaration */
890static void piped_log_maintenance(int reason, void *data, apr_wait_t status);
891
892/* Spawn the piped logger process pl->program. */
893static apr_status_t piped_log_spawn(piped_log *pl)
894{
895    apr_procattr_t *procattr;
896    apr_proc_t *procnew = NULL;
897    apr_status_t status;
898
899    if (((status = apr_procattr_create(&procattr, pl->p)) != APR_SUCCESS) ||
900        ((status = apr_procattr_cmdtype_set(procattr, pl->cmdtype))
901         != APR_SUCCESS) ||
902        ((status = apr_procattr_child_in_set(procattr,
903                                             ap_piped_log_read_fd(pl),
904                                             ap_piped_log_write_fd(pl)))
905         != APR_SUCCESS) ||
906        ((status = apr_procattr_child_errfn_set(procattr, log_child_errfn))
907         != APR_SUCCESS) ||
908        ((status = apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS)) {
909        char buf[120];
910        /* Something bad happened, give up and go away. */
911        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
912                     "piped_log_spawn: unable to setup child process '%s': %s",
913                     pl->program, apr_strerror(status, buf, sizeof(buf)));
914    }
915    else {
916        char **args;
917        const char *pname;
918        apr_file_t *outfile, *errfile;
919
920        if ((status = apr_file_open_stdout(&outfile, pl->p)) == APR_SUCCESS)
921            status = apr_procattr_child_out_set(procattr, outfile, NULL);
922        if ((status = apr_file_open_stderr(&errfile, pl->p)) == APR_SUCCESS)
923            status = apr_procattr_child_err_set(procattr, errfile, NULL);
924
925        apr_tokenize_to_argv(pl->program, &args, pl->p);
926        pname = apr_pstrdup(pl->p, args[0]);
927        procnew = apr_pcalloc(pl->p, sizeof(apr_proc_t));
928        status = apr_proc_create(procnew, pname, (const char * const *) args,
929                                 NULL, procattr, pl->p);
930
931        if (status == APR_SUCCESS) {
932            pl->pid = procnew;
933            /* procnew->in was dup2'd from ap_piped_log_write_fd(pl);
934             * since the original fd is still valid, close the copy to
935             * avoid a leak. */
936            apr_file_close(procnew->in);
937            procnew->in = NULL;
938            apr_proc_other_child_register(procnew, piped_log_maintenance, pl,
939                                          ap_piped_log_write_fd(pl), pl->p);
940            close_handle_in_child(pl->p, ap_piped_log_read_fd(pl));
941        }
942        else {
943            char buf[120];
944            /* Something bad happened, give up and go away. */
945            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
946                         "unable to start piped log program '%s': %s",
947                         pl->program, apr_strerror(status, buf, sizeof(buf)));
948        }
949    }
950
951    return status;
952}
953
954
955static void piped_log_maintenance(int reason, void *data, apr_wait_t status)
956{
957    piped_log *pl = data;
958    apr_status_t stats;
959    int mpm_state;
960
961    switch (reason) {
962    case APR_OC_REASON_DEATH:
963    case APR_OC_REASON_LOST:
964        pl->pid = NULL; /* in case we don't get it going again, this
965                         * tells other logic not to try to kill it
966                         */
967        apr_proc_other_child_unregister(pl);
968        stats = ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state);
969        if (stats != APR_SUCCESS) {
970            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
971                         "can't query MPM state; not restarting "
972                         "piped log program '%s'",
973                         pl->program);
974        }
975        else if (mpm_state != AP_MPMQ_STOPPING) {
976            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
977                         "piped log program '%s' failed unexpectedly",
978                         pl->program);
979            if ((stats = piped_log_spawn(pl)) != APR_SUCCESS) {
980                /* what can we do?  This could be the error log we're having
981                 * problems opening up... */
982                char buf[120];
983                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
984                             "piped_log_maintenance: unable to respawn '%s': %s",
985                             pl->program, apr_strerror(stats, buf, sizeof(buf)));
986            }
987        }
988        break;
989
990    case APR_OC_REASON_UNWRITABLE:
991        /* We should not kill off the pipe here, since it may only be full.
992         * If it really is locked, we should kill it off manually. */
993    break;
994
995    case APR_OC_REASON_RESTART:
996        if (pl->pid != NULL) {
997            apr_proc_kill(pl->pid, SIGTERM);
998            pl->pid = NULL;
999        }
1000        break;
1001
1002    case APR_OC_REASON_UNREGISTER:
1003        break;
1004    }
1005}
1006
1007
1008static apr_status_t piped_log_cleanup_for_exec(void *data)
1009{
1010    piped_log *pl = data;
1011
1012    apr_file_close(ap_piped_log_read_fd(pl));
1013    apr_file_close(ap_piped_log_write_fd(pl));
1014    return APR_SUCCESS;
1015}
1016
1017
1018static apr_status_t piped_log_cleanup(void *data)
1019{
1020    piped_log *pl = data;
1021
1022    if (pl->pid != NULL) {
1023        apr_proc_kill(pl->pid, SIGTERM);
1024    }
1025    return piped_log_cleanup_for_exec(data);
1026}
1027
1028
1029AP_DECLARE(piped_log *) ap_open_piped_log_ex(apr_pool_t *p,
1030                                             const char *program,
1031                                             apr_cmdtype_e cmdtype)
1032{
1033    piped_log *pl;
1034
1035    pl = apr_palloc(p, sizeof (*pl));
1036    pl->p = p;
1037    pl->program = apr_pstrdup(p, program);
1038    pl->pid = NULL;
1039    pl->cmdtype = cmdtype;
1040    if (apr_file_pipe_create(&ap_piped_log_read_fd(pl),
1041                             &ap_piped_log_write_fd(pl), p) != APR_SUCCESS) {
1042        return NULL;
1043    }
1044    apr_pool_cleanup_register(p, pl, piped_log_cleanup,
1045                              piped_log_cleanup_for_exec);
1046    if (piped_log_spawn(pl) != APR_SUCCESS) {
1047        apr_pool_cleanup_kill(p, pl, piped_log_cleanup);
1048        apr_file_close(ap_piped_log_read_fd(pl));
1049        apr_file_close(ap_piped_log_write_fd(pl));
1050        return NULL;
1051    }
1052    return pl;
1053}
1054
1055#else /* !AP_HAVE_RELIABLE_PIPED_LOGS */
1056
1057static apr_status_t piped_log_cleanup(void *data)
1058{
1059    piped_log *pl = data;
1060
1061    apr_file_close(ap_piped_log_write_fd(pl));
1062    return APR_SUCCESS;
1063}
1064
1065AP_DECLARE(piped_log *) ap_open_piped_log_ex(apr_pool_t *p,
1066                                             const char *program,
1067                                             apr_cmdtype_e cmdtype)
1068{
1069    piped_log *pl;
1070    apr_file_t *dummy = NULL;
1071    int rc;
1072
1073    rc = log_child(p, program, &dummy, cmdtype, 0);
1074    if (rc != APR_SUCCESS) {
1075        ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
1076                     "Couldn't start piped log process");
1077        return NULL;
1078    }
1079
1080    pl = apr_palloc(p, sizeof (*pl));
1081    pl->p = p;
1082    ap_piped_log_read_fd(pl) = NULL;
1083    ap_piped_log_write_fd(pl) = dummy;
1084    apr_pool_cleanup_register(p, pl, piped_log_cleanup, piped_log_cleanup);
1085
1086    return pl;
1087}
1088
1089#endif
1090
1091AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p,
1092                                          const char *program)
1093{
1094    apr_cmdtype_e cmdtype = APR_SHELLCMD_ENV;
1095
1096    /* In 2.4 favor PROGRAM_ENV, accept "||prog" syntax for compatibility
1097     * and "|$cmd" to override the default.
1098     * Any 2.2 backport would continue to favor SHELLCMD_ENV so there
1099     * accept "||prog" to override, and "|$cmd" to ease conversion.
1100     */
1101    if (*program == '|') {
1102        cmdtype = APR_PROGRAM_ENV;
1103        ++program;
1104    }
1105    if (*program == '$')
1106        ++program;
1107
1108    return ap_open_piped_log_ex(p, program, cmdtype);
1109}
1110
1111AP_DECLARE(void) ap_close_piped_log(piped_log *pl)
1112{
1113    apr_pool_cleanup_run(pl->p, pl, piped_log_cleanup);
1114}
1115
1116AP_IMPLEMENT_HOOK_VOID(error_log,
1117                       (const char *file, int line, int level,
1118                        apr_status_t status, const server_rec *s,
1119                        const request_rec *r, apr_pool_t *pool,
1120                        const char *errstr), (file, line, level,
1121                        status, s, r, pool, errstr))
1122
1123