log.c revision c8548ba8
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#include <errno.h>
89
90#include "input.h"
91#include "site.h"
92#include "opaque.h"
93
94#ifdef WIN32
95#include <process.h>
96#define getpid(x) _getpid(x)
97#endif
98
99#ifdef XF86BIGFONT
100#include "xf86bigfontsrv.h"
101#endif
102
103#ifdef __clang__
104#pragma clang diagnostic ignored "-Wformat-nonliteral"
105#endif
106
107#ifdef DDXOSVERRORF
108void (*OsVendorVErrorFProc) (const char *, va_list args) = NULL;
109#endif
110
111static FILE *logFile = NULL;
112static int logFileFd = -1;
113static Bool logFlush = FALSE;
114static Bool logSync = FALSE;
115static int logVerbosity = DEFAULT_LOG_VERBOSITY;
116static int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY;
117
118/* Buffer to information logged before the log file is opened. */
119static char *saveBuffer = NULL;
120static int bufferSize = 0, bufferUnused = 0, bufferPos = 0;
121static Bool needBuffer = TRUE;
122
123#ifdef __APPLE__
124static char __crashreporter_info_buff__[4096] = { 0 };
125
126static const char *__crashreporter_info__ __attribute__ ((__used__)) =
127    &__crashreporter_info_buff__[0];
128asm(".desc ___crashreporter_info__, 0x10");
129#endif
130
131/* Prefix strings for log messages. */
132#ifndef X_UNKNOWN_STRING
133#define X_UNKNOWN_STRING		"(\?\?)"
134#endif
135#ifndef X_PROBE_STRING
136#define X_PROBE_STRING			"(--)"
137#endif
138#ifndef X_CONFIG_STRING
139#define X_CONFIG_STRING			"(**)"
140#endif
141#ifndef X_DEFAULT_STRING
142#define X_DEFAULT_STRING		"(==)"
143#endif
144#ifndef X_CMDLINE_STRING
145#define X_CMDLINE_STRING		"(++)"
146#endif
147#ifndef X_NOTICE_STRING
148#define X_NOTICE_STRING			"(!!)"
149#endif
150#ifndef X_ERROR_STRING
151#define X_ERROR_STRING			"(EE)"
152#endif
153#ifndef X_WARNING_STRING
154#define X_WARNING_STRING		"(WW)"
155#endif
156#ifndef X_INFO_STRING
157#define X_INFO_STRING			"(II)"
158#endif
159#ifndef X_NOT_IMPLEMENTED_STRING
160#define X_NOT_IMPLEMENTED_STRING	"(NI)"
161#endif
162#ifndef X_DEBUG_STRING
163#define X_DEBUG_STRING			"(DB)"
164#endif
165#ifndef X_NONE_STRING
166#define X_NONE_STRING			""
167#endif
168
169static size_t
170strlen_sigsafe(const char *s)
171{
172    size_t len;
173    for (len = 0; s[len]; len++);
174    return len;
175}
176
177/*
178 * LogFilePrep is called to setup files for logging, including getting
179 * an old file out of the way, but it doesn't actually open the file,
180 * since it may be used for renaming a file we're already logging to.
181 */
182#pragma GCC diagnostic push
183#pragma GCC diagnostic ignored "-Wformat-nonliteral"
184
185static char *
186LogFilePrep(const char *fname, const char *backup, const char *idstring)
187{
188    char *logFileName = NULL;
189
190    /* the format string below is controlled by the user,
191       this code should never be called with elevated privileges */
192    if (asprintf(&logFileName, fname, idstring) == -1)
193        FatalError("Cannot allocate space for the log file name\n");
194
195    if (backup && *backup) {
196        struct stat buf;
197
198        if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) {
199            char *suffix;
200            char *oldLog;
201
202            if ((asprintf(&suffix, backup, idstring) == -1) ||
203                (asprintf(&oldLog, "%s%s", logFileName, suffix) == -1)) {
204                FatalError("Cannot allocate space for the log file name\n");
205            }
206            free(suffix);
207
208            if (rename(logFileName, oldLog) == -1) {
209                FatalError("Cannot move old log file \"%s\" to \"%s\"\n",
210                           logFileName, oldLog);
211            }
212            free(oldLog);
213        }
214    }
215    else {
216        if (remove(logFileName) != 0 && errno != ENOENT) {
217            FatalError("Cannot remove old log file \"%s\": %s\n",
218                       logFileName, strerror(errno));
219        }
220    }
221
222    return logFileName;
223}
224#pragma GCC diagnostic pop
225
226/*
227 * LogInit is called to start logging to a file.  It is also called (with
228 * NULL arguments) when logging to a file is not wanted.  It must always be
229 * called, otherwise log messages will continue to accumulate in a buffer.
230 *
231 * %s, if present in the fname or backup strings, is expanded to the display
232 * string (or to a string containing the pid if the display is not yet set).
233 */
234
235static char *saved_log_fname;
236static char *saved_log_backup;
237static char *saved_log_tempname;
238
239const char *
240LogInit(const char *fname, const char *backup)
241{
242    char *logFileName = NULL;
243
244    if (fname && *fname) {
245        if (displayfd != -1) {
246            /* Display isn't set yet, so we can't use it in filenames yet. */
247            char pidstring[32];
248            snprintf(pidstring, sizeof(pidstring), "pid-%ld",
249                     (unsigned long) getpid());
250            logFileName = LogFilePrep(fname, backup, pidstring);
251            saved_log_tempname = logFileName;
252
253            /* Save the patterns for use when the display is named. */
254            saved_log_fname = strdup(fname);
255            if (backup == NULL)
256                saved_log_backup = NULL;
257            else
258                saved_log_backup = strdup(backup);
259        } else
260            logFileName = LogFilePrep(fname, backup, display);
261        if ((logFile = fopen(logFileName, "w")) == NULL)
262            FatalError("Cannot open log file \"%s\"\n", logFileName);
263        setvbuf(logFile, NULL, _IONBF, 0);
264
265        logFileFd = fileno(logFile);
266
267        /* Flush saved log information. */
268        if (saveBuffer && bufferSize > 0) {
269            fwrite(saveBuffer, bufferPos, 1, logFile);
270            fflush(logFile);
271#ifndef WIN32
272            fsync(fileno(logFile));
273#endif
274        }
275    }
276
277    /*
278     * Unconditionally free the buffer, and flag that the buffer is no longer
279     * needed.
280     */
281    if (saveBuffer && bufferSize > 0) {
282        free(saveBuffer);
283        saveBuffer = NULL;
284        bufferSize = 0;
285    }
286    needBuffer = FALSE;
287
288    return logFileName;
289}
290
291void
292LogSetDisplay(void)
293{
294    if (saved_log_fname && strstr(saved_log_fname, "%s")) {
295        char *logFileName;
296
297        logFileName = LogFilePrep(saved_log_fname, saved_log_backup, display);
298
299        if (rename(saved_log_tempname, logFileName) == 0) {
300            LogMessageVerb(X_PROBED, 0,
301                           "Log file renamed from \"%s\" to \"%s\"\n",
302                           saved_log_tempname, logFileName);
303
304            if (strlen(saved_log_tempname) >= strlen(logFileName))
305                strncpy(saved_log_tempname, logFileName,
306                        strlen(saved_log_tempname));
307        }
308        else {
309            ErrorF("Failed to rename log file \"%s\" to \"%s\": %s\n",
310                   saved_log_tempname, logFileName, strerror(errno));
311        }
312
313        /* free newly allocated string - can't free old one since existing
314           pointers to it may exist in DDX callers. */
315        free(logFileName);
316        free(saved_log_fname);
317        free(saved_log_backup);
318    }
319}
320
321void
322LogClose(enum ExitCode error)
323{
324    if (logFile) {
325        int msgtype = (error == EXIT_NO_ERROR) ? X_INFO : X_ERROR;
326        LogMessageVerbSigSafe(msgtype, -1,
327                "Server terminated %s (%d). Closing log file.\n",
328                (error == EXIT_NO_ERROR) ? "successfully" : "with error",
329                error);
330        fclose(logFile);
331        logFile = NULL;
332        logFileFd = -1;
333    }
334}
335
336Bool
337LogSetParameter(LogParameter param, int value)
338{
339    switch (param) {
340    case XLOG_FLUSH:
341        logFlush = value ? TRUE : FALSE;
342        return TRUE;
343    case XLOG_SYNC:
344        logSync = value ? TRUE : FALSE;
345        return TRUE;
346    case XLOG_VERBOSITY:
347        logVerbosity = value;
348        return TRUE;
349    case XLOG_FILE_VERBOSITY:
350        logFileVerbosity = value;
351        return TRUE;
352    default:
353        return FALSE;
354    }
355}
356
357enum {
358    LMOD_LONG     = 0x1,
359    LMOD_LONGLONG = 0x2,
360    LMOD_SHORT    = 0x4,
361    LMOD_SIZET    = 0x8,
362};
363
364/**
365 * Parse non-digit length modifiers and set the corresponding flag in
366 * flags_return.
367 *
368 * @return the number of bytes parsed
369 */
370static int parse_length_modifier(const char *format, size_t len, int *flags_return)
371{
372    int idx = 0;
373    int length_modifier = 0;
374
375    while (idx < len) {
376        switch (format[idx]) {
377            case 'l':
378                BUG_RETURN_VAL(length_modifier & LMOD_SHORT, 0);
379
380                if (length_modifier & LMOD_LONG)
381                    length_modifier |= LMOD_LONGLONG;
382                else
383                    length_modifier |= LMOD_LONG;
384                break;
385            case 'h':
386                BUG_RETURN_VAL(length_modifier & (LMOD_LONG|LMOD_LONGLONG), 0);
387                length_modifier |= LMOD_SHORT;
388                /* gcc says 'short int' is promoted to 'int' when
389                 * passed through '...', so ignored during
390                 * processing */
391                break;
392            case 'z':
393                length_modifier |= LMOD_SIZET;
394                break;
395            default:
396                goto out;
397        }
398        idx++;
399    }
400
401out:
402    *flags_return = length_modifier;
403    return idx;
404}
405
406/**
407 * Signal-safe snprintf, with some limitations over snprintf. Be careful
408 * which directives you use.
409 */
410static int
411vpnprintf(char *string, int size_in, const char *f, va_list args)
412{
413    int f_idx = 0;
414    int s_idx = 0;
415    int f_len = strlen_sigsafe(f);
416    char *string_arg;
417    char number[21];
418    int p_len;
419    int i;
420    uint64_t ui;
421    int64_t si;
422    size_t size = size_in;
423    int precision;
424
425    for (; f_idx < f_len && s_idx < size - 1; f_idx++) {
426        int length_modifier = 0;
427        if (f[f_idx] != '%') {
428            string[s_idx++] = f[f_idx];
429            continue;
430        }
431
432        f_idx++;
433
434        /* silently swallow minimum field width */
435        if (f[f_idx] == '*') {
436            f_idx++;
437            va_arg(args, int);
438        } else {
439            while (f_idx < f_len && ((f[f_idx] >= '0' && f[f_idx] <= '9')))
440                f_idx++;
441        }
442
443        /* is there a precision? */
444        precision = size;
445        if (f[f_idx] == '.') {
446            f_idx++;
447            if (f[f_idx] == '*') {
448                f_idx++;
449                /* precision is supplied in an int argument */
450                precision = va_arg(args, int);
451            } else {
452                /* silently swallow precision digits */
453                while (f_idx < f_len && ((f[f_idx] >= '0' && f[f_idx] <= '9')))
454                    f_idx++;
455            }
456        }
457
458        /* non-digit length modifiers */
459        if (f_idx < f_len) {
460            int parsed_bytes = parse_length_modifier(&f[f_idx], f_len - f_idx, &length_modifier);
461            if (parsed_bytes < 0)
462                return 0;
463            f_idx += parsed_bytes;
464        }
465
466        if (f_idx >= f_len)
467            break;
468
469        switch (f[f_idx]) {
470        case 's':
471            string_arg = va_arg(args, char*);
472
473            for (i = 0; string_arg[i] != 0 && s_idx < size - 1 && s_idx < precision; i++)
474                string[s_idx++] = string_arg[i];
475            break;
476
477        case 'u':
478            if (length_modifier & LMOD_LONGLONG)
479                ui = va_arg(args, unsigned long long);
480            else if (length_modifier & LMOD_LONG)
481                ui = va_arg(args, unsigned long);
482            else if (length_modifier & LMOD_SIZET)
483                ui = va_arg(args, size_t);
484            else
485                ui = va_arg(args, unsigned);
486
487            FormatUInt64(ui, number);
488            p_len = strlen_sigsafe(number);
489
490            for (i = 0; i < p_len && s_idx < size - 1; i++)
491                string[s_idx++] = number[i];
492            break;
493        case 'i':
494        case 'd':
495            if (length_modifier & LMOD_LONGLONG)
496                si = va_arg(args, long long);
497            else if (length_modifier & LMOD_LONG)
498                si = va_arg(args, long);
499            else if (length_modifier & LMOD_SIZET)
500                si = va_arg(args, ssize_t);
501            else
502                si = va_arg(args, int);
503
504            FormatInt64(si, number);
505            p_len = strlen_sigsafe(number);
506
507            for (i = 0; i < p_len && s_idx < size - 1; i++)
508                string[s_idx++] = number[i];
509            break;
510
511        case 'p':
512            string[s_idx++] = '0';
513            if (s_idx < size - 1)
514                string[s_idx++] = 'x';
515            ui = (uintptr_t)va_arg(args, void*);
516            FormatUInt64Hex(ui, number);
517            p_len = strlen_sigsafe(number);
518
519            for (i = 0; i < p_len && s_idx < size - 1; i++)
520                string[s_idx++] = number[i];
521            break;
522
523        case 'x':
524            if (length_modifier & LMOD_LONGLONG)
525                ui = va_arg(args, unsigned long long);
526            else if (length_modifier & LMOD_LONG)
527                ui = va_arg(args, unsigned long);
528            else if (length_modifier & LMOD_SIZET)
529                ui = va_arg(args, size_t);
530            else
531                ui = va_arg(args, unsigned);
532
533            FormatUInt64Hex(ui, number);
534            p_len = strlen_sigsafe(number);
535
536            for (i = 0; i < p_len && s_idx < size - 1; i++)
537                string[s_idx++] = number[i];
538            break;
539        case 'f':
540            {
541                double d = va_arg(args, double);
542                FormatDouble(d, number);
543                p_len = strlen_sigsafe(number);
544
545                for (i = 0; i < p_len && s_idx < size - 1; i++)
546                    string[s_idx++] = number[i];
547            }
548            break;
549        case 'c':
550            {
551                char c = va_arg(args, int);
552                if (s_idx < size - 1)
553                    string[s_idx++] = c;
554            }
555            break;
556        case '%':
557            string[s_idx++] = '%';
558            break;
559        default:
560            BUG_WARN_MSG(f[f_idx], "Unsupported printf directive '%c'\n", f[f_idx]);
561            va_arg(args, char*);
562            string[s_idx++] = '%';
563            if (s_idx < size - 1)
564                string[s_idx++] = f[f_idx];
565            break;
566        }
567    }
568
569    string[s_idx] = '\0';
570
571    return s_idx;
572}
573
574static int
575pnprintf(char *string, int size, const char *f, ...)
576{
577    int rc;
578    va_list args;
579
580    va_start(args, f);
581    rc = vpnprintf(string, size, f, args);
582    va_end(args);
583
584    return rc;
585}
586
587/* This function does the actual log message writes. It must be signal safe.
588 * When attempting to call non-signal-safe functions, guard them with a check
589 * of the inSignalContext global variable. */
590static void
591LogSWrite(int verb, const char *buf, size_t len, Bool end_line)
592{
593    static Bool newline = TRUE;
594    int ret;
595
596    if (verb < 0 || logVerbosity >= verb)
597        ret = write(2, buf, len);
598
599    if (verb < 0 || logFileVerbosity >= verb) {
600        if (inSignalContext && logFileFd >= 0) {
601            ret = write(logFileFd, buf, len);
602#ifndef WIN32
603            if (logFlush && logSync)
604                fsync(logFileFd);
605#endif
606        }
607        else if (!inSignalContext && logFile) {
608            if (newline)
609                fprintf(logFile, "[%10.3f] ", GetTimeInMillis() / 1000.0);
610            newline = end_line;
611            fwrite(buf, len, 1, logFile);
612            if (logFlush) {
613                fflush(logFile);
614#ifndef WIN32
615                if (logSync)
616                    fsync(fileno(logFile));
617#endif
618            }
619        }
620        else if (!inSignalContext && needBuffer) {
621            if (len > bufferUnused) {
622                bufferSize += 1024;
623                bufferUnused += 1024;
624                saveBuffer = realloc(saveBuffer, bufferSize);
625                if (!saveBuffer)
626                    FatalError("realloc() failed while saving log messages\n");
627            }
628            bufferUnused -= len;
629            memcpy(saveBuffer + bufferPos, buf, len);
630            bufferPos += len;
631        }
632    }
633
634    /* There's no place to log an error message if the log write
635     * fails...
636     */
637    (void) ret;
638}
639
640void
641LogVWrite(int verb, const char *f, va_list args)
642{
643    return LogVMessageVerb(X_NONE, verb, f, args);
644}
645
646void
647LogWrite(int verb, const char *f, ...)
648{
649    va_list args;
650
651    va_start(args, f);
652    LogVWrite(verb, f, args);
653    va_end(args);
654}
655
656/* Returns the Message Type string to prepend to a logging message, or NULL
657 * if the message will be dropped due to insufficient verbosity. */
658static const char *
659LogMessageTypeVerbString(MessageType type, int verb)
660{
661    if (type == X_ERROR)
662        verb = 0;
663
664    if (logVerbosity < verb && logFileVerbosity < verb)
665        return NULL;
666
667    switch (type) {
668    case X_PROBED:
669        return X_PROBE_STRING;
670    case X_CONFIG:
671        return X_CONFIG_STRING;
672    case X_DEFAULT:
673        return X_DEFAULT_STRING;
674    case X_CMDLINE:
675        return X_CMDLINE_STRING;
676    case X_NOTICE:
677        return X_NOTICE_STRING;
678    case X_ERROR:
679        return X_ERROR_STRING;
680    case X_WARNING:
681        return X_WARNING_STRING;
682    case X_INFO:
683        return X_INFO_STRING;
684    case X_NOT_IMPLEMENTED:
685        return X_NOT_IMPLEMENTED_STRING;
686    case X_UNKNOWN:
687        return X_UNKNOWN_STRING;
688    case X_NONE:
689        return X_NONE_STRING;
690    case X_DEBUG:
691        return X_DEBUG_STRING;
692    default:
693        return X_UNKNOWN_STRING;
694    }
695}
696
697void
698LogVMessageVerb(MessageType type, int verb, const char *format, va_list args)
699{
700    const char *type_str;
701    char buf[1024];
702    const size_t size = sizeof(buf);
703    Bool newline;
704    size_t len = 0;
705
706    if (inSignalContext) {
707        LogVMessageVerbSigSafe(type, verb, format, args);
708        return;
709    }
710
711    type_str = LogMessageTypeVerbString(type, verb);
712    if (!type_str)
713        return;
714
715    /* if type_str is not "", prepend it and ' ', to message */
716    if (type_str[0] != '\0')
717        len += Xscnprintf(&buf[len], size - len, "%s ", type_str);
718
719    if (size - len > 1)
720        len += Xvscnprintf(&buf[len], size - len, format, args);
721
722    /* Force '\n' at end of truncated line */
723    if (size - len == 1)
724        buf[len - 1] = '\n';
725
726    newline = (buf[len - 1] == '\n');
727    LogSWrite(verb, buf, len, newline);
728}
729
730/* Log message with verbosity level specified. */
731void
732LogMessageVerb(MessageType type, int verb, const char *format, ...)
733{
734    va_list ap;
735
736    va_start(ap, format);
737    LogVMessageVerb(type, verb, format, ap);
738    va_end(ap);
739}
740
741/* Log a message with the standard verbosity level of 1. */
742void
743LogMessage(MessageType type, const char *format, ...)
744{
745    va_list ap;
746
747    va_start(ap, format);
748    LogVMessageVerb(type, 1, format, ap);
749    va_end(ap);
750}
751
752/* Log a message using only signal safe functions. */
753void
754LogMessageVerbSigSafe(MessageType type, int verb, const char *format, ...)
755{
756    va_list ap;
757    va_start(ap, format);
758    LogVMessageVerbSigSafe(type, verb, format, ap);
759    va_end(ap);
760}
761
762void
763LogVMessageVerbSigSafe(MessageType type, int verb, const char *format, va_list args)
764{
765    const char *type_str;
766    char buf[1024];
767    int len;
768    Bool newline;
769
770    type_str = LogMessageTypeVerbString(type, verb);
771    if (!type_str)
772        return;
773
774    /* if type_str is not "", prepend it and ' ', to message */
775    if (type_str[0] != '\0') {
776        LogSWrite(verb, type_str, strlen_sigsafe(type_str), FALSE);
777        LogSWrite(verb, " ", 1, FALSE);
778    }
779
780    len = vpnprintf(buf, sizeof(buf), format, args);
781
782    /* Force '\n' at end of truncated line */
783    if (sizeof(buf) - len == 1)
784        buf[len - 1] = '\n';
785
786    newline = (len > 0 && buf[len - 1] == '\n');
787    LogSWrite(verb, buf, len, newline);
788}
789
790void
791LogVHdrMessageVerb(MessageType type, int verb, const char *msg_format,
792                   va_list msg_args, const char *hdr_format, va_list hdr_args)
793{
794    const char *type_str;
795    char buf[1024];
796    const size_t size = sizeof(buf);
797    Bool newline;
798    size_t len = 0;
799    int (*vprintf_func)(char *, int, const char* _X_RESTRICT_KYWD f, va_list args)
800            _X_ATTRIBUTE_PRINTF(3, 0);
801    int (*printf_func)(char *, int, const char* _X_RESTRICT_KYWD f, ...)
802            _X_ATTRIBUTE_PRINTF(3, 4);
803
804    type_str = LogMessageTypeVerbString(type, verb);
805    if (!type_str)
806        return;
807
808    if (inSignalContext) {
809        vprintf_func = vpnprintf;
810        printf_func = pnprintf;
811    } else {
812        vprintf_func = Xvscnprintf;
813        printf_func = Xscnprintf;
814    }
815
816    /* if type_str is not "", prepend it and ' ', to message */
817    if (type_str[0] != '\0')
818        len += printf_func(&buf[len], size - len, "%s ", type_str);
819
820    if (hdr_format && size - len > 1)
821        len += vprintf_func(&buf[len], size - len, hdr_format, hdr_args);
822
823    if (msg_format && size - len > 1)
824        len += vprintf_func(&buf[len], size - len, msg_format, msg_args);
825
826    /* Force '\n' at end of truncated line */
827    if (size - len == 1)
828        buf[len - 1] = '\n';
829
830    newline = (buf[len - 1] == '\n');
831    LogSWrite(verb, buf, len, newline);
832}
833
834void
835LogHdrMessageVerb(MessageType type, int verb, const char *msg_format,
836                  va_list msg_args, const char *hdr_format, ...)
837{
838    va_list hdr_args;
839
840    va_start(hdr_args, hdr_format);
841    LogVHdrMessageVerb(type, verb, msg_format, msg_args, hdr_format, hdr_args);
842    va_end(hdr_args);
843}
844
845void
846LogHdrMessage(MessageType type, const char *msg_format, va_list msg_args,
847              const char *hdr_format, ...)
848{
849    va_list hdr_args;
850
851    va_start(hdr_args, hdr_format);
852    LogVHdrMessageVerb(type, 1, msg_format, msg_args, hdr_format, hdr_args);
853    va_end(hdr_args);
854}
855
856void
857AbortServer(void)
858    _X_NORETURN;
859
860void
861AbortServer(void)
862{
863#ifdef XF86BIGFONT
864    XF86BigfontCleanup();
865#endif
866    CloseWellKnownConnections();
867    OsCleanup(TRUE);
868    AbortDevices();
869    AbortDDX(EXIT_ERR_ABORT);
870    fflush(stderr);
871    if (CoreDump)
872        OsAbort();
873    exit(1);
874}
875
876#define AUDIT_PREFIX "AUDIT: %s: %ld: "
877#ifndef AUDIT_TIMEOUT
878#define AUDIT_TIMEOUT ((CARD32)(120 * 1000))    /* 2 mn */
879#endif
880
881static int nrepeat = 0;
882static int oldlen = -1;
883static OsTimerPtr auditTimer = NULL;
884
885void
886FreeAuditTimer(void)
887{
888    if (auditTimer != NULL) {
889        /* Force output of pending messages */
890        TimerForce(auditTimer);
891        TimerFree(auditTimer);
892        auditTimer = NULL;
893    }
894}
895
896static char *
897AuditPrefix(void)
898{
899    time_t tm;
900    char *autime, *s;
901    char *tmpBuf;
902    int len;
903
904    time(&tm);
905    autime = ctime(&tm);
906    if ((s = strchr(autime, '\n')))
907        *s = '\0';
908    len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + 1;
909    tmpBuf = malloc(len);
910    if (!tmpBuf)
911        return NULL;
912    snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long) getpid());
913    return tmpBuf;
914}
915
916void
917AuditF(const char *f, ...)
918{
919    va_list args;
920
921    va_start(args, f);
922
923    VAuditF(f, args);
924    va_end(args);
925}
926
927static CARD32
928AuditFlush(OsTimerPtr timer, CARD32 now, void *arg)
929{
930    char *prefix;
931
932    if (nrepeat > 0) {
933        prefix = AuditPrefix();
934        ErrorF("%slast message repeated %d times\n",
935               prefix != NULL ? prefix : "", nrepeat);
936        nrepeat = 0;
937        free(prefix);
938        return AUDIT_TIMEOUT;
939    }
940    else {
941        /* if the timer expires without anything to print, flush the message */
942        oldlen = -1;
943        return 0;
944    }
945}
946
947void
948VAuditF(const char *f, va_list args)
949{
950    char *prefix;
951    char buf[1024];
952    int len;
953    static char oldbuf[1024];
954
955    prefix = AuditPrefix();
956    len = vsnprintf(buf, sizeof(buf), f, args);
957
958    if (len == oldlen && strcmp(buf, oldbuf) == 0) {
959        /* Message already seen */
960        nrepeat++;
961    }
962    else {
963        /* new message */
964        if (auditTimer != NULL)
965            TimerForce(auditTimer);
966        ErrorF("%s%s", prefix != NULL ? prefix : "", buf);
967        strlcpy(oldbuf, buf, sizeof(oldbuf));
968        oldlen = len;
969        nrepeat = 0;
970        auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL);
971    }
972    free(prefix);
973}
974
975void
976FatalError(const char *f, ...)
977{
978    va_list args;
979    va_list args2;
980    static Bool beenhere = FALSE;
981
982    if (beenhere)
983        ErrorFSigSafe("\nFatalError re-entered, aborting\n");
984    else
985        ErrorFSigSafe("\nFatal server error:\n");
986
987    va_start(args, f);
988
989    /* Make a copy for OsVendorFatalError */
990    va_copy(args2, args);
991
992#ifdef __APPLE__
993    {
994        va_list apple_args;
995
996        va_copy(apple_args, args);
997        (void)vsnprintf(__crashreporter_info_buff__,
998                        sizeof(__crashreporter_info_buff__), f, apple_args);
999        va_end(apple_args);
1000    }
1001#endif
1002    VErrorFSigSafe(f, args);
1003    va_end(args);
1004    ErrorFSigSafe("\n");
1005    if (!beenhere)
1006        OsVendorFatalError(f, args2);
1007    va_end(args2);
1008    if (!beenhere) {
1009        beenhere = TRUE;
1010        AbortServer();
1011    }
1012    else
1013        OsAbort();
1014 /*NOTREACHED*/}
1015
1016void
1017VErrorF(const char *f, va_list args)
1018{
1019#ifdef DDXOSVERRORF
1020    if (OsVendorVErrorFProc)
1021        OsVendorVErrorFProc(f, args);
1022    else
1023        LogVWrite(-1, f, args);
1024#else
1025    LogVWrite(-1, f, args);
1026#endif
1027}
1028
1029void
1030ErrorF(const char *f, ...)
1031{
1032    va_list args;
1033
1034    va_start(args, f);
1035    VErrorF(f, args);
1036    va_end(args);
1037}
1038
1039void
1040VErrorFSigSafe(const char *f, va_list args)
1041{
1042    LogVMessageVerbSigSafe(X_ERROR, -1, f, args);
1043}
1044
1045void
1046ErrorFSigSafe(const char *f, ...)
1047{
1048    va_list args;
1049
1050    va_start(args, f);
1051    VErrorFSigSafe(f, args);
1052    va_end(args);
1053}
1054
1055void
1056LogPrintMarkers(void)
1057{
1058    /* Show what the message marker symbols mean. */
1059    LogWrite(0, "Markers: ");
1060    LogMessageVerb(X_PROBED, 0, "probed, ");
1061    LogMessageVerb(X_CONFIG, 0, "from config file, ");
1062    LogMessageVerb(X_DEFAULT, 0, "default setting,\n\t");
1063    LogMessageVerb(X_CMDLINE, 0, "from command line, ");
1064    LogMessageVerb(X_NOTICE, 0, "notice, ");
1065    LogMessageVerb(X_INFO, 0, "informational,\n\t");
1066    LogMessageVerb(X_WARNING, 0, "warning, ");
1067    LogMessageVerb(X_ERROR, 0, "error, ");
1068    LogMessageVerb(X_NOT_IMPLEMENTED, 0, "not implemented, ");
1069    LogMessageVerb(X_UNKNOWN, 0, "unknown.\n");
1070}
1071