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