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