log.c revision 35c4bbdf
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 "site.h"
9205b261ecSmrg#include "opaque.h"
9305b261ecSmrg
9405b261ecSmrg#ifdef WIN32
9505b261ecSmrg#include <process.h>
9605b261ecSmrg#define getpid(x) _getpid(x)
9705b261ecSmrg#endif
9805b261ecSmrg
996747b715Smrg#ifdef XF86BIGFONT
1006747b715Smrg#include "xf86bigfontsrv.h"
1016747b715Smrg#endif
10205b261ecSmrg
1039ace9065Smrg#ifdef __clang__
1049ace9065Smrg#pragma clang diagnostic ignored "-Wformat-nonliteral"
1059ace9065Smrg#endif
1069ace9065Smrg
10705b261ecSmrg#ifdef DDXOSVERRORF
10835c4bbdfSmrgvoid (*OsVendorVErrorFProc) (const char *, va_list args) = NULL;
10905b261ecSmrg#endif
11005b261ecSmrg
11105b261ecSmrgstatic FILE *logFile = NULL;
11235c4bbdfSmrgstatic int logFileFd = -1;
11305b261ecSmrgstatic Bool logFlush = FALSE;
11405b261ecSmrgstatic Bool logSync = FALSE;
11505b261ecSmrgstatic int logVerbosity = DEFAULT_LOG_VERBOSITY;
11605b261ecSmrgstatic int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY;
11705b261ecSmrg
11805b261ecSmrg/* Buffer to information logged before the log file is opened. */
11905b261ecSmrgstatic char *saveBuffer = NULL;
12005b261ecSmrgstatic int bufferSize = 0, bufferUnused = 0, bufferPos = 0;
12105b261ecSmrgstatic Bool needBuffer = TRUE;
12205b261ecSmrg
1236747b715Smrg#ifdef __APPLE__
1246747b715Smrg#include <AvailabilityMacros.h>
1256747b715Smrg
12635c4bbdfSmrgstatic char __crashreporter_info_buff__[4096] = { 0 };
12735c4bbdfSmrg
12835c4bbdfSmrgstatic const char *__crashreporter_info__ __attribute__ ((__used__)) =
12935c4bbdfSmrg    &__crashreporter_info_buff__[0];
1306747b715Smrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
13135c4bbdfSmrg// This is actually a toolchain requirement, but I'm not sure the correct check,
1326747b715Smrg// but it should be fine to just only include it for Leopard and later.  This line
1336747b715Smrg// just tells the linker to never strip this symbol (such as for space optimization)
13435c4bbdfSmrgasm(".desc ___crashreporter_info__, 0x10");
1356747b715Smrg#endif
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
19735c4bbdfSmrg    if (asprintf(&logFileName, fname, idstring) == -1)
19835c4bbdfSmrg        FatalError("Cannot allocate space for the log file name\n");
19935c4bbdfSmrg
20035c4bbdfSmrg    if (backup && *backup) {
20135c4bbdfSmrg        struct stat buf;
20235c4bbdfSmrg
20335c4bbdfSmrg        if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) {
20435c4bbdfSmrg            char *suffix;
20535c4bbdfSmrg            char *oldLog;
20635c4bbdfSmrg
20735c4bbdfSmrg            if ((asprintf(&suffix, backup, idstring) == -1) ||
20835c4bbdfSmrg                (asprintf(&oldLog, "%s%s", logFileName, suffix) == -1)) {
20935c4bbdfSmrg                FatalError("Cannot allocate space for the log file name\n");
21035c4bbdfSmrg            }
21135c4bbdfSmrg            free(suffix);
21235c4bbdfSmrg
21335c4bbdfSmrg            if (rename(logFileName, oldLog) == -1) {
21435c4bbdfSmrg                FatalError("Cannot move old log file \"%s\" to \"%s\"\n",
21535c4bbdfSmrg                           logFileName, oldLog);
21635c4bbdfSmrg            }
21735c4bbdfSmrg            free(oldLog);
21835c4bbdfSmrg        }
21935c4bbdfSmrg    }
22035c4bbdfSmrg    else {
22135c4bbdfSmrg        if (remove(logFileName) != 0 && errno != ENOENT) {
22235c4bbdfSmrg            FatalError("Cannot remove old log file \"%s\": %s\n",
22335c4bbdfSmrg                       logFileName, strerror(errno));
22435c4bbdfSmrg        }
22535c4bbdfSmrg    }
22635c4bbdfSmrg
22735c4bbdfSmrg    return logFileName;
22835c4bbdfSmrg}
22935c4bbdfSmrg#pragma GCC diagnostic pop
23005b261ecSmrg
23105b261ecSmrg/*
23205b261ecSmrg * LogInit is called to start logging to a file.  It is also called (with
23305b261ecSmrg * NULL arguments) when logging to a file is not wanted.  It must always be
23405b261ecSmrg * called, otherwise log messages will continue to accumulate in a buffer.
23505b261ecSmrg *
23605b261ecSmrg * %s, if present in the fname or backup strings, is expanded to the display
23735c4bbdfSmrg * string (or to a string containing the pid if the display is not yet set).
23805b261ecSmrg */
23905b261ecSmrg
24035c4bbdfSmrgstatic char *saved_log_fname;
24135c4bbdfSmrgstatic char *saved_log_backup;
24235c4bbdfSmrgstatic char *saved_log_tempname;
24335c4bbdfSmrg
24405b261ecSmrgconst char *
24505b261ecSmrgLogInit(const char *fname, const char *backup)
24605b261ecSmrg{
24705b261ecSmrg    char *logFileName = NULL;
24805b261ecSmrg
24905b261ecSmrg    if (fname && *fname) {
25035c4bbdfSmrg        if (displayfd != -1) {
25135c4bbdfSmrg            /* Display isn't set yet, so we can't use it in filenames yet. */
25235c4bbdfSmrg            char pidstring[32];
25335c4bbdfSmrg            snprintf(pidstring, sizeof(pidstring), "pid-%ld",
25435c4bbdfSmrg                     (unsigned long) getpid());
25535c4bbdfSmrg            logFileName = LogFilePrep(fname, backup, pidstring);
25635c4bbdfSmrg            saved_log_tempname = logFileName;
25735c4bbdfSmrg
25835c4bbdfSmrg            /* Save the patterns for use when the display is named. */
25935c4bbdfSmrg            saved_log_fname = strdup(fname);
26035c4bbdfSmrg            if (backup == NULL)
26135c4bbdfSmrg                saved_log_backup = NULL;
26235c4bbdfSmrg            else
26335c4bbdfSmrg                saved_log_backup = strdup(backup);
26435c4bbdfSmrg        } else
26535c4bbdfSmrg            logFileName = LogFilePrep(fname, backup, display);
26635c4bbdfSmrg        if ((logFile = fopen(logFileName, "w")) == NULL)
26735c4bbdfSmrg            FatalError("Cannot open log file \"%s\"\n", logFileName);
26835c4bbdfSmrg        setvbuf(logFile, NULL, _IONBF, 0);
26935c4bbdfSmrg
27035c4bbdfSmrg        logFileFd = fileno(logFile);
27135c4bbdfSmrg
27235c4bbdfSmrg        /* Flush saved log information. */
27335c4bbdfSmrg        if (saveBuffer && bufferSize > 0) {
27435c4bbdfSmrg            fwrite(saveBuffer, bufferPos, 1, logFile);
27535c4bbdfSmrg            fflush(logFile);
27605b261ecSmrg#ifndef WIN32
27735c4bbdfSmrg            fsync(fileno(logFile));
27805b261ecSmrg#endif
27935c4bbdfSmrg        }
28005b261ecSmrg    }
28105b261ecSmrg
28205b261ecSmrg    /*
28305b261ecSmrg     * Unconditionally free the buffer, and flag that the buffer is no longer
28405b261ecSmrg     * needed.
28505b261ecSmrg     */
28605b261ecSmrg    if (saveBuffer && bufferSize > 0) {
28735c4bbdfSmrg        free(saveBuffer);
28835c4bbdfSmrg        saveBuffer = NULL;
28935c4bbdfSmrg        bufferSize = 0;
29005b261ecSmrg    }
29105b261ecSmrg    needBuffer = FALSE;
29205b261ecSmrg
29305b261ecSmrg    return logFileName;
29405b261ecSmrg}
29505b261ecSmrg
29605b261ecSmrgvoid
29735c4bbdfSmrgLogSetDisplay(void)
29835c4bbdfSmrg{
29935c4bbdfSmrg    if (saved_log_fname) {
30035c4bbdfSmrg        char *logFileName;
30135c4bbdfSmrg
30235c4bbdfSmrg        logFileName = LogFilePrep(saved_log_fname, saved_log_backup, display);
30335c4bbdfSmrg
30435c4bbdfSmrg        if (rename(saved_log_tempname, logFileName) == 0) {
30535c4bbdfSmrg            LogMessageVerb(X_PROBED, 0,
30635c4bbdfSmrg                           "Log file renamed from \"%s\" to \"%s\"\n",
30735c4bbdfSmrg                           saved_log_tempname, logFileName);
30835c4bbdfSmrg
30935c4bbdfSmrg            if (strlen(saved_log_tempname) >= strlen(logFileName))
31035c4bbdfSmrg                strncpy(saved_log_tempname, logFileName,
31135c4bbdfSmrg                        strlen(saved_log_tempname));
31235c4bbdfSmrg        }
31335c4bbdfSmrg        else {
31435c4bbdfSmrg            ErrorF("Failed to rename log file \"%s\" to \"%s\": %s\n",
31535c4bbdfSmrg                   saved_log_tempname, logFileName, strerror(errno));
31635c4bbdfSmrg        }
31735c4bbdfSmrg
31835c4bbdfSmrg        /* free newly allocated string - can't free old one since existing
31935c4bbdfSmrg           pointers to it may exist in DDX callers. */
32035c4bbdfSmrg        free(logFileName);
32135c4bbdfSmrg        free(saved_log_fname);
32235c4bbdfSmrg        free(saved_log_backup);
32335c4bbdfSmrg    }
32435c4bbdfSmrg}
32535c4bbdfSmrg
32635c4bbdfSmrgvoid
32735c4bbdfSmrgLogClose(enum ExitCode error)
32805b261ecSmrg{
32905b261ecSmrg    if (logFile) {
33035c4bbdfSmrg        int msgtype = (error == EXIT_NO_ERROR) ? X_INFO : X_ERROR;
33135c4bbdfSmrg        LogMessageVerbSigSafe(msgtype, -1,
33235c4bbdfSmrg                "Server terminated %s (%d). Closing log file.\n",
33335c4bbdfSmrg                (error == EXIT_NO_ERROR) ? "successfully" : "with error",
33435c4bbdfSmrg                error);
33535c4bbdfSmrg        fclose(logFile);
33635c4bbdfSmrg        logFile = NULL;
33735c4bbdfSmrg        logFileFd = -1;
33805b261ecSmrg    }
33905b261ecSmrg}
34005b261ecSmrg
34105b261ecSmrgBool
34205b261ecSmrgLogSetParameter(LogParameter param, int value)
34305b261ecSmrg{
34405b261ecSmrg    switch (param) {
34505b261ecSmrg    case XLOG_FLUSH:
34635c4bbdfSmrg        logFlush = value ? TRUE : FALSE;
34735c4bbdfSmrg        return TRUE;
34805b261ecSmrg    case XLOG_SYNC:
34935c4bbdfSmrg        logSync = value ? TRUE : FALSE;
35035c4bbdfSmrg        return TRUE;
35105b261ecSmrg    case XLOG_VERBOSITY:
35235c4bbdfSmrg        logVerbosity = value;
35335c4bbdfSmrg        return TRUE;
35405b261ecSmrg    case XLOG_FILE_VERBOSITY:
35535c4bbdfSmrg        logFileVerbosity = value;
35635c4bbdfSmrg        return TRUE;
35705b261ecSmrg    default:
35835c4bbdfSmrg        return FALSE;
35905b261ecSmrg    }
36005b261ecSmrg}
36105b261ecSmrg
36235c4bbdfSmrgenum {
36335c4bbdfSmrg    LMOD_LONG     = 0x1,
36435c4bbdfSmrg    LMOD_LONGLONG = 0x2,
36535c4bbdfSmrg    LMOD_SHORT    = 0x4,
36635c4bbdfSmrg    LMOD_SIZET    = 0x8,
36735c4bbdfSmrg};
36805b261ecSmrg
36935c4bbdfSmrg/**
37035c4bbdfSmrg * Parse non-digit length modifiers and set the corresponding flag in
37135c4bbdfSmrg * flags_return.
37235c4bbdfSmrg *
37335c4bbdfSmrg * @return the number of bytes parsed
37435c4bbdfSmrg */
37535c4bbdfSmrgstatic int parse_length_modifier(const char *format, size_t len, int *flags_return)
37605b261ecSmrg{
37735c4bbdfSmrg    int idx = 0;
37835c4bbdfSmrg    int length_modifier = 0;
37935c4bbdfSmrg
38035c4bbdfSmrg    while (idx < len) {
38135c4bbdfSmrg        switch (format[idx]) {
38235c4bbdfSmrg            case 'l':
38335c4bbdfSmrg                BUG_RETURN_VAL(length_modifier & LMOD_SHORT, 0);
38435c4bbdfSmrg
38535c4bbdfSmrg                if (length_modifier & LMOD_LONG)
38635c4bbdfSmrg                    length_modifier |= LMOD_LONGLONG;
38735c4bbdfSmrg                else
38835c4bbdfSmrg                    length_modifier |= LMOD_LONG;
38935c4bbdfSmrg                break;
39035c4bbdfSmrg            case 'h':
39135c4bbdfSmrg                BUG_RETURN_VAL(length_modifier & (LMOD_LONG|LMOD_LONGLONG), 0);
39235c4bbdfSmrg                length_modifier |= LMOD_SHORT;
39335c4bbdfSmrg                /* gcc says 'short int' is promoted to 'int' when
39435c4bbdfSmrg                 * passed through '...', so ignored during
39535c4bbdfSmrg                 * processing */
39635c4bbdfSmrg                break;
39735c4bbdfSmrg            case 'z':
39835c4bbdfSmrg                length_modifier |= LMOD_SIZET;
39935c4bbdfSmrg                break;
40035c4bbdfSmrg            default:
40135c4bbdfSmrg                goto out;
40235c4bbdfSmrg        }
40335c4bbdfSmrg        idx++;
4046747b715Smrg    }
40505b261ecSmrg
40635c4bbdfSmrgout:
40735c4bbdfSmrg    *flags_return = length_modifier;
40835c4bbdfSmrg    return idx;
40935c4bbdfSmrg}
41035c4bbdfSmrg
41135c4bbdfSmrg/**
41235c4bbdfSmrg * Signal-safe snprintf, with some limitations over snprintf. Be careful
41335c4bbdfSmrg * which directives you use.
41435c4bbdfSmrg */
41535c4bbdfSmrgstatic int
41635c4bbdfSmrgvpnprintf(char *string, int size_in, const char *f, va_list args)
41735c4bbdfSmrg{
41835c4bbdfSmrg    int f_idx = 0;
41935c4bbdfSmrg    int s_idx = 0;
42035c4bbdfSmrg    int f_len = strlen_sigsafe(f);
42135c4bbdfSmrg    char *string_arg;
42235c4bbdfSmrg    char number[21];
42335c4bbdfSmrg    int p_len;
42435c4bbdfSmrg    int i;
42535c4bbdfSmrg    uint64_t ui;
42635c4bbdfSmrg    int64_t si;
42735c4bbdfSmrg    size_t size = size_in;
42835c4bbdfSmrg    int precision;
42935c4bbdfSmrg
43035c4bbdfSmrg    for (; f_idx < f_len && s_idx < size - 1; f_idx++) {
43135c4bbdfSmrg        int length_modifier = 0;
43235c4bbdfSmrg        if (f[f_idx] != '%') {
43335c4bbdfSmrg            string[s_idx++] = f[f_idx];
43435c4bbdfSmrg            continue;
43535c4bbdfSmrg        }
43635c4bbdfSmrg
43735c4bbdfSmrg        f_idx++;
43835c4bbdfSmrg
43935c4bbdfSmrg        /* silently swallow minimum field width */
44035c4bbdfSmrg        if (f[f_idx] == '*') {
44135c4bbdfSmrg            f_idx++;
44235c4bbdfSmrg            va_arg(args, int);
44335c4bbdfSmrg        } else {
44435c4bbdfSmrg            while (f_idx < f_len && ((f[f_idx] >= '0' && f[f_idx] <= '9')))
44535c4bbdfSmrg                f_idx++;
44635c4bbdfSmrg        }
44735c4bbdfSmrg
44835c4bbdfSmrg        /* is there a precision? */
44935c4bbdfSmrg        precision = size;
45035c4bbdfSmrg        if (f[f_idx] == '.') {
45135c4bbdfSmrg            f_idx++;
45235c4bbdfSmrg            if (f[f_idx] == '*') {
45335c4bbdfSmrg                f_idx++;
45435c4bbdfSmrg                /* precision is supplied in an int argument */
45535c4bbdfSmrg                precision = va_arg(args, int);
45635c4bbdfSmrg            } else {
45735c4bbdfSmrg                /* silently swallow precision digits */
45835c4bbdfSmrg                while (f_idx < f_len && ((f[f_idx] >= '0' && f[f_idx] <= '9')))
45935c4bbdfSmrg                    f_idx++;
46035c4bbdfSmrg            }
46135c4bbdfSmrg        }
46235c4bbdfSmrg
46335c4bbdfSmrg        /* non-digit length modifiers */
46435c4bbdfSmrg        if (f_idx < f_len) {
46535c4bbdfSmrg            int parsed_bytes = parse_length_modifier(&f[f_idx], f_len - f_idx, &length_modifier);
46635c4bbdfSmrg            if (parsed_bytes < 0)
46735c4bbdfSmrg                return 0;
46835c4bbdfSmrg            f_idx += parsed_bytes;
46935c4bbdfSmrg        }
47035c4bbdfSmrg
47135c4bbdfSmrg        if (f_idx >= f_len)
47235c4bbdfSmrg            break;
47335c4bbdfSmrg
47435c4bbdfSmrg        switch (f[f_idx]) {
47535c4bbdfSmrg        case 's':
47635c4bbdfSmrg            string_arg = va_arg(args, char*);
47735c4bbdfSmrg
47835c4bbdfSmrg            for (i = 0; string_arg[i] != 0 && s_idx < size - 1 && s_idx < precision; i++)
47935c4bbdfSmrg                string[s_idx++] = string_arg[i];
48035c4bbdfSmrg            break;
48135c4bbdfSmrg
48235c4bbdfSmrg        case 'u':
48335c4bbdfSmrg            if (length_modifier & LMOD_LONGLONG)
48435c4bbdfSmrg                ui = va_arg(args, unsigned long long);
48535c4bbdfSmrg            else if (length_modifier & LMOD_LONG)
48635c4bbdfSmrg                ui = va_arg(args, unsigned long);
48735c4bbdfSmrg            else if (length_modifier & LMOD_SIZET)
48835c4bbdfSmrg                ui = va_arg(args, size_t);
48935c4bbdfSmrg            else
49035c4bbdfSmrg                ui = va_arg(args, unsigned);
49135c4bbdfSmrg
49235c4bbdfSmrg            FormatUInt64(ui, number);
49335c4bbdfSmrg            p_len = strlen_sigsafe(number);
49435c4bbdfSmrg
49535c4bbdfSmrg            for (i = 0; i < p_len && s_idx < size - 1; i++)
49635c4bbdfSmrg                string[s_idx++] = number[i];
49735c4bbdfSmrg            break;
49835c4bbdfSmrg        case 'i':
49935c4bbdfSmrg        case 'd':
50035c4bbdfSmrg            if (length_modifier & LMOD_LONGLONG)
50135c4bbdfSmrg                si = va_arg(args, long long);
50235c4bbdfSmrg            else if (length_modifier & LMOD_LONG)
50335c4bbdfSmrg                si = va_arg(args, long);
50435c4bbdfSmrg            else if (length_modifier & LMOD_SIZET)
50535c4bbdfSmrg                si = va_arg(args, ssize_t);
50635c4bbdfSmrg            else
50735c4bbdfSmrg                si = va_arg(args, int);
50835c4bbdfSmrg
50935c4bbdfSmrg            FormatInt64(si, number);
51035c4bbdfSmrg            p_len = strlen_sigsafe(number);
51135c4bbdfSmrg
51235c4bbdfSmrg            for (i = 0; i < p_len && s_idx < size - 1; i++)
51335c4bbdfSmrg                string[s_idx++] = number[i];
51435c4bbdfSmrg            break;
51535c4bbdfSmrg
51635c4bbdfSmrg        case 'p':
51735c4bbdfSmrg            string[s_idx++] = '0';
51835c4bbdfSmrg            if (s_idx < size - 1)
51935c4bbdfSmrg                string[s_idx++] = 'x';
52035c4bbdfSmrg            ui = (uintptr_t)va_arg(args, void*);
52135c4bbdfSmrg            FormatUInt64Hex(ui, number);
52235c4bbdfSmrg            p_len = strlen_sigsafe(number);
52335c4bbdfSmrg
52435c4bbdfSmrg            for (i = 0; i < p_len && s_idx < size - 1; i++)
52535c4bbdfSmrg                string[s_idx++] = number[i];
52635c4bbdfSmrg            break;
52735c4bbdfSmrg
52835c4bbdfSmrg        case 'x':
52935c4bbdfSmrg            if (length_modifier & LMOD_LONGLONG)
53035c4bbdfSmrg                ui = va_arg(args, unsigned long long);
53135c4bbdfSmrg            else if (length_modifier & LMOD_LONG)
53235c4bbdfSmrg                ui = va_arg(args, unsigned long);
53335c4bbdfSmrg            else if (length_modifier & LMOD_SIZET)
53435c4bbdfSmrg                ui = va_arg(args, size_t);
53535c4bbdfSmrg            else
53635c4bbdfSmrg                ui = va_arg(args, unsigned);
53735c4bbdfSmrg
53835c4bbdfSmrg            FormatUInt64Hex(ui, number);
53935c4bbdfSmrg            p_len = strlen_sigsafe(number);
54035c4bbdfSmrg
54135c4bbdfSmrg            for (i = 0; i < p_len && s_idx < size - 1; i++)
54235c4bbdfSmrg                string[s_idx++] = number[i];
54335c4bbdfSmrg            break;
54435c4bbdfSmrg        case 'f':
54535c4bbdfSmrg            {
54635c4bbdfSmrg                double d = va_arg(args, double);
54735c4bbdfSmrg                FormatDouble(d, number);
54835c4bbdfSmrg                p_len = strlen_sigsafe(number);
54935c4bbdfSmrg
55035c4bbdfSmrg                for (i = 0; i < p_len && s_idx < size - 1; i++)
55135c4bbdfSmrg                    string[s_idx++] = number[i];
55235c4bbdfSmrg            }
55335c4bbdfSmrg            break;
55435c4bbdfSmrg        case 'c':
55535c4bbdfSmrg            {
55635c4bbdfSmrg                char c = va_arg(args, int);
55735c4bbdfSmrg                if (s_idx < size - 1)
55835c4bbdfSmrg                    string[s_idx++] = c;
55935c4bbdfSmrg            }
56035c4bbdfSmrg            break;
56135c4bbdfSmrg        case '%':
56235c4bbdfSmrg            string[s_idx++] = '%';
56335c4bbdfSmrg            break;
56435c4bbdfSmrg        default:
56535c4bbdfSmrg            BUG_WARN_MSG(f[f_idx], "Unsupported printf directive '%c'\n", f[f_idx]);
56635c4bbdfSmrg            va_arg(args, char*);
56735c4bbdfSmrg            string[s_idx++] = '%';
56835c4bbdfSmrg            if (s_idx < size - 1)
56935c4bbdfSmrg                string[s_idx++] = f[f_idx];
57035c4bbdfSmrg            break;
57135c4bbdfSmrg        }
57205b261ecSmrg    }
57335c4bbdfSmrg
57435c4bbdfSmrg    string[s_idx] = '\0';
57535c4bbdfSmrg
57635c4bbdfSmrg    return s_idx;
57735c4bbdfSmrg}
57835c4bbdfSmrg
57935c4bbdfSmrgstatic int
58035c4bbdfSmrgpnprintf(char *string, int size, const char *f, ...)
58135c4bbdfSmrg{
58235c4bbdfSmrg    int rc;
58335c4bbdfSmrg    va_list args;
58435c4bbdfSmrg
58535c4bbdfSmrg    va_start(args, f);
58635c4bbdfSmrg    rc = vpnprintf(string, size, f, args);
58735c4bbdfSmrg    va_end(args);
58835c4bbdfSmrg
58935c4bbdfSmrg    return rc;
59035c4bbdfSmrg}
59135c4bbdfSmrg
59235c4bbdfSmrg/* This function does the actual log message writes. It must be signal safe.
59335c4bbdfSmrg * When attempting to call non-signal-safe functions, guard them with a check
59435c4bbdfSmrg * of the inSignalContext global variable. */
59535c4bbdfSmrgstatic void
59635c4bbdfSmrgLogSWrite(int verb, const char *buf, size_t len, Bool end_line)
59735c4bbdfSmrg{
59835c4bbdfSmrg    static Bool newline = TRUE;
59935c4bbdfSmrg    int ret;
60035c4bbdfSmrg
60135c4bbdfSmrg    if (verb < 0 || logVerbosity >= verb)
60235c4bbdfSmrg        ret = write(2, buf, len);
60335c4bbdfSmrg
60435c4bbdfSmrg    if (verb < 0 || logFileVerbosity >= verb) {
60535c4bbdfSmrg        if (inSignalContext && logFileFd >= 0) {
60635c4bbdfSmrg            ret = write(logFileFd, buf, len);
60705b261ecSmrg#ifndef WIN32
60835c4bbdfSmrg            if (logFlush && logSync)
60935c4bbdfSmrg                fsync(logFileFd);
61005b261ecSmrg#endif
61135c4bbdfSmrg        }
61235c4bbdfSmrg        else if (!inSignalContext && logFile) {
61335c4bbdfSmrg            if (newline)
61435c4bbdfSmrg                fprintf(logFile, "[%10.3f] ", GetTimeInMillis() / 1000.0);
61535c4bbdfSmrg            newline = end_line;
61635c4bbdfSmrg            fwrite(buf, len, 1, logFile);
61735c4bbdfSmrg            if (logFlush) {
61835c4bbdfSmrg                fflush(logFile);
61935c4bbdfSmrg#ifndef WIN32
62035c4bbdfSmrg                if (logSync)
62135c4bbdfSmrg                    fsync(fileno(logFile));
62235c4bbdfSmrg#endif
62335c4bbdfSmrg            }
62435c4bbdfSmrg        }
62535c4bbdfSmrg        else if (!inSignalContext && needBuffer) {
62635c4bbdfSmrg            if (len > bufferUnused) {
62735c4bbdfSmrg                bufferSize += 1024;
62835c4bbdfSmrg                bufferUnused += 1024;
62935c4bbdfSmrg                saveBuffer = realloc(saveBuffer, bufferSize);
63035c4bbdfSmrg                if (!saveBuffer)
63135c4bbdfSmrg                    FatalError("realloc() failed while saving log messages\n");
63235c4bbdfSmrg            }
63335c4bbdfSmrg            bufferUnused -= len;
63435c4bbdfSmrg            memcpy(saveBuffer + bufferPos, buf, len);
63535c4bbdfSmrg            bufferPos += len;
63635c4bbdfSmrg        }
63705b261ecSmrg    }
63835c4bbdfSmrg
63935c4bbdfSmrg    /* There's no place to log an error message if the log write
64035c4bbdfSmrg     * fails...
64135c4bbdfSmrg     */
64235c4bbdfSmrg    (void) ret;
64335c4bbdfSmrg}
64435c4bbdfSmrg
64535c4bbdfSmrgvoid
64635c4bbdfSmrgLogVWrite(int verb, const char *f, va_list args)
64735c4bbdfSmrg{
64835c4bbdfSmrg    return LogVMessageVerb(X_NONE, verb, f, args);
64905b261ecSmrg}
65005b261ecSmrg
6516747b715Smrgvoid
65205b261ecSmrgLogWrite(int verb, const char *f, ...)
65305b261ecSmrg{
65405b261ecSmrg    va_list args;
65505b261ecSmrg
65605b261ecSmrg    va_start(args, f);
65705b261ecSmrg    LogVWrite(verb, f, args);
65805b261ecSmrg    va_end(args);
65905b261ecSmrg}
66005b261ecSmrg
66135c4bbdfSmrg/* Returns the Message Type string to prepend to a logging message, or NULL
66235c4bbdfSmrg * if the message will be dropped due to insufficient verbosity. */
66335c4bbdfSmrgstatic const char *
66435c4bbdfSmrgLogMessageTypeVerbString(MessageType type, int verb)
66535c4bbdfSmrg{
66635c4bbdfSmrg    if (type == X_ERROR)
66735c4bbdfSmrg        verb = 0;
66835c4bbdfSmrg
66935c4bbdfSmrg    if (logVerbosity < verb && logFileVerbosity < verb)
67035c4bbdfSmrg        return NULL;
67135c4bbdfSmrg
67235c4bbdfSmrg    switch (type) {
67335c4bbdfSmrg    case X_PROBED:
67435c4bbdfSmrg        return X_PROBE_STRING;
67535c4bbdfSmrg    case X_CONFIG:
67635c4bbdfSmrg        return X_CONFIG_STRING;
67735c4bbdfSmrg    case X_DEFAULT:
67835c4bbdfSmrg        return X_DEFAULT_STRING;
67935c4bbdfSmrg    case X_CMDLINE:
68035c4bbdfSmrg        return X_CMDLINE_STRING;
68135c4bbdfSmrg    case X_NOTICE:
68235c4bbdfSmrg        return X_NOTICE_STRING;
68335c4bbdfSmrg    case X_ERROR:
68435c4bbdfSmrg        return X_ERROR_STRING;
68535c4bbdfSmrg    case X_WARNING:
68635c4bbdfSmrg        return X_WARNING_STRING;
68735c4bbdfSmrg    case X_INFO:
68835c4bbdfSmrg        return X_INFO_STRING;
68935c4bbdfSmrg    case X_NOT_IMPLEMENTED:
69035c4bbdfSmrg        return X_NOT_IMPLEMENTED_STRING;
69135c4bbdfSmrg    case X_UNKNOWN:
69235c4bbdfSmrg        return X_UNKNOWN_STRING;
69335c4bbdfSmrg    case X_NONE:
69435c4bbdfSmrg        return X_NONE_STRING;
69535c4bbdfSmrg    case X_DEBUG:
69635c4bbdfSmrg        return X_DEBUG_STRING;
69735c4bbdfSmrg    default:
69835c4bbdfSmrg        return X_UNKNOWN_STRING;
69935c4bbdfSmrg    }
70035c4bbdfSmrg}
70135c4bbdfSmrg
7026747b715Smrgvoid
70305b261ecSmrgLogVMessageVerb(MessageType type, int verb, const char *format, va_list args)
70405b261ecSmrg{
70535c4bbdfSmrg    const char *type_str;
70635c4bbdfSmrg    char buf[1024];
70735c4bbdfSmrg    const size_t size = sizeof(buf);
70835c4bbdfSmrg    Bool newline;
70935c4bbdfSmrg    size_t len = 0;
71035c4bbdfSmrg
71135c4bbdfSmrg    if (inSignalContext) {
71235c4bbdfSmrg        LogVMessageVerbSigSafe(type, verb, format, args);
71335c4bbdfSmrg        return;
71405b261ecSmrg    }
71535c4bbdfSmrg
71635c4bbdfSmrg    type_str = LogMessageTypeVerbString(type, verb);
71735c4bbdfSmrg    if (!type_str)
71835c4bbdfSmrg        return;
71935c4bbdfSmrg
72035c4bbdfSmrg    /* if type_str is not "", prepend it and ' ', to message */
72135c4bbdfSmrg    if (type_str[0] != '\0')
72235c4bbdfSmrg        len += Xscnprintf(&buf[len], size - len, "%s ", type_str);
72335c4bbdfSmrg
72435c4bbdfSmrg    if (size - len > 1)
72535c4bbdfSmrg        len += Xvscnprintf(&buf[len], size - len, format, args);
72635c4bbdfSmrg
72735c4bbdfSmrg    /* Force '\n' at end of truncated line */
72835c4bbdfSmrg    if (size - len == 1)
72935c4bbdfSmrg        buf[len - 1] = '\n';
73035c4bbdfSmrg
73135c4bbdfSmrg    newline = (buf[len - 1] == '\n');
73235c4bbdfSmrg    LogSWrite(verb, buf, len, newline);
73305b261ecSmrg}
73405b261ecSmrg
73505b261ecSmrg/* Log message with verbosity level specified. */
7366747b715Smrgvoid
73705b261ecSmrgLogMessageVerb(MessageType type, int verb, const char *format, ...)
73805b261ecSmrg{
73905b261ecSmrg    va_list ap;
74005b261ecSmrg
74105b261ecSmrg    va_start(ap, format);
74205b261ecSmrg    LogVMessageVerb(type, verb, format, ap);
74305b261ecSmrg    va_end(ap);
74405b261ecSmrg}
74505b261ecSmrg
74605b261ecSmrg/* Log a message with the standard verbosity level of 1. */
7476747b715Smrgvoid
74805b261ecSmrgLogMessage(MessageType type, const char *format, ...)
74905b261ecSmrg{
75005b261ecSmrg    va_list ap;
75105b261ecSmrg
75205b261ecSmrg    va_start(ap, format);
75305b261ecSmrg    LogVMessageVerb(type, 1, format, ap);
75405b261ecSmrg    va_end(ap);
75505b261ecSmrg}
75605b261ecSmrg
75735c4bbdfSmrg/* Log a message using only signal safe functions. */
7586747b715Smrgvoid
75935c4bbdfSmrgLogMessageVerbSigSafe(MessageType type, int verb, const char *format, ...)
76035c4bbdfSmrg{
76135c4bbdfSmrg    va_list ap;
76235c4bbdfSmrg    va_start(ap, format);
76335c4bbdfSmrg    LogVMessageVerbSigSafe(type, verb, format, ap);
76435c4bbdfSmrg    va_end(ap);
76535c4bbdfSmrg}
76635c4bbdfSmrg
76735c4bbdfSmrgvoid
76835c4bbdfSmrgLogVMessageVerbSigSafe(MessageType type, int verb, const char *format, va_list args)
76935c4bbdfSmrg{
77035c4bbdfSmrg    const char *type_str;
77135c4bbdfSmrg    char buf[1024];
77235c4bbdfSmrg    int len;
77335c4bbdfSmrg    Bool newline;
77435c4bbdfSmrg
77535c4bbdfSmrg    type_str = LogMessageTypeVerbString(type, verb);
77635c4bbdfSmrg    if (!type_str)
77735c4bbdfSmrg        return;
77835c4bbdfSmrg
77935c4bbdfSmrg    /* if type_str is not "", prepend it and ' ', to message */
78035c4bbdfSmrg    if (type_str[0] != '\0') {
78135c4bbdfSmrg        LogSWrite(verb, type_str, strlen_sigsafe(type_str), FALSE);
78235c4bbdfSmrg        LogSWrite(verb, " ", 1, FALSE);
78335c4bbdfSmrg    }
78435c4bbdfSmrg
78535c4bbdfSmrg    len = vpnprintf(buf, sizeof(buf), format, args);
78635c4bbdfSmrg
78735c4bbdfSmrg    /* Force '\n' at end of truncated line */
78835c4bbdfSmrg    if (sizeof(buf) - len == 1)
78935c4bbdfSmrg        buf[len - 1] = '\n';
79035c4bbdfSmrg
79135c4bbdfSmrg    newline = (len > 0 && buf[len - 1] == '\n');
79235c4bbdfSmrg    LogSWrite(verb, buf, len, newline);
79335c4bbdfSmrg}
79435c4bbdfSmrg
79535c4bbdfSmrgvoid
79635c4bbdfSmrgLogVHdrMessageVerb(MessageType type, int verb, const char *msg_format,
79735c4bbdfSmrg                   va_list msg_args, const char *hdr_format, va_list hdr_args)
79835c4bbdfSmrg{
79935c4bbdfSmrg    const char *type_str;
80035c4bbdfSmrg    char buf[1024];
80135c4bbdfSmrg    const size_t size = sizeof(buf);
80235c4bbdfSmrg    Bool newline;
80335c4bbdfSmrg    size_t len = 0;
80435c4bbdfSmrg    int (*vprintf_func)(char *, int, const char* _X_RESTRICT_KYWD f, va_list args)
80535c4bbdfSmrg            _X_ATTRIBUTE_PRINTF(3, 0);
80635c4bbdfSmrg    int (*printf_func)(char *, int, const char* _X_RESTRICT_KYWD f, ...)
80735c4bbdfSmrg            _X_ATTRIBUTE_PRINTF(3, 4);
80835c4bbdfSmrg
80935c4bbdfSmrg    type_str = LogMessageTypeVerbString(type, verb);
81035c4bbdfSmrg    if (!type_str)
81135c4bbdfSmrg        return;
81235c4bbdfSmrg
81335c4bbdfSmrg    if (inSignalContext) {
81435c4bbdfSmrg        vprintf_func = vpnprintf;
81535c4bbdfSmrg        printf_func = pnprintf;
81635c4bbdfSmrg    } else {
81735c4bbdfSmrg        vprintf_func = Xvscnprintf;
81835c4bbdfSmrg        printf_func = Xscnprintf;
81935c4bbdfSmrg    }
82035c4bbdfSmrg
82135c4bbdfSmrg    /* if type_str is not "", prepend it and ' ', to message */
82235c4bbdfSmrg    if (type_str[0] != '\0')
82335c4bbdfSmrg        len += printf_func(&buf[len], size - len, "%s ", type_str);
82435c4bbdfSmrg
82535c4bbdfSmrg    if (hdr_format && size - len > 1)
82635c4bbdfSmrg        len += vprintf_func(&buf[len], size - len, hdr_format, hdr_args);
82735c4bbdfSmrg
82835c4bbdfSmrg    if (msg_format && size - len > 1)
82935c4bbdfSmrg        len += vprintf_func(&buf[len], size - len, msg_format, msg_args);
83035c4bbdfSmrg
83135c4bbdfSmrg    /* Force '\n' at end of truncated line */
83235c4bbdfSmrg    if (size - len == 1)
83335c4bbdfSmrg        buf[len - 1] = '\n';
83435c4bbdfSmrg
83535c4bbdfSmrg    newline = (buf[len - 1] == '\n');
83635c4bbdfSmrg    LogSWrite(verb, buf, len, newline);
83735c4bbdfSmrg}
83835c4bbdfSmrg
83935c4bbdfSmrgvoid
84035c4bbdfSmrgLogHdrMessageVerb(MessageType type, int verb, const char *msg_format,
84135c4bbdfSmrg                  va_list msg_args, const char *hdr_format, ...)
84235c4bbdfSmrg{
84335c4bbdfSmrg    va_list hdr_args;
84435c4bbdfSmrg
84535c4bbdfSmrg    va_start(hdr_args, hdr_format);
84635c4bbdfSmrg    LogVHdrMessageVerb(type, verb, msg_format, msg_args, hdr_format, hdr_args);
84735c4bbdfSmrg    va_end(hdr_args);
84835c4bbdfSmrg}
84935c4bbdfSmrg
85035c4bbdfSmrgvoid
85135c4bbdfSmrgLogHdrMessage(MessageType type, const char *msg_format, va_list msg_args,
85235c4bbdfSmrg              const char *hdr_format, ...)
85335c4bbdfSmrg{
85435c4bbdfSmrg    va_list hdr_args;
85535c4bbdfSmrg
85635c4bbdfSmrg    va_start(hdr_args, hdr_format);
85735c4bbdfSmrg    LogVHdrMessageVerb(type, 1, msg_format, msg_args, hdr_format, hdr_args);
85835c4bbdfSmrg    va_end(hdr_args);
85935c4bbdfSmrg}
86035c4bbdfSmrg
86135c4bbdfSmrgvoid
86235c4bbdfSmrgAbortServer(void)
86335c4bbdfSmrg    _X_NORETURN;
86405b261ecSmrg
86505b261ecSmrgvoid
86605b261ecSmrgAbortServer(void)
86705b261ecSmrg{
8686747b715Smrg#ifdef XF86BIGFONT
8696747b715Smrg    XF86BigfontCleanup();
8706747b715Smrg#endif
8714642e01fSmrg    CloseWellKnownConnections();
87205b261ecSmrg    OsCleanup(TRUE);
87335c4bbdfSmrg    AbortDevices();
87435c4bbdfSmrg    AbortDDX(EXIT_ERR_ABORT);
87505b261ecSmrg    fflush(stderr);
87605b261ecSmrg    if (CoreDump)
87735c4bbdfSmrg        OsAbort();
87835c4bbdfSmrg    exit(1);
87905b261ecSmrg}
88005b261ecSmrg
8814642e01fSmrg#define AUDIT_PREFIX "AUDIT: %s: %ld: "
88205b261ecSmrg#ifndef AUDIT_TIMEOUT
88335c4bbdfSmrg#define AUDIT_TIMEOUT ((CARD32)(120 * 1000))    /* 2 mn */
88405b261ecSmrg#endif
88505b261ecSmrg
88605b261ecSmrgstatic int nrepeat = 0;
88705b261ecSmrgstatic int oldlen = -1;
88805b261ecSmrgstatic OsTimerPtr auditTimer = NULL;
88905b261ecSmrg
8906747b715Smrgvoid
89105b261ecSmrgFreeAuditTimer(void)
89205b261ecSmrg{
89305b261ecSmrg    if (auditTimer != NULL) {
89435c4bbdfSmrg        /* Force output of pending messages */
89535c4bbdfSmrg        TimerForce(auditTimer);
89635c4bbdfSmrg        TimerFree(auditTimer);
89735c4bbdfSmrg        auditTimer = NULL;
89805b261ecSmrg    }
89905b261ecSmrg}
90005b261ecSmrg
90105b261ecSmrgstatic char *
90205b261ecSmrgAuditPrefix(void)
90305b261ecSmrg{
90405b261ecSmrg    time_t tm;
90505b261ecSmrg    char *autime, *s;
90605b261ecSmrg    char *tmpBuf;
90705b261ecSmrg    int len;
90805b261ecSmrg
90905b261ecSmrg    time(&tm);
91005b261ecSmrg    autime = ctime(&tm);
91105b261ecSmrg    if ((s = strchr(autime, '\n')))
91235c4bbdfSmrg        *s = '\0';
9134642e01fSmrg    len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + 1;
91405b261ecSmrg    tmpBuf = malloc(len);
91505b261ecSmrg    if (!tmpBuf)
91635c4bbdfSmrg        return NULL;
91735c4bbdfSmrg    snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long) getpid());
91805b261ecSmrg    return tmpBuf;
91905b261ecSmrg}
92005b261ecSmrg
92105b261ecSmrgvoid
92235c4bbdfSmrgAuditF(const char *f, ...)
92305b261ecSmrg{
92405b261ecSmrg    va_list args;
92505b261ecSmrg
92605b261ecSmrg    va_start(args, f);
92705b261ecSmrg
92805b261ecSmrg    VAuditF(f, args);
92905b261ecSmrg    va_end(args);
93005b261ecSmrg}
93105b261ecSmrg
93205b261ecSmrgstatic CARD32
93335c4bbdfSmrgAuditFlush(OsTimerPtr timer, CARD32 now, void *arg)
93405b261ecSmrg{
93505b261ecSmrg    char *prefix;
93605b261ecSmrg
93705b261ecSmrg    if (nrepeat > 0) {
93835c4bbdfSmrg        prefix = AuditPrefix();
93935c4bbdfSmrg        ErrorF("%slast message repeated %d times\n",
94035c4bbdfSmrg               prefix != NULL ? prefix : "", nrepeat);
94135c4bbdfSmrg        nrepeat = 0;
94235c4bbdfSmrg        free(prefix);
94335c4bbdfSmrg        return AUDIT_TIMEOUT;
94435c4bbdfSmrg    }
94535c4bbdfSmrg    else {
94635c4bbdfSmrg        /* if the timer expires without anything to print, flush the message */
94735c4bbdfSmrg        oldlen = -1;
94835c4bbdfSmrg        return 0;
94905b261ecSmrg    }
95005b261ecSmrg}
95105b261ecSmrg
95205b261ecSmrgvoid
95305b261ecSmrgVAuditF(const char *f, va_list args)
95405b261ecSmrg{
95505b261ecSmrg    char *prefix;
95605b261ecSmrg    char buf[1024];
95705b261ecSmrg    int len;
95805b261ecSmrg    static char oldbuf[1024];
95905b261ecSmrg
96005b261ecSmrg    prefix = AuditPrefix();
96105b261ecSmrg    len = vsnprintf(buf, sizeof(buf), f, args);
96205b261ecSmrg
96305b261ecSmrg    if (len == oldlen && strcmp(buf, oldbuf) == 0) {
96435c4bbdfSmrg        /* Message already seen */
96535c4bbdfSmrg        nrepeat++;
96635c4bbdfSmrg    }
96735c4bbdfSmrg    else {
96835c4bbdfSmrg        /* new message */
96935c4bbdfSmrg        if (auditTimer != NULL)
97035c4bbdfSmrg            TimerForce(auditTimer);
97135c4bbdfSmrg        ErrorF("%s%s", prefix != NULL ? prefix : "", buf);
97235c4bbdfSmrg        strlcpy(oldbuf, buf, sizeof(oldbuf));
97335c4bbdfSmrg        oldlen = len;
97435c4bbdfSmrg        nrepeat = 0;
97535c4bbdfSmrg        auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL);
97605b261ecSmrg    }
9779ace9065Smrg    free(prefix);
97805b261ecSmrg}
97905b261ecSmrg
9806747b715Smrgvoid
98105b261ecSmrgFatalError(const char *f, ...)
98205b261ecSmrg{
98305b261ecSmrg    va_list args;
98435c4bbdfSmrg    va_list args2;
98505b261ecSmrg    static Bool beenhere = FALSE;
98605b261ecSmrg
98705b261ecSmrg    if (beenhere)
98835c4bbdfSmrg        ErrorFSigSafe("\nFatalError re-entered, aborting\n");
98905b261ecSmrg    else
99035c4bbdfSmrg        ErrorFSigSafe("\nFatal server error:\n");
99105b261ecSmrg
99205b261ecSmrg    va_start(args, f);
99335c4bbdfSmrg
99435c4bbdfSmrg    /* Make a copy for OsVendorFatalError */
99535c4bbdfSmrg    va_copy(args2, args);
99635c4bbdfSmrg
9976747b715Smrg#ifdef __APPLE__
99835c4bbdfSmrg    {
99935c4bbdfSmrg        va_list apple_args;
100035c4bbdfSmrg
100135c4bbdfSmrg        va_copy(apple_args, args);
100235c4bbdfSmrg        (void)vsnprintf(__crashreporter_info_buff__,
100335c4bbdfSmrg                        sizeof(__crashreporter_info_buff__), f, apple_args);
100435c4bbdfSmrg        va_end(apple_args);
100535c4bbdfSmrg    }
10066747b715Smrg#endif
100735c4bbdfSmrg    VErrorFSigSafe(f, args);
100805b261ecSmrg    va_end(args);
100935c4bbdfSmrg    ErrorFSigSafe("\n");
101005b261ecSmrg    if (!beenhere)
101135c4bbdfSmrg        OsVendorFatalError(f, args2);
101235c4bbdfSmrg    va_end(args2);
101305b261ecSmrg    if (!beenhere) {
101435c4bbdfSmrg        beenhere = TRUE;
101535c4bbdfSmrg        AbortServer();
101635c4bbdfSmrg    }
101735c4bbdfSmrg    else
101835c4bbdfSmrg        OsAbort();
101935c4bbdfSmrg /*NOTREACHED*/}
102005b261ecSmrg
10216747b715Smrgvoid
102205b261ecSmrgVErrorF(const char *f, va_list args)
102305b261ecSmrg{
102405b261ecSmrg#ifdef DDXOSVERRORF
102505b261ecSmrg    if (OsVendorVErrorFProc)
102635c4bbdfSmrg        OsVendorVErrorFProc(f, args);
102705b261ecSmrg    else
102835c4bbdfSmrg        LogVWrite(-1, f, args);
102905b261ecSmrg#else
103005b261ecSmrg    LogVWrite(-1, f, args);
103105b261ecSmrg#endif
103205b261ecSmrg}
103305b261ecSmrg
10346747b715Smrgvoid
103535c4bbdfSmrgErrorF(const char *f, ...)
103605b261ecSmrg{
103705b261ecSmrg    va_list args;
103805b261ecSmrg
103905b261ecSmrg    va_start(args, f);
104005b261ecSmrg    VErrorF(f, args);
104105b261ecSmrg    va_end(args);
104205b261ecSmrg}
104305b261ecSmrg
104435c4bbdfSmrgvoid
104535c4bbdfSmrgVErrorFSigSafe(const char *f, va_list args)
104635c4bbdfSmrg{
104735c4bbdfSmrg    LogVMessageVerbSigSafe(X_ERROR, -1, f, args);
104835c4bbdfSmrg}
104905b261ecSmrg
10506747b715Smrgvoid
105135c4bbdfSmrgErrorFSigSafe(const char *f, ...)
105205b261ecSmrg{
105335c4bbdfSmrg    va_list args;
10549ace9065Smrg
105535c4bbdfSmrg    va_start(args, f);
105635c4bbdfSmrg    VErrorFSigSafe(f, args);
105735c4bbdfSmrg    va_end(args);
105805b261ecSmrg}
105905b261ecSmrg
106005b261ecSmrgvoid
106105b261ecSmrgLogPrintMarkers(void)
106205b261ecSmrg{
106305b261ecSmrg    /* Show what the message marker symbols mean. */
10646747b715Smrg    LogWrite(0, "Markers: ");
10656747b715Smrg    LogMessageVerb(X_PROBED, 0, "probed, ");
10666747b715Smrg    LogMessageVerb(X_CONFIG, 0, "from config file, ");
10676747b715Smrg    LogMessageVerb(X_DEFAULT, 0, "default setting,\n\t");
10686747b715Smrg    LogMessageVerb(X_CMDLINE, 0, "from command line, ");
10696747b715Smrg    LogMessageVerb(X_NOTICE, 0, "notice, ");
10706747b715Smrg    LogMessageVerb(X_INFO, 0, "informational,\n\t");
10716747b715Smrg    LogMessageVerb(X_WARNING, 0, "warning, ");
10726747b715Smrg    LogMessageVerb(X_ERROR, 0, "error, ");
10736747b715Smrg    LogMessageVerb(X_NOT_IMPLEMENTED, 0, "not implemented, ");
10746747b715Smrg    LogMessageVerb(X_UNKNOWN, 0, "unknown.\n");
107505b261ecSmrg}
1076