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