Apply a patch for fixing TDIS-5990 (CVE-2013-1940 allow physically proximate attacker...
[framework/uifw/xorg/server/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         if ((logFile = fopen(logFileName, "w")) == NULL)
220             FatalError("Cannot open log file \"%s\"\n", logFileName);
221         setvbuf(logFile, NULL, _IONBF, 0);
222
223         logFileFd = fileno(logFile);
224
225         /* Flush saved log information. */
226         if (saveBuffer && bufferSize > 0) {
227             fwrite(saveBuffer, bufferPos, 1, logFile);
228             fflush(logFile);
229 #ifndef WIN32
230             fsync(fileno(logFile));
231 #endif
232         }
233     }
234
235     /*
236      * Unconditionally free the buffer, and flag that the buffer is no longer
237      * needed.
238      */
239     if (saveBuffer && bufferSize > 0) {
240         free(saveBuffer);
241         saveBuffer = NULL;
242         bufferSize = 0;
243     }
244     needBuffer = FALSE;
245
246     return logFileName;
247 }
248
249 void
250 LogClose(enum ExitCode error)
251 {
252     if (logFile) {
253         ErrorF("Server terminated %s (%d). Closing log file.\n",
254                (error == EXIT_NO_ERROR) ? "successfully" : "with error", error);
255         fclose(logFile);
256         logFile = NULL;
257         logFileFd = -1;
258     }
259 }
260
261 Bool
262 LogSetParameter(LogParameter param, int value)
263 {
264     switch (param) {
265     case XLOG_FLUSH:
266         logFlush = value ? TRUE : FALSE;
267         return TRUE;
268     case XLOG_SYNC:
269         logSync = value ? TRUE : FALSE;
270         return TRUE;
271     case XLOG_VERBOSITY:
272         logVerbosity = value;
273         return TRUE;
274     case XLOG_FILE_VERBOSITY:
275         logFileVerbosity = value;
276         return TRUE;
277     default:
278         return FALSE;
279     }
280 }
281
282 static int
283 pnprintf(char *string, size_t size, const char *f, va_list args)
284 {
285     int f_idx = 0;
286     int s_idx = 0;
287     int f_len = strlen_sigsafe(f);
288     char *string_arg;
289     char number[21];
290     int p_len;
291     int i;
292     uint64_t ui;
293     int64_t si;
294
295     for (; f_idx < f_len && s_idx < size - 1; f_idx++) {
296         if (f[f_idx] != '%') {
297             string[s_idx++] = f[f_idx];
298             continue;
299         }
300
301         switch (f[++f_idx]) {
302         case 's':
303             string_arg = va_arg(args, char*);
304             p_len = strlen_sigsafe(string_arg);
305
306             for (i = 0; i < p_len && s_idx < size - 1; i++)
307                 string[s_idx++] = string_arg[i];
308             break;
309
310         case 'u':
311             ui = va_arg(args, unsigned);
312             FormatUInt64(ui, number);
313             p_len = strlen_sigsafe(number);
314
315             for (i = 0; i < p_len && s_idx < size - 1; i++)
316                 string[s_idx++] = number[i];
317             break;
318         case 'i':
319         case 'd':
320             si = va_arg(args, int);
321             FormatInt64(si, number);
322             p_len = strlen_sigsafe(number);
323
324             for (i = 0; i < p_len && s_idx < size - 1; i++)
325                 string[s_idx++] = number[i];
326             break;
327
328         case 'p':
329             string[s_idx++] = '0';
330             if (s_idx < size - 1)
331                 string[s_idx++] = 'x';
332             ui = (uintptr_t)va_arg(args, void*);
333             FormatUInt64Hex(ui, number);
334             p_len = strlen_sigsafe(number);
335
336             for (i = 0; i < p_len && s_idx < size - 1; i++)
337                 string[s_idx++] = number[i];
338             break;
339
340         case 'x':
341             ui = va_arg(args, unsigned);
342             FormatUInt64Hex(ui, number);
343             p_len = strlen_sigsafe(number);
344
345             for (i = 0; i < p_len && s_idx < size - 1; i++)
346                 string[s_idx++] = number[i];
347             break;
348
349         default:
350             va_arg(args, char*);
351             string[s_idx++] = '%';
352             if (s_idx < size - 1)
353                 string[s_idx++] = f[f_idx];
354             break;
355         }
356     }
357
358     string[s_idx] = '\0';
359
360     return s_idx;
361 }
362
363 /* This function does the actual log message writes. It must be signal safe.
364  * When attempting to call non-signal-safe functions, guard them with a check
365  * of the inSignalContext global variable. */
366 static void
367 LogSWrite(int verb, const char *buf, size_t len, Bool end_line)
368 {
369     static Bool newline = TRUE;
370
371     if (verb < 0 || logVerbosity >= verb)
372         write(2, buf, len);
373
374     if (verb < 0 || logFileVerbosity >= verb) {
375         if (inSignalContext && logFileFd >= 0) {
376             write(logFileFd, buf, len);
377 #ifndef WIN32
378             if (logFlush && logSync)
379                 fsync(logFileFd);
380 #endif
381         }
382         else if (!inSignalContext && logFile) {
383             if (newline)
384                 fprintf(logFile, "[%10.3f] ", GetTimeInMillis() / 1000.0);
385             newline = end_line;
386             fwrite(buf, len, 1, logFile);
387             if (logFlush) {
388                 fflush(logFile);
389 #ifndef WIN32
390                 if (logSync)
391                     fsync(fileno(logFile));
392 #endif
393             }
394         }
395         else if (!inSignalContext && needBuffer) {
396             if (len > bufferUnused) {
397                 bufferSize += 1024;
398                 bufferUnused += 1024;
399                 saveBuffer = realloc(saveBuffer, bufferSize);
400                 if (!saveBuffer)
401                     FatalError("realloc() failed while saving log messages\n");
402             }
403             bufferUnused -= len;
404             memcpy(saveBuffer + bufferPos, buf, len);
405             bufferPos += len;
406         }
407     }
408 }
409
410 void
411 LogVWrite(int verb, const char *f, va_list args)
412 {
413     return LogVMessageVerb(X_NONE, verb, f, args);
414 }
415
416 void
417 LogWrite(int verb, const char *f, ...)
418 {
419     va_list args;
420
421     va_start(args, f);
422     LogVWrite(verb, f, args);
423     va_end(args);
424 }
425
426 /* Returns the Message Type string to prepend to a logging message, or NULL
427  * if the message will be dropped due to insufficient verbosity. */
428 static const char *
429 LogMessageTypeVerbString(MessageType type, int verb)
430 {
431     if (type == X_ERROR)
432         verb = 0;
433
434     if (logVerbosity < verb && logFileVerbosity < verb)
435         return NULL;
436
437     switch (type) {
438     case X_PROBED:
439         return X_PROBE_STRING;
440     case X_CONFIG:
441         return X_CONFIG_STRING;
442     case X_DEFAULT:
443         return X_DEFAULT_STRING;
444     case X_CMDLINE:
445         return X_CMDLINE_STRING;
446     case X_NOTICE:
447         return X_NOTICE_STRING;
448     case X_ERROR:
449         return X_ERROR_STRING;
450     case X_WARNING:
451         return X_WARNING_STRING;
452     case X_INFO:
453         return X_INFO_STRING;
454     case X_NOT_IMPLEMENTED:
455         return X_NOT_IMPLEMENTED_STRING;
456     case X_UNKNOWN:
457         return X_UNKNOWN_STRING;
458     case X_NONE:
459         return X_NONE_STRING;
460     case X_DEBUG:
461         return X_DEBUG_STRING;
462     default:
463         return X_UNKNOWN_STRING;
464     }
465 }
466
467 void
468 LogVMessageVerb(MessageType type, int verb, const char *format, va_list args)
469 {
470     static unsigned int warned;
471     const char *type_str;
472     char buf[1024];
473     const size_t size = sizeof(buf);
474     Bool newline;
475     size_t len = 0;
476
477     if (inSignalContext) {
478         if (warned < 3) {
479             BUG_WARN_MSG(inSignalContext,
480                          "Warning: attempting to log data in a signal unsafe "
481                          "manner while in signal context.\nPlease update to check "
482                          "inSignalContext and/or use LogMessageVerbSigSafe() or "
483                          "ErrorFSigSafe().\nThe offending log format message is:\n"
484                          "%s\n", format);
485             warned++;
486             if (warned == 3)
487                 LogMessageVerbSigSafe(X_WARNING, -1, "Warned %u times about sigsafe logging. Will be quiet now.\n", warned);
488         }
489     }
490
491     type_str = LogMessageTypeVerbString(type, verb);
492     if (!type_str)
493         return;
494
495     /* if type_str is not "", prepend it and ' ', to message */
496     if (type_str[0] != '\0')
497         len += Xscnprintf(&buf[len], size - len, "%s ", type_str);
498
499     if (size - len > 1)
500         len += Xvscnprintf(&buf[len], size - len, format, args);
501
502     /* Force '\n' at end of truncated line */
503     if (size - len == 1)
504         buf[len - 1] = '\n';
505
506     newline = (buf[len - 1] == '\n');
507     LogSWrite(verb, buf, len, newline);
508 }
509
510 /* Log message with verbosity level specified. */
511 void
512 LogMessageVerb(MessageType type, int verb, const char *format, ...)
513 {
514     va_list ap;
515
516     va_start(ap, format);
517     LogVMessageVerb(type, verb, format, ap);
518     va_end(ap);
519 }
520
521 /* Log a message with the standard verbosity level of 1. */
522 void
523 LogMessage(MessageType type, const char *format, ...)
524 {
525     va_list ap;
526
527     va_start(ap, format);
528     LogVMessageVerb(type, 1, format, ap);
529     va_end(ap);
530 }
531
532 /* Log a message using only signal safe functions. */
533 void
534 LogMessageVerbSigSafe(MessageType type, int verb, const char *format, ...)
535 {
536     va_list ap;
537     va_start(ap, format);
538     LogVMessageVerbSigSafe(type, verb, format, ap);
539     va_end(ap);
540 }
541
542 void
543 LogVMessageVerbSigSafe(MessageType type, int verb, const char *format, va_list args)
544 {
545     const char *type_str;
546     char buf[1024];
547     int len;
548     Bool newline;
549
550     type_str = LogMessageTypeVerbString(type, verb);
551     if (!type_str)
552         return;
553
554     /* if type_str is not "", prepend it and ' ', to message */
555     if (type_str[0] != '\0') {
556         LogSWrite(verb, type_str, strlen_sigsafe(type_str), FALSE);
557         LogSWrite(verb, " ", 1, FALSE);
558     }
559
560     len = pnprintf(buf, sizeof(buf), format, args);
561
562     /* Force '\n' at end of truncated line */
563     if (sizeof(buf) - len == 1)
564         buf[len - 1] = '\n';
565
566     newline = (buf[len - 1] == '\n');
567     LogSWrite(verb, buf, len, newline);
568 }
569
570 void
571 LogVHdrMessageVerb(MessageType type, int verb, const char *msg_format,
572                    va_list msg_args, const char *hdr_format, va_list hdr_args)
573 {
574     static unsigned int warned;
575     const char *type_str;
576     char buf[1024];
577     const size_t size = sizeof(buf);
578     Bool newline;
579     size_t len = 0;
580
581     if (inSignalContext) {
582         if (warned < 3) {
583             BUG_WARN_MSG(inSignalContext,
584                          "Warning: attempting to log data in a signal unsafe "
585                          "manner while in signal context.\nPlease update to check "
586                          "inSignalContext and/or use LogMessageVerbSigSafe().\nThe "
587                          "offending header and log message formats are:\n%s %s\n",
588                          hdr_format, msg_format);
589             warned++;
590             if (warned == 3)
591                 LogMessageVerbSigSafe(X_WARNING, -1, "Warned %u times about sigsafe logging. Will be quiet now.\n", warned);
592         }
593     }
594
595     type_str = LogMessageTypeVerbString(type, verb);
596     if (!type_str)
597         return;
598
599     /* if type_str is not "", prepend it and ' ', to message */
600     if (type_str[0] != '\0')
601         len += Xscnprintf(&buf[len], size - len, "%s ", type_str);
602
603     if (hdr_format && size - len > 1)
604         len += Xvscnprintf(&buf[len], size - len, hdr_format, hdr_args);
605
606     if (msg_format && size - len > 1)
607         len += Xvscnprintf(&buf[len], size - len, msg_format, msg_args);
608
609     /* Force '\n' at end of truncated line */
610     if (size - len == 1)
611         buf[len - 1] = '\n';
612
613     newline = (buf[len - 1] == '\n');
614     LogSWrite(verb, buf, len, newline);
615 }
616
617 void
618 LogHdrMessageVerb(MessageType type, int verb, const char *msg_format,
619                   va_list msg_args, const char *hdr_format, ...)
620 {
621     va_list hdr_args;
622
623     va_start(hdr_args, hdr_format);
624     LogVHdrMessageVerb(type, verb, msg_format, msg_args, hdr_format, hdr_args);
625     va_end(hdr_args);
626 }
627
628 void
629 LogHdrMessage(MessageType type, const char *msg_format, va_list msg_args,
630               const char *hdr_format, ...)
631 {
632     va_list hdr_args;
633
634     va_start(hdr_args, hdr_format);
635     LogVHdrMessageVerb(type, 1, msg_format, msg_args, hdr_format, hdr_args);
636     va_end(hdr_args);
637 }
638
639 void
640 AbortServer(void)
641     _X_NORETURN;
642
643 void
644 AbortServer(void)
645 {
646 #ifdef XF86BIGFONT
647     XF86BigfontCleanup();
648 #endif
649     CloseWellKnownConnections();
650     OsCleanup(TRUE);
651     CloseDownDevices();
652     AbortDDX(EXIT_ERR_ABORT);
653     fflush(stderr);
654     if (CoreDump)
655         OsAbort();
656     exit(1);
657 }
658
659 #define AUDIT_PREFIX "AUDIT: %s: %ld: "
660 #ifndef AUDIT_TIMEOUT
661 #define AUDIT_TIMEOUT ((CARD32)(120 * 1000))    /* 2 mn */
662 #endif
663
664 static int nrepeat = 0;
665 static int oldlen = -1;
666 static OsTimerPtr auditTimer = NULL;
667
668 void
669 FreeAuditTimer(void)
670 {
671     if (auditTimer != NULL) {
672         /* Force output of pending messages */
673         TimerForce(auditTimer);
674         TimerFree(auditTimer);
675         auditTimer = NULL;
676     }
677 }
678
679 static char *
680 AuditPrefix(void)
681 {
682     time_t tm;
683     char *autime, *s;
684     char *tmpBuf;
685     int len;
686
687     time(&tm);
688     autime = ctime(&tm);
689     if ((s = strchr(autime, '\n')))
690         *s = '\0';
691     len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + 1;
692     tmpBuf = malloc(len);
693     if (!tmpBuf)
694         return NULL;
695     snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long) getpid());
696     return tmpBuf;
697 }
698
699 void
700 AuditF(const char *f, ...)
701 {
702     va_list args;
703
704     va_start(args, f);
705
706     VAuditF(f, args);
707     va_end(args);
708 }
709
710 static CARD32
711 AuditFlush(OsTimerPtr timer, CARD32 now, pointer arg)
712 {
713     char *prefix;
714
715     if (nrepeat > 0) {
716         prefix = AuditPrefix();
717         ErrorF("%slast message repeated %d times\n",
718                prefix != NULL ? prefix : "", nrepeat);
719         nrepeat = 0;
720         free(prefix);
721         return AUDIT_TIMEOUT;
722     }
723     else {
724         /* if the timer expires without anything to print, flush the message */
725         oldlen = -1;
726         return 0;
727     }
728 }
729
730 void
731 VAuditF(const char *f, va_list args)
732 {
733     char *prefix;
734     char buf[1024];
735     int len;
736     static char oldbuf[1024];
737
738     prefix = AuditPrefix();
739     len = vsnprintf(buf, sizeof(buf), f, args);
740
741     if (len == oldlen && strcmp(buf, oldbuf) == 0) {
742         /* Message already seen */
743         nrepeat++;
744     }
745     else {
746         /* new message */
747         if (auditTimer != NULL)
748             TimerForce(auditTimer);
749         ErrorF("%s%s", prefix != NULL ? prefix : "", buf);
750         strlcpy(oldbuf, buf, sizeof(oldbuf));
751         oldlen = len;
752         nrepeat = 0;
753         auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL);
754     }
755     free(prefix);
756 }
757
758 void
759 FatalError(const char *f, ...)
760 {
761     va_list args;
762     va_list args2;
763     static Bool beenhere = FALSE;
764
765     if (beenhere)
766         ErrorF("\nFatalError re-entered, aborting\n");
767     else
768         ErrorF("\nFatal server error:\n");
769
770     va_start(args, f);
771
772     /* Make a copy for OsVendorFatalError */
773     va_copy(args2, args);
774
775 #ifdef __APPLE__
776     {
777         va_list apple_args;
778
779         va_copy(apple_args, args);
780         (void)vsnprintf(__crashreporter_info_buff__,
781                         sizeof(__crashreporter_info_buff__), f, apple_args);
782         va_end(apple_args);
783     }
784 #endif
785     VErrorF(f, args);
786     va_end(args);
787     ErrorF("\n");
788     if (!beenhere)
789         OsVendorFatalError(f, args2);
790     va_end(args2);
791     if (!beenhere) {
792         beenhere = TRUE;
793         AbortServer();
794     }
795     else
796         OsAbort();
797  /*NOTREACHED*/}
798
799 void
800 VErrorF(const char *f, va_list args)
801 {
802 #ifdef DDXOSVERRORF
803     if (OsVendorVErrorFProc)
804         OsVendorVErrorFProc(f, args);
805     else
806         LogVWrite(-1, f, args);
807 #else
808     LogVWrite(-1, f, args);
809 #endif
810 }
811
812 void
813 ErrorF(const char *f, ...)
814 {
815     va_list args;
816
817     va_start(args, f);
818     VErrorF(f, args);
819     va_end(args);
820 }
821
822 void
823 VErrorFSigSafe(const char *f, va_list args)
824 {
825     LogVMessageVerbSigSafe(X_ERROR, -1, f, args);
826 }
827
828 void
829 ErrorFSigSafe(const char *f, ...)
830 {
831     va_list args;
832
833     va_start(args, f);
834     VErrorFSigSafe(f, args);
835     va_end(args);
836 }
837
838 void
839 LogPrintMarkers(void)
840 {
841     /* Show what the message marker symbols mean. */
842     LogWrite(0, "Markers: ");
843     LogMessageVerb(X_PROBED, 0, "probed, ");
844     LogMessageVerb(X_CONFIG, 0, "from config file, ");
845     LogMessageVerb(X_DEFAULT, 0, "default setting,\n\t");
846     LogMessageVerb(X_CMDLINE, 0, "from command line, ");
847     LogMessageVerb(X_NOTICE, 0, "notice, ");
848     LogMessageVerb(X_INFO, 0, "informational,\n\t");
849     LogMessageVerb(X_WARNING, 0, "warning, ");
850     LogMessageVerb(X_ERROR, 0, "error, ");
851     LogMessageVerb(X_NOT_IMPLEMENTED, 0, "not implemented, ");
852     LogMessageVerb(X_UNKNOWN, 0, "unknown.\n");
853 }