Add patch that contain Mali fixes.
[deb_xorg-server.git] / os / log.c
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 }