Imported Upstream version 1.15.1
[deb_xorg-server.git] / os / log.c
CommitLineData
a09e091a
JB
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
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
107void (*OsVendorVErrorFProc) (const char *, va_list args) = NULL;
108#endif
109
110static FILE *logFile = NULL;
111static int logFileFd = -1;
112static Bool logFlush = FALSE;
113static Bool logSync = FALSE;
114static int logVerbosity = DEFAULT_LOG_VERBOSITY;
115static int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY;
116
117/* Buffer to information logged before the log file is opened. */
118static char *saveBuffer = NULL;
119static int bufferSize = 0, bufferUnused = 0, bufferPos = 0;
120static Bool needBuffer = TRUE;
121
122#ifdef __APPLE__
123#include <AvailabilityMacros.h>
124
125static char __crashreporter_info_buff__[4096] = { 0 };
126
127static 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)
133asm(".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
175static size_t
176strlen_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
192const char *
193LogInit(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
252void
253LogClose(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
264Bool
265LogSetParameter(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
285enum {
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 */
298static 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
329out:
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 */
338static int
339pnprintf(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. */
484static void
485LogSWrite(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
528void
529LogVWrite(int verb, const char *f, va_list args)
530{
531 return LogVMessageVerb(X_NONE, verb, f, args);
532}
533
534void
535LogWrite(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. */
546static const char *
547LogMessageTypeVerbString(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
585void
586LogVMessageVerb(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. */
629void
630LogMessageVerb(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. */
640void
641LogMessage(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. */
651void
652LogMessageVerbSigSafe(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
660void
661LogVMessageVerbSigSafe(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
688void
689LogVHdrMessageVerb(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
735void
736LogHdrMessageVerb(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
746void
747LogHdrMessage(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
757void
758AbortServer(void)
759 _X_NORETURN;
760
761void
762AbortServer(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
782static int nrepeat = 0;
783static int oldlen = -1;
784static OsTimerPtr auditTimer = NULL;
785
786void
787FreeAuditTimer(void)
788{
789 if (auditTimer != NULL) {
790 /* Force output of pending messages */
791 TimerForce(auditTimer);
792 TimerFree(auditTimer);
793 auditTimer = NULL;
794 }
795}
796
797static char *
798AuditPrefix(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
817void
818AuditF(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
828static CARD32
829AuditFlush(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
848void
849VAuditF(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
876void
877FatalError(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
917void
918VErrorF(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
930void
931ErrorF(const char *f, ...)
932{
933 va_list args;
934
935 va_start(args, f);
936 VErrorF(f, args);
937 va_end(args);
938}
939
940void
941VErrorFSigSafe(const char *f, va_list args)
942{
943 LogVMessageVerbSigSafe(X_ERROR, -1, f, args);
944}
945
946void
947ErrorFSigSafe(const char *f, ...)
948{
949 va_list args;
950
951 va_start(args, f);
952 VErrorFSigSafe(f, args);
953 va_end(args);
954}
955
956void
957LogPrintMarkers(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}