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