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