xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

log.c (29581B)


      1 /*
      2 
      3 Copyright 1987, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included
     12 in all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 Except as contained in this notice, the name of The Open Group shall
     23 not be used in advertising or otherwise to promote the sale, use or
     24 other dealings in this Software without prior written authorization
     25 from The Open Group.
     26 
     27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
     28 Copyright 1994 Quarterdeck Office Systems.
     29 
     30                         All Rights Reserved
     31 
     32 Permission to use, copy, modify, and distribute this software and its
     33 documentation for any purpose and without fee is hereby granted,
     34 provided that the above copyright notice appear in all copies and that
     35 both that copyright notice and this permission notice appear in
     36 supporting documentation, and that the names of Digital and
     37 Quarterdeck not be used in advertising or publicity pertaining to
     38 distribution of the software without specific, written prior
     39 permission.
     40 
     41 DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
     42 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
     43 FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
     44 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
     45 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
     46 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
     47 OR 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
    107 void (*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 
    118 static FILE *logFile = NULL;
    119 static int logFileFd = -1;
    120 static Bool logFlush = FALSE;
    121 static Bool logSync = FALSE;
    122 static int logVerbosity = DEFAULT_LOG_VERBOSITY;
    123 static int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY;
    124 
    125 /* Buffer to information logged before the log file is opened. */
    126 static char *saveBuffer = NULL;
    127 static int bufferSize = 0, bufferUnused = 0, bufferPos = 0;
    128 static Bool needBuffer = TRUE;
    129 
    130 #ifdef __APPLE__
    131 static char __crashreporter_info_buff__[4096] = { 0 };
    132 
    133 static const char *__crashreporter_info__ __attribute__ ((__used__)) =
    134     &__crashreporter_info_buff__[0];
    135 asm(".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 
    176 static size_t
    177 strlen_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 
    192 static char *
    193 LogFilePrep(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 
    242 static char *saved_log_fname;
    243 static char *saved_log_backup;
    244 static char *saved_log_tempname;
    245 
    246 const char *
    247 LogInit(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 
    298 void
    299 LogSetDisplay(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 
    328 void
    329 LogClose(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 
    343 Bool
    344 LogSetParameter(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 
    364 enum {
    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  */
    377 static 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 
    408 out:
    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  */
    417 static int
    418 vpnprintf(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 
    581 static int
    582 pnprintf(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. */
    597 static void
    598 LogSWrite(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 
    647 void
    648 LogVWrite(int verb, const char *f, va_list args)
    649 {
    650     return LogVMessageVerb(X_NONE, verb, f, args);
    651 }
    652 
    653 void
    654 LogWrite(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. */
    665 static const char *
    666 LogMessageTypeVerbString(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 
    704 void
    705 LogVMessageVerb(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. */
    738 void
    739 LogMessageVerb(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. */
    749 void
    750 LogMessage(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. */
    760 void
    761 LogMessageVerbSigSafe(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 
    769 void
    770 LogVMessageVerbSigSafe(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 
    797 void
    798 LogVHdrMessageVerb(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 
    841 void
    842 LogHdrMessageVerb(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 
    852 void
    853 LogHdrMessage(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 
    863 void
    864 AbortServer(void)
    865     _X_NORETURN;
    866 
    867 void
    868 AbortServer(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 
    888 static int nrepeat = 0;
    889 static int oldlen = -1;
    890 static OsTimerPtr auditTimer = NULL;
    891 
    892 void
    893 FreeAuditTimer(void)
    894 {
    895     if (auditTimer != NULL) {
    896         /* Force output of pending messages */
    897         TimerForce(auditTimer);
    898         TimerFree(auditTimer);
    899         auditTimer = NULL;
    900     }
    901 }
    902 
    903 static char *
    904 AuditPrefix(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 
    923 void
    924 AuditF(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 
    934 static CARD32
    935 AuditFlush(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 
    954 void
    955 VAuditF(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 
    982 void
    983 FatalError(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 
   1023 void
   1024 VErrorF(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 
   1036 void
   1037 ErrorF(const char *f, ...)
   1038 {
   1039     va_list args;
   1040 
   1041     va_start(args, f);
   1042     VErrorF(f, args);
   1043     va_end(args);
   1044 }
   1045 
   1046 void
   1047 VErrorFSigSafe(const char *f, va_list args)
   1048 {
   1049     LogVMessageVerbSigSafe(X_ERROR, -1, f, args);
   1050 }
   1051 
   1052 void
   1053 ErrorFSigSafe(const char *f, ...)
   1054 {
   1055     va_list args;
   1056 
   1057     va_start(args, f);
   1058     VErrorFSigSafe(f, args);
   1059     va_end(args);
   1060 }
   1061 
   1062 void
   1063 LogPrintMarkers(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 }