log.c revision 05b261ec
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
2705b261ecSmrg
2805b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
2905b261ecSmrgCopyright 1994 Quarterdeck Office Systems.
3005b261ecSmrg
3105b261ecSmrg                        All Rights Reserved
3205b261ecSmrg
3305b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3405b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3505b261ecSmrgprovided that the above copyright notice appear in all copies and that
3605b261ecSmrgboth that copyright notice and this permission notice appear in
3705b261ecSmrgsupporting documentation, and that the names of Digital and
3805b261ecSmrgQuarterdeck not be used in advertising or publicity pertaining to
3905b261ecSmrgdistribution of the software without specific, written prior
4005b261ecSmrgpermission.
4105b261ecSmrg
4205b261ecSmrgDIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
4305b261ecSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
4405b261ecSmrgFITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
4505b261ecSmrgOR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
4605b261ecSmrgOF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
4705b261ecSmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
4805b261ecSmrgOR PERFORMANCE OF THIS SOFTWARE.
4905b261ecSmrg
5005b261ecSmrg*/
5105b261ecSmrg
5205b261ecSmrg/*
5305b261ecSmrg * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
5405b261ecSmrg *
5505b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5605b261ecSmrg * copy of this software and associated documentation files (the "Software"),
5705b261ecSmrg * to deal in the Software without restriction, including without limitation
5805b261ecSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
5905b261ecSmrg * and/or sell copies of the Software, and to permit persons to whom the
6005b261ecSmrg * Software is furnished to do so, subject to the following conditions:
6105b261ecSmrg *
6205b261ecSmrg * The above copyright notice and this permission notice shall be included in
6305b261ecSmrg * all copies or substantial portions of the Software.
6405b261ecSmrg *
6505b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6605b261ecSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6705b261ecSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
6805b261ecSmrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
6905b261ecSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
7005b261ecSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
7105b261ecSmrg * OTHER DEALINGS IN THE SOFTWARE.
7205b261ecSmrg *
7305b261ecSmrg * Except as contained in this notice, the name of the copyright holder(s)
7405b261ecSmrg * and author(s) shall not be used in advertising or otherwise to promote
7505b261ecSmrg * the sale, use or other dealings in this Software without prior written
7605b261ecSmrg * authorization from the copyright holder(s) and author(s).
7705b261ecSmrg */
7805b261ecSmrg
7905b261ecSmrg
8005b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
8105b261ecSmrg#include <dix-config.h>
8205b261ecSmrg#endif
8305b261ecSmrg
8405b261ecSmrg#include <X11/Xos.h>
8505b261ecSmrg#include <stdio.h>
8605b261ecSmrg#include <time.h>
8705b261ecSmrg#include <sys/stat.h>
8805b261ecSmrg#include <stdarg.h>
8905b261ecSmrg#include <stdlib.h>	/* for malloc() */
9005b261ecSmrg#include <errno.h>
9105b261ecSmrg
9205b261ecSmrg#include "input.h"
9305b261ecSmrg#include "site.h"
9405b261ecSmrg#include "opaque.h"
9505b261ecSmrg
9605b261ecSmrg#ifdef WIN32
9705b261ecSmrg#include <process.h>
9805b261ecSmrg#define getpid(x) _getpid(x)
9905b261ecSmrg#endif
10005b261ecSmrg
10105b261ecSmrg
10205b261ecSmrg#ifdef DDXOSVERRORF
10305b261ecSmrgvoid (*OsVendorVErrorFProc)(const char *, va_list args) = NULL;
10405b261ecSmrg#endif
10505b261ecSmrg
10605b261ecSmrgstatic FILE *logFile = NULL;
10705b261ecSmrgstatic Bool logFlush = FALSE;
10805b261ecSmrgstatic Bool logSync = FALSE;
10905b261ecSmrgstatic int logVerbosity = DEFAULT_LOG_VERBOSITY;
11005b261ecSmrgstatic int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY;
11105b261ecSmrg
11205b261ecSmrg/* Buffer to information logged before the log file is opened. */
11305b261ecSmrgstatic char *saveBuffer = NULL;
11405b261ecSmrgstatic int bufferSize = 0, bufferUnused = 0, bufferPos = 0;
11505b261ecSmrgstatic Bool needBuffer = TRUE;
11605b261ecSmrg
11705b261ecSmrg/* Prefix strings for log messages. */
11805b261ecSmrg#ifndef X_UNKNOWN_STRING
11905b261ecSmrg#define X_UNKNOWN_STRING		"(\?\?)"
12005b261ecSmrg#endif
12105b261ecSmrg#ifndef X_PROBE_STRING
12205b261ecSmrg#define X_PROBE_STRING			"(--)"
12305b261ecSmrg#endif
12405b261ecSmrg#ifndef X_CONFIG_STRING
12505b261ecSmrg#define X_CONFIG_STRING			"(**)"
12605b261ecSmrg#endif
12705b261ecSmrg#ifndef X_DEFAULT_STRING
12805b261ecSmrg#define X_DEFAULT_STRING		"(==)"
12905b261ecSmrg#endif
13005b261ecSmrg#ifndef X_CMDLINE_STRING
13105b261ecSmrg#define X_CMDLINE_STRING		"(++)"
13205b261ecSmrg#endif
13305b261ecSmrg#ifndef X_NOTICE_STRING
13405b261ecSmrg#define X_NOTICE_STRING			"(!!)"
13505b261ecSmrg#endif
13605b261ecSmrg#ifndef X_ERROR_STRING
13705b261ecSmrg#define X_ERROR_STRING			"(EE)"
13805b261ecSmrg#endif
13905b261ecSmrg#ifndef X_WARNING_STRING
14005b261ecSmrg#define X_WARNING_STRING		"(WW)"
14105b261ecSmrg#endif
14205b261ecSmrg#ifndef X_INFO_STRING
14305b261ecSmrg#define X_INFO_STRING			"(II)"
14405b261ecSmrg#endif
14505b261ecSmrg#ifndef X_NOT_IMPLEMENTED_STRING
14605b261ecSmrg#define X_NOT_IMPLEMENTED_STRING	"(NI)"
14705b261ecSmrg#endif
14805b261ecSmrg
14905b261ecSmrg/*
15005b261ecSmrg * LogInit is called to start logging to a file.  It is also called (with
15105b261ecSmrg * NULL arguments) when logging to a file is not wanted.  It must always be
15205b261ecSmrg * called, otherwise log messages will continue to accumulate in a buffer.
15305b261ecSmrg *
15405b261ecSmrg * %s, if present in the fname or backup strings, is expanded to the display
15505b261ecSmrg * string.
15605b261ecSmrg */
15705b261ecSmrg
15805b261ecSmrgconst char *
15905b261ecSmrgLogInit(const char *fname, const char *backup)
16005b261ecSmrg{
16105b261ecSmrg    char *logFileName = NULL;
16205b261ecSmrg
16305b261ecSmrg    if (fname && *fname) {
16405b261ecSmrg	/* xalloc() can't be used yet. */
16505b261ecSmrg	logFileName = malloc(strlen(fname) + strlen(display) + 1);
16605b261ecSmrg	if (!logFileName)
16705b261ecSmrg	    FatalError("Cannot allocate space for the log file name\n");
16805b261ecSmrg	sprintf(logFileName, fname, display);
16905b261ecSmrg
17005b261ecSmrg	if (backup && *backup) {
17105b261ecSmrg	    struct stat buf;
17205b261ecSmrg
17305b261ecSmrg	    if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) {
17405b261ecSmrg		char *suffix;
17505b261ecSmrg		char *oldLog;
17605b261ecSmrg
17705b261ecSmrg		oldLog = malloc(strlen(logFileName) + strlen(backup) +
17805b261ecSmrg				strlen(display) + 1);
17905b261ecSmrg		suffix = malloc(strlen(backup) + strlen(display) + 1);
18005b261ecSmrg		if (!oldLog || !suffix)
18105b261ecSmrg		    FatalError("Cannot allocate space for the log file name\n");
18205b261ecSmrg		sprintf(suffix, backup, display);
18305b261ecSmrg		sprintf(oldLog, "%s%s", logFileName, suffix);
18405b261ecSmrg		free(suffix);
18505b261ecSmrg		if (rename(logFileName, oldLog) == -1) {
18605b261ecSmrg		    FatalError("Cannot move old log file (\"%s\" to \"%s\"\n",
18705b261ecSmrg			       logFileName, oldLog);
18805b261ecSmrg		}
18905b261ecSmrg		free(oldLog);
19005b261ecSmrg	    }
19105b261ecSmrg	}
19205b261ecSmrg	if ((logFile = fopen(logFileName, "w")) == NULL)
19305b261ecSmrg	    FatalError("Cannot open log file \"%s\"\n", logFileName);
19405b261ecSmrg	setvbuf(logFile, NULL, _IONBF, 0);
19505b261ecSmrg
19605b261ecSmrg	/* Flush saved log information. */
19705b261ecSmrg	if (saveBuffer && bufferSize > 0) {
19805b261ecSmrg	    fwrite(saveBuffer, bufferPos, 1, logFile);
19905b261ecSmrg	    fflush(logFile);
20005b261ecSmrg#ifndef WIN32
20105b261ecSmrg	    fsync(fileno(logFile));
20205b261ecSmrg#endif
20305b261ecSmrg	}
20405b261ecSmrg    }
20505b261ecSmrg
20605b261ecSmrg    /*
20705b261ecSmrg     * Unconditionally free the buffer, and flag that the buffer is no longer
20805b261ecSmrg     * needed.
20905b261ecSmrg     */
21005b261ecSmrg    if (saveBuffer && bufferSize > 0) {
21105b261ecSmrg	free(saveBuffer);	/* Must be free(), not xfree() */
21205b261ecSmrg	saveBuffer = NULL;
21305b261ecSmrg	bufferSize = 0;
21405b261ecSmrg    }
21505b261ecSmrg    needBuffer = FALSE;
21605b261ecSmrg
21705b261ecSmrg    return logFileName;
21805b261ecSmrg}
21905b261ecSmrg
22005b261ecSmrgvoid
22105b261ecSmrgLogClose(void)
22205b261ecSmrg{
22305b261ecSmrg    if (logFile) {
22405b261ecSmrg	fclose(logFile);
22505b261ecSmrg	logFile = NULL;
22605b261ecSmrg    }
22705b261ecSmrg}
22805b261ecSmrg
22905b261ecSmrgBool
23005b261ecSmrgLogSetParameter(LogParameter param, int value)
23105b261ecSmrg{
23205b261ecSmrg    switch (param) {
23305b261ecSmrg    case XLOG_FLUSH:
23405b261ecSmrg	logFlush = value ? TRUE : FALSE;
23505b261ecSmrg	return TRUE;
23605b261ecSmrg    case XLOG_SYNC:
23705b261ecSmrg	logSync = value ? TRUE : FALSE;
23805b261ecSmrg	return TRUE;
23905b261ecSmrg    case XLOG_VERBOSITY:
24005b261ecSmrg	logVerbosity = value;
24105b261ecSmrg	return TRUE;
24205b261ecSmrg    case XLOG_FILE_VERBOSITY:
24305b261ecSmrg	logFileVerbosity = value;
24405b261ecSmrg	return TRUE;
24505b261ecSmrg    default:
24605b261ecSmrg	return FALSE;
24705b261ecSmrg    }
24805b261ecSmrg}
24905b261ecSmrg
25005b261ecSmrg/* This function does the actual log message writes. */
25105b261ecSmrg
25205b261ecSmrg_X_EXPORT void
25305b261ecSmrgLogVWrite(int verb, const char *f, va_list args)
25405b261ecSmrg{
25505b261ecSmrg    static char tmpBuffer[1024];
25605b261ecSmrg    int len = 0;
25705b261ecSmrg
25805b261ecSmrg    /*
25905b261ecSmrg     * Since a va_list can only be processed once, write the string to a
26005b261ecSmrg     * buffer, and then write the buffer out to the appropriate output
26105b261ecSmrg     * stream(s).
26205b261ecSmrg     */
26305b261ecSmrg    if (verb < 0 || logFileVerbosity >= verb || logVerbosity >= verb) {
26405b261ecSmrg	vsnprintf(tmpBuffer, sizeof(tmpBuffer), f, args);
26505b261ecSmrg	len = strlen(tmpBuffer);
26605b261ecSmrg    }
26705b261ecSmrg    if ((verb < 0 || logVerbosity >= verb) && len > 0)
26805b261ecSmrg	fwrite(tmpBuffer, len, 1, stderr);
26905b261ecSmrg    if ((verb < 0 || logFileVerbosity >= verb) && len > 0) {
27005b261ecSmrg	if (logFile) {
27105b261ecSmrg	    fwrite(tmpBuffer, len, 1, logFile);
27205b261ecSmrg	    if (logFlush) {
27305b261ecSmrg		fflush(logFile);
27405b261ecSmrg#ifndef WIN32
27505b261ecSmrg		if (logSync)
27605b261ecSmrg		    fsync(fileno(logFile));
27705b261ecSmrg#endif
27805b261ecSmrg	    }
27905b261ecSmrg	} else if (needBuffer) {
28005b261ecSmrg	    /*
28105b261ecSmrg	     * Note, this code is used before OsInit() has been called, so
28205b261ecSmrg	     * xalloc() and friends can't be used.
28305b261ecSmrg	     */
28405b261ecSmrg	    if (len > bufferUnused) {
28505b261ecSmrg		bufferSize += 1024;
28605b261ecSmrg		bufferUnused += 1024;
28705b261ecSmrg		if (saveBuffer)
28805b261ecSmrg		    saveBuffer = realloc(saveBuffer, bufferSize);
28905b261ecSmrg		else
29005b261ecSmrg		    saveBuffer = malloc(bufferSize);
29105b261ecSmrg		if (!saveBuffer)
29205b261ecSmrg		    FatalError("realloc() failed while saving log messages\n");
29305b261ecSmrg	    }
29405b261ecSmrg	    bufferUnused -= len;
29505b261ecSmrg	    memcpy(saveBuffer + bufferPos, tmpBuffer, len);
29605b261ecSmrg	    bufferPos += len;
29705b261ecSmrg	}
29805b261ecSmrg    }
29905b261ecSmrg}
30005b261ecSmrg
30105b261ecSmrg_X_EXPORT void
30205b261ecSmrgLogWrite(int verb, const char *f, ...)
30305b261ecSmrg{
30405b261ecSmrg    va_list args;
30505b261ecSmrg
30605b261ecSmrg    va_start(args, f);
30705b261ecSmrg    LogVWrite(verb, f, args);
30805b261ecSmrg    va_end(args);
30905b261ecSmrg}
31005b261ecSmrg
31105b261ecSmrg_X_EXPORT void
31205b261ecSmrgLogVMessageVerb(MessageType type, int verb, const char *format, va_list args)
31305b261ecSmrg{
31405b261ecSmrg    const char *s  = X_UNKNOWN_STRING;
31505b261ecSmrg    char *tmpBuf = NULL;
31605b261ecSmrg
31705b261ecSmrg    /* Ignore verbosity for X_ERROR */
31805b261ecSmrg    if (logVerbosity >= verb || logFileVerbosity >= verb || type == X_ERROR) {
31905b261ecSmrg	switch (type) {
32005b261ecSmrg	case X_PROBED:
32105b261ecSmrg	    s = X_PROBE_STRING;
32205b261ecSmrg	    break;
32305b261ecSmrg	case X_CONFIG:
32405b261ecSmrg	    s = X_CONFIG_STRING;
32505b261ecSmrg	    break;
32605b261ecSmrg	case X_DEFAULT:
32705b261ecSmrg	    s = X_DEFAULT_STRING;
32805b261ecSmrg	    break;
32905b261ecSmrg	case X_CMDLINE:
33005b261ecSmrg	    s = X_CMDLINE_STRING;
33105b261ecSmrg	    break;
33205b261ecSmrg	case X_NOTICE:
33305b261ecSmrg	    s = X_NOTICE_STRING;
33405b261ecSmrg	    break;
33505b261ecSmrg	case X_ERROR:
33605b261ecSmrg	    s = X_ERROR_STRING;
33705b261ecSmrg	    if (verb > 0)
33805b261ecSmrg		verb = 0;
33905b261ecSmrg	    break;
34005b261ecSmrg	case X_WARNING:
34105b261ecSmrg	    s = X_WARNING_STRING;
34205b261ecSmrg	    break;
34305b261ecSmrg	case X_INFO:
34405b261ecSmrg	    s = X_INFO_STRING;
34505b261ecSmrg	    break;
34605b261ecSmrg	case X_NOT_IMPLEMENTED:
34705b261ecSmrg	    s = X_NOT_IMPLEMENTED_STRING;
34805b261ecSmrg	    break;
34905b261ecSmrg	case X_UNKNOWN:
35005b261ecSmrg	    s = X_UNKNOWN_STRING;
35105b261ecSmrg	    break;
35205b261ecSmrg	case X_NONE:
35305b261ecSmrg	    s = NULL;
35405b261ecSmrg	    break;
35505b261ecSmrg	}
35605b261ecSmrg
35705b261ecSmrg	/*
35805b261ecSmrg	 * Prefix the format string with the message type.  We do it this way
35905b261ecSmrg	 * so that LogVWrite() is only called once per message.
36005b261ecSmrg	 */
36105b261ecSmrg	if (s) {
36205b261ecSmrg	    tmpBuf = malloc(strlen(format) + strlen(s) + 1 + 1);
36305b261ecSmrg	    /* Silently return if malloc fails here. */
36405b261ecSmrg	    if (!tmpBuf)
36505b261ecSmrg		return;
36605b261ecSmrg	    sprintf(tmpBuf, "%s ", s);
36705b261ecSmrg	    strcat(tmpBuf, format);
36805b261ecSmrg	    LogVWrite(verb, tmpBuf, args);
36905b261ecSmrg	    free(tmpBuf);
37005b261ecSmrg	} else
37105b261ecSmrg	    LogVWrite(verb, format, args);
37205b261ecSmrg    }
37305b261ecSmrg}
37405b261ecSmrg
37505b261ecSmrg/* Log message with verbosity level specified. */
37605b261ecSmrg_X_EXPORT void
37705b261ecSmrgLogMessageVerb(MessageType type, int verb, const char *format, ...)
37805b261ecSmrg{
37905b261ecSmrg    va_list ap;
38005b261ecSmrg
38105b261ecSmrg    va_start(ap, format);
38205b261ecSmrg    LogVMessageVerb(type, verb, format, ap);
38305b261ecSmrg    va_end(ap);
38405b261ecSmrg}
38505b261ecSmrg
38605b261ecSmrg/* Log a message with the standard verbosity level of 1. */
38705b261ecSmrg_X_EXPORT void
38805b261ecSmrgLogMessage(MessageType type, const char *format, ...)
38905b261ecSmrg{
39005b261ecSmrg    va_list ap;
39105b261ecSmrg
39205b261ecSmrg    va_start(ap, format);
39305b261ecSmrg    LogVMessageVerb(type, 1, format, ap);
39405b261ecSmrg    va_end(ap);
39505b261ecSmrg}
39605b261ecSmrg
39705b261ecSmrg#ifdef __GNUC__
39805b261ecSmrgvoid AbortServer(void) __attribute__((noreturn));
39905b261ecSmrg#endif
40005b261ecSmrg
40105b261ecSmrgvoid
40205b261ecSmrgAbortServer(void)
40305b261ecSmrg{
40405b261ecSmrg    OsCleanup(TRUE);
40505b261ecSmrg    CloseDownDevices();
40605b261ecSmrg    AbortDDX();
40705b261ecSmrg    fflush(stderr);
40805b261ecSmrg    if (CoreDump)
40905b261ecSmrg	abort();
41005b261ecSmrg    exit (1);
41105b261ecSmrg}
41205b261ecSmrg
41305b261ecSmrg#ifndef AUDIT_PREFIX
41405b261ecSmrg#define AUDIT_PREFIX "AUDIT: %s: %ld %s: "
41505b261ecSmrg#endif
41605b261ecSmrg#ifndef AUDIT_TIMEOUT
41705b261ecSmrg#define AUDIT_TIMEOUT ((CARD32)(120 * 1000)) /* 2 mn */
41805b261ecSmrg#endif
41905b261ecSmrg
42005b261ecSmrgstatic int nrepeat = 0;
42105b261ecSmrgstatic int oldlen = -1;
42205b261ecSmrgstatic OsTimerPtr auditTimer = NULL;
42305b261ecSmrg
42405b261ecSmrgvoid
42505b261ecSmrgFreeAuditTimer(void)
42605b261ecSmrg{
42705b261ecSmrg    if (auditTimer != NULL) {
42805b261ecSmrg	/* Force output of pending messages */
42905b261ecSmrg	TimerForce(auditTimer);
43005b261ecSmrg	TimerFree(auditTimer);
43105b261ecSmrg	auditTimer = NULL;
43205b261ecSmrg    }
43305b261ecSmrg}
43405b261ecSmrg
43505b261ecSmrgstatic char *
43605b261ecSmrgAuditPrefix(void)
43705b261ecSmrg{
43805b261ecSmrg    time_t tm;
43905b261ecSmrg    char *autime, *s;
44005b261ecSmrg    char *tmpBuf;
44105b261ecSmrg    int len;
44205b261ecSmrg
44305b261ecSmrg    time(&tm);
44405b261ecSmrg    autime = ctime(&tm);
44505b261ecSmrg    if ((s = strchr(autime, '\n')))
44605b261ecSmrg	*s = '\0';
44705b261ecSmrg    if ((s = strrchr(argvGlobal[0], '/')))
44805b261ecSmrg	s++;
44905b261ecSmrg    else
45005b261ecSmrg	s = argvGlobal[0];
45105b261ecSmrg    len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + strlen(s) + 1;
45205b261ecSmrg    tmpBuf = malloc(len);
45305b261ecSmrg    if (!tmpBuf)
45405b261ecSmrg	return NULL;
45505b261ecSmrg    snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long)getpid(), s);
45605b261ecSmrg    return tmpBuf;
45705b261ecSmrg}
45805b261ecSmrg
45905b261ecSmrgvoid
46005b261ecSmrgAuditF(const char * f, ...)
46105b261ecSmrg{
46205b261ecSmrg    va_list args;
46305b261ecSmrg
46405b261ecSmrg    va_start(args, f);
46505b261ecSmrg
46605b261ecSmrg    VAuditF(f, args);
46705b261ecSmrg    va_end(args);
46805b261ecSmrg}
46905b261ecSmrg
47005b261ecSmrgstatic CARD32
47105b261ecSmrgAuditFlush(OsTimerPtr timer, CARD32 now, pointer arg)
47205b261ecSmrg{
47305b261ecSmrg    char *prefix;
47405b261ecSmrg
47505b261ecSmrg    if (nrepeat > 0) {
47605b261ecSmrg	prefix = AuditPrefix();
47705b261ecSmrg	ErrorF("%slast message repeated %d times\n",
47805b261ecSmrg	       prefix != NULL ? prefix : "", nrepeat);
47905b261ecSmrg	nrepeat = 0;
48005b261ecSmrg	if (prefix != NULL)
48105b261ecSmrg	    free(prefix);
48205b261ecSmrg	return AUDIT_TIMEOUT;
48305b261ecSmrg    } else {
48405b261ecSmrg	/* if the timer expires without anything to print, flush the message */
48505b261ecSmrg	oldlen = -1;
48605b261ecSmrg	return 0;
48705b261ecSmrg    }
48805b261ecSmrg}
48905b261ecSmrg
49005b261ecSmrgvoid
49105b261ecSmrgVAuditF(const char *f, va_list args)
49205b261ecSmrg{
49305b261ecSmrg    char *prefix;
49405b261ecSmrg    char buf[1024];
49505b261ecSmrg    int len;
49605b261ecSmrg    static char oldbuf[1024];
49705b261ecSmrg
49805b261ecSmrg    prefix = AuditPrefix();
49905b261ecSmrg    len = vsnprintf(buf, sizeof(buf), f, args);
50005b261ecSmrg
50105b261ecSmrg#if 1
50205b261ecSmrg    /* XXX Compressing duplicated messages is temporarily disabled to
50305b261ecSmrg     * work around bugzilla 964:
50405b261ecSmrg     *     https://freedesktop.org/bugzilla/show_bug.cgi?id=964
50505b261ecSmrg     */
50605b261ecSmrg    ErrorF("%s%s", prefix != NULL ? prefix : "", buf);
50705b261ecSmrg    oldlen = -1;
50805b261ecSmrg    nrepeat = 0;
50905b261ecSmrg#else
51005b261ecSmrg    if (len == oldlen && strcmp(buf, oldbuf) == 0) {
51105b261ecSmrg	/* Message already seen */
51205b261ecSmrg	nrepeat++;
51305b261ecSmrg    } else {
51405b261ecSmrg	/* new message */
51505b261ecSmrg	if (auditTimer != NULL)
51605b261ecSmrg	    TimerForce(auditTimer);
51705b261ecSmrg	ErrorF("%s%s", prefix != NULL ? prefix : "", buf);
51805b261ecSmrg	strlcpy(oldbuf, buf, sizeof(oldbuf));
51905b261ecSmrg	oldlen = len;
52005b261ecSmrg	nrepeat = 0;
52105b261ecSmrg	auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL);
52205b261ecSmrg    }
52305b261ecSmrg#endif
52405b261ecSmrg    if (prefix != NULL)
52505b261ecSmrg	free(prefix);
52605b261ecSmrg}
52705b261ecSmrg
52805b261ecSmrg_X_EXPORT void
52905b261ecSmrgFatalError(const char *f, ...)
53005b261ecSmrg{
53105b261ecSmrg    va_list args;
53205b261ecSmrg    static Bool beenhere = FALSE;
53305b261ecSmrg
53405b261ecSmrg    if (beenhere)
53505b261ecSmrg	ErrorF("\nFatalError re-entered, aborting\n");
53605b261ecSmrg    else
53705b261ecSmrg	ErrorF("\nFatal server error:\n");
53805b261ecSmrg
53905b261ecSmrg    va_start(args, f);
54005b261ecSmrg    VErrorF(f, args);
54105b261ecSmrg    va_end(args);
54205b261ecSmrg    ErrorF("\n");
54305b261ecSmrg#ifdef DDXOSFATALERROR
54405b261ecSmrg    if (!beenhere)
54505b261ecSmrg	OsVendorFatalError();
54605b261ecSmrg#endif
54705b261ecSmrg#ifdef ABORTONFATALERROR
54805b261ecSmrg    abort();
54905b261ecSmrg#endif
55005b261ecSmrg    if (!beenhere) {
55105b261ecSmrg	beenhere = TRUE;
55205b261ecSmrg	AbortServer();
55305b261ecSmrg    } else
55405b261ecSmrg	abort();
55505b261ecSmrg    /*NOTREACHED*/
55605b261ecSmrg}
55705b261ecSmrg
55805b261ecSmrg_X_EXPORT void
55905b261ecSmrgVErrorF(const char *f, va_list args)
56005b261ecSmrg{
56105b261ecSmrg#ifdef DDXOSVERRORF
56205b261ecSmrg    if (OsVendorVErrorFProc)
56305b261ecSmrg	OsVendorVErrorFProc(f, args);
56405b261ecSmrg    else
56505b261ecSmrg	LogVWrite(-1, f, args);
56605b261ecSmrg#else
56705b261ecSmrg    LogVWrite(-1, f, args);
56805b261ecSmrg#endif
56905b261ecSmrg}
57005b261ecSmrg
57105b261ecSmrg_X_EXPORT void
57205b261ecSmrgErrorF(const char * f, ...)
57305b261ecSmrg{
57405b261ecSmrg    va_list args;
57505b261ecSmrg
57605b261ecSmrg    va_start(args, f);
57705b261ecSmrg    VErrorF(f, args);
57805b261ecSmrg    va_end(args);
57905b261ecSmrg}
58005b261ecSmrg
58105b261ecSmrg/* A perror() workalike. */
58205b261ecSmrg
58305b261ecSmrg#ifndef NEED_STRERROR
58405b261ecSmrg#ifdef SYSV
58505b261ecSmrg#if !defined(ISC) || defined(ISC202) || defined(ISC22)
58605b261ecSmrg#define NEED_STRERROR
58705b261ecSmrg#endif
58805b261ecSmrg#endif
58905b261ecSmrg#endif
59005b261ecSmrg
59105b261ecSmrg#if defined(NEED_STRERROR) && !defined(strerror)
59205b261ecSmrgextern char *sys_errlist[];
59305b261ecSmrgextern int sys_nerr;
59405b261ecSmrg#define strerror(n) \
59505b261ecSmrg	((n) >= 0 && (n) < sys_nerr) ? sys_errlist[(n)] : "unknown error"
59605b261ecSmrg#endif
59705b261ecSmrg
59805b261ecSmrg_X_EXPORT void
59905b261ecSmrgError(char *str)
60005b261ecSmrg{
60105b261ecSmrg    char *err = NULL;
60205b261ecSmrg    int saveErrno = errno;
60305b261ecSmrg
60405b261ecSmrg    if (str) {
60505b261ecSmrg	err = malloc(strlen(strerror(saveErrno)) + strlen(str) + 2 + 1);
60605b261ecSmrg	if (!err)
60705b261ecSmrg	    return;
60805b261ecSmrg	sprintf(err, "%s: ", str);
60905b261ecSmrg	strcat(err, strerror(saveErrno));
61005b261ecSmrg	LogWrite(-1, err);
61105b261ecSmrg    } else
61205b261ecSmrg	LogWrite(-1, strerror(saveErrno));
61305b261ecSmrg}
61405b261ecSmrg
61505b261ecSmrgvoid
61605b261ecSmrgLogPrintMarkers(void)
61705b261ecSmrg{
61805b261ecSmrg    /* Show what the message marker symbols mean. */
61905b261ecSmrg    ErrorF("Markers: ");
62005b261ecSmrg    LogMessageVerb(X_PROBED, -1, "probed, ");
62105b261ecSmrg    LogMessageVerb(X_CONFIG, -1, "from config file, ");
62205b261ecSmrg    LogMessageVerb(X_DEFAULT, -1, "default setting,\n\t");
62305b261ecSmrg    LogMessageVerb(X_CMDLINE, -1, "from command line, ");
62405b261ecSmrg    LogMessageVerb(X_NOTICE, -1, "notice, ");
62505b261ecSmrg    LogMessageVerb(X_INFO, -1, "informational,\n\t");
62605b261ecSmrg    LogMessageVerb(X_WARNING, -1, "warning, ");
62705b261ecSmrg    LogMessageVerb(X_ERROR, -1, "error, ");
62805b261ecSmrg    LogMessageVerb(X_NOT_IMPLEMENTED, -1, "not implemented, ");
62905b261ecSmrg    LogMessageVerb(X_UNKNOWN, -1, "unknown.\n");
63005b261ecSmrg}
63105b261ecSmrg
632