]> granicus.if.org Git - apache/blob - server/log.c
More mod_cache tweakage.
[apache] / server / log.c
1 /* Copyright 1999-2005 The Apache Software Foundation or its licensors, as
2  * applicable.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * 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
54 typedef struct {
55     char    *t_name;
56     int      t_val;
57 } TRANS;
58
59 APR_HOOK_STRUCT(
60     APR_HOOK_LINK(error_log)
61 )
62
63 int AP_DECLARE_DATA ap_default_loglevel = DEFAULT_LOGLEVEL;
64
65 #ifdef HAVE_SYSLOG
66
67 static 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
130 static 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
142 static apr_file_t *stderr_log = NULL;
143
144 AP_DECLARE(void) ap_open_stderr_log(apr_pool_t *p)
145 {
146     apr_file_open_stderr(&stderr_log, p);
147 }
148
149 AP_DECLARE(apr_status_t) ap_replace_stderr_log(apr_pool_t *p, 
150                                                const char *fname)
151 {
152     apr_file_t *stderr_file;
153     apr_status_t rc;
154     char *filename = ap_server_root_relative(p, fname);
155     if (!filename) {
156         ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT,
157                      APR_EBADPATH, NULL, "Invalid -E error log file %s",
158                      fname);
159         return APR_EBADPATH;
160     }
161     if ((rc = apr_file_open(&stderr_file, filename,
162                             APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
163                             APR_OS_DEFAULT, p)) != APR_SUCCESS) {
164         ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
165                      "%s: could not open error log file %s.",
166                      ap_server_argv0, fname);
167         return rc;
168     }
169     if ((rc = apr_file_open_stderr(&stderr_log, p)) == APR_SUCCESS) {
170         apr_file_flush(stderr_log);
171         if ((rc = apr_file_dup2(stderr_log, stderr_file, p)) == APR_SUCCESS) {
172             apr_file_close(stderr_file);
173         }
174     }
175     if (rc != APR_SUCCESS) {
176         ap_log_error(APLOG_MARK, APLOG_CRIT, rc, NULL,
177                      "unable to replace stderr with error_log");
178     }
179     return rc;
180 }
181
182 static void log_child_errfn(apr_pool_t *pool, apr_status_t err,
183                             const char *description)
184 {
185     ap_log_error(APLOG_MARK, APLOG_ERR, err, NULL,
186                  "%s", description);
187 }
188
189 static int log_child(apr_pool_t *p, const char *progname,
190                      apr_file_t **fpin)
191 {
192     /* Child process code for 'ErrorLog "|..."';
193      * may want a common framework for this, since I expect it will
194      * be common for other foo-loggers to want this sort of thing...
195      */
196     apr_status_t rc;
197     apr_procattr_t *procattr;
198     apr_proc_t *procnew;
199
200     if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS)
201         && ((rc = apr_procattr_cmdtype_set(procattr,
202                                            APR_SHELLCMD_ENV)) == APR_SUCCESS)
203         && ((rc = apr_procattr_io_set(procattr,
204                                       APR_FULL_BLOCK,
205                                       APR_NO_PIPE,
206                                       APR_NO_PIPE)) == APR_SUCCESS)
207         && ((rc = apr_procattr_error_check_set(procattr, 1)) == APR_SUCCESS)
208         && ((rc = apr_procattr_child_errfn_set(procattr, log_child_errfn)) == APR_SUCCESS)) {
209         char **args;
210         const char *pname;
211
212         apr_tokenize_to_argv(progname, &args, p);
213         pname = apr_pstrdup(p, args[0]);
214         procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew));
215         rc = apr_proc_create(procnew, pname, (const char * const *)args,
216                              NULL, procattr, p);
217
218         if (rc == APR_SUCCESS) {
219             apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
220             (*fpin) = procnew->in;
221         }
222     }
223
224     return rc;
225 }
226
227 static int open_error_log(server_rec *s, apr_pool_t *p)
228 {
229     const char *fname;
230     int rc;
231
232     if (*s->error_fname == '|') {
233         apr_file_t *dummy = NULL;
234
235         /* This starts a new process... */
236         rc = log_child (p, s->error_fname + 1, &dummy);
237         if (rc != APR_SUCCESS) {
238             ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
239                          "Couldn't start ErrorLog process");
240             return DONE;
241         }
242
243         s->error_log = dummy;
244     }
245
246 #ifdef HAVE_SYSLOG
247     else if (!strncasecmp(s->error_fname, "syslog", 6)) {
248         if ((fname = strchr(s->error_fname, ':'))) {
249             const TRANS *fac;
250
251             fname++;
252             for (fac = facilities; fac->t_name; fac++) {
253                 if (!strcasecmp(fname, fac->t_name)) {
254                     openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID,
255                             fac->t_val);
256                     s->error_log = NULL;
257                     return OK;
258                 }
259             }
260         }
261         else {
262             openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID, LOG_LOCAL7);
263         }
264
265         s->error_log = NULL;
266     }
267 #endif
268     else {
269         fname = ap_server_root_relative(p, s->error_fname);
270         if (!fname) {
271             ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EBADPATH, NULL,
272                          "%s: Invalid error log path %s.",
273                          ap_server_argv0, s->error_fname);
274             return DONE;
275         }
276         if ((rc = apr_file_open(&s->error_log, fname,
277                                APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
278                                APR_OS_DEFAULT, p)) != APR_SUCCESS) {
279             ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
280                          "%s: could not open error log file %s.",
281                          ap_server_argv0, fname);
282             return DONE;
283         }
284     }
285
286     return OK;
287 }
288
289 int ap_open_logs(apr_pool_t *pconf, apr_pool_t *p /* plog */, 
290                  apr_pool_t *ptemp, server_rec *s_main)
291 {
292     apr_status_t rc = APR_SUCCESS;
293     server_rec *virt, *q;
294     int replace_stderr;
295     apr_file_t *errfile = NULL;
296
297     if (open_error_log(s_main, p) != OK) {
298         return DONE;
299     }
300
301     replace_stderr = 1;
302     if (s_main->error_log) {
303         /* replace stderr with this new log */
304         apr_file_flush(s_main->error_log);
305         if ((rc = apr_file_open_stderr(&errfile, p)) == APR_SUCCESS) {
306             rc = apr_file_dup2(errfile, s_main->error_log, p);
307         }
308         if (rc != APR_SUCCESS) {
309             ap_log_error(APLOG_MARK, APLOG_CRIT, rc, s_main,
310                          "unable to replace stderr with error_log");
311         }
312         else {
313             replace_stderr = 0;
314         }
315     }
316     /* note that stderr may still need to be replaced with something
317      * because it points to the old error log, or back to the tty
318      * of the submitter.
319      * XXX: This is BS - /dev/null is non-portable
320      */
321     if (replace_stderr && freopen("/dev/null", "w", stderr) == NULL) {
322         ap_log_error(APLOG_MARK, APLOG_CRIT, errno, s_main,
323                      "unable to replace stderr with /dev/null");
324     }
325
326     for (virt = s_main->next; virt; virt = virt->next) {
327         if (virt->error_fname) {
328             for (q=s_main; q != virt; q = q->next) {
329                 if (q->error_fname != NULL
330                     && strcmp(q->error_fname, virt->error_fname) == 0) {
331                     break;
332                 }
333             }
334
335             if (q == virt) {
336                 if (open_error_log(virt, p) != OK) {
337                     return DONE;
338                 }
339             }
340             else {
341                 virt->error_log = q->error_log;
342             }
343         }
344         else {
345             virt->error_log = s_main->error_log;
346         }
347     }
348     return OK;
349 }
350
351 AP_DECLARE(void) ap_error_log2stderr(server_rec *s) {
352     apr_file_t *errfile = NULL;
353
354     apr_file_open_stderr(&errfile, s->process->pool);
355     if (s->error_log != NULL) {
356         apr_file_dup2(s->error_log, errfile, s->process->pool);
357     }
358 }
359
360 static void log_error_core(const char *file, int line, int level,
361                            apr_status_t status, const server_rec *s,
362                            const conn_rec *c,
363                            const request_rec *r, apr_pool_t *pool,
364                            const char *fmt, va_list args)
365 {
366     char errstr[MAX_STRING_LEN];
367 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
368     char scratch[MAX_STRING_LEN];
369 #endif
370     apr_size_t len, errstrlen;
371     apr_file_t *logf = NULL;
372     const char *referer;
373     int level_and_mask = level & APLOG_LEVELMASK;
374
375     if (r && r->connection) {
376         c = r->connection;
377     }
378
379     if (s == NULL) {
380         /*
381          * If we are doing stderr logging (startup), don't log messages that are
382          * above the default server log level unless it is a startup/shutdown
383          * notice
384          */
385         if ((level_and_mask != APLOG_NOTICE)
386             && (level_and_mask > ap_default_loglevel)) {
387             return;
388         }
389
390         logf = stderr_log;
391     }
392     else if (s->error_log) {
393         /*
394          * If we are doing normal logging, don't log messages that are
395          * above the server log level unless it is a startup/shutdown notice
396          */
397         if ((level_and_mask != APLOG_NOTICE)
398             && (level_and_mask > s->loglevel)) {
399             return;
400         }
401
402         logf = s->error_log;
403     }
404 #ifdef TPF
405     else if (tpf_child) {
406         /*
407          * If we are doing normal logging, don't log messages that are
408          * above the server log level unless it is a startup/shutdown notice
409          */
410         if ((level_and_mask != APLOG_NOTICE)
411             && (level_and_mask > s->loglevel)) {
412             return;
413         }
414
415         logf = stderr;
416     }
417 #endif /* TPF */
418     else {
419         /*
420          * If we are doing syslog logging, don't log messages that are
421          * above the server log level (including a startup/shutdown notice)
422          */
423         if (level_and_mask > s->loglevel) {
424             return;
425         }
426     }
427
428     if (logf && ((level & APLOG_STARTUP) != APLOG_STARTUP)) {
429         errstr[0] = '[';
430         ap_recent_ctime(errstr + 1, apr_time_now());
431         errstr[1 + APR_CTIME_LEN - 1] = ']';
432         errstr[1 + APR_CTIME_LEN    ] = ' ';
433         len = 1 + APR_CTIME_LEN + 1;
434     } else {
435         len = 0;
436     }
437
438     if ((level & APLOG_STARTUP) != APLOG_STARTUP) {
439         len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
440                             "[%s] ", priorities[level_and_mask].t_name);
441     }
442
443 #ifndef TPF
444     if (file && level_and_mask == APLOG_DEBUG) {
445 #if defined(_OSD_POSIX) || defined(WIN32)
446         char tmp[256];
447         char *e = strrchr(file, '/');
448 #ifdef WIN32
449         if (!e) {
450             e = strrchr(file, '\\');
451         }
452 #endif
453
454         /* In OSD/POSIX, the compiler returns for __FILE__
455          * a string like: __FILE__="*POSIX(/usr/include/stdio.h)"
456          * (it even returns an absolute path for sources in
457          * the current directory). Here we try to strip this
458          * down to the basename.
459          */
460         if (e != NULL && e[1] != '\0') {
461             apr_snprintf(tmp, sizeof(tmp), "%s", &e[1]);
462             e = &tmp[strlen(tmp)-1];
463             if (*e == ')') {
464                 *e = '\0';
465             }
466             file = tmp;
467         }
468 #else /* _OSD_POSIX || WIN32 */
469         const char *p;
470         /* On Unix, __FILE__ may be an absolute path in a
471          * VPATH build. */
472         if (file[0] == '/' && (p = ap_strrchr_c(file, '/')) != NULL) {
473             file = p + 1;
474         }
475 #endif /*_OSD_POSIX || WIN32 */
476         len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
477                             "%s(%d): ", file, line);
478     }
479 #endif /* TPF */
480
481     if (c) {
482         /* XXX: TODO: add a method of selecting whether logged client
483          * addresses are in dotted quad or resolved form... dotted
484          * quad is the most secure, which is why I'm implementing it
485          * first. -djg
486          */
487         len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
488                             "[client %s] ", c->remote_ip);
489     }
490     if (status != 0) {
491         if (status < APR_OS_START_EAIERR) {
492             len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
493                                 "(%d)", status);
494         }
495         else if (status < APR_OS_START_SYSERR) {
496             len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
497                                 "(EAI %d)", status - APR_OS_START_EAIERR);
498         }
499         else if (status < 100000 + APR_OS_START_SYSERR) {
500             len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
501                                 "(OS %d)", status - APR_OS_START_SYSERR);
502         }
503         else {
504             len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
505                                 "(os 0x%08x)", status - APR_OS_START_SYSERR);
506         }
507         apr_strerror(status, errstr + len, MAX_STRING_LEN - len);
508         len += strlen(errstr + len);
509         if (MAX_STRING_LEN - len > 2) {
510             errstr[len++] = ':';
511             errstr[len++] = ' ';
512             errstr[len] = '\0';
513         }
514     }
515
516     errstrlen = len;
517 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
518     if (apr_vsnprintf(scratch, MAX_STRING_LEN - len, fmt, args)) {
519         len += ap_escape_errorlog_item(errstr + len, scratch,
520                                        MAX_STRING_LEN - len);
521     }
522 #else
523     len += apr_vsnprintf(errstr + len, MAX_STRING_LEN - len, fmt, args);
524 #endif
525
526     if (   r && (referer = apr_table_get(r->headers_in, "Referer"))
527 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
528         && ap_escape_errorlog_item(scratch, referer, MAX_STRING_LEN - len)
529 #endif
530         ) {
531         len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
532                             ", referer: %s",
533 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
534                             scratch
535 #else
536                             referer
537 #endif
538                             );
539     }
540
541     /* NULL if we are logging to syslog */
542     if (logf) {
543         /* Truncate for the terminator (as apr_snprintf does) */
544         if (len > MAX_STRING_LEN - sizeof(APR_EOL_STR)) {
545             len = MAX_STRING_LEN - sizeof(APR_EOL_STR);
546         }
547         strcpy(errstr + len, APR_EOL_STR);
548         apr_file_puts(errstr, logf);
549         apr_file_flush(logf);
550     }
551 #ifdef HAVE_SYSLOG
552     else {
553         syslog(level_and_mask, "%s", errstr);
554     }
555 #endif
556
557     ap_run_error_log(file, line, level, status, s, r, pool, errstr + errstrlen);
558 }
559
560 AP_DECLARE(void) ap_log_error(const char *file, int line, int level,
561                               apr_status_t status, const server_rec *s,
562                               const char *fmt, ...)
563 {
564     va_list args;
565
566     va_start(args, fmt);
567     log_error_core(file, line, level, status, s, NULL, NULL, NULL, fmt, args);
568     va_end(args);
569 }
570
571 AP_DECLARE(void) ap_log_perror(const char *file, int line, int level,
572                                apr_status_t status, apr_pool_t *p,
573                                const char *fmt, ...)
574 {
575     va_list args;
576
577     va_start(args, fmt);
578     log_error_core(file, line, level, status, NULL, NULL, NULL, p, fmt, args);
579     va_end(args);
580 }
581
582 AP_DECLARE(void) ap_log_rerror(const char *file, int line, int level,
583                                apr_status_t status, const request_rec *r,
584                                const char *fmt, ...)
585 {
586     va_list args;
587
588     va_start(args, fmt);
589     log_error_core(file, line, level, status, r->server, NULL, r, NULL, fmt,
590                    args);
591
592     /*
593      * IF APLOG_TOCLIENT is set,
594      * AND the error level is 'warning' or more severe,
595      * AND there isn't already error text associated with this request,
596      * THEN make the message text available to ErrorDocument and
597      * other error processors.
598      */
599     va_end(args);
600     va_start(args,fmt);
601     if ((level & APLOG_TOCLIENT)
602         && ((level & APLOG_LEVELMASK) <= APLOG_WARNING)
603         && (apr_table_get(r->notes, "error-notes") == NULL)) {
604         apr_table_setn(r->notes, "error-notes",
605                        ap_escape_html(r->pool, apr_pvsprintf(r->pool, fmt,
606                                                              args)));
607     }
608     va_end(args);
609 }
610
611 AP_DECLARE(void) ap_log_cerror(const char *file, int line, int level,
612                                apr_status_t status, const conn_rec *c,
613                                const char *fmt, ...)
614 {
615     va_list args;
616
617     va_start(args, fmt);
618     log_error_core(file, line, level, status, c->base_server, c, NULL, NULL,
619                    fmt, args);
620     va_end(args);
621 }
622
623 AP_DECLARE(void) ap_log_pid(apr_pool_t *p, const char *filename)
624 {
625     apr_file_t *pid_file = NULL;
626     apr_finfo_t finfo;
627     static pid_t saved_pid = -1;
628     pid_t mypid;
629     apr_status_t rv;
630     const char *fname;
631
632     if (!filename) {
633         return;
634     }
635
636     fname = ap_server_root_relative(p, filename);
637     if (!fname) {
638         ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, APR_EBADPATH, 
639                      NULL, "Invalid PID file path %s, ignoring.", filename);
640         return;
641     }
642
643     mypid = getpid();
644     if (mypid != saved_pid
645         && apr_stat(&finfo, fname, APR_FINFO_MTIME, p) == APR_SUCCESS) {
646         /* AP_SIG_GRACEFUL and HUP call this on each restart.
647          * Only warn on first time through for this pid.
648          *
649          * XXX: Could just write first time through too, although
650          *      that may screw up scripts written to do something
651          *      based on the last modification time of the pid file.
652          */
653         ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, p,
654                       "pid file %s overwritten -- Unclean "
655                       "shutdown of previous Apache run?",
656                       fname);
657     }
658
659     if ((rv = apr_file_open(&pid_file, fname,
660                             APR_WRITE | APR_CREATE | APR_TRUNCATE,
661                             APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD, p))
662         != APR_SUCCESS) {
663         ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL,
664                      "could not create %s", fname);
665         ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
666                      "%s: could not log pid to file %s",
667                      ap_server_argv0, fname);
668         exit(1);
669     }
670     apr_file_printf(pid_file, "%ld" APR_EOL_STR, (long)mypid);
671     apr_file_close(pid_file);
672     saved_pid = mypid;
673 }
674
675 AP_DECLARE(apr_status_t) ap_read_pid(apr_pool_t *p, const char *filename,
676                                      pid_t *mypid)
677 {
678     const apr_size_t BUFFER_SIZE = sizeof(long) * 3 + 2; /* see apr_ltoa */
679     apr_file_t *pid_file = NULL;
680     apr_status_t rv;
681     const char *fname;
682     char *buf, *endptr;
683     apr_size_t bytes_read;
684
685     if (!filename) {
686         return APR_EGENERAL;
687     }
688
689     fname = ap_server_root_relative(p, filename);
690     if (!fname) {
691         ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, APR_EBADPATH, 
692                      NULL, "Invalid PID file path %s, ignoring.", filename);
693         return APR_EGENERAL;
694     }
695
696     rv = apr_file_open(&pid_file, fname, APR_READ, APR_OS_DEFAULT, p);
697     if (rv != APR_SUCCESS) {
698         return rv;
699     }
700
701     buf = apr_palloc(p, BUFFER_SIZE);
702
703     rv = apr_file_read_full(pid_file, buf, BUFFER_SIZE - 1, &bytes_read);
704     if (rv != APR_SUCCESS && rv != APR_EOF) {
705         return rv;
706     }
707
708     /* If we fill the buffer, we're probably reading a corrupt pid file.
709      * To be nice, let's also ensure the first char is a digit. */
710     if (bytes_read == 0 || bytes_read == BUFFER_SIZE - 1 || !apr_isdigit(*buf)) {
711         return APR_EGENERAL;
712     }
713
714     buf[bytes_read] = '\0';
715     *mypid = strtol(buf, &endptr, 10);
716
717     apr_file_close(pid_file);
718     return APR_SUCCESS;
719 }
720
721 AP_DECLARE(void) ap_log_assert(const char *szExp, const char *szFile,
722                                int nLine)
723 {
724     char time_str[APR_CTIME_LEN];
725
726     apr_ctime(time_str, apr_time_now());
727     ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL,
728                  "[%s] file %s, line %d, assertion \"%s\" failed",
729                  time_str, szFile, nLine, szExp);
730 #if defined(WIN32)
731     DebugBreak();
732 #else
733     /* unix assert does an abort leading to a core dump */
734     abort();
735 #endif
736 }
737
738 /* piped log support */
739
740 #ifdef AP_HAVE_RELIABLE_PIPED_LOGS
741 /* forward declaration */
742 static void piped_log_maintenance(int reason, void *data, apr_wait_t status);
743
744 static int piped_log_spawn(piped_log *pl)
745 {
746     int rc = 0;
747     apr_procattr_t *procattr;
748     apr_proc_t *procnew = NULL;
749     apr_status_t status;
750
751     if (((status = apr_procattr_create(&procattr, pl->p)) != APR_SUCCESS) ||
752         ((status = apr_procattr_cmdtype_set(procattr,
753                                             APR_SHELLCMD_ENV)) != APR_SUCCESS) || 
754         ((status = apr_procattr_child_in_set(procattr,
755                                              ap_piped_log_read_fd(pl),
756                                              ap_piped_log_write_fd(pl)))
757         != APR_SUCCESS) ||
758         ((status = apr_procattr_child_errfn_set(procattr, log_child_errfn))
759          != APR_SUCCESS) ||
760         ((status = apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS)) {
761         char buf[120];
762         /* Something bad happened, give up and go away. */
763         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
764                      "piped_log_spawn: unable to setup child process '%s': %s",
765                      pl->program, apr_strerror(status, buf, sizeof(buf)));
766         rc = -1;
767     }
768     else {
769         char **args;
770         const char *pname;
771
772         apr_tokenize_to_argv(pl->program, &args, pl->p);
773         pname = apr_pstrdup(pl->p, args[0]);
774         procnew = apr_pcalloc(pl->p, sizeof(apr_proc_t));
775         status = apr_proc_create(procnew, pname, (const char * const *) args,
776                                  NULL, procattr, pl->p);
777
778         if (status == APR_SUCCESS) {
779             pl->pid = procnew;
780             ap_piped_log_write_fd(pl) = procnew->in;
781             apr_proc_other_child_register(procnew, piped_log_maintenance, pl,
782                                           ap_piped_log_write_fd(pl), pl->p);
783         }
784         else {
785             char buf[120];
786             /* Something bad happened, give up and go away. */
787             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
788                          "unable to start piped log program '%s': %s",
789                          pl->program, apr_strerror(status, buf, sizeof(buf)));
790             rc = -1;
791         }
792     }
793
794     return rc;
795 }
796
797
798 static void piped_log_maintenance(int reason, void *data, apr_wait_t status)
799 {
800     piped_log *pl = data;
801     apr_status_t stats;
802     int mpm_state;
803
804     switch (reason) {
805     case APR_OC_REASON_DEATH:
806     case APR_OC_REASON_LOST:
807         pl->pid = NULL; /* in case we don't get it going again, this
808                          * tells other logic not to try to kill it
809                          */
810         apr_proc_other_child_unregister(pl);
811         stats = ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state);
812         if (stats != APR_SUCCESS) {
813             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
814                          "can't query MPM state; not restarting "
815                          "piped log program '%s'",
816                          pl->program);
817         }
818         else if (mpm_state != AP_MPMQ_STOPPING) {
819             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
820                          "piped log program '%s' failed unexpectedly",
821                          pl->program);
822             if ((stats = piped_log_spawn(pl)) != APR_SUCCESS) {
823                 /* what can we do?  This could be the error log we're having
824                  * problems opening up... */
825                 char buf[120];
826                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
827                              "piped_log_maintenance: unable to respawn '%s': %s",
828                              pl->program, apr_strerror(stats, buf, sizeof(buf)));
829             }
830         }
831         break;
832
833     case APR_OC_REASON_UNWRITABLE:
834         /* We should not kill off the pipe here, since it may only be full.
835          * If it really is locked, we should kill it off manually. */
836     break;
837
838     case APR_OC_REASON_RESTART:
839         if (pl->pid != NULL) {
840             apr_proc_kill(pl->pid, SIGTERM);
841             pl->pid = NULL;
842         }
843         break;
844
845     case APR_OC_REASON_UNREGISTER:
846         break;
847     }
848 }
849
850
851 static apr_status_t piped_log_cleanup_for_exec(void *data)
852 {
853     piped_log *pl = data;
854
855     apr_file_close(ap_piped_log_read_fd(pl));
856     apr_file_close(ap_piped_log_write_fd(pl));
857     return APR_SUCCESS;
858 }
859
860
861 static apr_status_t piped_log_cleanup(void *data)
862 {
863     piped_log *pl = data;
864
865     if (pl->pid != NULL) {
866         apr_proc_kill(pl->pid, SIGTERM);
867     }
868     return piped_log_cleanup_for_exec(data);
869 }
870
871
872 AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program)
873 {
874     piped_log *pl;
875
876     pl = apr_palloc(p, sizeof (*pl));
877     pl->p = p;
878     pl->program = apr_pstrdup(p, program);
879     pl->pid = NULL;
880     if (apr_file_pipe_create(&ap_piped_log_read_fd(pl),
881                              &ap_piped_log_write_fd(pl), p) != APR_SUCCESS) {
882         return NULL;
883     }
884     apr_pool_cleanup_register(p, pl, piped_log_cleanup,
885                               piped_log_cleanup_for_exec);
886     if (piped_log_spawn(pl) == -1) {
887         int save_errno = errno;
888         apr_pool_cleanup_kill(p, pl, piped_log_cleanup);
889         apr_file_close(ap_piped_log_read_fd(pl));
890         apr_file_close(ap_piped_log_write_fd(pl));
891         errno = save_errno;
892         return NULL;
893     }
894     return pl;
895 }
896
897 #else /* !AP_HAVE_RELIABLE_PIPED_LOGS */
898
899 static apr_status_t piped_log_cleanup(void *data)
900 {
901     piped_log *pl = data;
902
903     apr_file_close(ap_piped_log_write_fd(pl));
904     return APR_SUCCESS;
905 }
906
907 AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program)
908 {
909     piped_log *pl;
910     apr_file_t *dummy = NULL;
911     int rc;
912
913     rc = log_child(p, program, &dummy);
914     if (rc != APR_SUCCESS) {
915         ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
916                      "Couldn't start piped log process");
917         return NULL;
918     }
919
920     pl = apr_palloc(p, sizeof (*pl));
921     pl->p = p;
922     ap_piped_log_read_fd(pl) = NULL;
923     ap_piped_log_write_fd(pl) = dummy;
924     apr_pool_cleanup_register(p, pl, piped_log_cleanup, piped_log_cleanup);
925
926     return pl;
927 }
928
929 #endif
930
931 AP_DECLARE(void) ap_close_piped_log(piped_log *pl)
932 {
933     apr_pool_cleanup_run(pl->p, pl, piped_log_cleanup);
934 }
935
936 AP_IMPLEMENT_HOOK_VOID(error_log,
937                        (const char *file, int line, int level,
938                         apr_status_t status, const server_rec *s,
939                         const request_rec *r, apr_pool_t *pool,
940                         const char *errstr), (file, line, level,
941                         status, s, r, pool, errstr))
942