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