log.c revision c8548ba8
1/* 2 3Copyright 1987, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, 28Copyright 1994 Quarterdeck Office Systems. 29 30 All Rights Reserved 31 32Permission to use, copy, modify, and distribute this software and its 33documentation for any purpose and without fee is hereby granted, 34provided that the above copyright notice appear in all copies and that 35both that copyright notice and this permission notice appear in 36supporting documentation, and that the names of Digital and 37Quarterdeck not be used in advertising or publicity pertaining to 38distribution of the software without specific, written prior 39permission. 40 41DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 42SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 43FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT 44OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 45OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 46OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 47OR PERFORMANCE OF THIS SOFTWARE. 48 49*/ 50 51/* 52 * Copyright (c) 1997-2003 by The XFree86 Project, Inc. 53 * 54 * Permission is hereby granted, free of charge, to any person obtaining a 55 * copy of this software and associated documentation files (the "Software"), 56 * to deal in the Software without restriction, including without limitation 57 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 58 * and/or sell copies of the Software, and to permit persons to whom the 59 * Software is furnished to do so, subject to the following conditions: 60 * 61 * The above copyright notice and this permission notice shall be included in 62 * all copies or substantial portions of the Software. 63 * 64 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 65 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 66 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 67 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 68 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 69 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 70 * OTHER DEALINGS IN THE SOFTWARE. 71 * 72 * Except as contained in this notice, the name of the copyright holder(s) 73 * and author(s) shall not be used in advertising or otherwise to promote 74 * the sale, use or other dealings in this Software without prior written 75 * authorization from the copyright holder(s) and author(s). 76 */ 77 78#ifdef HAVE_DIX_CONFIG_H 79#include <dix-config.h> 80#endif 81 82#include <X11/Xos.h> 83#include <stdio.h> 84#include <time.h> 85#include <sys/stat.h> 86#include <stdarg.h> 87#include <stdlib.h> /* for malloc() */ 88#include <errno.h> 89 90#include "input.h" 91#include "site.h" 92#include "opaque.h" 93 94#ifdef WIN32 95#include <process.h> 96#define getpid(x) _getpid(x) 97#endif 98 99#ifdef XF86BIGFONT 100#include "xf86bigfontsrv.h" 101#endif 102 103#ifdef __clang__ 104#pragma clang diagnostic ignored "-Wformat-nonliteral" 105#endif 106 107#ifdef DDXOSVERRORF 108void (*OsVendorVErrorFProc) (const char *, va_list args) = NULL; 109#endif 110 111static FILE *logFile = NULL; 112static int logFileFd = -1; 113static Bool logFlush = FALSE; 114static Bool logSync = FALSE; 115static int logVerbosity = DEFAULT_LOG_VERBOSITY; 116static int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY; 117 118/* Buffer to information logged before the log file is opened. */ 119static char *saveBuffer = NULL; 120static int bufferSize = 0, bufferUnused = 0, bufferPos = 0; 121static Bool needBuffer = TRUE; 122 123#ifdef __APPLE__ 124static char __crashreporter_info_buff__[4096] = { 0 }; 125 126static const char *__crashreporter_info__ __attribute__ ((__used__)) = 127 &__crashreporter_info_buff__[0]; 128asm(".desc ___crashreporter_info__, 0x10"); 129#endif 130 131/* Prefix strings for log messages. */ 132#ifndef X_UNKNOWN_STRING 133#define X_UNKNOWN_STRING "(\?\?)" 134#endif 135#ifndef X_PROBE_STRING 136#define X_PROBE_STRING "(--)" 137#endif 138#ifndef X_CONFIG_STRING 139#define X_CONFIG_STRING "(**)" 140#endif 141#ifndef X_DEFAULT_STRING 142#define X_DEFAULT_STRING "(==)" 143#endif 144#ifndef X_CMDLINE_STRING 145#define X_CMDLINE_STRING "(++)" 146#endif 147#ifndef X_NOTICE_STRING 148#define X_NOTICE_STRING "(!!)" 149#endif 150#ifndef X_ERROR_STRING 151#define X_ERROR_STRING "(EE)" 152#endif 153#ifndef X_WARNING_STRING 154#define X_WARNING_STRING "(WW)" 155#endif 156#ifndef X_INFO_STRING 157#define X_INFO_STRING "(II)" 158#endif 159#ifndef X_NOT_IMPLEMENTED_STRING 160#define X_NOT_IMPLEMENTED_STRING "(NI)" 161#endif 162#ifndef X_DEBUG_STRING 163#define X_DEBUG_STRING "(DB)" 164#endif 165#ifndef X_NONE_STRING 166#define X_NONE_STRING "" 167#endif 168 169static size_t 170strlen_sigsafe(const char *s) 171{ 172 size_t len; 173 for (len = 0; s[len]; len++); 174 return len; 175} 176 177/* 178 * LogFilePrep is called to setup files for logging, including getting 179 * an old file out of the way, but it doesn't actually open the file, 180 * since it may be used for renaming a file we're already logging to. 181 */ 182#pragma GCC diagnostic push 183#pragma GCC diagnostic ignored "-Wformat-nonliteral" 184 185static char * 186LogFilePrep(const char *fname, const char *backup, const char *idstring) 187{ 188 char *logFileName = NULL; 189 190 /* the format string below is controlled by the user, 191 this code should never be called with elevated privileges */ 192 if (asprintf(&logFileName, fname, idstring) == -1) 193 FatalError("Cannot allocate space for the log file name\n"); 194 195 if (backup && *backup) { 196 struct stat buf; 197 198 if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) { 199 char *suffix; 200 char *oldLog; 201 202 if ((asprintf(&suffix, backup, idstring) == -1) || 203 (asprintf(&oldLog, "%s%s", logFileName, suffix) == -1)) { 204 FatalError("Cannot allocate space for the log file name\n"); 205 } 206 free(suffix); 207 208 if (rename(logFileName, oldLog) == -1) { 209 FatalError("Cannot move old log file \"%s\" to \"%s\"\n", 210 logFileName, oldLog); 211 } 212 free(oldLog); 213 } 214 } 215 else { 216 if (remove(logFileName) != 0 && errno != ENOENT) { 217 FatalError("Cannot remove old log file \"%s\": %s\n", 218 logFileName, strerror(errno)); 219 } 220 } 221 222 return logFileName; 223} 224#pragma GCC diagnostic pop 225 226/* 227 * LogInit is called to start logging to a file. It is also called (with 228 * NULL arguments) when logging to a file is not wanted. It must always be 229 * called, otherwise log messages will continue to accumulate in a buffer. 230 * 231 * %s, if present in the fname or backup strings, is expanded to the display 232 * string (or to a string containing the pid if the display is not yet set). 233 */ 234 235static char *saved_log_fname; 236static char *saved_log_backup; 237static char *saved_log_tempname; 238 239const char * 240LogInit(const char *fname, const char *backup) 241{ 242 char *logFileName = NULL; 243 244 if (fname && *fname) { 245 if (displayfd != -1) { 246 /* Display isn't set yet, so we can't use it in filenames yet. */ 247 char pidstring[32]; 248 snprintf(pidstring, sizeof(pidstring), "pid-%ld", 249 (unsigned long) getpid()); 250 logFileName = LogFilePrep(fname, backup, pidstring); 251 saved_log_tempname = logFileName; 252 253 /* Save the patterns for use when the display is named. */ 254 saved_log_fname = strdup(fname); 255 if (backup == NULL) 256 saved_log_backup = NULL; 257 else 258 saved_log_backup = strdup(backup); 259 } else 260 logFileName = LogFilePrep(fname, backup, display); 261 if ((logFile = fopen(logFileName, "w")) == NULL) 262 FatalError("Cannot open log file \"%s\"\n", logFileName); 263 setvbuf(logFile, NULL, _IONBF, 0); 264 265 logFileFd = fileno(logFile); 266 267 /* Flush saved log information. */ 268 if (saveBuffer && bufferSize > 0) { 269 fwrite(saveBuffer, bufferPos, 1, logFile); 270 fflush(logFile); 271#ifndef WIN32 272 fsync(fileno(logFile)); 273#endif 274 } 275 } 276 277 /* 278 * Unconditionally free the buffer, and flag that the buffer is no longer 279 * needed. 280 */ 281 if (saveBuffer && bufferSize > 0) { 282 free(saveBuffer); 283 saveBuffer = NULL; 284 bufferSize = 0; 285 } 286 needBuffer = FALSE; 287 288 return logFileName; 289} 290 291void 292LogSetDisplay(void) 293{ 294 if (saved_log_fname && strstr(saved_log_fname, "%s")) { 295 char *logFileName; 296 297 logFileName = LogFilePrep(saved_log_fname, saved_log_backup, display); 298 299 if (rename(saved_log_tempname, logFileName) == 0) { 300 LogMessageVerb(X_PROBED, 0, 301 "Log file renamed from \"%s\" to \"%s\"\n", 302 saved_log_tempname, logFileName); 303 304 if (strlen(saved_log_tempname) >= strlen(logFileName)) 305 strncpy(saved_log_tempname, logFileName, 306 strlen(saved_log_tempname)); 307 } 308 else { 309 ErrorF("Failed to rename log file \"%s\" to \"%s\": %s\n", 310 saved_log_tempname, logFileName, strerror(errno)); 311 } 312 313 /* free newly allocated string - can't free old one since existing 314 pointers to it may exist in DDX callers. */ 315 free(logFileName); 316 free(saved_log_fname); 317 free(saved_log_backup); 318 } 319} 320 321void 322LogClose(enum ExitCode error) 323{ 324 if (logFile) { 325 int msgtype = (error == EXIT_NO_ERROR) ? X_INFO : X_ERROR; 326 LogMessageVerbSigSafe(msgtype, -1, 327 "Server terminated %s (%d). Closing log file.\n", 328 (error == EXIT_NO_ERROR) ? "successfully" : "with error", 329 error); 330 fclose(logFile); 331 logFile = NULL; 332 logFileFd = -1; 333 } 334} 335 336Bool 337LogSetParameter(LogParameter param, int value) 338{ 339 switch (param) { 340 case XLOG_FLUSH: 341 logFlush = value ? TRUE : FALSE; 342 return TRUE; 343 case XLOG_SYNC: 344 logSync = value ? TRUE : FALSE; 345 return TRUE; 346 case XLOG_VERBOSITY: 347 logVerbosity = value; 348 return TRUE; 349 case XLOG_FILE_VERBOSITY: 350 logFileVerbosity = value; 351 return TRUE; 352 default: 353 return FALSE; 354 } 355} 356 357enum { 358 LMOD_LONG = 0x1, 359 LMOD_LONGLONG = 0x2, 360 LMOD_SHORT = 0x4, 361 LMOD_SIZET = 0x8, 362}; 363 364/** 365 * Parse non-digit length modifiers and set the corresponding flag in 366 * flags_return. 367 * 368 * @return the number of bytes parsed 369 */ 370static int parse_length_modifier(const char *format, size_t len, int *flags_return) 371{ 372 int idx = 0; 373 int length_modifier = 0; 374 375 while (idx < len) { 376 switch (format[idx]) { 377 case 'l': 378 BUG_RETURN_VAL(length_modifier & LMOD_SHORT, 0); 379 380 if (length_modifier & LMOD_LONG) 381 length_modifier |= LMOD_LONGLONG; 382 else 383 length_modifier |= LMOD_LONG; 384 break; 385 case 'h': 386 BUG_RETURN_VAL(length_modifier & (LMOD_LONG|LMOD_LONGLONG), 0); 387 length_modifier |= LMOD_SHORT; 388 /* gcc says 'short int' is promoted to 'int' when 389 * passed through '...', so ignored during 390 * processing */ 391 break; 392 case 'z': 393 length_modifier |= LMOD_SIZET; 394 break; 395 default: 396 goto out; 397 } 398 idx++; 399 } 400 401out: 402 *flags_return = length_modifier; 403 return idx; 404} 405 406/** 407 * Signal-safe snprintf, with some limitations over snprintf. Be careful 408 * which directives you use. 409 */ 410static int 411vpnprintf(char *string, int size_in, const char *f, va_list args) 412{ 413 int f_idx = 0; 414 int s_idx = 0; 415 int f_len = strlen_sigsafe(f); 416 char *string_arg; 417 char number[21]; 418 int p_len; 419 int i; 420 uint64_t ui; 421 int64_t si; 422 size_t size = size_in; 423 int precision; 424 425 for (; f_idx < f_len && s_idx < size - 1; f_idx++) { 426 int length_modifier = 0; 427 if (f[f_idx] != '%') { 428 string[s_idx++] = f[f_idx]; 429 continue; 430 } 431 432 f_idx++; 433 434 /* silently swallow minimum field width */ 435 if (f[f_idx] == '*') { 436 f_idx++; 437 va_arg(args, int); 438 } else { 439 while (f_idx < f_len && ((f[f_idx] >= '0' && f[f_idx] <= '9'))) 440 f_idx++; 441 } 442 443 /* is there a precision? */ 444 precision = size; 445 if (f[f_idx] == '.') { 446 f_idx++; 447 if (f[f_idx] == '*') { 448 f_idx++; 449 /* precision is supplied in an int argument */ 450 precision = va_arg(args, int); 451 } else { 452 /* silently swallow precision digits */ 453 while (f_idx < f_len && ((f[f_idx] >= '0' && f[f_idx] <= '9'))) 454 f_idx++; 455 } 456 } 457 458 /* non-digit length modifiers */ 459 if (f_idx < f_len) { 460 int parsed_bytes = parse_length_modifier(&f[f_idx], f_len - f_idx, &length_modifier); 461 if (parsed_bytes < 0) 462 return 0; 463 f_idx += parsed_bytes; 464 } 465 466 if (f_idx >= f_len) 467 break; 468 469 switch (f[f_idx]) { 470 case 's': 471 string_arg = va_arg(args, char*); 472 473 for (i = 0; string_arg[i] != 0 && s_idx < size - 1 && s_idx < precision; i++) 474 string[s_idx++] = string_arg[i]; 475 break; 476 477 case 'u': 478 if (length_modifier & LMOD_LONGLONG) 479 ui = va_arg(args, unsigned long long); 480 else if (length_modifier & LMOD_LONG) 481 ui = va_arg(args, unsigned long); 482 else if (length_modifier & LMOD_SIZET) 483 ui = va_arg(args, size_t); 484 else 485 ui = va_arg(args, unsigned); 486 487 FormatUInt64(ui, number); 488 p_len = strlen_sigsafe(number); 489 490 for (i = 0; i < p_len && s_idx < size - 1; i++) 491 string[s_idx++] = number[i]; 492 break; 493 case 'i': 494 case 'd': 495 if (length_modifier & LMOD_LONGLONG) 496 si = va_arg(args, long long); 497 else if (length_modifier & LMOD_LONG) 498 si = va_arg(args, long); 499 else if (length_modifier & LMOD_SIZET) 500 si = va_arg(args, ssize_t); 501 else 502 si = va_arg(args, int); 503 504 FormatInt64(si, number); 505 p_len = strlen_sigsafe(number); 506 507 for (i = 0; i < p_len && s_idx < size - 1; i++) 508 string[s_idx++] = number[i]; 509 break; 510 511 case 'p': 512 string[s_idx++] = '0'; 513 if (s_idx < size - 1) 514 string[s_idx++] = 'x'; 515 ui = (uintptr_t)va_arg(args, void*); 516 FormatUInt64Hex(ui, number); 517 p_len = strlen_sigsafe(number); 518 519 for (i = 0; i < p_len && s_idx < size - 1; i++) 520 string[s_idx++] = number[i]; 521 break; 522 523 case 'x': 524 if (length_modifier & LMOD_LONGLONG) 525 ui = va_arg(args, unsigned long long); 526 else if (length_modifier & LMOD_LONG) 527 ui = va_arg(args, unsigned long); 528 else if (length_modifier & LMOD_SIZET) 529 ui = va_arg(args, size_t); 530 else 531 ui = va_arg(args, unsigned); 532 533 FormatUInt64Hex(ui, number); 534 p_len = strlen_sigsafe(number); 535 536 for (i = 0; i < p_len && s_idx < size - 1; i++) 537 string[s_idx++] = number[i]; 538 break; 539 case 'f': 540 { 541 double d = va_arg(args, double); 542 FormatDouble(d, number); 543 p_len = strlen_sigsafe(number); 544 545 for (i = 0; i < p_len && s_idx < size - 1; i++) 546 string[s_idx++] = number[i]; 547 } 548 break; 549 case 'c': 550 { 551 char c = va_arg(args, int); 552 if (s_idx < size - 1) 553 string[s_idx++] = c; 554 } 555 break; 556 case '%': 557 string[s_idx++] = '%'; 558 break; 559 default: 560 BUG_WARN_MSG(f[f_idx], "Unsupported printf directive '%c'\n", f[f_idx]); 561 va_arg(args, char*); 562 string[s_idx++] = '%'; 563 if (s_idx < size - 1) 564 string[s_idx++] = f[f_idx]; 565 break; 566 } 567 } 568 569 string[s_idx] = '\0'; 570 571 return s_idx; 572} 573 574static int 575pnprintf(char *string, int size, const char *f, ...) 576{ 577 int rc; 578 va_list args; 579 580 va_start(args, f); 581 rc = vpnprintf(string, size, f, args); 582 va_end(args); 583 584 return rc; 585} 586 587/* This function does the actual log message writes. It must be signal safe. 588 * When attempting to call non-signal-safe functions, guard them with a check 589 * of the inSignalContext global variable. */ 590static void 591LogSWrite(int verb, const char *buf, size_t len, Bool end_line) 592{ 593 static Bool newline = TRUE; 594 int ret; 595 596 if (verb < 0 || logVerbosity >= verb) 597 ret = write(2, buf, len); 598 599 if (verb < 0 || logFileVerbosity >= verb) { 600 if (inSignalContext && logFileFd >= 0) { 601 ret = write(logFileFd, buf, len); 602#ifndef WIN32 603 if (logFlush && logSync) 604 fsync(logFileFd); 605#endif 606 } 607 else if (!inSignalContext && logFile) { 608 if (newline) 609 fprintf(logFile, "[%10.3f] ", GetTimeInMillis() / 1000.0); 610 newline = end_line; 611 fwrite(buf, len, 1, logFile); 612 if (logFlush) { 613 fflush(logFile); 614#ifndef WIN32 615 if (logSync) 616 fsync(fileno(logFile)); 617#endif 618 } 619 } 620 else if (!inSignalContext && needBuffer) { 621 if (len > bufferUnused) { 622 bufferSize += 1024; 623 bufferUnused += 1024; 624 saveBuffer = realloc(saveBuffer, bufferSize); 625 if (!saveBuffer) 626 FatalError("realloc() failed while saving log messages\n"); 627 } 628 bufferUnused -= len; 629 memcpy(saveBuffer + bufferPos, buf, len); 630 bufferPos += len; 631 } 632 } 633 634 /* There's no place to log an error message if the log write 635 * fails... 636 */ 637 (void) ret; 638} 639 640void 641LogVWrite(int verb, const char *f, va_list args) 642{ 643 return LogVMessageVerb(X_NONE, verb, f, args); 644} 645 646void 647LogWrite(int verb, const char *f, ...) 648{ 649 va_list args; 650 651 va_start(args, f); 652 LogVWrite(verb, f, args); 653 va_end(args); 654} 655 656/* Returns the Message Type string to prepend to a logging message, or NULL 657 * if the message will be dropped due to insufficient verbosity. */ 658static const char * 659LogMessageTypeVerbString(MessageType type, int verb) 660{ 661 if (type == X_ERROR) 662 verb = 0; 663 664 if (logVerbosity < verb && logFileVerbosity < verb) 665 return NULL; 666 667 switch (type) { 668 case X_PROBED: 669 return X_PROBE_STRING; 670 case X_CONFIG: 671 return X_CONFIG_STRING; 672 case X_DEFAULT: 673 return X_DEFAULT_STRING; 674 case X_CMDLINE: 675 return X_CMDLINE_STRING; 676 case X_NOTICE: 677 return X_NOTICE_STRING; 678 case X_ERROR: 679 return X_ERROR_STRING; 680 case X_WARNING: 681 return X_WARNING_STRING; 682 case X_INFO: 683 return X_INFO_STRING; 684 case X_NOT_IMPLEMENTED: 685 return X_NOT_IMPLEMENTED_STRING; 686 case X_UNKNOWN: 687 return X_UNKNOWN_STRING; 688 case X_NONE: 689 return X_NONE_STRING; 690 case X_DEBUG: 691 return X_DEBUG_STRING; 692 default: 693 return X_UNKNOWN_STRING; 694 } 695} 696 697void 698LogVMessageVerb(MessageType type, int verb, const char *format, va_list args) 699{ 700 const char *type_str; 701 char buf[1024]; 702 const size_t size = sizeof(buf); 703 Bool newline; 704 size_t len = 0; 705 706 if (inSignalContext) { 707 LogVMessageVerbSigSafe(type, verb, format, args); 708 return; 709 } 710 711 type_str = LogMessageTypeVerbString(type, verb); 712 if (!type_str) 713 return; 714 715 /* if type_str is not "", prepend it and ' ', to message */ 716 if (type_str[0] != '\0') 717 len += Xscnprintf(&buf[len], size - len, "%s ", type_str); 718 719 if (size - len > 1) 720 len += Xvscnprintf(&buf[len], size - len, format, args); 721 722 /* Force '\n' at end of truncated line */ 723 if (size - len == 1) 724 buf[len - 1] = '\n'; 725 726 newline = (buf[len - 1] == '\n'); 727 LogSWrite(verb, buf, len, newline); 728} 729 730/* Log message with verbosity level specified. */ 731void 732LogMessageVerb(MessageType type, int verb, const char *format, ...) 733{ 734 va_list ap; 735 736 va_start(ap, format); 737 LogVMessageVerb(type, verb, format, ap); 738 va_end(ap); 739} 740 741/* Log a message with the standard verbosity level of 1. */ 742void 743LogMessage(MessageType type, const char *format, ...) 744{ 745 va_list ap; 746 747 va_start(ap, format); 748 LogVMessageVerb(type, 1, format, ap); 749 va_end(ap); 750} 751 752/* Log a message using only signal safe functions. */ 753void 754LogMessageVerbSigSafe(MessageType type, int verb, const char *format, ...) 755{ 756 va_list ap; 757 va_start(ap, format); 758 LogVMessageVerbSigSafe(type, verb, format, ap); 759 va_end(ap); 760} 761 762void 763LogVMessageVerbSigSafe(MessageType type, int verb, const char *format, va_list args) 764{ 765 const char *type_str; 766 char buf[1024]; 767 int len; 768 Bool newline; 769 770 type_str = LogMessageTypeVerbString(type, verb); 771 if (!type_str) 772 return; 773 774 /* if type_str is not "", prepend it and ' ', to message */ 775 if (type_str[0] != '\0') { 776 LogSWrite(verb, type_str, strlen_sigsafe(type_str), FALSE); 777 LogSWrite(verb, " ", 1, FALSE); 778 } 779 780 len = vpnprintf(buf, sizeof(buf), format, args); 781 782 /* Force '\n' at end of truncated line */ 783 if (sizeof(buf) - len == 1) 784 buf[len - 1] = '\n'; 785 786 newline = (len > 0 && buf[len - 1] == '\n'); 787 LogSWrite(verb, buf, len, newline); 788} 789 790void 791LogVHdrMessageVerb(MessageType type, int verb, const char *msg_format, 792 va_list msg_args, const char *hdr_format, va_list hdr_args) 793{ 794 const char *type_str; 795 char buf[1024]; 796 const size_t size = sizeof(buf); 797 Bool newline; 798 size_t len = 0; 799 int (*vprintf_func)(char *, int, const char* _X_RESTRICT_KYWD f, va_list args) 800 _X_ATTRIBUTE_PRINTF(3, 0); 801 int (*printf_func)(char *, int, const char* _X_RESTRICT_KYWD f, ...) 802 _X_ATTRIBUTE_PRINTF(3, 4); 803 804 type_str = LogMessageTypeVerbString(type, verb); 805 if (!type_str) 806 return; 807 808 if (inSignalContext) { 809 vprintf_func = vpnprintf; 810 printf_func = pnprintf; 811 } else { 812 vprintf_func = Xvscnprintf; 813 printf_func = Xscnprintf; 814 } 815 816 /* if type_str is not "", prepend it and ' ', to message */ 817 if (type_str[0] != '\0') 818 len += printf_func(&buf[len], size - len, "%s ", type_str); 819 820 if (hdr_format && size - len > 1) 821 len += vprintf_func(&buf[len], size - len, hdr_format, hdr_args); 822 823 if (msg_format && size - len > 1) 824 len += vprintf_func(&buf[len], size - len, msg_format, msg_args); 825 826 /* Force '\n' at end of truncated line */ 827 if (size - len == 1) 828 buf[len - 1] = '\n'; 829 830 newline = (buf[len - 1] == '\n'); 831 LogSWrite(verb, buf, len, newline); 832} 833 834void 835LogHdrMessageVerb(MessageType type, int verb, const char *msg_format, 836 va_list msg_args, const char *hdr_format, ...) 837{ 838 va_list hdr_args; 839 840 va_start(hdr_args, hdr_format); 841 LogVHdrMessageVerb(type, verb, msg_format, msg_args, hdr_format, hdr_args); 842 va_end(hdr_args); 843} 844 845void 846LogHdrMessage(MessageType type, const char *msg_format, va_list msg_args, 847 const char *hdr_format, ...) 848{ 849 va_list hdr_args; 850 851 va_start(hdr_args, hdr_format); 852 LogVHdrMessageVerb(type, 1, msg_format, msg_args, hdr_format, hdr_args); 853 va_end(hdr_args); 854} 855 856void 857AbortServer(void) 858 _X_NORETURN; 859 860void 861AbortServer(void) 862{ 863#ifdef XF86BIGFONT 864 XF86BigfontCleanup(); 865#endif 866 CloseWellKnownConnections(); 867 OsCleanup(TRUE); 868 AbortDevices(); 869 AbortDDX(EXIT_ERR_ABORT); 870 fflush(stderr); 871 if (CoreDump) 872 OsAbort(); 873 exit(1); 874} 875 876#define AUDIT_PREFIX "AUDIT: %s: %ld: " 877#ifndef AUDIT_TIMEOUT 878#define AUDIT_TIMEOUT ((CARD32)(120 * 1000)) /* 2 mn */ 879#endif 880 881static int nrepeat = 0; 882static int oldlen = -1; 883static OsTimerPtr auditTimer = NULL; 884 885void 886FreeAuditTimer(void) 887{ 888 if (auditTimer != NULL) { 889 /* Force output of pending messages */ 890 TimerForce(auditTimer); 891 TimerFree(auditTimer); 892 auditTimer = NULL; 893 } 894} 895 896static char * 897AuditPrefix(void) 898{ 899 time_t tm; 900 char *autime, *s; 901 char *tmpBuf; 902 int len; 903 904 time(&tm); 905 autime = ctime(&tm); 906 if ((s = strchr(autime, '\n'))) 907 *s = '\0'; 908 len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + 1; 909 tmpBuf = malloc(len); 910 if (!tmpBuf) 911 return NULL; 912 snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long) getpid()); 913 return tmpBuf; 914} 915 916void 917AuditF(const char *f, ...) 918{ 919 va_list args; 920 921 va_start(args, f); 922 923 VAuditF(f, args); 924 va_end(args); 925} 926 927static CARD32 928AuditFlush(OsTimerPtr timer, CARD32 now, void *arg) 929{ 930 char *prefix; 931 932 if (nrepeat > 0) { 933 prefix = AuditPrefix(); 934 ErrorF("%slast message repeated %d times\n", 935 prefix != NULL ? prefix : "", nrepeat); 936 nrepeat = 0; 937 free(prefix); 938 return AUDIT_TIMEOUT; 939 } 940 else { 941 /* if the timer expires without anything to print, flush the message */ 942 oldlen = -1; 943 return 0; 944 } 945} 946 947void 948VAuditF(const char *f, va_list args) 949{ 950 char *prefix; 951 char buf[1024]; 952 int len; 953 static char oldbuf[1024]; 954 955 prefix = AuditPrefix(); 956 len = vsnprintf(buf, sizeof(buf), f, args); 957 958 if (len == oldlen && strcmp(buf, oldbuf) == 0) { 959 /* Message already seen */ 960 nrepeat++; 961 } 962 else { 963 /* new message */ 964 if (auditTimer != NULL) 965 TimerForce(auditTimer); 966 ErrorF("%s%s", prefix != NULL ? prefix : "", buf); 967 strlcpy(oldbuf, buf, sizeof(oldbuf)); 968 oldlen = len; 969 nrepeat = 0; 970 auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL); 971 } 972 free(prefix); 973} 974 975void 976FatalError(const char *f, ...) 977{ 978 va_list args; 979 va_list args2; 980 static Bool beenhere = FALSE; 981 982 if (beenhere) 983 ErrorFSigSafe("\nFatalError re-entered, aborting\n"); 984 else 985 ErrorFSigSafe("\nFatal server error:\n"); 986 987 va_start(args, f); 988 989 /* Make a copy for OsVendorFatalError */ 990 va_copy(args2, args); 991 992#ifdef __APPLE__ 993 { 994 va_list apple_args; 995 996 va_copy(apple_args, args); 997 (void)vsnprintf(__crashreporter_info_buff__, 998 sizeof(__crashreporter_info_buff__), f, apple_args); 999 va_end(apple_args); 1000 } 1001#endif 1002 VErrorFSigSafe(f, args); 1003 va_end(args); 1004 ErrorFSigSafe("\n"); 1005 if (!beenhere) 1006 OsVendorFatalError(f, args2); 1007 va_end(args2); 1008 if (!beenhere) { 1009 beenhere = TRUE; 1010 AbortServer(); 1011 } 1012 else 1013 OsAbort(); 1014 /*NOTREACHED*/} 1015 1016void 1017VErrorF(const char *f, va_list args) 1018{ 1019#ifdef DDXOSVERRORF 1020 if (OsVendorVErrorFProc) 1021 OsVendorVErrorFProc(f, args); 1022 else 1023 LogVWrite(-1, f, args); 1024#else 1025 LogVWrite(-1, f, args); 1026#endif 1027} 1028 1029void 1030ErrorF(const char *f, ...) 1031{ 1032 va_list args; 1033 1034 va_start(args, f); 1035 VErrorF(f, args); 1036 va_end(args); 1037} 1038 1039void 1040VErrorFSigSafe(const char *f, va_list args) 1041{ 1042 LogVMessageVerbSigSafe(X_ERROR, -1, f, args); 1043} 1044 1045void 1046ErrorFSigSafe(const char *f, ...) 1047{ 1048 va_list args; 1049 1050 va_start(args, f); 1051 VErrorFSigSafe(f, args); 1052 va_end(args); 1053} 1054 1055void 1056LogPrintMarkers(void) 1057{ 1058 /* Show what the message marker symbols mean. */ 1059 LogWrite(0, "Markers: "); 1060 LogMessageVerb(X_PROBED, 0, "probed, "); 1061 LogMessageVerb(X_CONFIG, 0, "from config file, "); 1062 LogMessageVerb(X_DEFAULT, 0, "default setting,\n\t"); 1063 LogMessageVerb(X_CMDLINE, 0, "from command line, "); 1064 LogMessageVerb(X_NOTICE, 0, "notice, "); 1065 LogMessageVerb(X_INFO, 0, "informational,\n\t"); 1066 LogMessageVerb(X_WARNING, 0, "warning, "); 1067 LogMessageVerb(X_ERROR, 0, "error, "); 1068 LogMessageVerb(X_NOT_IMPLEMENTED, 0, "not implemented, "); 1069 LogMessageVerb(X_UNKNOWN, 0, "unknown.\n"); 1070} 1071