log.c revision 4642e01f
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{
4044642e01fSmrg    CloseWellKnownConnections();
40505b261ecSmrg    OsCleanup(TRUE);
40605b261ecSmrg    CloseDownDevices();
40705b261ecSmrg    AbortDDX();
40805b261ecSmrg    fflush(stderr);
40905b261ecSmrg    if (CoreDump)
41005b261ecSmrg	abort();
41105b261ecSmrg    exit (1);
41205b261ecSmrg}
41305b261ecSmrg
4144642e01fSmrg#define AUDIT_PREFIX "AUDIT: %s: %ld: "
41505b261ecSmrg#ifndef AUDIT_TIMEOUT
41605b261ecSmrg#define AUDIT_TIMEOUT ((CARD32)(120 * 1000)) /* 2 mn */
41705b261ecSmrg#endif
41805b261ecSmrg
41905b261ecSmrgstatic int nrepeat = 0;
42005b261ecSmrgstatic int oldlen = -1;
42105b261ecSmrgstatic OsTimerPtr auditTimer = NULL;
42205b261ecSmrg
42305b261ecSmrgvoid
42405b261ecSmrgFreeAuditTimer(void)
42505b261ecSmrg{
42605b261ecSmrg    if (auditTimer != NULL) {
42705b261ecSmrg	/* Force output of pending messages */
42805b261ecSmrg	TimerForce(auditTimer);
42905b261ecSmrg	TimerFree(auditTimer);
43005b261ecSmrg	auditTimer = NULL;
43105b261ecSmrg    }
43205b261ecSmrg}
43305b261ecSmrg
43405b261ecSmrgstatic char *
43505b261ecSmrgAuditPrefix(void)
43605b261ecSmrg{
43705b261ecSmrg    time_t tm;
43805b261ecSmrg    char *autime, *s;
43905b261ecSmrg    char *tmpBuf;
44005b261ecSmrg    int len;
44105b261ecSmrg
44205b261ecSmrg    time(&tm);
44305b261ecSmrg    autime = ctime(&tm);
44405b261ecSmrg    if ((s = strchr(autime, '\n')))
44505b261ecSmrg	*s = '\0';
4464642e01fSmrg    len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + 1;
44705b261ecSmrg    tmpBuf = malloc(len);
44805b261ecSmrg    if (!tmpBuf)
44905b261ecSmrg	return NULL;
4504642e01fSmrg    snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long)getpid());
45105b261ecSmrg    return tmpBuf;
45205b261ecSmrg}
45305b261ecSmrg
45405b261ecSmrgvoid
45505b261ecSmrgAuditF(const char * f, ...)
45605b261ecSmrg{
45705b261ecSmrg    va_list args;
45805b261ecSmrg
45905b261ecSmrg    va_start(args, f);
46005b261ecSmrg
46105b261ecSmrg    VAuditF(f, args);
46205b261ecSmrg    va_end(args);
46305b261ecSmrg}
46405b261ecSmrg
46505b261ecSmrgstatic CARD32
46605b261ecSmrgAuditFlush(OsTimerPtr timer, CARD32 now, pointer arg)
46705b261ecSmrg{
46805b261ecSmrg    char *prefix;
46905b261ecSmrg
47005b261ecSmrg    if (nrepeat > 0) {
47105b261ecSmrg	prefix = AuditPrefix();
47205b261ecSmrg	ErrorF("%slast message repeated %d times\n",
47305b261ecSmrg	       prefix != NULL ? prefix : "", nrepeat);
47405b261ecSmrg	nrepeat = 0;
47505b261ecSmrg	if (prefix != NULL)
47605b261ecSmrg	    free(prefix);
47705b261ecSmrg	return AUDIT_TIMEOUT;
47805b261ecSmrg    } else {
47905b261ecSmrg	/* if the timer expires without anything to print, flush the message */
48005b261ecSmrg	oldlen = -1;
48105b261ecSmrg	return 0;
48205b261ecSmrg    }
48305b261ecSmrg}
48405b261ecSmrg
48505b261ecSmrgvoid
48605b261ecSmrgVAuditF(const char *f, va_list args)
48705b261ecSmrg{
48805b261ecSmrg    char *prefix;
48905b261ecSmrg    char buf[1024];
49005b261ecSmrg    int len;
49105b261ecSmrg    static char oldbuf[1024];
49205b261ecSmrg
49305b261ecSmrg    prefix = AuditPrefix();
49405b261ecSmrg    len = vsnprintf(buf, sizeof(buf), f, args);
49505b261ecSmrg
49605b261ecSmrg    if (len == oldlen && strcmp(buf, oldbuf) == 0) {
49705b261ecSmrg	/* Message already seen */
49805b261ecSmrg	nrepeat++;
49905b261ecSmrg    } else {
50005b261ecSmrg	/* new message */
50105b261ecSmrg	if (auditTimer != NULL)
50205b261ecSmrg	    TimerForce(auditTimer);
50305b261ecSmrg	ErrorF("%s%s", prefix != NULL ? prefix : "", buf);
50405b261ecSmrg	strlcpy(oldbuf, buf, sizeof(oldbuf));
50505b261ecSmrg	oldlen = len;
50605b261ecSmrg	nrepeat = 0;
50705b261ecSmrg	auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL);
50805b261ecSmrg    }
50905b261ecSmrg    if (prefix != NULL)
51005b261ecSmrg	free(prefix);
51105b261ecSmrg}
51205b261ecSmrg
51305b261ecSmrg_X_EXPORT void
51405b261ecSmrgFatalError(const char *f, ...)
51505b261ecSmrg{
51605b261ecSmrg    va_list args;
51705b261ecSmrg    static Bool beenhere = FALSE;
51805b261ecSmrg
51905b261ecSmrg    if (beenhere)
52005b261ecSmrg	ErrorF("\nFatalError re-entered, aborting\n");
52105b261ecSmrg    else
52205b261ecSmrg	ErrorF("\nFatal server error:\n");
52305b261ecSmrg
52405b261ecSmrg    va_start(args, f);
52505b261ecSmrg    VErrorF(f, args);
52605b261ecSmrg    va_end(args);
52705b261ecSmrg    ErrorF("\n");
52805b261ecSmrg    if (!beenhere)
52905b261ecSmrg	OsVendorFatalError();
53005b261ecSmrg    if (!beenhere) {
53105b261ecSmrg	beenhere = TRUE;
53205b261ecSmrg	AbortServer();
53305b261ecSmrg    } else
53405b261ecSmrg	abort();
53505b261ecSmrg    /*NOTREACHED*/
53605b261ecSmrg}
53705b261ecSmrg
53805b261ecSmrg_X_EXPORT void
53905b261ecSmrgVErrorF(const char *f, va_list args)
54005b261ecSmrg{
54105b261ecSmrg#ifdef DDXOSVERRORF
54205b261ecSmrg    if (OsVendorVErrorFProc)
54305b261ecSmrg	OsVendorVErrorFProc(f, args);
54405b261ecSmrg    else
54505b261ecSmrg	LogVWrite(-1, f, args);
54605b261ecSmrg#else
54705b261ecSmrg    LogVWrite(-1, f, args);
54805b261ecSmrg#endif
54905b261ecSmrg}
55005b261ecSmrg
55105b261ecSmrg_X_EXPORT void
55205b261ecSmrgErrorF(const char * f, ...)
55305b261ecSmrg{
55405b261ecSmrg    va_list args;
55505b261ecSmrg
55605b261ecSmrg    va_start(args, f);
55705b261ecSmrg    VErrorF(f, args);
55805b261ecSmrg    va_end(args);
55905b261ecSmrg}
56005b261ecSmrg
56105b261ecSmrg/* A perror() workalike. */
56205b261ecSmrg
56305b261ecSmrg_X_EXPORT void
56405b261ecSmrgError(char *str)
56505b261ecSmrg{
56605b261ecSmrg    char *err = NULL;
56705b261ecSmrg    int saveErrno = errno;
56805b261ecSmrg
56905b261ecSmrg    if (str) {
57005b261ecSmrg	err = malloc(strlen(strerror(saveErrno)) + strlen(str) + 2 + 1);
57105b261ecSmrg	if (!err)
57205b261ecSmrg	    return;
57305b261ecSmrg	sprintf(err, "%s: ", str);
57405b261ecSmrg	strcat(err, strerror(saveErrno));
5754642e01fSmrg	LogWrite(-1, "%s", err);
5764642e01fSmrg	free(err);
57705b261ecSmrg    } else
5784642e01fSmrg	LogWrite(-1, "%s", strerror(saveErrno));
57905b261ecSmrg}
58005b261ecSmrg
58105b261ecSmrgvoid
58205b261ecSmrgLogPrintMarkers(void)
58305b261ecSmrg{
58405b261ecSmrg    /* Show what the message marker symbols mean. */
58505b261ecSmrg    ErrorF("Markers: ");
58605b261ecSmrg    LogMessageVerb(X_PROBED, -1, "probed, ");
58705b261ecSmrg    LogMessageVerb(X_CONFIG, -1, "from config file, ");
58805b261ecSmrg    LogMessageVerb(X_DEFAULT, -1, "default setting,\n\t");
58905b261ecSmrg    LogMessageVerb(X_CMDLINE, -1, "from command line, ");
59005b261ecSmrg    LogMessageVerb(X_NOTICE, -1, "notice, ");
59105b261ecSmrg    LogMessageVerb(X_INFO, -1, "informational,\n\t");
59205b261ecSmrg    LogMessageVerb(X_WARNING, -1, "warning, ");
59305b261ecSmrg    LogMessageVerb(X_ERROR, -1, "error, ");
59405b261ecSmrg    LogMessageVerb(X_NOT_IMPLEMENTED, -1, "not implemented, ");
59505b261ecSmrg    LogMessageVerb(X_UNKNOWN, -1, "unknown.\n");
59605b261ecSmrg}
59705b261ecSmrg
598