log.c 17.7 KB
Newer Older
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/*

Copyright 1987, 1998  The Open Group

Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of The Open Group shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from The Open Group.

Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
Copyright 1994 Quarterdeck Office Systems.

                        All Rights Reserved

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Digital and
Quarterdeck not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.

DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
OR PERFORMANCE OF THIS SOFTWARE.

*/

/*
 * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of the copyright holder(s)
 * and author(s) shall not be used in advertising or otherwise to promote
 * the sale, use or other dealings in this Software without prior written
 * authorization from the copyright holder(s) and author(s).
 */

78
79
80
81
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif

82
#include <X11/Xos.h>
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
83
84
85
86
#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
#include <stdarg.h>
87
#include <stdlib.h>             /* for malloc() */
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
88

89
#include "input.h"
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
90
91
92
#include "site.h"
#include "opaque.h"

93
94
95
96
97
#ifdef WIN32
#include <process.h>
#define getpid(x) _getpid(x)
#endif

98
#ifdef XF86BIGFONT
99
#include "xf86bigfontsrv.h"
100
#endif
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
101

102
103
104
105
#ifdef __clang__
#pragma clang diagnostic ignored "-Wformat-nonliteral"
#endif

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
106
#ifdef DDXOSVERRORF
107
void (*OsVendorVErrorFProc) (const char *, va_list args) = NULL;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
108
109
110
#endif

static FILE *logFile = NULL;
111
static int logFileFd = -1;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
112
113
114
115
116
117
118
119
120
121
static Bool logFlush = FALSE;
static Bool logSync = FALSE;
static int logVerbosity = DEFAULT_LOG_VERBOSITY;
static int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY;

/* Buffer to information logged before the log file is opened. */
static char *saveBuffer = NULL;
static int bufferSize = 0, bufferUnused = 0, bufferPos = 0;
static Bool needBuffer = TRUE;

122
#ifdef __APPLE__
123
124
#include <AvailabilityMacros.h>

125
126
127
128
static char __crashreporter_info_buff__[4096] = { 0 };

static const char *__crashreporter_info__ __attribute__ ((__used__)) =
    &__crashreporter_info_buff__[0];
129
130
131
132
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
// This is actually a toolchain requirement, but I'm not sure the correct check,        
// but it should be fine to just only include it for Leopard and later.  This line
// 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

Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* Prefix strings for log messages. */
#ifndef X_UNKNOWN_STRING
#define X_UNKNOWN_STRING		"(\?\?)"
#endif
#ifndef X_PROBE_STRING
#define X_PROBE_STRING			"(--)"
#endif
#ifndef X_CONFIG_STRING
#define X_CONFIG_STRING			"(**)"
#endif
#ifndef X_DEFAULT_STRING
#define X_DEFAULT_STRING		"(==)"
#endif
#ifndef X_CMDLINE_STRING
#define X_CMDLINE_STRING		"(++)"
#endif
#ifndef X_NOTICE_STRING
#define X_NOTICE_STRING			"(!!)"
#endif
#ifndef X_ERROR_STRING
#define X_ERROR_STRING			"(EE)"
#endif
#ifndef X_WARNING_STRING
#define X_WARNING_STRING		"(WW)"
#endif
#ifndef X_INFO_STRING
#define X_INFO_STRING			"(II)"
#endif
#ifndef X_NOT_IMPLEMENTED_STRING
#define X_NOT_IMPLEMENTED_STRING	"(NI)"
#endif
168
169
170
#ifndef X_DEBUG_STRING
#define X_DEBUG_STRING			"(DB)"
#endif
171
#ifndef X_NONE_STRING
Daniel Kurtz's avatar
Daniel Kurtz committed
172
#define X_NONE_STRING			""
173
#endif
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
174
175
176
177
178
179
180
181
182
183

/*
 * LogInit is called to start logging to a file.  It is also called (with
 * NULL arguments) when logging to a file is not wanted.  It must always be
 * called, otherwise log messages will continue to accumulate in a buffer.
 *
 * %s, if present in the fname or backup strings, is expanded to the display
 * string.
 */

184
const char *
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
185
186
187
188
189
LogInit(const char *fname, const char *backup)
{
    char *logFileName = NULL;

    if (fname && *fname) {
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
        if (asprintf(&logFileName, fname, display) == -1)
            FatalError("Cannot allocate space for the log file name\n");

        if (backup && *backup) {
            struct stat buf;

            if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) {
                char *suffix;
                char *oldLog;

                if ((asprintf(&suffix, backup, display) == -1) ||
                    (asprintf(&oldLog, "%s%s", logFileName, suffix) == -1))
                    FatalError("Cannot allocate space for the log file name\n");
                free(suffix);
                if (rename(logFileName, oldLog) == -1) {
                    FatalError("Cannot move old log file \"%s\" to \"%s\"\n",
                               logFileName, oldLog);
                }
                free(oldLog);
            }
        }
        if ((logFile = fopen(logFileName, "w")) == NULL)
            FatalError("Cannot open log file \"%s\"\n", logFileName);
        setvbuf(logFile, NULL, _IONBF, 0);

215
216
        logFileFd = fileno(logFile);

217
218
219
220
        /* Flush saved log information. */
        if (saveBuffer && bufferSize > 0) {
            fwrite(saveBuffer, bufferPos, 1, logFile);
            fflush(logFile);
221
#ifndef WIN32
222
            fsync(fileno(logFile));
223
#endif
224
        }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
225
226
227
228
229
230
231
    }

    /*
     * Unconditionally free the buffer, and flag that the buffer is no longer
     * needed.
     */
    if (saveBuffer && bufferSize > 0) {
Daniel Kurtz's avatar
Daniel Kurtz committed
232
        free(saveBuffer);
233
234
        saveBuffer = NULL;
        bufferSize = 0;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
235
236
237
238
239
240
    }
    needBuffer = FALSE;

    return logFileName;
}

241
void
242
LogClose(enum ExitCode error)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
243
244
{
    if (logFile) {
245
246
247
248
        ErrorF("Server terminated %s (%d). Closing log file.\n",
               (error == EXIT_NO_ERROR) ? "successfully" : "with error", error);
        fclose(logFile);
        logFile = NULL;
249
        logFileFd = -1;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
250
251
252
    }
}

253
Bool
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
254
255
256
257
LogSetParameter(LogParameter param, int value)
{
    switch (param) {
    case XLOG_FLUSH:
258
259
        logFlush = value ? TRUE : FALSE;
        return TRUE;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
260
    case XLOG_SYNC:
261
262
        logSync = value ? TRUE : FALSE;
        return TRUE;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
263
    case XLOG_VERBOSITY:
264
265
        logVerbosity = value;
        return TRUE;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
266
    case XLOG_FILE_VERBOSITY:
267
268
        logFileVerbosity = value;
        return TRUE;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
269
    default:
270
        return FALSE;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
271
272
273
274
    }
}

/* This function does the actual log message writes. */
Daniel Kurtz's avatar
Daniel Kurtz committed
275
276
static void
LogSWrite(int verb, const char *buf, size_t len, Bool end_line)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
277
{
278
279
    static Bool newline = TRUE;

Daniel Kurtz's avatar
Daniel Kurtz committed
280
281
282
    if (verb < 0 || logVerbosity >= verb)
        fwrite(buf, len, 1, stderr);
    if (verb < 0 || logFileVerbosity >= verb) {
283
        if (logFile) {
284
285
            if (newline)
                fprintf(logFile, "[%10.3f] ", GetTimeInMillis() / 1000.0);
Daniel Kurtz's avatar
Daniel Kurtz committed
286
287
            newline = end_line;
            fwrite(buf, len, 1, logFile);
288
289
            if (logFlush) {
                fflush(logFile);
290
#ifndef WIN32
291
292
                if (logSync)
                    fsync(fileno(logFile));
293
#endif
294
295
296
297
298
299
300
301
302
303
304
            }
        }
        else if (needBuffer) {
            if (len > bufferUnused) {
                bufferSize += 1024;
                bufferUnused += 1024;
                saveBuffer = realloc(saveBuffer, bufferSize);
                if (!saveBuffer)
                    FatalError("realloc() failed while saving log messages\n");
            }
            bufferUnused -= len;
Daniel Kurtz's avatar
Daniel Kurtz committed
305
            memcpy(saveBuffer + bufferPos, buf, len);
306
307
            bufferPos += len;
        }
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
308
309
310
    }
}

Daniel Kurtz's avatar
Daniel Kurtz committed
311
312
313
314
315
316
void
LogVWrite(int verb, const char *f, va_list args)
{
    return LogVMessageVerb(X_NONE, verb, f, args);
}

317
void
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
318
319
320
321
322
323
324
325
326
LogWrite(int verb, const char *f, ...)
{
    va_list args;

    va_start(args, f);
    LogVWrite(verb, f, args);
    va_end(args);
}

327
328
329
330
331
332
/* Returns the Message Type string to prepend to a logging message, or NULL
 * if the message will be dropped due to insufficient verbosity. */
static const char *
LogMessageTypeVerbString(MessageType type, int verb)
{
    if (type == X_ERROR)
333
        verb = 0;
334
335

    if (logVerbosity < verb && logFileVerbosity < verb)
336
        return NULL;
337
338
339

    switch (type) {
    case X_PROBED:
340
        return X_PROBE_STRING;
341
    case X_CONFIG:
342
        return X_CONFIG_STRING;
343
    case X_DEFAULT:
344
        return X_DEFAULT_STRING;
345
    case X_CMDLINE:
346
        return X_CMDLINE_STRING;
347
    case X_NOTICE:
348
        return X_NOTICE_STRING;
349
    case X_ERROR:
350
        return X_ERROR_STRING;
351
    case X_WARNING:
352
        return X_WARNING_STRING;
353
    case X_INFO:
354
        return X_INFO_STRING;
355
    case X_NOT_IMPLEMENTED:
356
        return X_NOT_IMPLEMENTED_STRING;
357
    case X_UNKNOWN:
358
        return X_UNKNOWN_STRING;
359
    case X_NONE:
360
        return X_NONE_STRING;
361
362
    case X_DEBUG:
        return X_DEBUG_STRING;
363
    default:
364
        return X_UNKNOWN_STRING;
365
366
367
    }
}

368
void
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
369
370
LogVMessageVerb(MessageType type, int verb, const char *format, va_list args)
{
371
    const char *type_str;
Daniel Kurtz's avatar
Daniel Kurtz committed
372
373
374
375
    char buf[1024];
    const size_t size = sizeof(buf);
    Bool newline;
    size_t len = 0;
376
377
378

    type_str = LogMessageTypeVerbString(type, verb);
    if (!type_str)
379
        return;
380

Daniel Kurtz's avatar
Daniel Kurtz committed
381
382
383
384
385
386
    /* if type_str is not "", prepend it and ' ', to message */
    if (type_str[0] != '\0')
        len += Xscnprintf(&buf[len], size - len, "%s ", type_str);

    if (size - len > 1)
        len += Xvscnprintf(&buf[len], size - len, format, args);
387

Daniel Kurtz's avatar
Daniel Kurtz committed
388
389
390
391
392
393
    /* Force '\n' at end of truncated line */
    if (size - len == 1)
        buf[len - 1] = '\n';

    newline = (buf[len - 1] == '\n');
    LogSWrite(verb, buf, len, newline);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
394
395
396
}

/* Log message with verbosity level specified. */
397
void
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
398
399
400
401
402
403
404
405
406
407
LogMessageVerb(MessageType type, int verb, const char *format, ...)
{
    va_list ap;

    va_start(ap, format);
    LogVMessageVerb(type, verb, format, ap);
    va_end(ap);
}

/* Log a message with the standard verbosity level of 1. */
408
void
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
409
410
411
412
413
414
415
416
417
LogMessage(MessageType type, const char *format, ...)
{
    va_list ap;

    va_start(ap, format);
    LogVMessageVerb(type, 1, format, ap);
    va_end(ap);
}

418
419
void
LogVHdrMessageVerb(MessageType type, int verb, const char *msg_format,
420
                   va_list msg_args, const char *hdr_format, va_list hdr_args)
421
422
{
    const char *type_str;
Daniel Kurtz's avatar
Daniel Kurtz committed
423
424
425
426
    char buf[1024];
    const size_t size = sizeof(buf);
    Bool newline;
    size_t len = 0;
427
428
429

    type_str = LogMessageTypeVerbString(type, verb);
    if (!type_str)
430
        return;
431

Daniel Kurtz's avatar
Daniel Kurtz committed
432
    /* if type_str is not "", prepend it and ' ', to message */
433
    if (type_str[0] != '\0')
Daniel Kurtz's avatar
Daniel Kurtz committed
434
435
436
437
        len += Xscnprintf(&buf[len], size - len, "%s ", type_str);

    if (hdr_format && size - len > 1)
        len += Xvscnprintf(&buf[len], size - len, hdr_format, hdr_args);
438

Daniel Kurtz's avatar
Daniel Kurtz committed
439
440
    if (msg_format && size - len > 1)
        len += Xvscnprintf(&buf[len], size - len, msg_format, msg_args);
441

Daniel Kurtz's avatar
Daniel Kurtz committed
442
443
444
    /* Force '\n' at end of truncated line */
    if (size - len == 1)
        buf[len - 1] = '\n';
445

Daniel Kurtz's avatar
Daniel Kurtz committed
446
447
    newline = (buf[len - 1] == '\n');
    LogSWrite(verb, buf, len, newline);
448
449
450
451
}

void
LogHdrMessageVerb(MessageType type, int verb, const char *msg_format,
452
                  va_list msg_args, const char *hdr_format, ...)
453
454
455
456
457
458
459
460
461
462
{
    va_list hdr_args;

    va_start(hdr_args, hdr_format);
    LogVHdrMessageVerb(type, verb, msg_format, msg_args, hdr_format, hdr_args);
    va_end(hdr_args);
}

void
LogHdrMessage(MessageType type, const char *msg_format, va_list msg_args,
463
              const char *hdr_format, ...)
464
465
466
467
468
469
470
471
{
    va_list hdr_args;

    va_start(hdr_args, hdr_format);
    LogVHdrMessageVerb(type, 1, msg_format, msg_args, hdr_format, hdr_args);
    va_end(hdr_args);
}

472
void
473
474
AbortServer(void)
    _X_NORETURN;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
475

476
void
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
477
478
AbortServer(void)
{
479
480
481
#ifdef XF86BIGFONT
    XF86BigfontCleanup();
#endif
482
    CloseWellKnownConnections();
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
483
    OsCleanup(TRUE);
484
    CloseDownDevices();
485
    AbortDDX(EXIT_ERR_ABORT);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
486
487
    fflush(stderr);
    if (CoreDump)
488
489
        OsAbort();
    exit(1);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
490
491
}

492
#define AUDIT_PREFIX "AUDIT: %s: %ld: "
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
493
#ifndef AUDIT_TIMEOUT
494
#define AUDIT_TIMEOUT ((CARD32)(120 * 1000))    /* 2 mn */
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
495
496
497
498
499
500
#endif

static int nrepeat = 0;
static int oldlen = -1;
static OsTimerPtr auditTimer = NULL;

501
void
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
502
503
504
FreeAuditTimer(void)
{
    if (auditTimer != NULL) {
505
506
507
508
        /* Force output of pending messages */
        TimerForce(auditTimer);
        TimerFree(auditTimer);
        auditTimer = NULL;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
509
510
511
512
513
514
515
516
517
518
519
520
521
522
    }
}

static char *
AuditPrefix(void)
{
    time_t tm;
    char *autime, *s;
    char *tmpBuf;
    int len;

    time(&tm);
    autime = ctime(&tm);
    if ((s = strchr(autime, '\n')))
523
        *s = '\0';
524
    len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + 1;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
525
526
    tmpBuf = malloc(len);
    if (!tmpBuf)
527
528
        return NULL;
    snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long) getpid());
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
529
530
531
    return tmpBuf;
}

532
void
533
AuditF(const char *f, ...)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
{
    va_list args;

    va_start(args, f);

    VAuditF(f, args);
    va_end(args);
}

static CARD32
AuditFlush(OsTimerPtr timer, CARD32 now, pointer arg)
{
    char *prefix;

    if (nrepeat > 0) {
549
550
551
552
553
554
555
556
557
558
559
        prefix = AuditPrefix();
        ErrorF("%slast message repeated %d times\n",
               prefix != NULL ? prefix : "", nrepeat);
        nrepeat = 0;
        free(prefix);
        return AUDIT_TIMEOUT;
    }
    else {
        /* if the timer expires without anything to print, flush the message */
        oldlen = -1;
        return 0;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
560
561
562
    }
}

563
void
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
564
565
566
567
568
569
570
571
572
573
574
VAuditF(const char *f, va_list args)
{
    char *prefix;
    char buf[1024];
    int len;
    static char oldbuf[1024];

    prefix = AuditPrefix();
    len = vsnprintf(buf, sizeof(buf), f, args);

    if (len == oldlen && strcmp(buf, oldbuf) == 0) {
575
576
577
578
579
580
581
582
583
584
585
586
        /* Message already seen */
        nrepeat++;
    }
    else {
        /* new message */
        if (auditTimer != NULL)
            TimerForce(auditTimer);
        ErrorF("%s%s", prefix != NULL ? prefix : "", buf);
        strlcpy(oldbuf, buf, sizeof(oldbuf));
        oldlen = len;
        nrepeat = 0;
        auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
587
    }
588
    free(prefix);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
589
590
}

591
void
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
592
593
594
FatalError(const char *f, ...)
{
    va_list args;
595
    va_list args2;
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
596
597
598
    static Bool beenhere = FALSE;

    if (beenhere)
599
        ErrorF("\nFatalError re-entered, aborting\n");
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
600
    else
601
        ErrorF("\nFatal server error:\n");
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
602

603
604
    va_start(args, f);

605
606
607
    /* Make a copy for OsVendorFatalError */
    va_copy(args2, args);

608
#ifdef __APPLE__
609
    {
610
        va_list apple_args;
611

612
613
614
615
        va_copy(apple_args, args);
        (void)vsnprintf(__crashreporter_info_buff__,
                        sizeof(__crashreporter_info_buff__), f, apple_args);
        va_end(apple_args);
616
    }
617
#endif
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
618
619
620
621
    VErrorF(f, args);
    va_end(args);
    ErrorF("\n");
    if (!beenhere)
622
623
        OsVendorFatalError(f, args2);
    va_end(args2);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
624
    if (!beenhere) {
625
626
627
628
629
630
        beenhere = TRUE;
        AbortServer();
    }
    else
        OsAbort();
 /*NOTREACHED*/}
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
631

632
void
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
633
634
635
636
VErrorF(const char *f, va_list args)
{
#ifdef DDXOSVERRORF
    if (OsVendorVErrorFProc)
637
        OsVendorVErrorFProc(f, args);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
638
    else
639
        LogVWrite(-1, f, args);
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
640
641
642
643
644
#else
    LogVWrite(-1, f, args);
#endif
}

645
void
646
ErrorF(const char *f, ...)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
647
648
649
650
651
652
653
654
{
    va_list args;

    va_start(args, f);
    VErrorF(f, args);
    va_end(args);
}

655
void
656
LogPrintMarkers(void)
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
657
658
{
    /* Show what the message marker symbols mean. */
659
660
661
662
663
664
665
666
667
668
669
    LogWrite(0, "Markers: ");
    LogMessageVerb(X_PROBED, 0, "probed, ");
    LogMessageVerb(X_CONFIG, 0, "from config file, ");
    LogMessageVerb(X_DEFAULT, 0, "default setting,\n\t");
    LogMessageVerb(X_CMDLINE, 0, "from command line, ");
    LogMessageVerb(X_NOTICE, 0, "notice, ");
    LogMessageVerb(X_INFO, 0, "informational,\n\t");
    LogMessageVerb(X_WARNING, 0, "warning, ");
    LogMessageVerb(X_ERROR, 0, "error, ");
    LogMessageVerb(X_NOT_IMPLEMENTED, 0, "not implemented, ");
    LogMessageVerb(X_UNKNOWN, 0, "unknown.\n");
Kaleb Keithley Keithley's avatar
Kaleb Keithley Keithley committed
670
}