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