105b261ecSmrg/*
205b261ecSmrg
305b261ecSmrgCopyright 1987, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included
1205b261ecSmrgin all copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1505b261ecSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1605b261ecSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1705b261ecSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
1805b261ecSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1905b261ecSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2005b261ecSmrgOTHER DEALINGS IN THE SOFTWARE.
2105b261ecSmrg
2205b261ecSmrgExcept as contained in this notice, the name of The Open Group shall
2305b261ecSmrgnot be used in advertising or otherwise to promote the sale, use or
2405b261ecSmrgother dealings in this Software without prior written authorization
2505b261ecSmrgfrom The Open Group.
2605b261ecSmrg
2705b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
2805b261ecSmrgCopyright 1994 Quarterdeck Office Systems.
2905b261ecSmrg
3005b261ecSmrg                        All Rights Reserved
3105b261ecSmrg
3205b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3305b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3405b261ecSmrgprovided that the above copyright notice appear in all copies and that
3505b261ecSmrgboth that copyright notice and this permission notice appear in
3605b261ecSmrgsupporting documentation, and that the names of Digital and
3705b261ecSmrgQuarterdeck not be used in advertising or publicity pertaining to
3805b261ecSmrgdistribution of the software without specific, written prior
3905b261ecSmrgpermission.
4005b261ecSmrg
4105b261ecSmrgDIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
4205b261ecSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
4305b261ecSmrgFITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
4405b261ecSmrgOR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
4505b261ecSmrgOF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
4605b261ecSmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
4705b261ecSmrgOR PERFORMANCE OF THIS SOFTWARE.
4805b261ecSmrg
4905b261ecSmrg*/
5005b261ecSmrg
5105b261ecSmrg/*
5205b261ecSmrg * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
5305b261ecSmrg *
5405b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5505b261ecSmrg * copy of this software and associated documentation files (the "Software"),
5605b261ecSmrg * to deal in the Software without restriction, including without limitation
5705b261ecSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
5805b261ecSmrg * and/or sell copies of the Software, and to permit persons to whom the
5905b261ecSmrg * Software is furnished to do so, subject to the following conditions:
6005b261ecSmrg *
6105b261ecSmrg * The above copyright notice and this permission notice shall be included in
6205b261ecSmrg * all copies or substantial portions of the Software.
6305b261ecSmrg *
6405b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6505b261ecSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6605b261ecSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
6705b261ecSmrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
6805b261ecSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
6905b261ecSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
7005b261ecSmrg * OTHER DEALINGS IN THE SOFTWARE.
7105b261ecSmrg *
7205b261ecSmrg * Except as contained in this notice, the name of the copyright holder(s)
7305b261ecSmrg * and author(s) shall not be used in advertising or otherwise to promote
7405b261ecSmrg * the sale, use or other dealings in this Software without prior written
7505b261ecSmrg * authorization from the copyright holder(s) and author(s).
7605b261ecSmrg */
7705b261ecSmrg
7805b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
7905b261ecSmrg#include <dix-config.h>
8005b261ecSmrg#endif
8105b261ecSmrg
8205b261ecSmrg#include <X11/Xos.h>
8305b261ecSmrg#include <stdio.h>
8405b261ecSmrg#include <time.h>
8505b261ecSmrg#include <sys/stat.h>
8605b261ecSmrg#include <stdarg.h>
8735c4bbdfSmrg#include <stdlib.h>             /* for malloc() */
8805b261ecSmrg#include <errno.h>
8905b261ecSmrg
9005b261ecSmrg#include "input.h"
9105b261ecSmrg#include "opaque.h"
9205b261ecSmrg
9305b261ecSmrg#ifdef WIN32
9405b261ecSmrg#include <process.h>
9505b261ecSmrg#define getpid(x) _getpid(x)
9605b261ecSmrg#endif
9705b261ecSmrg
986747b715Smrg#ifdef XF86BIGFONT
996747b715Smrg#include "xf86bigfontsrv.h"
1006747b715Smrg#endif
10105b261ecSmrg
1029ace9065Smrg#ifdef __clang__
1039ace9065Smrg#pragma clang diagnostic ignored "-Wformat-nonliteral"
1049ace9065Smrg#endif
1059ace9065Smrg
10605b261ecSmrg#ifdef DDXOSVERRORF
10735c4bbdfSmrgvoid (*OsVendorVErrorFProc) (const char *, va_list args) = NULL;
10805b261ecSmrg#endif
10905b261ecSmrg
110ed6184dfSmrg/* Default logging parameters. */
111ed6184dfSmrg#ifndef DEFAULT_LOG_VERBOSITY
112ed6184dfSmrg#define DEFAULT_LOG_VERBOSITY		0
113ed6184dfSmrg#endif
114ed6184dfSmrg#ifndef DEFAULT_LOG_FILE_VERBOSITY
115ed6184dfSmrg#define DEFAULT_LOG_FILE_VERBOSITY	3
116ed6184dfSmrg#endif
117ed6184dfSmrg
11805b261ecSmrgstatic FILE *logFile = NULL;
11935c4bbdfSmrgstatic int logFileFd = -1;
12005b261ecSmrgstatic Bool logFlush = FALSE;
12105b261ecSmrgstatic Bool logSync = FALSE;
12205b261ecSmrgstatic int logVerbosity = DEFAULT_LOG_VERBOSITY;
12305b261ecSmrgstatic int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY;
12405b261ecSmrg
12505b261ecSmrg/* Buffer to information logged before the log file is opened. */
12605b261ecSmrgstatic char *saveBuffer = NULL;
12705b261ecSmrgstatic int bufferSize = 0, bufferUnused = 0, bufferPos = 0;
12805b261ecSmrgstatic Bool needBuffer = TRUE;
12905b261ecSmrg
1306747b715Smrg#ifdef __APPLE__
13135c4bbdfSmrgstatic char __crashreporter_info_buff__[4096] = { 0 };
13235c4bbdfSmrg
13335c4bbdfSmrgstatic const char *__crashreporter_info__ __attribute__ ((__used__)) =
13435c4bbdfSmrg    &__crashreporter_info_buff__[0];
13535c4bbdfSmrgasm(".desc ___crashreporter_info__, 0x10");
1366747b715Smrg#endif
1376747b715Smrg
13805b261ecSmrg/* Prefix strings for log messages. */
13905b261ecSmrg#ifndef X_UNKNOWN_STRING
14005b261ecSmrg#define X_UNKNOWN_STRING		"(\?\?)"
14105b261ecSmrg#endif
14205b261ecSmrg#ifndef X_PROBE_STRING
14305b261ecSmrg#define X_PROBE_STRING			"(--)"
14405b261ecSmrg#endif
14505b261ecSmrg#ifndef X_CONFIG_STRING
14605b261ecSmrg#define X_CONFIG_STRING			"(**)"
14705b261ecSmrg#endif
14805b261ecSmrg#ifndef X_DEFAULT_STRING
14905b261ecSmrg#define X_DEFAULT_STRING		"(==)"
15005b261ecSmrg#endif
15105b261ecSmrg#ifndef X_CMDLINE_STRING
15205b261ecSmrg#define X_CMDLINE_STRING		"(++)"
15305b261ecSmrg#endif
15405b261ecSmrg#ifndef X_NOTICE_STRING
15505b261ecSmrg#define X_NOTICE_STRING			"(!!)"
15605b261ecSmrg#endif
15705b261ecSmrg#ifndef X_ERROR_STRING
15805b261ecSmrg#define X_ERROR_STRING			"(EE)"
15905b261ecSmrg#endif
16005b261ecSmrg#ifndef X_WARNING_STRING
16105b261ecSmrg#define X_WARNING_STRING		"(WW)"
16205b261ecSmrg#endif
16305b261ecSmrg#ifndef X_INFO_STRING
16405b261ecSmrg#define X_INFO_STRING			"(II)"
16505b261ecSmrg#endif
16605b261ecSmrg#ifndef X_NOT_IMPLEMENTED_STRING
16705b261ecSmrg#define X_NOT_IMPLEMENTED_STRING	"(NI)"
16805b261ecSmrg#endif
16935c4bbdfSmrg#ifndef X_DEBUG_STRING
17035c4bbdfSmrg#define X_DEBUG_STRING			"(DB)"
17135c4bbdfSmrg#endif
17235c4bbdfSmrg#ifndef X_NONE_STRING
17335c4bbdfSmrg#define X_NONE_STRING			""
17435c4bbdfSmrg#endif
17535c4bbdfSmrg
17635c4bbdfSmrgstatic size_t
17735c4bbdfSmrgstrlen_sigsafe(const char *s)
17835c4bbdfSmrg{
17935c4bbdfSmrg    size_t len;
18035c4bbdfSmrg    for (len = 0; s[len]; len++);
18135c4bbdfSmrg    return len;
18235c4bbdfSmrg}
18335c4bbdfSmrg
18435c4bbdfSmrg/*
18535c4bbdfSmrg * LogFilePrep is called to setup files for logging, including getting
18635c4bbdfSmrg * an old file out of the way, but it doesn't actually open the file,
18735c4bbdfSmrg * since it may be used for renaming a file we're already logging to.
18835c4bbdfSmrg */
18935c4bbdfSmrg#pragma GCC diagnostic push
19035c4bbdfSmrg#pragma GCC diagnostic ignored "-Wformat-nonliteral"
19135c4bbdfSmrg
19235c4bbdfSmrgstatic char *
19335c4bbdfSmrgLogFilePrep(const char *fname, const char *backup, const char *idstring)
19435c4bbdfSmrg{
19535c4bbdfSmrg    char *logFileName = NULL;
19635c4bbdfSmrg
1971b5d61b8Smrg    /* the format string below is controlled by the user,
1981b5d61b8Smrg       this code should never be called with elevated privileges */
19935c4bbdfSmrg    if (asprintf(&logFileName, fname, idstring) == -1)
20035c4bbdfSmrg        FatalError("Cannot allocate space for the log file name\n");
20135c4bbdfSmrg
20235c4bbdfSmrg    if (backup && *backup) {
20335c4bbdfSmrg        struct stat buf;
20435c4bbdfSmrg
20535c4bbdfSmrg        if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) {
20635c4bbdfSmrg            char *suffix;
20735c4bbdfSmrg            char *oldLog;
20835c4bbdfSmrg
20935c4bbdfSmrg            if ((asprintf(&suffix, backup, idstring) == -1) ||
21035c4bbdfSmrg                (asprintf(&oldLog, "%s%s", logFileName, suffix) == -1)) {
21135c4bbdfSmrg                FatalError("Cannot allocate space for the log file name\n");
21235c4bbdfSmrg            }
21335c4bbdfSmrg            free(suffix);
21435c4bbdfSmrg
21535c4bbdfSmrg            if (rename(logFileName, oldLog) == -1) {
21635c4bbdfSmrg                FatalError("Cannot move old log file \"%s\" to \"%s\"\n",
21735c4bbdfSmrg                           logFileName, oldLog);
21835c4bbdfSmrg            }
21935c4bbdfSmrg            free(oldLog);
22035c4bbdfSmrg        }
22135c4bbdfSmrg    }
22235c4bbdfSmrg    else {
22335c4bbdfSmrg        if (remove(logFileName) != 0 && errno != ENOENT) {
22435c4bbdfSmrg            FatalError("Cannot remove old log file \"%s\": %s\n",
22535c4bbdfSmrg                       logFileName, strerror(errno));
22635c4bbdfSmrg        }
22735c4bbdfSmrg    }
22835c4bbdfSmrg
22935c4bbdfSmrg    return logFileName;
23035c4bbdfSmrg}
23135c4bbdfSmrg#pragma GCC diagnostic pop
23205b261ecSmrg
23305b261ecSmrg/*
23405b261ecSmrg * LogInit is called to start logging to a file.  It is also called (with
23505b261ecSmrg * NULL arguments) when logging to a file is not wanted.  It must always be
23605b261ecSmrg * called, otherwise log messages will continue to accumulate in a buffer.
23705b261ecSmrg *
23805b261ecSmrg * %s, if present in the fname or backup strings, is expanded to the display
23935c4bbdfSmrg * string (or to a string containing the pid if the display is not yet set).
24005b261ecSmrg */
24105b261ecSmrg
24235c4bbdfSmrgstatic char *saved_log_fname;
24335c4bbdfSmrgstatic char *saved_log_backup;
24435c4bbdfSmrgstatic char *saved_log_tempname;
24535c4bbdfSmrg
24605b261ecSmrgconst char *
24705b261ecSmrgLogInit(const char *fname, const char *backup)
24805b261ecSmrg{
24905b261ecSmrg    char *logFileName = NULL;
25005b261ecSmrg
25105b261ecSmrg    if (fname && *fname) {
25235c4bbdfSmrg        if (displayfd != -1) {
25335c4bbdfSmrg            /* Display isn't set yet, so we can't use it in filenames yet. */
25435c4bbdfSmrg            char pidstring[32];
25535c4bbdfSmrg            snprintf(pidstring, sizeof(pidstring), "pid-%ld",
25635c4bbdfSmrg                     (unsigned long) getpid());
25735c4bbdfSmrg            logFileName = LogFilePrep(fname, backup, pidstring);
25835c4bbdfSmrg            saved_log_tempname = logFileName;
25935c4bbdfSmrg
26035c4bbdfSmrg            /* Save the patterns for use when the display is named. */
26135c4bbdfSmrg            saved_log_fname = strdup(fname);
26235c4bbdfSmrg            if (backup == NULL)
26335c4bbdfSmrg                saved_log_backup = NULL;
26435c4bbdfSmrg            else
26535c4bbdfSmrg                saved_log_backup = strdup(backup);
26635c4bbdfSmrg        } else
26735c4bbdfSmrg            logFileName = LogFilePrep(fname, backup, display);
26835c4bbdfSmrg        if ((logFile = fopen(logFileName, "w")) == NULL)
26935c4bbdfSmrg            FatalError("Cannot open log file \"%s\"\n", logFileName);
27035c4bbdfSmrg        setvbuf(logFile, NULL, _IONBF, 0);
27135c4bbdfSmrg
27235c4bbdfSmrg        logFileFd = fileno(logFile);
27335c4bbdfSmrg
27435c4bbdfSmrg        /* Flush saved log information. */
27535c4bbdfSmrg        if (saveBuffer && bufferSize > 0) {
27635c4bbdfSmrg            fwrite(saveBuffer, bufferPos, 1, logFile);
27735c4bbdfSmrg            fflush(logFile);
27805b261ecSmrg#ifndef WIN32
27935c4bbdfSmrg            fsync(fileno(logFile));
28005b261ecSmrg#endif
28135c4bbdfSmrg        }
28205b261ecSmrg    }
28305b261ecSmrg
28405b261ecSmrg    /*
28505b261ecSmrg     * Unconditionally free the buffer, and flag that the buffer is no longer
28605b261ecSmrg     * needed.
28705b261ecSmrg     */
28805b261ecSmrg    if (saveBuffer && bufferSize > 0) {
28935c4bbdfSmrg        free(saveBuffer);
29035c4bbdfSmrg        saveBuffer = NULL;
29135c4bbdfSmrg        bufferSize = 0;
29205b261ecSmrg    }
29305b261ecSmrg    needBuffer = FALSE;
29405b261ecSmrg
29505b261ecSmrg    return logFileName;
29605b261ecSmrg}
29705b261ecSmrg
29805b261ecSmrgvoid
29935c4bbdfSmrgLogSetDisplay(void)
30035c4bbdfSmrg{
3011b5d61b8Smrg    if (saved_log_fname && strstr(saved_log_fname, "%s")) {
30235c4bbdfSmrg        char *logFileName;
30335c4bbdfSmrg
30435c4bbdfSmrg        logFileName = LogFilePrep(saved_log_fname, saved_log_backup, display);
30535c4bbdfSmrg
30635c4bbdfSmrg        if (rename(saved_log_tempname, logFileName) == 0) {
30735c4bbdfSmrg            LogMessageVerb(X_PROBED, 0,
30835c4bbdfSmrg                           "Log file renamed from \"%s\" to \"%s\"\n",
30935c4bbdfSmrg                           saved_log_tempname, logFileName);
31035c4bbdfSmrg
31135c4bbdfSmrg            if (strlen(saved_log_tempname) >= strlen(logFileName))
31235c4bbdfSmrg                strncpy(saved_log_tempname, logFileName,
31335c4bbdfSmrg                        strlen(saved_log_tempname));
31435c4bbdfSmrg        }
31535c4bbdfSmrg        else {
31635c4bbdfSmrg            ErrorF("Failed to rename log file \"%s\" to \"%s\": %s\n",
31735c4bbdfSmrg                   saved_log_tempname, logFileName, strerror(errno));
31835c4bbdfSmrg        }
31935c4bbdfSmrg
32035c4bbdfSmrg        /* free newly allocated string - can't free old one since existing
32135c4bbdfSmrg           pointers to it may exist in DDX callers. */
32235c4bbdfSmrg        free(logFileName);
32335c4bbdfSmrg        free(saved_log_fname);
32435c4bbdfSmrg        free(saved_log_backup);
32535c4bbdfSmrg    }
32635c4bbdfSmrg}
32735c4bbdfSmrg
32835c4bbdfSmrgvoid
32935c4bbdfSmrgLogClose(enum ExitCode error)
33005b261ecSmrg{
33105b261ecSmrg    if (logFile) {
33235c4bbdfSmrg        int msgtype = (error == EXIT_NO_ERROR) ? X_INFO : X_ERROR;
33335c4bbdfSmrg        LogMessageVerbSigSafe(msgtype, -1,
33435c4bbdfSmrg                "Server terminated %s (%d). Closing log file.\n",
33535c4bbdfSmrg                (error == EXIT_NO_ERROR) ? "successfully" : "with error",
33635c4bbdfSmrg                error);
33735c4bbdfSmrg        fclose(logFile);
33835c4bbdfSmrg        logFile = NULL;
33935c4bbdfSmrg        logFileFd = -1;
34005b261ecSmrg    }
34105b261ecSmrg}
34205b261ecSmrg
34305b261ecSmrgBool
34405b261ecSmrgLogSetParameter(LogParameter param, int value)
34505b261ecSmrg{
34605b261ecSmrg    switch (param) {
34705b261ecSmrg    case XLOG_FLUSH:
34835c4bbdfSmrg        logFlush = value ? TRUE : FALSE;
34935c4bbdfSmrg        return TRUE;
35005b261ecSmrg    case XLOG_SYNC:
35135c4bbdfSmrg        logSync = value ? TRUE : FALSE;
35235c4bbdfSmrg        return TRUE;
35305b261ecSmrg    case XLOG_VERBOSITY:
35435c4bbdfSmrg        logVerbosity = value;
35535c4bbdfSmrg        return TRUE;
35605b261ecSmrg    case XLOG_FILE_VERBOSITY:
35735c4bbdfSmrg        logFileVerbosity = value;
35835c4bbdfSmrg        return TRUE;
35905b261ecSmrg    default:
36035c4bbdfSmrg        return FALSE;
36105b261ecSmrg    }
36205b261ecSmrg}
36305b261ecSmrg
36435c4bbdfSmrgenum {
36535c4bbdfSmrg    LMOD_LONG     = 0x1,
36635c4bbdfSmrg    LMOD_LONGLONG = 0x2,
36735c4bbdfSmrg    LMOD_SHORT    = 0x4,
36835c4bbdfSmrg    LMOD_SIZET    = 0x8,
36935c4bbdfSmrg};
37005b261ecSmrg
37135c4bbdfSmrg/**
37235c4bbdfSmrg * Parse non-digit length modifiers and set the corresponding flag in
37335c4bbdfSmrg * flags_return.
37435c4bbdfSmrg *
37535c4bbdfSmrg * @return the number of bytes parsed
37635c4bbdfSmrg */
37735c4bbdfSmrgstatic int parse_length_modifier(const char *format, size_t len, int *flags_return)
37805b261ecSmrg{
37935c4bbdfSmrg    int idx = 0;
38035c4bbdfSmrg    int length_modifier = 0;
38135c4bbdfSmrg
38235c4bbdfSmrg    while (idx < len) {
38335c4bbdfSmrg        switch (format[idx]) {
38435c4bbdfSmrg            case 'l':
38535c4bbdfSmrg                BUG_RETURN_VAL(length_modifier & LMOD_SHORT, 0);
38635c4bbdfSmrg
38735c4bbdfSmrg                if (length_modifier & LMOD_LONG)
38835c4bbdfSmrg                    length_modifier |= LMOD_LONGLONG;
38935c4bbdfSmrg                else
39035c4bbdfSmrg                    length_modifier |= LMOD_LONG;
39135c4bbdfSmrg                break;
39235c4bbdfSmrg            case 'h':
39335c4bbdfSmrg                BUG_RETURN_VAL(length_modifier & (LMOD_LONG|LMOD_LONGLONG), 0);
39435c4bbdfSmrg                length_modifier |= LMOD_SHORT;
39535c4bbdfSmrg                /* gcc says 'short int' is promoted to 'int' when
39635c4bbdfSmrg                 * passed through '...', so ignored during
39735c4bbdfSmrg                 * processing */
39835c4bbdfSmrg                break;
39935c4bbdfSmrg            case 'z':
40035c4bbdfSmrg                length_modifier |= LMOD_SIZET;
40135c4bbdfSmrg                break;
40235c4bbdfSmrg            default:
40335c4bbdfSmrg                goto out;
40435c4bbdfSmrg        }
40535c4bbdfSmrg        idx++;
4066747b715Smrg    }
40705b261ecSmrg
40835c4bbdfSmrgout:
40935c4bbdfSmrg    *flags_return = length_modifier;
41035c4bbdfSmrg    return idx;
41135c4bbdfSmrg}
41235c4bbdfSmrg
41335c4bbdfSmrg/**
41435c4bbdfSmrg * Signal-safe snprintf, with some limitations over snprintf. Be careful
41535c4bbdfSmrg * which directives you use.
41635c4bbdfSmrg */
41735c4bbdfSmrgstatic int
41835c4bbdfSmrgvpnprintf(char *string, int size_in, const char *f, va_list args)
41935c4bbdfSmrg{
42035c4bbdfSmrg    int f_idx = 0;
42135c4bbdfSmrg    int s_idx = 0;
42235c4bbdfSmrg    int f_len = strlen_sigsafe(f);
42335c4bbdfSmrg    char *string_arg;
42435c4bbdfSmrg    char number[21];
42535c4bbdfSmrg    int p_len;
42635c4bbdfSmrg    int i;
42735c4bbdfSmrg    uint64_t ui;
42835c4bbdfSmrg    int64_t si;
42935c4bbdfSmrg    size_t size = size_in;
43035c4bbdfSmrg    int precision;
43135c4bbdfSmrg
43235c4bbdfSmrg    for (; f_idx < f_len && s_idx < size - 1; f_idx++) {
43335c4bbdfSmrg        int length_modifier = 0;
43435c4bbdfSmrg        if (f[f_idx] != '%') {
43535c4bbdfSmrg            string[s_idx++] = f[f_idx];
43635c4bbdfSmrg            continue;
43735c4bbdfSmrg        }
43835c4bbdfSmrg
43935c4bbdfSmrg        f_idx++;
44035c4bbdfSmrg
44135c4bbdfSmrg        /* silently swallow minimum field width */
44235c4bbdfSmrg        if (f[f_idx] == '*') {
44335c4bbdfSmrg            f_idx++;
44435c4bbdfSmrg            va_arg(args, int);
44535c4bbdfSmrg        } else {
44635c4bbdfSmrg            while (f_idx < f_len && ((f[f_idx] >= '0' && f[f_idx] <= '9')))
44735c4bbdfSmrg                f_idx++;
44835c4bbdfSmrg        }
44935c4bbdfSmrg
45035c4bbdfSmrg        /* is there a precision? */
45135c4bbdfSmrg        precision = size;
45235c4bbdfSmrg        if (f[f_idx] == '.') {
45335c4bbdfSmrg            f_idx++;
45435c4bbdfSmrg            if (f[f_idx] == '*') {
45535c4bbdfSmrg                f_idx++;
45635c4bbdfSmrg                /* precision is supplied in an int argument */
45735c4bbdfSmrg                precision = va_arg(args, int);
45835c4bbdfSmrg            } else {
45935c4bbdfSmrg                /* silently swallow precision digits */
46035c4bbdfSmrg                while (f_idx < f_len && ((f[f_idx] >= '0' && f[f_idx] <= '9')))
46135c4bbdfSmrg                    f_idx++;
46235c4bbdfSmrg            }
46335c4bbdfSmrg        }
46435c4bbdfSmrg
46535c4bbdfSmrg        /* non-digit length modifiers */
46635c4bbdfSmrg        if (f_idx < f_len) {
46735c4bbdfSmrg            int parsed_bytes = parse_length_modifier(&f[f_idx], f_len - f_idx, &length_modifier);
46835c4bbdfSmrg            if (parsed_bytes < 0)
46935c4bbdfSmrg                return 0;
47035c4bbdfSmrg            f_idx += parsed_bytes;
47135c4bbdfSmrg        }
47235c4bbdfSmrg
47335c4bbdfSmrg        if (f_idx >= f_len)
47435c4bbdfSmrg            break;
47535c4bbdfSmrg
47635c4bbdfSmrg        switch (f[f_idx]) {
47735c4bbdfSmrg        case 's':
47835c4bbdfSmrg            string_arg = va_arg(args, char*);
47935c4bbdfSmrg
48035c4bbdfSmrg            for (i = 0; string_arg[i] != 0 && s_idx < size - 1 && s_idx < precision; i++)
48135c4bbdfSmrg                string[s_idx++] = string_arg[i];
48235c4bbdfSmrg            break;
48335c4bbdfSmrg
48435c4bbdfSmrg        case 'u':
48535c4bbdfSmrg            if (length_modifier & LMOD_LONGLONG)
48635c4bbdfSmrg                ui = va_arg(args, unsigned long long);
48735c4bbdfSmrg            else if (length_modifier & LMOD_LONG)
48835c4bbdfSmrg                ui = va_arg(args, unsigned long);
48935c4bbdfSmrg            else if (length_modifier & LMOD_SIZET)
49035c4bbdfSmrg                ui = va_arg(args, size_t);
49135c4bbdfSmrg            else
49235c4bbdfSmrg                ui = va_arg(args, unsigned);
49335c4bbdfSmrg
49435c4bbdfSmrg            FormatUInt64(ui, number);
49535c4bbdfSmrg            p_len = strlen_sigsafe(number);
49635c4bbdfSmrg
49735c4bbdfSmrg            for (i = 0; i < p_len && s_idx < size - 1; i++)
49835c4bbdfSmrg                string[s_idx++] = number[i];
49935c4bbdfSmrg            break;
50035c4bbdfSmrg        case 'i':
50135c4bbdfSmrg        case 'd':
50235c4bbdfSmrg            if (length_modifier & LMOD_LONGLONG)
50335c4bbdfSmrg                si = va_arg(args, long long);
50435c4bbdfSmrg            else if (length_modifier & LMOD_LONG)
50535c4bbdfSmrg                si = va_arg(args, long);
50635c4bbdfSmrg            else if (length_modifier & LMOD_SIZET)
50735c4bbdfSmrg                si = va_arg(args, ssize_t);
50835c4bbdfSmrg            else
50935c4bbdfSmrg                si = va_arg(args, int);
51035c4bbdfSmrg
51135c4bbdfSmrg            FormatInt64(si, number);
51235c4bbdfSmrg            p_len = strlen_sigsafe(number);
51335c4bbdfSmrg
51435c4bbdfSmrg            for (i = 0; i < p_len && s_idx < size - 1; i++)
51535c4bbdfSmrg                string[s_idx++] = number[i];
51635c4bbdfSmrg            break;
51735c4bbdfSmrg
51835c4bbdfSmrg        case 'p':
51935c4bbdfSmrg            string[s_idx++] = '0';
52035c4bbdfSmrg            if (s_idx < size - 1)
52135c4bbdfSmrg                string[s_idx++] = 'x';
52235c4bbdfSmrg            ui = (uintptr_t)va_arg(args, void*);
52335c4bbdfSmrg            FormatUInt64Hex(ui, number);
52435c4bbdfSmrg            p_len = strlen_sigsafe(number);
52535c4bbdfSmrg
52635c4bbdfSmrg            for (i = 0; i < p_len && s_idx < size - 1; i++)
52735c4bbdfSmrg                string[s_idx++] = number[i];
52835c4bbdfSmrg            break;
52935c4bbdfSmrg
53035c4bbdfSmrg        case 'x':
53135c4bbdfSmrg            if (length_modifier & LMOD_LONGLONG)
53235c4bbdfSmrg                ui = va_arg(args, unsigned long long);
53335c4bbdfSmrg            else if (length_modifier & LMOD_LONG)
53435c4bbdfSmrg                ui = va_arg(args, unsigned long);
53535c4bbdfSmrg            else if (length_modifier & LMOD_SIZET)
53635c4bbdfSmrg                ui = va_arg(args, size_t);
53735c4bbdfSmrg            else
53835c4bbdfSmrg                ui = va_arg(args, unsigned);
53935c4bbdfSmrg
54035c4bbdfSmrg            FormatUInt64Hex(ui, number);
54135c4bbdfSmrg            p_len = strlen_sigsafe(number);
54235c4bbdfSmrg
54335c4bbdfSmrg            for (i = 0; i < p_len && s_idx < size - 1; i++)
54435c4bbdfSmrg                string[s_idx++] = number[i];
54535c4bbdfSmrg            break;
54635c4bbdfSmrg        case 'f':
54735c4bbdfSmrg            {
54835c4bbdfSmrg                double d = va_arg(args, double);
54935c4bbdfSmrg                FormatDouble(d, number);
55035c4bbdfSmrg                p_len = strlen_sigsafe(number);
55135c4bbdfSmrg
55235c4bbdfSmrg                for (i = 0; i < p_len && s_idx < size - 1; i++)
55335c4bbdfSmrg                    string[s_idx++] = number[i];
55435c4bbdfSmrg            }
55535c4bbdfSmrg            break;
55635c4bbdfSmrg        case 'c':
55735c4bbdfSmrg            {
55835c4bbdfSmrg                char c = va_arg(args, int);
55935c4bbdfSmrg                if (s_idx < size - 1)
56035c4bbdfSmrg                    string[s_idx++] = c;
56135c4bbdfSmrg            }
56235c4bbdfSmrg            break;
56335c4bbdfSmrg        case '%':
56435c4bbdfSmrg            string[s_idx++] = '%';
56535c4bbdfSmrg            break;
56635c4bbdfSmrg        default:
56735c4bbdfSmrg            BUG_WARN_MSG(f[f_idx], "Unsupported printf directive '%c'\n", f[f_idx]);
56835c4bbdfSmrg            va_arg(args, char*);
56935c4bbdfSmrg            string[s_idx++] = '%';
57035c4bbdfSmrg            if (s_idx < size - 1)
57135c4bbdfSmrg                string[s_idx++] = f[f_idx];
57235c4bbdfSmrg            break;
57335c4bbdfSmrg        }
57405b261ecSmrg    }
57535c4bbdfSmrg
57635c4bbdfSmrg    string[s_idx] = '\0';
57735c4bbdfSmrg
57835c4bbdfSmrg    return s_idx;
57935c4bbdfSmrg}
58035c4bbdfSmrg
58135c4bbdfSmrgstatic int
58235c4bbdfSmrgpnprintf(char *string, int size, const char *f, ...)
58335c4bbdfSmrg{
58435c4bbdfSmrg    int rc;
58535c4bbdfSmrg    va_list args;
58635c4bbdfSmrg
58735c4bbdfSmrg    va_start(args, f);
58835c4bbdfSmrg    rc = vpnprintf(string, size, f, args);
58935c4bbdfSmrg    va_end(args);
59035c4bbdfSmrg
59135c4bbdfSmrg    return rc;
59235c4bbdfSmrg}
59335c4bbdfSmrg
59435c4bbdfSmrg/* This function does the actual log message writes. It must be signal safe.
59535c4bbdfSmrg * When attempting to call non-signal-safe functions, guard them with a check
59635c4bbdfSmrg * of the inSignalContext global variable. */
59735c4bbdfSmrgstatic void
59835c4bbdfSmrgLogSWrite(int verb, const char *buf, size_t len, Bool end_line)
59935c4bbdfSmrg{
60035c4bbdfSmrg    static Bool newline = TRUE;
60135c4bbdfSmrg    int ret;
60235c4bbdfSmrg
60335c4bbdfSmrg    if (verb < 0 || logVerbosity >= verb)
60435c4bbdfSmrg        ret = write(2, buf, len);
60535c4bbdfSmrg
60635c4bbdfSmrg    if (verb < 0 || logFileVerbosity >= verb) {
60735c4bbdfSmrg        if (inSignalContext && logFileFd >= 0) {
60835c4bbdfSmrg            ret = write(logFileFd, buf, len);
60905b261ecSmrg#ifndef WIN32
61035c4bbdfSmrg            if (logFlush && logSync)
61135c4bbdfSmrg                fsync(logFileFd);
61205b261ecSmrg#endif
61335c4bbdfSmrg        }
61435c4bbdfSmrg        else if (!inSignalContext && logFile) {
61535c4bbdfSmrg            if (newline)
61635c4bbdfSmrg                fprintf(logFile, "[%10.3f] ", GetTimeInMillis() / 1000.0);
61735c4bbdfSmrg            newline = end_line;
61835c4bbdfSmrg            fwrite(buf, len, 1, logFile);
61935c4bbdfSmrg            if (logFlush) {
62035c4bbdfSmrg                fflush(logFile);
62135c4bbdfSmrg#ifndef WIN32
62235c4bbdfSmrg                if (logSync)
62335c4bbdfSmrg                    fsync(fileno(logFile));
62435c4bbdfSmrg#endif
62535c4bbdfSmrg            }
62635c4bbdfSmrg        }
62735c4bbdfSmrg        else if (!inSignalContext && needBuffer) {
62835c4bbdfSmrg            if (len > bufferUnused) {
62935c4bbdfSmrg                bufferSize += 1024;
63035c4bbdfSmrg                bufferUnused += 1024;
63135c4bbdfSmrg                saveBuffer = realloc(saveBuffer, bufferSize);
63235c4bbdfSmrg                if (!saveBuffer)
63335c4bbdfSmrg                    FatalError("realloc() failed while saving log messages\n");
63435c4bbdfSmrg            }
63535c4bbdfSmrg            bufferUnused -= len;
63635c4bbdfSmrg            memcpy(saveBuffer + bufferPos, buf, len);
63735c4bbdfSmrg            bufferPos += len;
63835c4bbdfSmrg        }
63905b261ecSmrg    }
64035c4bbdfSmrg
64135c4bbdfSmrg    /* There's no place to log an error message if the log write
64235c4bbdfSmrg     * fails...
64335c4bbdfSmrg     */
64435c4bbdfSmrg    (void) ret;
64535c4bbdfSmrg}
64635c4bbdfSmrg
64735c4bbdfSmrgvoid
64835c4bbdfSmrgLogVWrite(int verb, const char *f, va_list args)
64935c4bbdfSmrg{
65035c4bbdfSmrg    return LogVMessageVerb(X_NONE, verb, f, args);
65105b261ecSmrg}
65205b261ecSmrg
6536747b715Smrgvoid
65405b261ecSmrgLogWrite(int verb, const char *f, ...)
65505b261ecSmrg{
65605b261ecSmrg    va_list args;
65705b261ecSmrg
65805b261ecSmrg    va_start(args, f);
65905b261ecSmrg    LogVWrite(verb, f, args);
66005b261ecSmrg    va_end(args);
66105b261ecSmrg}
66205b261ecSmrg
66335c4bbdfSmrg/* Returns the Message Type string to prepend to a logging message, or NULL
66435c4bbdfSmrg * if the message will be dropped due to insufficient verbosity. */
66535c4bbdfSmrgstatic const char *
66635c4bbdfSmrgLogMessageTypeVerbString(MessageType type, int verb)
66735c4bbdfSmrg{
66835c4bbdfSmrg    if (type == X_ERROR)
66935c4bbdfSmrg        verb = 0;
67035c4bbdfSmrg
67135c4bbdfSmrg    if (logVerbosity < verb && logFileVerbosity < verb)
67235c4bbdfSmrg        return NULL;
67335c4bbdfSmrg
67435c4bbdfSmrg    switch (type) {
67535c4bbdfSmrg    case X_PROBED:
67635c4bbdfSmrg        return X_PROBE_STRING;
67735c4bbdfSmrg    case X_CONFIG:
67835c4bbdfSmrg        return X_CONFIG_STRING;
67935c4bbdfSmrg    case X_DEFAULT:
68035c4bbdfSmrg        return X_DEFAULT_STRING;
68135c4bbdfSmrg    case X_CMDLINE:
68235c4bbdfSmrg        return X_CMDLINE_STRING;
68335c4bbdfSmrg    case X_NOTICE:
68435c4bbdfSmrg        return X_NOTICE_STRING;
68535c4bbdfSmrg    case X_ERROR:
68635c4bbdfSmrg        return X_ERROR_STRING;
68735c4bbdfSmrg    case X_WARNING:
68835c4bbdfSmrg        return X_WARNING_STRING;
68935c4bbdfSmrg    case X_INFO:
69035c4bbdfSmrg        return X_INFO_STRING;
69135c4bbdfSmrg    case X_NOT_IMPLEMENTED:
69235c4bbdfSmrg        return X_NOT_IMPLEMENTED_STRING;
69335c4bbdfSmrg    case X_UNKNOWN:
69435c4bbdfSmrg        return X_UNKNOWN_STRING;
69535c4bbdfSmrg    case X_NONE:
69635c4bbdfSmrg        return X_NONE_STRING;
69735c4bbdfSmrg    case X_DEBUG:
69835c4bbdfSmrg        return X_DEBUG_STRING;
69935c4bbdfSmrg    default:
70035c4bbdfSmrg        return X_UNKNOWN_STRING;
70135c4bbdfSmrg    }
70235c4bbdfSmrg}
70335c4bbdfSmrg
7046747b715Smrgvoid
70505b261ecSmrgLogVMessageVerb(MessageType type, int verb, const char *format, va_list args)
70605b261ecSmrg{
70735c4bbdfSmrg    const char *type_str;
70835c4bbdfSmrg    char buf[1024];
70935c4bbdfSmrg    const size_t size = sizeof(buf);
71035c4bbdfSmrg    Bool newline;
71135c4bbdfSmrg    size_t len = 0;
71235c4bbdfSmrg
71335c4bbdfSmrg    if (inSignalContext) {
71435c4bbdfSmrg        LogVMessageVerbSigSafe(type, verb, format, args);
71535c4bbdfSmrg        return;
71605b261ecSmrg    }
71735c4bbdfSmrg
71835c4bbdfSmrg    type_str = LogMessageTypeVerbString(type, verb);
71935c4bbdfSmrg    if (!type_str)
72035c4bbdfSmrg        return;
72135c4bbdfSmrg
72235c4bbdfSmrg    /* if type_str is not "", prepend it and ' ', to message */
72335c4bbdfSmrg    if (type_str[0] != '\0')
72435c4bbdfSmrg        len += Xscnprintf(&buf[len], size - len, "%s ", type_str);
72535c4bbdfSmrg
72635c4bbdfSmrg    if (size - len > 1)
72735c4bbdfSmrg        len += Xvscnprintf(&buf[len], size - len, format, args);
72835c4bbdfSmrg
72935c4bbdfSmrg    /* Force '\n' at end of truncated line */
73035c4bbdfSmrg    if (size - len == 1)
73135c4bbdfSmrg        buf[len - 1] = '\n';
73235c4bbdfSmrg
73335c4bbdfSmrg    newline = (buf[len - 1] == '\n');
73435c4bbdfSmrg    LogSWrite(verb, buf, len, newline);
73505b261ecSmrg}
73605b261ecSmrg
73705b261ecSmrg/* Log message with verbosity level specified. */
7386747b715Smrgvoid
73905b261ecSmrgLogMessageVerb(MessageType type, int verb, const char *format, ...)
74005b261ecSmrg{
74105b261ecSmrg    va_list ap;
74205b261ecSmrg
74305b261ecSmrg    va_start(ap, format);
74405b261ecSmrg    LogVMessageVerb(type, verb, format, ap);
74505b261ecSmrg    va_end(ap);
74605b261ecSmrg}
74705b261ecSmrg
74805b261ecSmrg/* Log a message with the standard verbosity level of 1. */
7496747b715Smrgvoid
75005b261ecSmrgLogMessage(MessageType type, const char *format, ...)
75105b261ecSmrg{
75205b261ecSmrg    va_list ap;
75305b261ecSmrg
75405b261ecSmrg    va_start(ap, format);
75505b261ecSmrg    LogVMessageVerb(type, 1, format, ap);
75605b261ecSmrg    va_end(ap);
75705b261ecSmrg}
75805b261ecSmrg
75935c4bbdfSmrg/* Log a message using only signal safe functions. */
7606747b715Smrgvoid
76135c4bbdfSmrgLogMessageVerbSigSafe(MessageType type, int verb, const char *format, ...)
76235c4bbdfSmrg{
76335c4bbdfSmrg    va_list ap;
76435c4bbdfSmrg    va_start(ap, format);
76535c4bbdfSmrg    LogVMessageVerbSigSafe(type, verb, format, ap);
76635c4bbdfSmrg    va_end(ap);
76735c4bbdfSmrg}
76835c4bbdfSmrg
76935c4bbdfSmrgvoid
77035c4bbdfSmrgLogVMessageVerbSigSafe(MessageType type, int verb, const char *format, va_list args)
77135c4bbdfSmrg{
77235c4bbdfSmrg    const char *type_str;
77335c4bbdfSmrg    char buf[1024];
77435c4bbdfSmrg    int len;
77535c4bbdfSmrg    Bool newline;
77635c4bbdfSmrg
77735c4bbdfSmrg    type_str = LogMessageTypeVerbString(type, verb);
77835c4bbdfSmrg    if (!type_str)
77935c4bbdfSmrg        return;
78035c4bbdfSmrg
78135c4bbdfSmrg    /* if type_str is not "", prepend it and ' ', to message */
78235c4bbdfSmrg    if (type_str[0] != '\0') {
78335c4bbdfSmrg        LogSWrite(verb, type_str, strlen_sigsafe(type_str), FALSE);
78435c4bbdfSmrg        LogSWrite(verb, " ", 1, FALSE);
78535c4bbdfSmrg    }
78635c4bbdfSmrg
78735c4bbdfSmrg    len = vpnprintf(buf, sizeof(buf), format, args);
78835c4bbdfSmrg
78935c4bbdfSmrg    /* Force '\n' at end of truncated line */
79035c4bbdfSmrg    if (sizeof(buf) - len == 1)
79135c4bbdfSmrg        buf[len - 1] = '\n';
79235c4bbdfSmrg
79335c4bbdfSmrg    newline = (len > 0 && buf[len - 1] == '\n');
79435c4bbdfSmrg    LogSWrite(verb, buf, len, newline);
79535c4bbdfSmrg}
79635c4bbdfSmrg
79735c4bbdfSmrgvoid
79835c4bbdfSmrgLogVHdrMessageVerb(MessageType type, int verb, const char *msg_format,
79935c4bbdfSmrg                   va_list msg_args, const char *hdr_format, va_list hdr_args)
80035c4bbdfSmrg{
80135c4bbdfSmrg    const char *type_str;
80235c4bbdfSmrg    char buf[1024];
80335c4bbdfSmrg    const size_t size = sizeof(buf);
80435c4bbdfSmrg    Bool newline;
80535c4bbdfSmrg    size_t len = 0;
80635c4bbdfSmrg    int (*vprintf_func)(char *, int, const char* _X_RESTRICT_KYWD f, va_list args)
80735c4bbdfSmrg            _X_ATTRIBUTE_PRINTF(3, 0);
80835c4bbdfSmrg    int (*printf_func)(char *, int, const char* _X_RESTRICT_KYWD f, ...)
80935c4bbdfSmrg            _X_ATTRIBUTE_PRINTF(3, 4);
81035c4bbdfSmrg
81135c4bbdfSmrg    type_str = LogMessageTypeVerbString(type, verb);
81235c4bbdfSmrg    if (!type_str)
81335c4bbdfSmrg        return;
81435c4bbdfSmrg
81535c4bbdfSmrg    if (inSignalContext) {
81635c4bbdfSmrg        vprintf_func = vpnprintf;
81735c4bbdfSmrg        printf_func = pnprintf;
81835c4bbdfSmrg    } else {
81935c4bbdfSmrg        vprintf_func = Xvscnprintf;
82035c4bbdfSmrg        printf_func = Xscnprintf;
82135c4bbdfSmrg    }
82235c4bbdfSmrg
82335c4bbdfSmrg    /* if type_str is not "", prepend it and ' ', to message */
82435c4bbdfSmrg    if (type_str[0] != '\0')
82535c4bbdfSmrg        len += printf_func(&buf[len], size - len, "%s ", type_str);
82635c4bbdfSmrg
82735c4bbdfSmrg    if (hdr_format && size - len > 1)
82835c4bbdfSmrg        len += vprintf_func(&buf[len], size - len, hdr_format, hdr_args);
82935c4bbdfSmrg
83035c4bbdfSmrg    if (msg_format && size - len > 1)
83135c4bbdfSmrg        len += vprintf_func(&buf[len], size - len, msg_format, msg_args);
83235c4bbdfSmrg
83335c4bbdfSmrg    /* Force '\n' at end of truncated line */
83435c4bbdfSmrg    if (size - len == 1)
83535c4bbdfSmrg        buf[len - 1] = '\n';
83635c4bbdfSmrg
83735c4bbdfSmrg    newline = (buf[len - 1] == '\n');
83835c4bbdfSmrg    LogSWrite(verb, buf, len, newline);
83935c4bbdfSmrg}
84035c4bbdfSmrg
84135c4bbdfSmrgvoid
84235c4bbdfSmrgLogHdrMessageVerb(MessageType type, int verb, const char *msg_format,
84335c4bbdfSmrg                  va_list msg_args, const char *hdr_format, ...)
84435c4bbdfSmrg{
84535c4bbdfSmrg    va_list hdr_args;
84635c4bbdfSmrg
84735c4bbdfSmrg    va_start(hdr_args, hdr_format);
84835c4bbdfSmrg    LogVHdrMessageVerb(type, verb, msg_format, msg_args, hdr_format, hdr_args);
84935c4bbdfSmrg    va_end(hdr_args);
85035c4bbdfSmrg}
85135c4bbdfSmrg
85235c4bbdfSmrgvoid
85335c4bbdfSmrgLogHdrMessage(MessageType type, const char *msg_format, va_list msg_args,
85435c4bbdfSmrg              const char *hdr_format, ...)
85535c4bbdfSmrg{
85635c4bbdfSmrg    va_list hdr_args;
85735c4bbdfSmrg
85835c4bbdfSmrg    va_start(hdr_args, hdr_format);
85935c4bbdfSmrg    LogVHdrMessageVerb(type, 1, msg_format, msg_args, hdr_format, hdr_args);
86035c4bbdfSmrg    va_end(hdr_args);
86135c4bbdfSmrg}
86235c4bbdfSmrg
86335c4bbdfSmrgvoid
86435c4bbdfSmrgAbortServer(void)
86535c4bbdfSmrg    _X_NORETURN;
86605b261ecSmrg
86705b261ecSmrgvoid
86805b261ecSmrgAbortServer(void)
86905b261ecSmrg{
8706747b715Smrg#ifdef XF86BIGFONT
8716747b715Smrg    XF86BigfontCleanup();
8726747b715Smrg#endif
8734642e01fSmrg    CloseWellKnownConnections();
87405b261ecSmrg    OsCleanup(TRUE);
87535c4bbdfSmrg    AbortDevices();
876ed6184dfSmrg    ddxGiveUp(EXIT_ERR_ABORT);
87705b261ecSmrg    fflush(stderr);
87805b261ecSmrg    if (CoreDump)
87935c4bbdfSmrg        OsAbort();
88035c4bbdfSmrg    exit(1);
88105b261ecSmrg}
88205b261ecSmrg
8834642e01fSmrg#define AUDIT_PREFIX "AUDIT: %s: %ld: "
88405b261ecSmrg#ifndef AUDIT_TIMEOUT
88535c4bbdfSmrg#define AUDIT_TIMEOUT ((CARD32)(120 * 1000))    /* 2 mn */
88605b261ecSmrg#endif
88705b261ecSmrg
88805b261ecSmrgstatic int nrepeat = 0;
88905b261ecSmrgstatic int oldlen = -1;
89005b261ecSmrgstatic OsTimerPtr auditTimer = NULL;
89105b261ecSmrg
8926747b715Smrgvoid
89305b261ecSmrgFreeAuditTimer(void)
89405b261ecSmrg{
89505b261ecSmrg    if (auditTimer != NULL) {
89635c4bbdfSmrg        /* Force output of pending messages */
89735c4bbdfSmrg        TimerForce(auditTimer);
89835c4bbdfSmrg        TimerFree(auditTimer);
89935c4bbdfSmrg        auditTimer = NULL;
90005b261ecSmrg    }
90105b261ecSmrg}
90205b261ecSmrg
90305b261ecSmrgstatic char *
90405b261ecSmrgAuditPrefix(void)
90505b261ecSmrg{
90605b261ecSmrg    time_t tm;
90705b261ecSmrg    char *autime, *s;
90805b261ecSmrg    char *tmpBuf;
90905b261ecSmrg    int len;
91005b261ecSmrg
91105b261ecSmrg    time(&tm);
91205b261ecSmrg    autime = ctime(&tm);
91305b261ecSmrg    if ((s = strchr(autime, '\n')))
91435c4bbdfSmrg        *s = '\0';
9154642e01fSmrg    len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + 1;
91605b261ecSmrg    tmpBuf = malloc(len);
91705b261ecSmrg    if (!tmpBuf)
91835c4bbdfSmrg        return NULL;
91935c4bbdfSmrg    snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long) getpid());
92005b261ecSmrg    return tmpBuf;
92105b261ecSmrg}
92205b261ecSmrg
92305b261ecSmrgvoid
92435c4bbdfSmrgAuditF(const char *f, ...)
92505b261ecSmrg{
92605b261ecSmrg    va_list args;
92705b261ecSmrg
92805b261ecSmrg    va_start(args, f);
92905b261ecSmrg
93005b261ecSmrg    VAuditF(f, args);
93105b261ecSmrg    va_end(args);
93205b261ecSmrg}
93305b261ecSmrg
93405b261ecSmrgstatic CARD32
93535c4bbdfSmrgAuditFlush(OsTimerPtr timer, CARD32 now, void *arg)
93605b261ecSmrg{
93705b261ecSmrg    char *prefix;
93805b261ecSmrg
93905b261ecSmrg    if (nrepeat > 0) {
94035c4bbdfSmrg        prefix = AuditPrefix();
94135c4bbdfSmrg        ErrorF("%slast message repeated %d times\n",
94235c4bbdfSmrg               prefix != NULL ? prefix : "", nrepeat);
94335c4bbdfSmrg        nrepeat = 0;
94435c4bbdfSmrg        free(prefix);
94535c4bbdfSmrg        return AUDIT_TIMEOUT;
94635c4bbdfSmrg    }
94735c4bbdfSmrg    else {
94835c4bbdfSmrg        /* if the timer expires without anything to print, flush the message */
94935c4bbdfSmrg        oldlen = -1;
95035c4bbdfSmrg        return 0;
95105b261ecSmrg    }
95205b261ecSmrg}
95305b261ecSmrg
95405b261ecSmrgvoid
95505b261ecSmrgVAuditF(const char *f, va_list args)
95605b261ecSmrg{
95705b261ecSmrg    char *prefix;
95805b261ecSmrg    char buf[1024];
95905b261ecSmrg    int len;
96005b261ecSmrg    static char oldbuf[1024];
96105b261ecSmrg
96205b261ecSmrg    prefix = AuditPrefix();
96305b261ecSmrg    len = vsnprintf(buf, sizeof(buf), f, args);
96405b261ecSmrg
96505b261ecSmrg    if (len == oldlen && strcmp(buf, oldbuf) == 0) {
96635c4bbdfSmrg        /* Message already seen */
96735c4bbdfSmrg        nrepeat++;
96835c4bbdfSmrg    }
96935c4bbdfSmrg    else {
97035c4bbdfSmrg        /* new message */
97135c4bbdfSmrg        if (auditTimer != NULL)
97235c4bbdfSmrg            TimerForce(auditTimer);
97335c4bbdfSmrg        ErrorF("%s%s", prefix != NULL ? prefix : "", buf);
97435c4bbdfSmrg        strlcpy(oldbuf, buf, sizeof(oldbuf));
97535c4bbdfSmrg        oldlen = len;
97635c4bbdfSmrg        nrepeat = 0;
97735c4bbdfSmrg        auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL);
97805b261ecSmrg    }
9799ace9065Smrg    free(prefix);
98005b261ecSmrg}
98105b261ecSmrg
9826747b715Smrgvoid
98305b261ecSmrgFatalError(const char *f, ...)
98405b261ecSmrg{
98505b261ecSmrg    va_list args;
98635c4bbdfSmrg    va_list args2;
98705b261ecSmrg    static Bool beenhere = FALSE;
98805b261ecSmrg
98905b261ecSmrg    if (beenhere)
99035c4bbdfSmrg        ErrorFSigSafe("\nFatalError re-entered, aborting\n");
99105b261ecSmrg    else
99235c4bbdfSmrg        ErrorFSigSafe("\nFatal server error:\n");
99305b261ecSmrg
99405b261ecSmrg    va_start(args, f);
99535c4bbdfSmrg
99635c4bbdfSmrg    /* Make a copy for OsVendorFatalError */
99735c4bbdfSmrg    va_copy(args2, args);
99835c4bbdfSmrg
9996747b715Smrg#ifdef __APPLE__
100035c4bbdfSmrg    {
100135c4bbdfSmrg        va_list apple_args;
100235c4bbdfSmrg
100335c4bbdfSmrg        va_copy(apple_args, args);
100435c4bbdfSmrg        (void)vsnprintf(__crashreporter_info_buff__,
100535c4bbdfSmrg                        sizeof(__crashreporter_info_buff__), f, apple_args);
100635c4bbdfSmrg        va_end(apple_args);
100735c4bbdfSmrg    }
10086747b715Smrg#endif
100935c4bbdfSmrg    VErrorFSigSafe(f, args);
101005b261ecSmrg    va_end(args);
101135c4bbdfSmrg    ErrorFSigSafe("\n");
101205b261ecSmrg    if (!beenhere)
101335c4bbdfSmrg        OsVendorFatalError(f, args2);
101435c4bbdfSmrg    va_end(args2);
101505b261ecSmrg    if (!beenhere) {
101635c4bbdfSmrg        beenhere = TRUE;
101735c4bbdfSmrg        AbortServer();
101835c4bbdfSmrg    }
101935c4bbdfSmrg    else
102035c4bbdfSmrg        OsAbort();
102135c4bbdfSmrg /*NOTREACHED*/}
102205b261ecSmrg
10236747b715Smrgvoid
102405b261ecSmrgVErrorF(const char *f, va_list args)
102505b261ecSmrg{
102605b261ecSmrg#ifdef DDXOSVERRORF
102705b261ecSmrg    if (OsVendorVErrorFProc)
102835c4bbdfSmrg        OsVendorVErrorFProc(f, args);
102905b261ecSmrg    else
103035c4bbdfSmrg        LogVWrite(-1, f, args);
103105b261ecSmrg#else
103205b261ecSmrg    LogVWrite(-1, f, args);
103305b261ecSmrg#endif
103405b261ecSmrg}
103505b261ecSmrg
10366747b715Smrgvoid
103735c4bbdfSmrgErrorF(const char *f, ...)
103805b261ecSmrg{
103905b261ecSmrg    va_list args;
104005b261ecSmrg
104105b261ecSmrg    va_start(args, f);
104205b261ecSmrg    VErrorF(f, args);
104305b261ecSmrg    va_end(args);
104405b261ecSmrg}
104505b261ecSmrg
104635c4bbdfSmrgvoid
104735c4bbdfSmrgVErrorFSigSafe(const char *f, va_list args)
104835c4bbdfSmrg{
104935c4bbdfSmrg    LogVMessageVerbSigSafe(X_ERROR, -1, f, args);
105035c4bbdfSmrg}
105105b261ecSmrg
10526747b715Smrgvoid
105335c4bbdfSmrgErrorFSigSafe(const char *f, ...)
105405b261ecSmrg{
105535c4bbdfSmrg    va_list args;
10569ace9065Smrg
105735c4bbdfSmrg    va_start(args, f);
105835c4bbdfSmrg    VErrorFSigSafe(f, args);
105935c4bbdfSmrg    va_end(args);
106005b261ecSmrg}
106105b261ecSmrg
106205b261ecSmrgvoid
106305b261ecSmrgLogPrintMarkers(void)
106405b261ecSmrg{
106505b261ecSmrg    /* Show what the message marker symbols mean. */
10666747b715Smrg    LogWrite(0, "Markers: ");
10676747b715Smrg    LogMessageVerb(X_PROBED, 0, "probed, ");
10686747b715Smrg    LogMessageVerb(X_CONFIG, 0, "from config file, ");
10696747b715Smrg    LogMessageVerb(X_DEFAULT, 0, "default setting,\n\t");
10706747b715Smrg    LogMessageVerb(X_CMDLINE, 0, "from command line, ");
10716747b715Smrg    LogMessageVerb(X_NOTICE, 0, "notice, ");
10726747b715Smrg    LogMessageVerb(X_INFO, 0, "informational,\n\t");
10736747b715Smrg    LogMessageVerb(X_WARNING, 0, "warning, ");
10746747b715Smrg    LogMessageVerb(X_ERROR, 0, "error, ");
10756747b715Smrg    LogMessageVerb(X_NOT_IMPLEMENTED, 0, "not implemented, ");
10766747b715Smrg    LogMessageVerb(X_UNKNOWN, 0, "unknown.\n");
107705b261ecSmrg}
1078