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