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