]> granicus.if.org Git - apache/blob - server/log.c
Fix wrong condition that may lead to NULL being set as 'Vary' header
[apache] / server / log.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * http_log.c: Dealing with the logs and errors
19  *
20  * Rob McCool
21  *
22  */
23
24 #include "apr.h"
25 #include "apr_general.h"        /* for signal stuff */
26 #include "apr_strings.h"
27 #include "apr_errno.h"
28 #include "apr_thread_proc.h"
29 #include "apr_lib.h"
30 #include "apr_signal.h"
31 #include "apr_portable.h"
32 #include "apr_base64.h"
33
34 #define APR_WANT_STDIO
35 #define APR_WANT_STRFUNC
36 #include "apr_want.h"
37
38 #if APR_HAVE_STDARG_H
39 #include <stdarg.h>
40 #endif
41 #if APR_HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44 #if APR_HAVE_PROCESS_H
45 #include <process.h>            /* for getpid() on Win32 */
46 #endif
47
48 #include "ap_config.h"
49 #include "httpd.h"
50 #include "http_config.h"
51 #include "http_core.h"
52 #include "http_log.h"
53 #include "http_main.h"
54 #include "util_time.h"
55 #include "ap_mpm.h"
56
57 APLOG_USE_MODULE(core);
58
59 typedef struct {
60     const char *t_name;
61     int t_val;
62 } TRANS;
63
64 APR_HOOK_STRUCT(
65     APR_HOOK_LINK(error_log)
66     APR_HOOK_LINK(generate_log_id)
67 )
68
69 int AP_DECLARE_DATA ap_default_loglevel = DEFAULT_LOGLEVEL;
70
71 #ifdef HAVE_SYSLOG
72
73 static const TRANS facilities[] = {
74     {"auth",    LOG_AUTH},
75 #ifdef LOG_AUTHPRIV
76     {"authpriv",LOG_AUTHPRIV},
77 #endif
78 #ifdef LOG_CRON
79     {"cron",    LOG_CRON},
80 #endif
81 #ifdef LOG_DAEMON
82     {"daemon",  LOG_DAEMON},
83 #endif
84 #ifdef LOG_FTP
85     {"ftp", LOG_FTP},
86 #endif
87 #ifdef LOG_KERN
88     {"kern",    LOG_KERN},
89 #endif
90 #ifdef LOG_LPR
91     {"lpr", LOG_LPR},
92 #endif
93 #ifdef LOG_MAIL
94     {"mail",    LOG_MAIL},
95 #endif
96 #ifdef LOG_NEWS
97     {"news",    LOG_NEWS},
98 #endif
99 #ifdef LOG_SYSLOG
100     {"syslog",  LOG_SYSLOG},
101 #endif
102 #ifdef LOG_USER
103     {"user",    LOG_USER},
104 #endif
105 #ifdef LOG_UUCP
106     {"uucp",    LOG_UUCP},
107 #endif
108 #ifdef LOG_LOCAL0
109     {"local0",  LOG_LOCAL0},
110 #endif
111 #ifdef LOG_LOCAL1
112     {"local1",  LOG_LOCAL1},
113 #endif
114 #ifdef LOG_LOCAL2
115     {"local2",  LOG_LOCAL2},
116 #endif
117 #ifdef LOG_LOCAL3
118     {"local3",  LOG_LOCAL3},
119 #endif
120 #ifdef LOG_LOCAL4
121     {"local4",  LOG_LOCAL4},
122 #endif
123 #ifdef LOG_LOCAL5
124     {"local5",  LOG_LOCAL5},
125 #endif
126 #ifdef LOG_LOCAL6
127     {"local6",  LOG_LOCAL6},
128 #endif
129 #ifdef LOG_LOCAL7
130     {"local7",  LOG_LOCAL7},
131 #endif
132     {NULL,      -1},
133 };
134 #endif
135
136 static const TRANS priorities[] = {
137     {"emerg",   APLOG_EMERG},
138     {"alert",   APLOG_ALERT},
139     {"crit",    APLOG_CRIT},
140     {"error",   APLOG_ERR},
141     {"warn",    APLOG_WARNING},
142     {"notice",  APLOG_NOTICE},
143     {"info",    APLOG_INFO},
144     {"debug",   APLOG_DEBUG},
145     {"trace1",  APLOG_TRACE1},
146     {"trace2",  APLOG_TRACE2},
147     {"trace3",  APLOG_TRACE3},
148     {"trace4",  APLOG_TRACE4},
149     {"trace5",  APLOG_TRACE5},
150     {"trace6",  APLOG_TRACE6},
151     {"trace7",  APLOG_TRACE7},
152     {"trace8",  APLOG_TRACE8},
153     {NULL,      -1},
154 };
155
156 static apr_pool_t *stderr_pool = NULL;
157
158 static apr_file_t *stderr_log = NULL;
159
160 /* track pipe handles to close in child process */
161 typedef struct read_handle_t {
162     struct read_handle_t *next;
163     apr_file_t *handle;
164 } read_handle_t;
165
166 static read_handle_t *read_handles;
167
168 /**
169  * @brief The piped logging structure.  
170  *
171  * Piped logs are used to move functionality out of the main server.  
172  * For example, log rotation is done with piped logs.
173  */
174 struct piped_log {
175     /** The pool to use for the piped log */
176     apr_pool_t *p;
177     /** The pipe between the server and the logging process */
178     apr_file_t *read_fd, *write_fd;
179 #ifdef AP_HAVE_RELIABLE_PIPED_LOGS
180     /** The name of the program the logging process is running */
181     char *program;
182     /** The pid of the logging process */
183     apr_proc_t *pid;
184     /** How to reinvoke program when it must be replaced */
185     apr_cmdtype_e cmdtype;
186 #endif
187 };
188
189 AP_DECLARE(apr_file_t *) ap_piped_log_read_fd(piped_log *pl)
190 {
191     return pl->read_fd;
192 }
193
194 AP_DECLARE(apr_file_t *) ap_piped_log_write_fd(piped_log *pl)
195 {
196     return pl->write_fd;
197 }
198
199 /* remember to close this handle in the child process
200  *
201  * On Win32 this makes zero sense, because we don't
202  * take the parent process's child procs.
203  * If the win32 parent instead passed each and every
204  * logger write handle from itself down to the child,
205  * and the parent manages all aspects of keeping the 
206  * reliable pipe log children alive, this would still
207  * make no sense :)  Cripple it on Win32.
208  */
209 static void close_handle_in_child(apr_pool_t *p, apr_file_t *f)
210 {
211 #ifndef WIN32
212     read_handle_t *new_handle;
213
214     new_handle = apr_pcalloc(p, sizeof(read_handle_t));
215     new_handle->next = read_handles;
216     new_handle->handle = f;
217     read_handles = new_handle;
218 #endif
219 }
220
221 void ap_logs_child_init(apr_pool_t *p, server_rec *s)
222 {
223     read_handle_t *cur = read_handles;
224
225     while (cur) {
226         apr_file_close(cur->handle);
227         cur = cur->next;
228     }
229 }
230
231 AP_DECLARE(void) ap_open_stderr_log(apr_pool_t *p)
232 {
233     apr_file_open_stderr(&stderr_log, p);
234 }
235
236 AP_DECLARE(apr_status_t) ap_replace_stderr_log(apr_pool_t *p,
237                                                const char *fname)
238 {
239     apr_file_t *stderr_file;
240     apr_status_t rc;
241     char *filename = ap_server_root_relative(p, fname);
242     if (!filename) {
243         ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT,
244                      APR_EBADPATH, NULL, "Invalid -E error log file %s",
245                      fname);
246         return APR_EBADPATH;
247     }
248     if ((rc = apr_file_open(&stderr_file, filename,
249                             APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
250                             APR_OS_DEFAULT, p)) != APR_SUCCESS) {
251         ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
252                      "%s: could not open error log file %s.",
253                      ap_server_argv0, fname);
254         return rc;
255     }
256     if (!stderr_pool) {
257         /* This is safe provided we revert it when we are finished.
258          * We don't manager the callers pool!
259          */
260         stderr_pool = p;
261     }
262     if ((rc = apr_file_open_stderr(&stderr_log, stderr_pool)) 
263             == APR_SUCCESS) {
264         apr_file_flush(stderr_log);
265         if ((rc = apr_file_dup2(stderr_log, stderr_file, stderr_pool)) 
266                 == APR_SUCCESS) {
267             apr_file_close(stderr_file);
268             /*
269              * You might ponder why stderr_pool should survive?
270              * The trouble is, stderr_pool may have s_main->error_log,
271              * so we aren't in a position to destory stderr_pool until
272              * the next recycle.  There's also an apparent bug which 
273              * is not; if some folk decided to call this function before 
274              * the core open error logs hook, this pool won't survive.
275              * Neither does the stderr logger, so this isn't a problem.
276              */
277         }
278     }
279     /* Revert, see above */
280     if (stderr_pool == p)
281         stderr_pool = NULL;
282
283     if (rc != APR_SUCCESS) {
284         ap_log_error(APLOG_MARK, APLOG_CRIT, rc, NULL,
285                      "unable to replace stderr with error log file");
286     }
287     return rc;
288 }
289
290 static void log_child_errfn(apr_pool_t *pool, apr_status_t err,
291                             const char *description)
292 {
293     ap_log_error(APLOG_MARK, APLOG_ERR, err, NULL,
294                  "%s", description);
295 }
296
297 /* Create a child process running PROGNAME with a pipe connected to
298  * the childs stdin.  The write-end of the pipe will be placed in
299  * *FPIN on successful return.  If dummy_stderr is non-zero, the
300  * stderr for the child will be the same as the stdout of the parent.
301  * Otherwise the child will inherit the stderr from the parent. */
302 static int log_child(apr_pool_t *p, const char *progname,
303                      apr_file_t **fpin, apr_cmdtype_e cmdtype,
304                      int dummy_stderr)
305 {
306     /* Child process code for 'ErrorLog "|..."';
307      * may want a common framework for this, since I expect it will
308      * be common for other foo-loggers to want this sort of thing...
309      */
310     apr_status_t rc;
311     apr_procattr_t *procattr;
312     apr_proc_t *procnew;
313     apr_file_t *errfile;
314
315     if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS)
316         && ((rc = apr_procattr_dir_set(procattr,
317                                        ap_server_root)) == APR_SUCCESS)
318         && ((rc = apr_procattr_cmdtype_set(procattr, cmdtype)) == APR_SUCCESS)
319         && ((rc = apr_procattr_io_set(procattr,
320                                       APR_FULL_BLOCK,
321                                       APR_NO_PIPE,
322                                       APR_NO_PIPE)) == APR_SUCCESS)
323         && ((rc = apr_procattr_error_check_set(procattr, 1)) == APR_SUCCESS)
324         && ((rc = apr_procattr_child_errfn_set(procattr, log_child_errfn)) 
325                 == APR_SUCCESS)) {
326         char **args;
327         const char *pname;
328
329         apr_tokenize_to_argv(progname, &args, p);
330         pname = apr_pstrdup(p, args[0]);
331         procnew = (apr_proc_t *)apr_pcalloc(p, sizeof(*procnew));
332
333         if (dummy_stderr) {
334             if ((rc = apr_file_open_stdout(&errfile, p)) == APR_SUCCESS)
335                 rc = apr_procattr_child_err_set(procattr, errfile, NULL);
336         }
337
338         rc = apr_proc_create(procnew, pname, (const char * const *)args,
339                              NULL, procattr, p);
340
341         if (rc == APR_SUCCESS) {
342             apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
343             (*fpin) = procnew->in;
344             /* read handle to pipe not kept open, so no need to call
345              * close_handle_in_child()
346              */
347         }
348     }
349
350     return rc;
351 }
352
353 /* Open the error log for the given server_rec.  If IS_MAIN is
354  * non-zero, s is the main server. */
355 static int open_error_log(server_rec *s, int is_main, apr_pool_t *p)
356 {
357     const char *fname;
358     int rc;
359
360     if (*s->error_fname == '|') {
361         apr_file_t *dummy = NULL;
362         apr_cmdtype_e cmdtype = APR_PROGRAM_ENV;
363         fname = s->error_fname + 1;
364
365         /* In 2.4 favor PROGRAM_ENV, accept "||prog" syntax for compatibility
366          * and "|$cmd" to override the default.
367          * Any 2.2 backport would continue to favor SHELLCMD_ENV so there 
368          * accept "||prog" to override, and "|$cmd" to ease conversion.
369          */
370         if (*fname == '|')
371             ++fname;
372         if (*fname == '$') {
373             cmdtype = APR_SHELLCMD_ENV;
374             ++fname;
375         }
376
377         /* Spawn a new child logger.  If this is the main server_rec,
378          * the new child must use a dummy stderr since the current
379          * stderr might be a pipe to the old logger.  Otherwise, the
380          * child inherits the parents stderr. */
381         rc = log_child(p, fname, &dummy, cmdtype, is_main);
382         if (rc != APR_SUCCESS) {
383             ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
384                          "Couldn't start ErrorLog process '%s'.",
385                          s->error_fname + 1);
386             return DONE;
387         }
388
389         s->error_log = dummy;
390     }
391
392 #ifdef HAVE_SYSLOG
393     else if (!strncasecmp(s->error_fname, "syslog", 6)) {
394         if ((fname = strchr(s->error_fname, ':'))) {
395             const TRANS *fac;
396
397             fname++;
398             for (fac = facilities; fac->t_name; fac++) {
399                 if (!strcasecmp(fname, fac->t_name)) {
400                     openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID,
401                             fac->t_val);
402                     s->error_log = NULL;
403                     return OK;
404                 }
405             }
406         }
407         else {
408             openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID, LOG_LOCAL7);
409         }
410
411         s->error_log = NULL;
412     }
413 #endif
414     else {
415         fname = ap_server_root_relative(p, s->error_fname);
416         if (!fname) {
417             ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EBADPATH, NULL,
418                          "%s: Invalid error log path %s.",
419                          ap_server_argv0, s->error_fname);
420             return DONE;
421         }
422         if ((rc = apr_file_open(&s->error_log, fname,
423                                APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
424                                APR_OS_DEFAULT, p)) != APR_SUCCESS) {
425             ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
426                          "%s: could not open error log file %s.",
427                          ap_server_argv0, fname);
428             return DONE;
429         }
430     }
431
432     return OK;
433 }
434
435 int ap_open_logs(apr_pool_t *pconf, apr_pool_t *p /* plog */,
436                  apr_pool_t *ptemp, server_rec *s_main)
437 {
438     apr_pool_t *stderr_p;
439     server_rec *virt, *q;
440     int replace_stderr;
441
442
443     /* Register to throw away the read_handles list when we
444      * cleanup plog.  Upon fork() for the apache children,
445      * this read_handles list is closed so only the parent
446      * can relaunch a lost log child.  These read handles 
447      * are always closed on exec.
448      * We won't care what happens to our stderr log child 
449      * between log phases, so we don't mind losing stderr's 
450      * read_handle a little bit early.
451      */
452     apr_pool_cleanup_register(p, &read_handles, ap_pool_cleanup_set_null,
453                               apr_pool_cleanup_null);
454
455     /* HERE we need a stdout log that outlives plog.
456      * We *presume* the parent of plog is a process 
457      * or global pool which spans server restarts.
458      * Create our stderr_pool as a child of the plog's
459      * parent pool.
460      */
461     apr_pool_create(&stderr_p, apr_pool_parent_get(p));
462     apr_pool_tag(stderr_p, "stderr_pool");
463
464     if (open_error_log(s_main, 1, stderr_p) != OK) {
465         return DONE;
466     }
467
468     replace_stderr = 1;
469     if (s_main->error_log) {
470         apr_status_t rv;
471
472         /* Replace existing stderr with new log. */
473         apr_file_flush(s_main->error_log);
474         rv = apr_file_dup2(stderr_log, s_main->error_log, stderr_p);
475         if (rv != APR_SUCCESS) {
476             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s_main,
477                          "unable to replace stderr with error_log");
478         }
479         else {
480             /* We are done with stderr_pool, close it, killing
481              * the previous generation's stderr logger
482              */
483             if (stderr_pool)
484                 apr_pool_destroy(stderr_pool);
485             stderr_pool = stderr_p;
486             replace_stderr = 0;
487             /*
488              * Now that we have dup'ed s_main->error_log to stderr_log
489              * close it and set s_main->error_log to stderr_log. This avoids
490              * this fd being inherited by the next piped logger who would
491              * keep open the writing end of the pipe that this one uses
492              * as stdin. This in turn would prevent the piped logger from
493              * exiting.
494              */
495              apr_file_close(s_main->error_log);
496              s_main->error_log = stderr_log;
497         }
498     }
499     /* note that stderr may still need to be replaced with something
500      * because it points to the old error log, or back to the tty
501      * of the submitter.
502      * XXX: This is BS - /dev/null is non-portable
503      *      errno-as-apr_status_t is also non-portable
504      */
505     if (replace_stderr && freopen("/dev/null", "w", stderr) == NULL) {
506         ap_log_error(APLOG_MARK, APLOG_CRIT, errno, s_main,
507                      "unable to replace stderr with /dev/null");
508     }
509
510     for (virt = s_main->next; virt; virt = virt->next) {
511         if (virt->error_fname) {
512             for (q=s_main; q != virt; q = q->next) {
513                 if (q->error_fname != NULL
514                     && strcmp(q->error_fname, virt->error_fname) == 0) {
515                     break;
516                 }
517             }
518
519             if (q == virt) {
520                 if (open_error_log(virt, 0, p) != OK) {
521                     return DONE;
522                 }
523             }
524             else {
525                 virt->error_log = q->error_log;
526             }
527         }
528         else {
529             virt->error_log = s_main->error_log;
530         }
531     }
532     return OK;
533 }
534
535 AP_DECLARE(void) ap_error_log2stderr(server_rec *s) {
536     apr_file_t *errfile = NULL;
537
538     apr_file_open_stderr(&errfile, s->process->pool);
539     if (s->error_log != NULL) {
540         apr_file_dup2(s->error_log, errfile, s->process->pool);
541     }
542 }
543
544 static int cpystrn(char *buf, const char *arg, int buflen)
545 {
546     char *end;
547     if (!arg)
548         return 0;
549     end = apr_cpystrn(buf, arg, buflen);
550     return end - buf;
551 }
552
553
554 static int log_remote_address(const ap_errorlog_info *info, const char *arg,
555                               char *buf, int buflen)
556 {
557     if (info->c)
558         return apr_snprintf(buf, buflen, "%s:%d", info->c->remote_ip,
559                             info->c->remote_addr->port);
560     else
561         return 0;
562 }
563
564 static int log_local_address(const ap_errorlog_info *info, const char *arg,
565                              char *buf, int buflen)
566 {
567     if (info->c)
568         return apr_snprintf(buf, buflen, "%s:%d", info->c->local_ip,
569                             info->c->local_addr->port);
570     else
571         return 0;
572 }
573
574 static int log_pid(const ap_errorlog_info *info, const char *arg,
575                    char *buf, int buflen)
576 {
577     pid_t pid = getpid();
578     return apr_snprintf(buf, buflen, "%" APR_PID_T_FMT, pid);
579 }
580
581 static int log_tid(const ap_errorlog_info *info, const char *arg,
582                    char *buf, int buflen)
583 {
584 #if APR_HAS_THREADS
585     int result;
586
587     if (ap_mpm_query(AP_MPMQ_IS_THREADED, &result) == APR_SUCCESS
588         && result != AP_MPMQ_NOT_SUPPORTED)
589     {
590         apr_os_thread_t tid = apr_os_thread_current();
591         return apr_snprintf(buf, buflen, "%pT", &tid);
592     }
593 #endif
594     return 0;
595 }
596
597 static int log_ctime(const ap_errorlog_info *info, const char *arg,
598                      char *buf, int buflen)
599 {
600     int time_len = buflen;
601     int option = AP_CTIME_OPTION_NONE;
602
603     while(arg && *arg) {
604         switch (*arg) {
605             case 'u':   option |= AP_CTIME_OPTION_USEC;
606                         break;
607             case 'c':   option |= AP_CTIME_OPTION_COMPACT;
608                         break;
609         }
610         arg++;
611     }
612
613     ap_recent_ctime_ex(buf, apr_time_now(), option, &time_len);
614
615     /* ap_recent_ctime_ex includes the trailing \0 in time_len */
616     return time_len - 1;
617 }
618
619 static int log_loglevel(const ap_errorlog_info *info, const char *arg,
620                         char *buf, int buflen)
621 {
622     if (info->level < 0)
623         return 0;
624     else
625         return cpystrn(buf, priorities[info->level].t_name, buflen);
626 }
627
628 static int log_log_id(const ap_errorlog_info *info, const char *arg,
629                       char *buf, int buflen)
630 {
631     /*
632      * C: log conn log_id if available,
633      * c: log conn log id if available and not a once-per-request log line
634      * else: log request log id if available
635      */
636     if (arg && !strcasecmp(arg, "c")) {
637         if (info->c && (*arg != 'C' || !info->r)) {
638             return cpystrn(buf, info->c->log_id, buflen);
639         }
640     }
641     else if (info->r) {
642         return cpystrn(buf, info->r->log_id, buflen);
643     }
644     return 0;
645 }
646
647 static int log_keepalives(const ap_errorlog_info *info, const char *arg,
648                           char *buf, int buflen)
649 {
650     if (!info->c)
651         return 0;
652
653     return apr_snprintf(buf, buflen, "%d", info->c->keepalives);
654 }
655
656 static int log_module_name(const ap_errorlog_info *info, const char *arg,
657                            char *buf, int buflen)
658 {
659     return cpystrn(buf, ap_find_module_short_name(info->module_index), buflen);
660 }
661
662 static int log_file_line(const ap_errorlog_info *info, const char *arg,
663                          char *buf, int buflen)
664 {
665     if (info->file == NULL) {
666         return 0;
667     }
668     else {
669         const char *file = info->file;
670 #if defined(_OSD_POSIX) || defined(WIN32) || defined(__MVS__)
671         char tmp[256];
672         char *e = strrchr(file, '/');
673 #ifdef WIN32
674         if (!e) {
675             e = strrchr(file, '\\');
676         }
677 #endif
678
679         /* In OSD/POSIX, the compiler returns for __FILE__
680          * a string like: __FILE__="*POSIX(/usr/include/stdio.h)"
681          * (it even returns an absolute path for sources in
682          * the current directory). Here we try to strip this
683          * down to the basename.
684          */
685         if (e != NULL && e[1] != '\0') {
686             apr_snprintf(tmp, sizeof(tmp), "%s", &e[1]);
687             e = &tmp[strlen(tmp)-1];
688             if (*e == ')') {
689                 *e = '\0';
690             }
691             file = tmp;
692         }
693 #else /* _OSD_POSIX || WIN32 */
694         const char *p;
695         /* On Unix, __FILE__ may be an absolute path in a
696          * VPATH build. */
697         if (file[0] == '/' && (p = ap_strrchr_c(file, '/')) != NULL) {
698             file = p + 1;
699         }
700 #endif /*_OSD_POSIX || WIN32 */
701         return apr_snprintf(buf, buflen, "%s(%d)", file, info->line);
702     }
703 }
704
705 static int log_apr_status(const ap_errorlog_info *info, const char *arg,
706                           char *buf, int buflen)
707 {
708     apr_status_t status = info->status;
709     int len;
710     if (!status)
711         return 0;
712
713     if (status < APR_OS_START_EAIERR) {
714         len = apr_snprintf(buf, buflen, "(%d)", status);
715     }
716     else if (status < APR_OS_START_SYSERR) {
717         len = apr_snprintf(buf, buflen, "(EAI %d)",
718                            status - APR_OS_START_EAIERR);
719     }
720     else if (status < 100000 + APR_OS_START_SYSERR) {
721         len = apr_snprintf(buf, buflen, "(OS %d)",
722                            status - APR_OS_START_SYSERR);
723     }
724     else {
725         len = apr_snprintf(buf, buflen, "(os 0x%08x)",
726                            status - APR_OS_START_SYSERR);
727     }
728     apr_strerror(status, buf + len, buflen - len);
729     len += strlen(buf + len);
730     return len;
731 }
732
733 static int log_server_name(const ap_errorlog_info *info, const char *arg,
734                            char *buf, int buflen)
735 {
736     if (info->r)
737         return cpystrn(buf, ap_get_server_name((request_rec *)info->r), buflen);
738
739     return 0;
740 }
741
742 static int log_virtual_host(const ap_errorlog_info *info, const char *arg,
743                             char *buf, int buflen)
744 {
745     if (info->s)
746         return cpystrn(buf, info->s->server_hostname, buflen);
747
748     return 0;
749 }
750
751
752 static int log_table_entry(const apr_table_t *table, const char *name,
753                            char *buf, int buflen)
754 {
755 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
756     const char *value;
757     char scratch[MAX_STRING_LEN];
758
759     if ((value = apr_table_get(table, name)) != NULL) {
760         ap_escape_errorlog_item(scratch, value, MAX_STRING_LEN);
761         return cpystrn(buf, scratch, buflen);
762     }
763
764     return 0;
765 #else
766     return cpystrn(buf, apr_table_get(table, name), buflen);
767 #endif
768 }
769
770 static int log_header(const ap_errorlog_info *info, const char *arg,
771                       char *buf, int buflen)
772 {
773     if (info->r)
774         return log_table_entry(info->r->headers_in, arg, buf, buflen);
775
776     return 0;
777 }
778
779 static int log_note(const ap_errorlog_info *info, const char *arg,
780                       char *buf, int buflen)
781 {
782     /* XXX: maybe escaping the entry is not necessary for notes? */
783     if (info->r)
784         return log_table_entry(info->r->notes, arg, buf, buflen);
785
786     return 0;
787 }
788
789 static int log_env_var(const ap_errorlog_info *info, const char *arg,
790                       char *buf, int buflen)
791 {
792     if (info->r)
793         return log_table_entry(info->r->subprocess_env, arg, buf, buflen);
794
795     return 0;
796 }
797
798 static int core_generate_log_id(const conn_rec *c, const request_rec *r,
799                                  const char **idstring)
800 {
801     apr_uint64_t id, tmp;
802     pid_t pid;
803     int len;
804     char *encoded;
805
806     if (r && r->request_time) {
807         id = (apr_uint64_t)r->request_time;
808     }
809     else {
810         id = (apr_uint64_t)apr_time_now();
811     }
812
813     pid = getpid();
814     if (sizeof(pid_t) > 2) {
815         tmp = pid;
816         tmp = tmp << 40;
817         id ^= tmp;
818         pid = pid >> 24;
819         tmp = pid;
820         tmp = tmp << 56;
821         id ^= tmp;
822     }
823     else {
824         tmp = pid;
825         tmp = tmp << 40;
826         id ^= tmp;
827     }
828 #if APR_HAS_THREADS
829     {
830         apr_uintptr_t tmp2 = (apr_uintptr_t)c->current_thread;
831         tmp = tmp2;
832         tmp = tmp << 32;
833         id ^= tmp;
834     }
835 #endif
836
837     len = apr_base64_encode_len(sizeof(id)); /* includes trailing \0 */
838     encoded = apr_palloc(r ? r->pool : c->pool, len);
839     apr_base64_encode(encoded, (char *)&id, sizeof(id));
840
841     /* Skip the last char, it is always '=' */
842     encoded[len - 2] = '\0';
843
844     *idstring = encoded;
845
846     return OK;
847 }
848
849 static void add_log_id(const conn_rec *c, const request_rec *r)
850 {
851     const char **id;
852     /* need to cast const away */
853     if (r) {
854         id = &((request_rec *)r)->log_id;
855     }
856     else {
857         id = &((conn_rec *)c)->log_id;
858     }
859
860     ap_run_generate_log_id(c, r, id);
861 }
862
863 AP_DECLARE(void) ap_register_log_hooks(apr_pool_t *p)
864 {
865     ap_hook_generate_log_id(core_generate_log_id, NULL, NULL,
866                             APR_HOOK_REALLY_LAST);
867
868     ap_register_errorlog_handler(p, "a", log_remote_address, 0);
869     ap_register_errorlog_handler(p, "A", log_local_address, 0);
870     ap_register_errorlog_handler(p, "e", log_env_var, 0);
871     ap_register_errorlog_handler(p, "E", log_apr_status, 0);
872     ap_register_errorlog_handler(p, "F", log_file_line, 0);
873     ap_register_errorlog_handler(p, "i", log_header, 0);
874     ap_register_errorlog_handler(p, "k", log_keepalives, 0);
875     ap_register_errorlog_handler(p, "l", log_loglevel, 0);
876     ap_register_errorlog_handler(p, "L", log_log_id, 0);
877     ap_register_errorlog_handler(p, "m", log_module_name, 0);
878     ap_register_errorlog_handler(p, "n", log_note, 0);
879     ap_register_errorlog_handler(p, "P", log_pid, 0);
880     ap_register_errorlog_handler(p, "t", log_ctime, 0);
881     ap_register_errorlog_handler(p, "T", log_tid, 0);
882     ap_register_errorlog_handler(p, "v", log_virtual_host, 0);
883     ap_register_errorlog_handler(p, "V", log_server_name, 0);
884 }
885
886 /*
887  * This is used if no error log format is defined and during startup.
888  * It automatically omits the timestamp if logging to syslog.
889  */
890 static int do_errorlog_default(const ap_errorlog_info *info, char *buf,
891                                int buflen, int *errstr_start, int *errstr_end,
892                                const char *errstr_fmt, va_list args)
893 {
894     int len = 0;
895     int field_start = 0;
896     int item_len;
897 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
898     char scratch[MAX_STRING_LEN];
899 #endif
900
901     if (!info->using_syslog && !info->startup) {
902         buf[len++] = '[';
903         len += log_ctime(info, "u", buf + len, buflen - len);
904         buf[len++] = ']';
905         buf[len++] = ' ';
906     }
907
908     if (!info->startup) {
909         buf[len++] = '[';
910         len += log_module_name(info, NULL, buf + len, buflen - len);
911         buf[len++] = ':';
912         len += log_loglevel(info, NULL, buf + len, buflen - len);
913         len += cpystrn(buf + len, "] [pid ", buflen - len);
914
915         len += log_pid(info, NULL, buf + len, buflen - len);
916 #if APR_HAS_THREADS
917         field_start = len;
918         len += cpystrn(buf + len, ":tid ", buflen - len);
919         item_len = log_tid(info, NULL, buf + len, buflen - len);
920         if (!item_len)
921             len = field_start;
922         else
923             len += item_len;
924 #endif
925         buf[len++] = ']';
926         buf[len++] = ' ';
927     }
928
929     if (info->level >= APLOG_DEBUG) {
930         item_len = log_file_line(info, NULL, buf + len, buflen - len);
931         if (item_len) {
932             len += item_len;
933             len += cpystrn(buf + len, ": ", buflen - len);
934         }
935     }
936
937     if (info->status) {
938         item_len = log_apr_status(info, NULL, buf + len, buflen - len);
939         if (item_len) {
940             len += item_len;
941             len += cpystrn(buf + len, ": ", buflen - len);
942         }
943     }
944
945     if (info->c) {
946         /*
947          * remote_ip can be client or backend server. If we have a scoreboard
948          * handle, it is likely a client.
949          */
950         len += apr_snprintf(buf + len, buflen - len,
951                             info->c->sbh ? "[client %s:%d] " : "[remote %s:%d] ",
952                             info->c->remote_ip, info->c->remote_addr->port);
953     }
954
955     /* the actual error message */
956     *errstr_start = len;
957 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
958     if (apr_vsnprintf(scratch, MAX_STRING_LEN, errstr_fmt, args)) {
959         len += ap_escape_errorlog_item(buf + len, scratch,
960                                        buflen - len);
961
962     }
963 #else
964     len += apr_vsnprintf(buf + len, buflen - len, errstr_fmt, args);
965 #endif
966     *errstr_end = len;
967
968     field_start = len;
969     len += cpystrn(buf + len, ", referer: ", buflen - len);
970     item_len = log_header(info, "Referer", buf + len, buflen - len);
971     if (item_len)
972         len += item_len;
973     else
974         len = field_start;
975
976     return len;
977 }
978
979 static int do_errorlog_format(apr_array_header_t *fmt, ap_errorlog_info *info,
980                               char *buf, int buflen, int *errstr_start,
981                               int *errstr_end, const char *err_fmt, va_list args)
982 {
983 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
984     char scratch[MAX_STRING_LEN];
985 #endif
986     int i;
987     int len = 0;
988     int field_start = 0;
989     int skipping = 0;
990     ap_errorlog_format_item *items = (ap_errorlog_format_item *)fmt->elts;
991
992     for (i = 0; i < fmt->nelts; ++i) {
993         ap_errorlog_format_item *item = &items[i];
994         if (item->flags & AP_ERRORLOG_FLAG_FIELD_SEP) {
995             if (skipping) {
996                 skipping = 0;
997             }
998             else {
999                 field_start = len;
1000             }
1001         }
1002
1003         if (item->flags & AP_ERRORLOG_FLAG_MESSAGE) {
1004             /* the actual error message */
1005             *errstr_start = len;
1006 #ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
1007             if (apr_vsnprintf(scratch, MAX_STRING_LEN, err_fmt, args)) {
1008                 len += ap_escape_errorlog_item(buf + len, scratch,
1009                                                buflen - len);
1010
1011             }
1012 #else
1013             len += apr_vsnprintf(buf + len, buflen - len, err_fmt, args);
1014 #endif
1015             *errstr_end = len;
1016         }
1017         else if (skipping) {
1018             continue;
1019         }
1020         else if ((int)item->min_loglevel > info->level) {
1021             len = field_start;
1022             skipping = 1;
1023         }
1024         else {
1025             int item_len = (*item->func)(info, item->arg, buf + len,
1026                                          buflen - len);
1027             if (!item_len) {
1028                 if (item->flags & AP_ERRORLOG_FLAG_REQUIRED) {
1029                     /* required item is empty. skip whole line */
1030                     buf[0] = '\0';
1031                     return 0;
1032                 }
1033                 else if (item->flags & AP_ERRORLOG_FLAG_NULL_AS_HYPHEN) {
1034                     buf[len++] = '-';
1035                 }
1036                 else {
1037                     len = field_start;
1038                     skipping = 1;
1039                 }
1040             }
1041             else {
1042                 len += item_len;
1043             }
1044         }
1045     }
1046     return len;
1047 }
1048
1049 static void write_logline(char *errstr, apr_size_t len, apr_file_t *logf,
1050                           int level)
1051 {
1052     /* NULL if we are logging to syslog */
1053     if (logf) {
1054         /* Truncate for the terminator (as apr_snprintf does) */
1055         if (len > MAX_STRING_LEN - sizeof(APR_EOL_STR)) {
1056             len = MAX_STRING_LEN - sizeof(APR_EOL_STR);
1057         }
1058         strcpy(errstr + len, APR_EOL_STR);
1059         apr_file_puts(errstr, logf);
1060         apr_file_flush(logf);
1061     }
1062 #ifdef HAVE_SYSLOG
1063     else {
1064         syslog(level < LOG_PRIMASK ? level : APLOG_DEBUG, "%s", errstr);
1065     }
1066 #endif
1067 }
1068
1069 static void log_error_core(const char *file, int line, int module_index,
1070                            int level,
1071                            apr_status_t status, const server_rec *s,
1072                            const conn_rec *c,
1073                            const request_rec *r, apr_pool_t *pool,
1074                            const char *fmt, va_list args)
1075 {
1076     char errstr[MAX_STRING_LEN];
1077     apr_file_t *logf = NULL;
1078     int level_and_mask = level & APLOG_LEVELMASK;
1079     const request_rec *rmain = NULL;
1080     core_server_config *sconf = NULL;
1081     ap_errorlog_info info;
1082
1083     /* do we need to log once-per-req or once-per-conn info? */
1084     int log_conn_info = 0, log_req_info = 0;
1085     apr_array_header_t **lines = NULL;
1086     int done = 0;
1087     int line_number = 0;
1088
1089     if (r && r->connection) {
1090         c = r->connection;
1091     }
1092
1093     if (s == NULL) {
1094         /*
1095          * If we are doing stderr logging (startup), don't log messages that are
1096          * above the default server log level unless it is a startup/shutdown
1097          * notice
1098          */
1099 #ifndef DEBUG
1100         if ((level_and_mask != APLOG_NOTICE)
1101             && (level_and_mask > ap_default_loglevel)) {
1102             return;
1103         }
1104 #endif
1105
1106         logf = stderr_log;
1107     }
1108     else {
1109         int configured_level = r ? ap_get_request_module_loglevel(r, module_index)        :
1110                                c ? ap_get_conn_server_module_loglevel(c, s, module_index) :
1111                                    ap_get_server_module_loglevel(s, module_index);
1112         if (s->error_log) {
1113             /*
1114              * If we are doing normal logging, don't log messages that are
1115              * above the module's log level unless it is a startup/shutdown notice
1116              */
1117             if ((level_and_mask != APLOG_NOTICE)
1118                 && (level_and_mask > configured_level)) {
1119                 return;
1120             }
1121
1122             logf = s->error_log;
1123         }
1124         else {
1125             /*
1126              * If we are doing syslog logging, don't log messages that are
1127              * above the module's log level (including a startup/shutdown notice)
1128              */
1129             if (level_and_mask > configured_level) {
1130                 return;
1131             }
1132         }
1133
1134         /* the faked server_rec from mod_cgid does not have s->module_config */
1135         if (s->module_config) {
1136             sconf = ap_get_module_config(s->module_config, &core_module);
1137             if (c && !c->log_id) {
1138                 add_log_id(c, NULL);
1139                 if (sconf->error_log_conn && sconf->error_log_conn->nelts > 0)
1140                     log_conn_info = 1;
1141             }
1142             if (r) {
1143                 if (r->main)
1144                     rmain = r->main;
1145                 else
1146                     rmain = r;
1147
1148                 if (!rmain->log_id) {
1149                     /* XXX: do we need separate log ids for subrequests? */
1150                     if (sconf->error_log_req && sconf->error_log_req->nelts > 0)
1151                         log_req_info = 1;
1152                     /*
1153                      * XXX: potential optimization: only create log id if %L is
1154                      * XXX: actually used
1155                      */
1156                     add_log_id(c, rmain);
1157                 }
1158             }
1159         }
1160     }
1161
1162     info.s             = s;
1163     info.c             = c;
1164     info.file          = NULL;
1165     info.line          = 0;
1166     info.status        = 0;
1167     info.using_syslog  = (logf == NULL);
1168     info.startup       = ((level & APLOG_STARTUP) == APLOG_STARTUP);
1169     info.format        = fmt;
1170
1171     while (!done) {
1172         apr_array_header_t *log_format;
1173         int len = 0, errstr_start = 0, errstr_end = 0;
1174         /* XXX: potential optimization: format common prefixes only once */
1175         if (log_conn_info) {
1176             /* once-per-connection info */
1177             if (line_number == 0) {
1178                 lines = (apr_array_header_t **)sconf->error_log_conn->elts;
1179                 info.r = NULL;
1180                 info.rmain = NULL;
1181                 info.level = -1;
1182                 info.module_index = APLOG_NO_MODULE;
1183             }
1184
1185             log_format = lines[line_number++];
1186
1187             if (line_number == sconf->error_log_conn->nelts) {
1188                 /* this is the last line of once-per-connection info */
1189                 line_number = 0;
1190                 log_conn_info = 0;
1191             }
1192         }
1193         else if (log_req_info) {
1194             /* once-per-request info */
1195             if (line_number == 0) {
1196                 lines = (apr_array_header_t **)sconf->error_log_req->elts;
1197                 info.r = rmain;
1198                 info.rmain = rmain;
1199                 info.level = -1;
1200                 info.module_index = APLOG_NO_MODULE;
1201             }
1202
1203             log_format = lines[line_number++];
1204
1205             if (line_number == sconf->error_log_req->nelts) {
1206                 /* this is the last line of once-per-request info */
1207                 line_number = 0;
1208                 log_req_info = 0;
1209             }
1210         }
1211         else {
1212             /* the actual error message */
1213             info.r            = r;
1214             info.rmain        = rmain;
1215             info.level        = level_and_mask;
1216             info.module_index = module_index;
1217             info.file         = file;
1218             info.line         = line;
1219             info.status       = status;
1220             log_format = sconf ? sconf->error_log_format : NULL;
1221             done = 1;
1222         }
1223
1224         /*
1225          * prepare and log one line
1226          */
1227
1228         if (log_format) {
1229             len += do_errorlog_format(log_format, &info, errstr + len,
1230                                       MAX_STRING_LEN - len,
1231                                       &errstr_start, &errstr_end, fmt, args);
1232         }
1233         else {
1234             len += do_errorlog_default(&info, errstr + len, MAX_STRING_LEN - len,
1235                                        &errstr_start, &errstr_end, fmt, args);
1236         }
1237
1238         if (!*errstr)
1239         {
1240             /*
1241              * Don't log empty lines. This can happen with once-per-conn/req
1242              * info if an item with AP_ERRORLOG_FLAG_REQUIRED is NULL.
1243              */
1244             continue;
1245         }
1246         write_logline(errstr, len, logf, level_and_mask);
1247
1248         if (!log_format) {
1249             /* only pass the real error string to the hook */
1250             errstr[errstr_end] = '\0';
1251             ap_run_error_log(file, line, module_index, level, status, s, r, pool,
1252                              errstr + errstr_start);
1253         }
1254
1255         *errstr = '\0';
1256     }
1257 }
1258
1259 AP_DECLARE(void) ap_log_error_(const char *file, int line, int module_index,
1260                                int level, apr_status_t status,
1261                                const server_rec *s, const char *fmt, ...)
1262 {
1263     va_list args;
1264
1265     va_start(args, fmt);
1266     log_error_core(file, line, module_index, level, status, s, NULL, NULL,
1267                    NULL, fmt, args);
1268     va_end(args);
1269 }
1270
1271 AP_DECLARE(void) ap_log_perror_(const char *file, int line, int module_index,
1272                                 int level, apr_status_t status, apr_pool_t *p,
1273                                 const char *fmt, ...)
1274 {
1275     va_list args;
1276
1277     va_start(args, fmt);
1278     log_error_core(file, line, module_index, level, status, NULL, NULL, NULL,
1279                    p, fmt, args);
1280     va_end(args);
1281 }
1282
1283 AP_DECLARE(void) ap_log_rerror_(const char *file, int line, int module_index,
1284                                 int level, apr_status_t status,
1285                                 const request_rec *r, const char *fmt, ...)
1286 {
1287     va_list args;
1288
1289     va_start(args, fmt);
1290     log_error_core(file, line, module_index, level, status, r->server, NULL, r,
1291                    NULL, fmt, args);
1292
1293     /*
1294      * IF APLOG_TOCLIENT is set,
1295      * AND the error level is 'warning' or more severe,
1296      * AND there isn't already error text associated with this request,
1297      * THEN make the message text available to ErrorDocument and
1298      * other error processors.
1299      */
1300     va_end(args);
1301     va_start(args,fmt);
1302     if ((level & APLOG_TOCLIENT)
1303         && ((level & APLOG_LEVELMASK) <= APLOG_WARNING)
1304         && (apr_table_get(r->notes, "error-notes") == NULL)) {
1305         apr_table_setn(r->notes, "error-notes",
1306                        ap_escape_html(r->pool, apr_pvsprintf(r->pool, fmt,
1307                                                              args)));
1308     }
1309     va_end(args);
1310 }
1311
1312 AP_DECLARE(void) ap_log_cserror_(const char *file, int line, int module_index,
1313                                  int level, apr_status_t status,
1314                                  const conn_rec *c, const server_rec *s,
1315                                  const char *fmt, ...)
1316 {
1317     va_list args;
1318
1319     va_start(args, fmt);
1320     log_error_core(file, line, module_index, level, status, s, c,
1321                    NULL, NULL, fmt, args);
1322     va_end(args);
1323 }
1324
1325 AP_DECLARE(void) ap_log_cerror_(const char *file, int line, int module_index,
1326                                 int level, apr_status_t status,
1327                                 const conn_rec *c, const char *fmt, ...)
1328 {
1329     va_list args;
1330
1331     va_start(args, fmt);
1332     log_error_core(file, line, module_index, level, status, c->base_server, c,
1333                    NULL, NULL, fmt, args);
1334     va_end(args);
1335 }
1336
1337 AP_DECLARE(void) ap_log_command_line(apr_pool_t *plog, server_rec *s)
1338 {
1339     int i;
1340     process_rec *process = s->process;
1341     char *result;
1342     int len_needed = 0;
1343     
1344     /* Piece together the command line from the pieces
1345      * in process->argv, with spaces in between.
1346      */
1347     for (i = 0; i < process->argc; i++) {
1348         len_needed += strlen(process->argv[i]) + 1;
1349     }
1350
1351     result = (char *) apr_palloc(plog, len_needed);
1352     *result = '\0';
1353
1354     for (i = 0; i < process->argc; i++) {
1355         strcat(result, process->argv[i]);
1356         if ((i+1)< process->argc) {
1357             strcat(result, " ");
1358         }
1359     }
1360     ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s,
1361                  "Command line: '%s'", result);
1362 }
1363
1364 AP_DECLARE(void) ap_remove_pid(apr_pool_t *p, const char *rel_fname)
1365 {
1366     apr_status_t rv;
1367     const char *fname = ap_server_root_relative(p, rel_fname);
1368
1369     if (fname != NULL) {
1370         rv = apr_file_remove(fname, p);
1371         if (rv != APR_SUCCESS) {
1372             ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
1373                          "failed to remove PID file %s", fname);
1374         }
1375         else {
1376             ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
1377                          "removed PID file %s (pid=%" APR_PID_T_FMT ")",
1378                          fname, getpid());
1379         }
1380     }
1381 }
1382
1383 AP_DECLARE(void) ap_log_pid(apr_pool_t *p, const char *filename)
1384 {
1385     apr_file_t *pid_file = NULL;
1386     apr_finfo_t finfo;
1387     static pid_t saved_pid = -1;
1388     pid_t mypid;
1389     apr_status_t rv;
1390     const char *fname;
1391
1392     if (!filename) {
1393         return;
1394     }
1395
1396     fname = ap_server_root_relative(p, filename);
1397     if (!fname) {
1398         ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, APR_EBADPATH,
1399                      NULL, "Invalid PID file path %s, ignoring.", filename);
1400         return;
1401     }
1402
1403     mypid = getpid();
1404     if (mypid != saved_pid
1405         && apr_stat(&finfo, fname, APR_FINFO_MTIME, p) == APR_SUCCESS) {
1406         /* AP_SIG_GRACEFUL and HUP call this on each restart.
1407          * Only warn on first time through for this pid.
1408          *
1409          * XXX: Could just write first time through too, although
1410          *      that may screw up scripts written to do something
1411          *      based on the last modification time of the pid file.
1412          */
1413         ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, p,
1414                       "pid file %s overwritten -- Unclean "
1415                       "shutdown of previous Apache run?",
1416                       fname);
1417     }
1418
1419     if ((rv = apr_file_open(&pid_file, fname,
1420                             APR_WRITE | APR_CREATE | APR_TRUNCATE,
1421                             APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD, p))
1422         != APR_SUCCESS) {
1423         ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL,
1424                      "could not create %s", fname);
1425         ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
1426                      "%s: could not log pid to file %s",
1427                      ap_server_argv0, fname);
1428         exit(1);
1429     }
1430     apr_file_printf(pid_file, "%" APR_PID_T_FMT APR_EOL_STR, mypid);
1431     apr_file_close(pid_file);
1432     saved_pid = mypid;
1433 }
1434
1435 AP_DECLARE(apr_status_t) ap_read_pid(apr_pool_t *p, const char *filename,
1436                                      pid_t *mypid)
1437 {
1438     const apr_size_t BUFFER_SIZE = sizeof(long) * 3 + 2; /* see apr_ltoa */
1439     apr_file_t *pid_file = NULL;
1440     apr_status_t rv;
1441     const char *fname;
1442     char *buf, *endptr;
1443     apr_size_t bytes_read;
1444
1445     if (!filename) {
1446         return APR_EGENERAL;
1447     }
1448
1449     fname = ap_server_root_relative(p, filename);
1450     if (!fname) {
1451         ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, APR_EBADPATH,
1452                      NULL, "Invalid PID file path %s, ignoring.", filename);
1453         return APR_EGENERAL;
1454     }
1455
1456     rv = apr_file_open(&pid_file, fname, APR_READ, APR_OS_DEFAULT, p);
1457     if (rv != APR_SUCCESS) {
1458         return rv;
1459     }
1460
1461     buf = apr_palloc(p, BUFFER_SIZE);
1462
1463     rv = apr_file_read_full(pid_file, buf, BUFFER_SIZE - 1, &bytes_read);
1464     if (rv != APR_SUCCESS && rv != APR_EOF) {
1465         return rv;
1466     }
1467
1468     /* If we fill the buffer, we're probably reading a corrupt pid file.
1469      * To be nice, let's also ensure the first char is a digit. */
1470     if (bytes_read == 0 || bytes_read == BUFFER_SIZE - 1 || !apr_isdigit(*buf)) {
1471         return APR_EGENERAL;
1472     }
1473
1474     buf[bytes_read] = '\0';
1475     *mypid = strtol(buf, &endptr, 10);
1476
1477     apr_file_close(pid_file);
1478     return APR_SUCCESS;
1479 }
1480
1481 AP_DECLARE(void) ap_log_assert(const char *szExp, const char *szFile,
1482                                int nLine)
1483 {
1484     char time_str[APR_CTIME_LEN];
1485
1486     apr_ctime(time_str, apr_time_now());
1487     ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL,
1488                  "[%s] file %s, line %d, assertion \"%s\" failed",
1489                  time_str, szFile, nLine, szExp);
1490 #if defined(WIN32)
1491     DebugBreak();
1492 #else
1493     /* unix assert does an abort leading to a core dump */
1494     abort();
1495 #endif
1496 }
1497
1498 /* piped log support */
1499
1500 #ifdef AP_HAVE_RELIABLE_PIPED_LOGS
1501 /* forward declaration */
1502 static void piped_log_maintenance(int reason, void *data, apr_wait_t status);
1503
1504 /* Spawn the piped logger process pl->program. */
1505 static apr_status_t piped_log_spawn(piped_log *pl)
1506 {
1507     apr_procattr_t *procattr;
1508     apr_proc_t *procnew = NULL;
1509     apr_status_t status;
1510
1511     if (((status = apr_procattr_create(&procattr, pl->p)) != APR_SUCCESS) ||
1512         ((status = apr_procattr_dir_set(procattr, ap_server_root))
1513          != APR_SUCCESS) ||
1514         ((status = apr_procattr_cmdtype_set(procattr, pl->cmdtype))
1515          != APR_SUCCESS) ||
1516         ((status = apr_procattr_child_in_set(procattr,
1517                                              pl->read_fd,
1518                                              pl->write_fd))
1519          != APR_SUCCESS) ||
1520         ((status = apr_procattr_child_errfn_set(procattr, log_child_errfn))
1521          != APR_SUCCESS) ||
1522         ((status = apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS)) {
1523         char buf[120];
1524         /* Something bad happened, give up and go away. */
1525         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1526                      "piped_log_spawn: unable to setup child process '%s': %s",
1527                      pl->program, apr_strerror(status, buf, sizeof(buf)));
1528     }
1529     else {
1530         char **args;
1531         const char *pname;
1532
1533         apr_tokenize_to_argv(pl->program, &args, pl->p);
1534         pname = apr_pstrdup(pl->p, args[0]);
1535         procnew = apr_pcalloc(pl->p, sizeof(apr_proc_t));
1536         status = apr_proc_create(procnew, pname, (const char * const *) args,
1537                                  NULL, procattr, pl->p);
1538
1539         if (status == APR_SUCCESS) {
1540             pl->pid = procnew;
1541             /* procnew->in was dup2'd from pl->write_fd;
1542              * since the original fd is still valid, close the copy to
1543              * avoid a leak. */
1544             apr_file_close(procnew->in);
1545             procnew->in = NULL;
1546             apr_proc_other_child_register(procnew, piped_log_maintenance, pl,
1547                                           pl->write_fd, pl->p);
1548             close_handle_in_child(pl->p, pl->read_fd);
1549         }
1550         else {
1551             char buf[120];
1552             /* Something bad happened, give up and go away. */
1553             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1554                          "unable to start piped log program '%s': %s",
1555                          pl->program, apr_strerror(status, buf, sizeof(buf)));
1556         }
1557     }
1558
1559     return status;
1560 }
1561
1562
1563 static void piped_log_maintenance(int reason, void *data, apr_wait_t status)
1564 {
1565     piped_log *pl = data;
1566     apr_status_t stats;
1567     int mpm_state;
1568
1569     switch (reason) {
1570     case APR_OC_REASON_DEATH:
1571     case APR_OC_REASON_LOST:
1572         pl->pid = NULL; /* in case we don't get it going again, this
1573                          * tells other logic not to try to kill it
1574                          */
1575         apr_proc_other_child_unregister(pl);
1576         stats = ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state);
1577         if (stats != APR_SUCCESS) {
1578             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1579                          "can't query MPM state; not restarting "
1580                          "piped log program '%s'",
1581                          pl->program);
1582         }
1583         else if (mpm_state != AP_MPMQ_STOPPING) {
1584             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1585                          "piped log program '%s' failed unexpectedly",
1586                          pl->program);
1587             if ((stats = piped_log_spawn(pl)) != APR_SUCCESS) {
1588                 /* what can we do?  This could be the error log we're having
1589                  * problems opening up... */
1590                 char buf[120];
1591                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1592                              "piped_log_maintenance: unable to respawn '%s': %s",
1593                              pl->program, apr_strerror(stats, buf, sizeof(buf)));
1594             }
1595         }
1596         break;
1597
1598     case APR_OC_REASON_UNWRITABLE:
1599         /* We should not kill off the pipe here, since it may only be full.
1600          * If it really is locked, we should kill it off manually. */
1601     break;
1602
1603     case APR_OC_REASON_RESTART:
1604         if (pl->pid != NULL) {
1605             apr_proc_kill(pl->pid, SIGTERM);
1606             pl->pid = NULL;
1607         }
1608         break;
1609
1610     case APR_OC_REASON_UNREGISTER:
1611         break;
1612     }
1613 }
1614
1615
1616 static apr_status_t piped_log_cleanup_for_exec(void *data)
1617 {
1618     piped_log *pl = data;
1619
1620     apr_file_close(pl->read_fd);
1621     apr_file_close(pl->write_fd);
1622     return APR_SUCCESS;
1623 }
1624
1625
1626 static apr_status_t piped_log_cleanup(void *data)
1627 {
1628     piped_log *pl = data;
1629
1630     if (pl->pid != NULL) {
1631         apr_proc_kill(pl->pid, SIGTERM);
1632     }
1633     return piped_log_cleanup_for_exec(data);
1634 }
1635
1636
1637 AP_DECLARE(piped_log *) ap_open_piped_log_ex(apr_pool_t *p,
1638                                              const char *program,
1639                                              apr_cmdtype_e cmdtype)
1640 {
1641     piped_log *pl;
1642
1643     pl = apr_palloc(p, sizeof (*pl));
1644     pl->p = p;
1645     pl->program = apr_pstrdup(p, program);
1646     pl->pid = NULL;
1647     pl->cmdtype = cmdtype;
1648     if (apr_file_pipe_create_ex(&pl->read_fd,
1649                                 &pl->write_fd,
1650                                 APR_FULL_BLOCK, p) != APR_SUCCESS) {
1651         return NULL;
1652     }
1653     apr_pool_cleanup_register(p, pl, piped_log_cleanup,
1654                               piped_log_cleanup_for_exec);
1655     if (piped_log_spawn(pl) != APR_SUCCESS) {
1656         apr_pool_cleanup_kill(p, pl, piped_log_cleanup);
1657         apr_file_close(pl->read_fd);
1658         apr_file_close(pl->write_fd);
1659         return NULL;
1660     }
1661     return pl;
1662 }
1663
1664 #else /* !AP_HAVE_RELIABLE_PIPED_LOGS */
1665
1666 static apr_status_t piped_log_cleanup(void *data)
1667 {
1668     piped_log *pl = data;
1669
1670     apr_file_close(pl->write_fd);
1671     return APR_SUCCESS;
1672 }
1673
1674 AP_DECLARE(piped_log *) ap_open_piped_log_ex(apr_pool_t *p,
1675                                              const char *program,
1676                                              apr_cmdtype_e cmdtype)
1677 {
1678     piped_log *pl;
1679     apr_file_t *dummy = NULL;
1680     int rc;
1681
1682     rc = log_child(p, program, &dummy, cmdtype, 0);
1683     if (rc != APR_SUCCESS) {
1684         ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL,
1685                      "Couldn't start piped log process '%s'.",
1686                      (program == NULL) ? "NULL" : program);
1687         return NULL;
1688     }
1689
1690     pl = apr_palloc(p, sizeof (*pl));
1691     pl->p = p;
1692     pl->read_fd = NULL;
1693     pl->write_fd = dummy;
1694     apr_pool_cleanup_register(p, pl, piped_log_cleanup, piped_log_cleanup);
1695
1696     return pl;
1697 }
1698
1699 #endif
1700
1701 AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p,
1702                                           const char *program)
1703 {
1704     apr_cmdtype_e cmdtype = APR_PROGRAM_ENV;
1705
1706     /* In 2.4 favor PROGRAM_ENV, accept "||prog" syntax for compatibility
1707      * and "|$cmd" to override the default.
1708      * Any 2.2 backport would continue to favor SHELLCMD_ENV so there 
1709      * accept "||prog" to override, and "|$cmd" to ease conversion.
1710      */
1711     if (*program == '|')
1712         ++program;
1713     if (*program == '$') {
1714         cmdtype = APR_SHELLCMD_ENV;
1715         ++program;
1716     }
1717
1718     return ap_open_piped_log_ex(p, program, cmdtype);
1719 }
1720
1721 AP_DECLARE(void) ap_close_piped_log(piped_log *pl)
1722 {
1723     apr_pool_cleanup_run(pl->p, pl, piped_log_cleanup);
1724 }
1725
1726 AP_DECLARE(const char *) ap_parse_log_level(const char *str, int *val)
1727 {
1728     char *err = "Log level keyword must be one of emerg/alert/crit/error/warn/"
1729                 "notice/info/debug/trace1/.../trace8";
1730     int i = 0;
1731
1732     if (str == NULL)
1733         return err;
1734
1735     while (priorities[i].t_name != NULL) {
1736         if (!strcasecmp(str, priorities[i].t_name)) {
1737             *val = priorities[i].t_val;
1738             return NULL;
1739         }
1740         i++;
1741     }
1742     return err;
1743 }
1744
1745 AP_IMPLEMENT_HOOK_VOID(error_log,
1746                        (const char *file, int line, int module_index, int level,
1747                         apr_status_t status, const server_rec *s,
1748                         const request_rec *r, apr_pool_t *pool,
1749                         const char *errstr), (file, line, module_index, level,
1750                         status, s, r, pool, errstr))
1751
1752 AP_IMPLEMENT_HOOK_RUN_FIRST(int, generate_log_id,
1753                             (const conn_rec *c, const request_rec *r,
1754                              const char **id),
1755                             (c, r, id), DECLINED)