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