log.c revision 6747b715
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 27 28Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, 29Copyright 1994 Quarterdeck Office Systems. 30 31 All Rights Reserved 32 33Permission to use, copy, modify, and distribute this software and its 34documentation for any purpose and without fee is hereby granted, 35provided that the above copyright notice appear in all copies and that 36both that copyright notice and this permission notice appear in 37supporting documentation, and that the names of Digital and 38Quarterdeck not be used in advertising or publicity pertaining to 39distribution of the software without specific, written prior 40permission. 41 42DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 43SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 44FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT 45OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 46OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 47OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 48OR PERFORMANCE OF THIS SOFTWARE. 49 50*/ 51 52/* 53 * Copyright (c) 1997-2003 by The XFree86 Project, Inc. 54 * 55 * Permission is hereby granted, free of charge, to any person obtaining a 56 * copy of this software and associated documentation files (the "Software"), 57 * to deal in the Software without restriction, including without limitation 58 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 59 * and/or sell copies of the Software, and to permit persons to whom the 60 * Software is furnished to do so, subject to the following conditions: 61 * 62 * The above copyright notice and this permission notice shall be included in 63 * all copies or substantial portions of the Software. 64 * 65 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 66 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 67 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 68 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 69 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 70 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 71 * OTHER DEALINGS IN THE SOFTWARE. 72 * 73 * Except as contained in this notice, the name of the copyright holder(s) 74 * and author(s) shall not be used in advertising or otherwise to promote 75 * the sale, use or other dealings in this Software without prior written 76 * authorization from the copyright holder(s) and author(s). 77 */ 78 79 80#ifdef HAVE_DIX_CONFIG_H 81#include <dix-config.h> 82#endif 83 84#include <X11/Xos.h> 85#include <stdio.h> 86#include <time.h> 87#include <sys/stat.h> 88#include <stdarg.h> 89#include <stdlib.h> /* for malloc() */ 90#include <errno.h> 91 92#include "input.h" 93#include "site.h" 94#include "opaque.h" 95 96#ifdef WIN32 97#include <process.h> 98#define getpid(x) _getpid(x) 99#endif 100 101#ifdef XF86BIGFONT 102#include "xf86bigfontsrv.h" 103#endif 104 105#ifdef DDXOSVERRORF 106void (*OsVendorVErrorFProc)(const char *, va_list args) = NULL; 107#endif 108 109static FILE *logFile = NULL; 110static Bool logFlush = FALSE; 111static Bool logSync = FALSE; 112static int logVerbosity = DEFAULT_LOG_VERBOSITY; 113static int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY; 114 115/* Buffer to information logged before the log file is opened. */ 116static char *saveBuffer = NULL; 117static int bufferSize = 0, bufferUnused = 0, bufferPos = 0; 118static Bool needBuffer = TRUE; 119 120#ifdef __APPLE__ 121#include <AvailabilityMacros.h> 122 123static char __crashreporter_info_buff__[4096] = {0}; 124static const char *__crashreporter_info__ = &__crashreporter_info_buff__[0]; 125#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 126// This is actually a toolchain requirement, but I'm not sure the correct check, 127// but it should be fine to just only include it for Leopard and later. This line 128// just tells the linker to never strip this symbol (such as for space optimization) 129asm (".desc ___crashreporter_info__, 0x10"); 130#endif 131#endif 132 133/* Prefix strings for log messages. */ 134#ifndef X_UNKNOWN_STRING 135#define X_UNKNOWN_STRING "(\?\?)" 136#endif 137#ifndef X_PROBE_STRING 138#define X_PROBE_STRING "(--)" 139#endif 140#ifndef X_CONFIG_STRING 141#define X_CONFIG_STRING "(**)" 142#endif 143#ifndef X_DEFAULT_STRING 144#define X_DEFAULT_STRING "(==)" 145#endif 146#ifndef X_CMDLINE_STRING 147#define X_CMDLINE_STRING "(++)" 148#endif 149#ifndef X_NOTICE_STRING 150#define X_NOTICE_STRING "(!!)" 151#endif 152#ifndef X_ERROR_STRING 153#define X_ERROR_STRING "(EE)" 154#endif 155#ifndef X_WARNING_STRING 156#define X_WARNING_STRING "(WW)" 157#endif 158#ifndef X_INFO_STRING 159#define X_INFO_STRING "(II)" 160#endif 161#ifndef X_NOT_IMPLEMENTED_STRING 162#define X_NOT_IMPLEMENTED_STRING "(NI)" 163#endif 164 165/* 166 * LogInit is called to start logging to a file. It is also called (with 167 * NULL arguments) when logging to a file is not wanted. It must always be 168 * called, otherwise log messages will continue to accumulate in a buffer. 169 * 170 * %s, if present in the fname or backup strings, is expanded to the display 171 * string. 172 */ 173 174const char * 175LogInit(const char *fname, const char *backup) 176{ 177 char *logFileName = NULL; 178 179 if (fname && *fname) { 180 /* malloc() can't be used yet. */ 181 logFileName = malloc(strlen(fname) + strlen(display) + 1); 182 if (!logFileName) 183 FatalError("Cannot allocate space for the log file name\n"); 184 sprintf(logFileName, fname, display); 185 186 if (backup && *backup) { 187 struct stat buf; 188 189 if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) { 190 char *suffix; 191 char *oldLog; 192 193 oldLog = malloc(strlen(logFileName) + strlen(backup) + 194 strlen(display) + 1); 195 suffix = malloc(strlen(backup) + strlen(display) + 1); 196 if (!oldLog || !suffix) 197 FatalError("Cannot allocate space for the log file name\n"); 198 sprintf(suffix, backup, display); 199 sprintf(oldLog, "%s%s", logFileName, suffix); 200 free(suffix); 201 if (rename(logFileName, oldLog) == -1) { 202 FatalError("Cannot move old log file \"%s\" to \"%s\"\n", 203 logFileName, oldLog); 204 } 205 free(oldLog); 206 } 207 } 208 if ((logFile = fopen(logFileName, "w")) == NULL) 209 FatalError("Cannot open log file \"%s\"\n", logFileName); 210 setvbuf(logFile, NULL, _IONBF, 0); 211 212 /* Flush saved log information. */ 213 if (saveBuffer && bufferSize > 0) { 214 fwrite(saveBuffer, bufferPos, 1, logFile); 215 fflush(logFile); 216#ifndef WIN32 217 fsync(fileno(logFile)); 218#endif 219 } 220 } 221 222 /* 223 * Unconditionally free the buffer, and flag that the buffer is no longer 224 * needed. 225 */ 226 if (saveBuffer && bufferSize > 0) { 227 free(saveBuffer); /* Must be free(), not free() */ 228 saveBuffer = NULL; 229 bufferSize = 0; 230 } 231 needBuffer = FALSE; 232 233 return logFileName; 234} 235 236void 237LogClose(void) 238{ 239 if (logFile) { 240 fclose(logFile); 241 logFile = NULL; 242 } 243} 244 245Bool 246LogSetParameter(LogParameter param, int value) 247{ 248 switch (param) { 249 case XLOG_FLUSH: 250 logFlush = value ? TRUE : FALSE; 251 return TRUE; 252 case XLOG_SYNC: 253 logSync = value ? TRUE : FALSE; 254 return TRUE; 255 case XLOG_VERBOSITY: 256 logVerbosity = value; 257 return TRUE; 258 case XLOG_FILE_VERBOSITY: 259 logFileVerbosity = value; 260 return TRUE; 261 default: 262 return FALSE; 263 } 264} 265 266/* This function does the actual log message writes. */ 267 268void 269LogVWrite(int verb, const char *f, va_list args) 270{ 271 static char tmpBuffer[1024]; 272 int len = 0; 273 static Bool newline = TRUE; 274 275 if (newline) { 276 sprintf(tmpBuffer, "[%10.3f] ", GetTimeInMillis() / 1000.0); 277 len = strlen(tmpBuffer); 278 if (logFile) 279 fwrite(tmpBuffer, len, 1, logFile); 280 } 281 282 /* 283 * Since a va_list can only be processed once, write the string to a 284 * buffer, and then write the buffer out to the appropriate output 285 * stream(s). 286 */ 287 if (verb < 0 || logFileVerbosity >= verb || logVerbosity >= verb) { 288 vsnprintf(tmpBuffer, sizeof(tmpBuffer), f, args); 289 len = strlen(tmpBuffer); 290 } 291 newline = (tmpBuffer[len-1] == '\n'); 292 if ((verb < 0 || logVerbosity >= verb) && len > 0) 293 fwrite(tmpBuffer, len, 1, stderr); 294 if ((verb < 0 || logFileVerbosity >= verb) && len > 0) { 295 if (logFile) { 296 fwrite(tmpBuffer, len, 1, logFile); 297 if (logFlush) { 298 fflush(logFile); 299#ifndef WIN32 300 if (logSync) 301 fsync(fileno(logFile)); 302#endif 303 } 304 } else if (needBuffer) { 305 /* 306 * Note, this code is used before OsInit() has been called, so 307 * malloc() and friends can't be used. 308 */ 309 if (len > bufferUnused) { 310 bufferSize += 1024; 311 bufferUnused += 1024; 312 if (saveBuffer) 313 saveBuffer = realloc(saveBuffer, bufferSize); 314 else 315 saveBuffer = malloc(bufferSize); 316 if (!saveBuffer) 317 FatalError("realloc() failed while saving log messages\n"); 318 } 319 bufferUnused -= len; 320 memcpy(saveBuffer + bufferPos, tmpBuffer, len); 321 bufferPos += len; 322 } 323 } 324} 325 326void 327LogWrite(int verb, const char *f, ...) 328{ 329 va_list args; 330 331 va_start(args, f); 332 LogVWrite(verb, f, args); 333 va_end(args); 334} 335 336void 337LogVMessageVerb(MessageType type, int verb, const char *format, va_list args) 338{ 339 const char *s = X_UNKNOWN_STRING; 340 char tmpBuf[1024]; 341 342 /* Ignore verbosity for X_ERROR */ 343 if (logVerbosity >= verb || logFileVerbosity >= verb || type == X_ERROR) { 344 switch (type) { 345 case X_PROBED: 346 s = X_PROBE_STRING; 347 break; 348 case X_CONFIG: 349 s = X_CONFIG_STRING; 350 break; 351 case X_DEFAULT: 352 s = X_DEFAULT_STRING; 353 break; 354 case X_CMDLINE: 355 s = X_CMDLINE_STRING; 356 break; 357 case X_NOTICE: 358 s = X_NOTICE_STRING; 359 break; 360 case X_ERROR: 361 s = X_ERROR_STRING; 362 if (verb > 0) 363 verb = 0; 364 break; 365 case X_WARNING: 366 s = X_WARNING_STRING; 367 break; 368 case X_INFO: 369 s = X_INFO_STRING; 370 break; 371 case X_NOT_IMPLEMENTED: 372 s = X_NOT_IMPLEMENTED_STRING; 373 break; 374 case X_UNKNOWN: 375 s = X_UNKNOWN_STRING; 376 break; 377 case X_NONE: 378 s = NULL; 379 break; 380 } 381 382 /* if s is not NULL we need a space before format */ 383 snprintf(tmpBuf, sizeof(tmpBuf), "%s%s%s", s ? s : "", 384 s ? " " : "", 385 format); 386 LogVWrite(verb, tmpBuf, args); 387 } 388} 389 390/* Log message with verbosity level specified. */ 391void 392LogMessageVerb(MessageType type, int verb, const char *format, ...) 393{ 394 va_list ap; 395 396 va_start(ap, format); 397 LogVMessageVerb(type, verb, format, ap); 398 va_end(ap); 399} 400 401/* Log a message with the standard verbosity level of 1. */ 402void 403LogMessage(MessageType type, const char *format, ...) 404{ 405 va_list ap; 406 407 va_start(ap, format); 408 LogVMessageVerb(type, 1, format, ap); 409 va_end(ap); 410} 411 412void 413AbortServer(void) _X_NORETURN; 414 415void 416AbortServer(void) 417{ 418#ifdef XF86BIGFONT 419 XF86BigfontCleanup(); 420#endif 421 CloseWellKnownConnections(); 422 OsCleanup(TRUE); 423 CloseDownDevices(); 424 AbortDDX(); 425 fflush(stderr); 426 if (CoreDump) 427 OsAbort(); 428 exit (1); 429} 430 431#define AUDIT_PREFIX "AUDIT: %s: %ld: " 432#ifndef AUDIT_TIMEOUT 433#define AUDIT_TIMEOUT ((CARD32)(120 * 1000)) /* 2 mn */ 434#endif 435 436static int nrepeat = 0; 437static int oldlen = -1; 438static OsTimerPtr auditTimer = NULL; 439 440void 441FreeAuditTimer(void) 442{ 443 if (auditTimer != NULL) { 444 /* Force output of pending messages */ 445 TimerForce(auditTimer); 446 TimerFree(auditTimer); 447 auditTimer = NULL; 448 } 449} 450 451static char * 452AuditPrefix(void) 453{ 454 time_t tm; 455 char *autime, *s; 456 char *tmpBuf; 457 int len; 458 459 time(&tm); 460 autime = ctime(&tm); 461 if ((s = strchr(autime, '\n'))) 462 *s = '\0'; 463 len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + 1; 464 tmpBuf = malloc(len); 465 if (!tmpBuf) 466 return NULL; 467 snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long)getpid()); 468 return tmpBuf; 469} 470 471void 472AuditF(const char * f, ...) 473{ 474 va_list args; 475 476 va_start(args, f); 477 478 VAuditF(f, args); 479 va_end(args); 480} 481 482static CARD32 483AuditFlush(OsTimerPtr timer, CARD32 now, pointer arg) 484{ 485 char *prefix; 486 487 if (nrepeat > 0) { 488 prefix = AuditPrefix(); 489 ErrorF("%slast message repeated %d times\n", 490 prefix != NULL ? prefix : "", nrepeat); 491 nrepeat = 0; 492 if (prefix != NULL) 493 free(prefix); 494 return AUDIT_TIMEOUT; 495 } else { 496 /* if the timer expires without anything to print, flush the message */ 497 oldlen = -1; 498 return 0; 499 } 500} 501 502void 503VAuditF(const char *f, va_list args) 504{ 505 char *prefix; 506 char buf[1024]; 507 int len; 508 static char oldbuf[1024]; 509 510 prefix = AuditPrefix(); 511 len = vsnprintf(buf, sizeof(buf), f, args); 512 513 if (len == oldlen && strcmp(buf, oldbuf) == 0) { 514 /* Message already seen */ 515 nrepeat++; 516 } else { 517 /* new message */ 518 if (auditTimer != NULL) 519 TimerForce(auditTimer); 520 ErrorF("%s%s", prefix != NULL ? prefix : "", buf); 521 strlcpy(oldbuf, buf, sizeof(oldbuf)); 522 oldlen = len; 523 nrepeat = 0; 524 auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL); 525 } 526 if (prefix != NULL) 527 free(prefix); 528} 529 530void 531FatalError(const char *f, ...) 532{ 533 va_list args; 534 static Bool beenhere = FALSE; 535 536 if (beenhere) 537 ErrorF("\nFatalError re-entered, aborting\n"); 538 else 539 ErrorF("\nFatal server error:\n"); 540 541 va_start(args, f); 542#ifdef __APPLE__ 543 (void)vsnprintf(__crashreporter_info_buff__, sizeof(__crashreporter_info_buff__), f, args); 544#endif 545 VErrorF(f, args); 546 va_end(args); 547 ErrorF("\n"); 548 if (!beenhere) 549 OsVendorFatalError(); 550 if (!beenhere) { 551 beenhere = TRUE; 552 AbortServer(); 553 } else 554 OsAbort(); 555 /*NOTREACHED*/ 556} 557 558void 559VErrorF(const char *f, va_list args) 560{ 561#ifdef DDXOSVERRORF 562 if (OsVendorVErrorFProc) 563 OsVendorVErrorFProc(f, args); 564 else 565 LogVWrite(-1, f, args); 566#else 567 LogVWrite(-1, f, args); 568#endif 569} 570 571void 572ErrorF(const char * f, ...) 573{ 574 va_list args; 575 576 va_start(args, f); 577 VErrorF(f, args); 578 va_end(args); 579} 580 581/* A perror() workalike. */ 582 583void 584Error(char *str) 585{ 586 char *err = NULL; 587 int saveErrno = errno; 588 589 if (str) { 590 err = malloc(strlen(strerror(saveErrno)) + strlen(str) + 2 + 1); 591 if (!err) 592 return; 593 sprintf(err, "%s: ", str); 594 strcat(err, strerror(saveErrno)); 595 LogWrite(-1, "%s", err); 596 free(err); 597 } else 598 LogWrite(-1, "%s", strerror(saveErrno)); 599} 600 601void 602LogPrintMarkers(void) 603{ 604 /* Show what the message marker symbols mean. */ 605 LogWrite(0, "Markers: "); 606 LogMessageVerb(X_PROBED, 0, "probed, "); 607 LogMessageVerb(X_CONFIG, 0, "from config file, "); 608 LogMessageVerb(X_DEFAULT, 0, "default setting,\n\t"); 609 LogMessageVerb(X_CMDLINE, 0, "from command line, "); 610 LogMessageVerb(X_NOTICE, 0, "notice, "); 611 LogMessageVerb(X_INFO, 0, "informational,\n\t"); 612 LogMessageVerb(X_WARNING, 0, "warning, "); 613 LogMessageVerb(X_ERROR, 0, "error, "); 614 LogMessageVerb(X_NOT_IMPLEMENTED, 0, "not implemented, "); 615 LogMessageVerb(X_UNKNOWN, 0, "unknown.\n"); 616} 617 618