log.c revision 52397711
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;
31552397711Smrg    char tmpBuf[1024];
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
35752397711Smrg        /* if s is not NULL we need a space before format */
35852397711Smrg        snprintf(tmpBuf, sizeof(tmpBuf), "%s%s%s", s ? s : "",
35952397711Smrg                                                   s ? " " : "",
36052397711Smrg                                                   format);
36152397711Smrg        LogVWrite(verb, tmpBuf, args);
36205b261ecSmrg    }
36305b261ecSmrg}
36405b261ecSmrg
36505b261ecSmrg/* Log message with verbosity level specified. */
36605b261ecSmrg_X_EXPORT void
36705b261ecSmrgLogMessageVerb(MessageType type, int verb, const char *format, ...)
36805b261ecSmrg{
36905b261ecSmrg    va_list ap;
37005b261ecSmrg
37105b261ecSmrg    va_start(ap, format);
37205b261ecSmrg    LogVMessageVerb(type, verb, format, ap);
37305b261ecSmrg    va_end(ap);
37405b261ecSmrg}
37505b261ecSmrg
37605b261ecSmrg/* Log a message with the standard verbosity level of 1. */
37705b261ecSmrg_X_EXPORT void
37805b261ecSmrgLogMessage(MessageType type, const char *format, ...)
37905b261ecSmrg{
38005b261ecSmrg    va_list ap;
38105b261ecSmrg
38205b261ecSmrg    va_start(ap, format);
38305b261ecSmrg    LogVMessageVerb(type, 1, format, ap);
38405b261ecSmrg    va_end(ap);
38505b261ecSmrg}
38605b261ecSmrg
38705b261ecSmrg#ifdef __GNUC__
38805b261ecSmrgvoid AbortServer(void) __attribute__((noreturn));
38905b261ecSmrg#endif
39005b261ecSmrg
39105b261ecSmrgvoid
39205b261ecSmrgAbortServer(void)
39305b261ecSmrg{
3944642e01fSmrg    CloseWellKnownConnections();
39505b261ecSmrg    OsCleanup(TRUE);
39605b261ecSmrg    CloseDownDevices();
39705b261ecSmrg    AbortDDX();
39805b261ecSmrg    fflush(stderr);
39905b261ecSmrg    if (CoreDump)
40005b261ecSmrg	abort();
40105b261ecSmrg    exit (1);
40205b261ecSmrg}
40305b261ecSmrg
4044642e01fSmrg#define AUDIT_PREFIX "AUDIT: %s: %ld: "
40505b261ecSmrg#ifndef AUDIT_TIMEOUT
40605b261ecSmrg#define AUDIT_TIMEOUT ((CARD32)(120 * 1000)) /* 2 mn */
40705b261ecSmrg#endif
40805b261ecSmrg
40905b261ecSmrgstatic int nrepeat = 0;
41005b261ecSmrgstatic int oldlen = -1;
41105b261ecSmrgstatic OsTimerPtr auditTimer = NULL;
41205b261ecSmrg
41305b261ecSmrgvoid
41405b261ecSmrgFreeAuditTimer(void)
41505b261ecSmrg{
41605b261ecSmrg    if (auditTimer != NULL) {
41705b261ecSmrg	/* Force output of pending messages */
41805b261ecSmrg	TimerForce(auditTimer);
41905b261ecSmrg	TimerFree(auditTimer);
42005b261ecSmrg	auditTimer = NULL;
42105b261ecSmrg    }
42205b261ecSmrg}
42305b261ecSmrg
42405b261ecSmrgstatic char *
42505b261ecSmrgAuditPrefix(void)
42605b261ecSmrg{
42705b261ecSmrg    time_t tm;
42805b261ecSmrg    char *autime, *s;
42905b261ecSmrg    char *tmpBuf;
43005b261ecSmrg    int len;
43105b261ecSmrg
43205b261ecSmrg    time(&tm);
43305b261ecSmrg    autime = ctime(&tm);
43405b261ecSmrg    if ((s = strchr(autime, '\n')))
43505b261ecSmrg	*s = '\0';
4364642e01fSmrg    len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + 1;
43705b261ecSmrg    tmpBuf = malloc(len);
43805b261ecSmrg    if (!tmpBuf)
43905b261ecSmrg	return NULL;
4404642e01fSmrg    snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long)getpid());
44105b261ecSmrg    return tmpBuf;
44205b261ecSmrg}
44305b261ecSmrg
44405b261ecSmrgvoid
44505b261ecSmrgAuditF(const char * f, ...)
44605b261ecSmrg{
44705b261ecSmrg    va_list args;
44805b261ecSmrg
44905b261ecSmrg    va_start(args, f);
45005b261ecSmrg
45105b261ecSmrg    VAuditF(f, args);
45205b261ecSmrg    va_end(args);
45305b261ecSmrg}
45405b261ecSmrg
45505b261ecSmrgstatic CARD32
45605b261ecSmrgAuditFlush(OsTimerPtr timer, CARD32 now, pointer arg)
45705b261ecSmrg{
45805b261ecSmrg    char *prefix;
45905b261ecSmrg
46005b261ecSmrg    if (nrepeat > 0) {
46105b261ecSmrg	prefix = AuditPrefix();
46205b261ecSmrg	ErrorF("%slast message repeated %d times\n",
46305b261ecSmrg	       prefix != NULL ? prefix : "", nrepeat);
46405b261ecSmrg	nrepeat = 0;
46505b261ecSmrg	if (prefix != NULL)
46605b261ecSmrg	    free(prefix);
46705b261ecSmrg	return AUDIT_TIMEOUT;
46805b261ecSmrg    } else {
46905b261ecSmrg	/* if the timer expires without anything to print, flush the message */
47005b261ecSmrg	oldlen = -1;
47105b261ecSmrg	return 0;
47205b261ecSmrg    }
47305b261ecSmrg}
47405b261ecSmrg
47505b261ecSmrgvoid
47605b261ecSmrgVAuditF(const char *f, va_list args)
47705b261ecSmrg{
47805b261ecSmrg    char *prefix;
47905b261ecSmrg    char buf[1024];
48005b261ecSmrg    int len;
48105b261ecSmrg    static char oldbuf[1024];
48205b261ecSmrg
48305b261ecSmrg    prefix = AuditPrefix();
48405b261ecSmrg    len = vsnprintf(buf, sizeof(buf), f, args);
48505b261ecSmrg
48605b261ecSmrg    if (len == oldlen && strcmp(buf, oldbuf) == 0) {
48705b261ecSmrg	/* Message already seen */
48805b261ecSmrg	nrepeat++;
48905b261ecSmrg    } else {
49005b261ecSmrg	/* new message */
49105b261ecSmrg	if (auditTimer != NULL)
49205b261ecSmrg	    TimerForce(auditTimer);
49305b261ecSmrg	ErrorF("%s%s", prefix != NULL ? prefix : "", buf);
49405b261ecSmrg	strlcpy(oldbuf, buf, sizeof(oldbuf));
49505b261ecSmrg	oldlen = len;
49605b261ecSmrg	nrepeat = 0;
49705b261ecSmrg	auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL);
49805b261ecSmrg    }
49905b261ecSmrg    if (prefix != NULL)
50005b261ecSmrg	free(prefix);
50105b261ecSmrg}
50205b261ecSmrg
50305b261ecSmrg_X_EXPORT void
50405b261ecSmrgFatalError(const char *f, ...)
50505b261ecSmrg{
50605b261ecSmrg    va_list args;
50705b261ecSmrg    static Bool beenhere = FALSE;
50805b261ecSmrg
50905b261ecSmrg    if (beenhere)
51005b261ecSmrg	ErrorF("\nFatalError re-entered, aborting\n");
51105b261ecSmrg    else
51205b261ecSmrg	ErrorF("\nFatal server error:\n");
51305b261ecSmrg
51405b261ecSmrg    va_start(args, f);
51505b261ecSmrg    VErrorF(f, args);
51605b261ecSmrg    va_end(args);
51705b261ecSmrg    ErrorF("\n");
51805b261ecSmrg    if (!beenhere)
51905b261ecSmrg	OsVendorFatalError();
52005b261ecSmrg    if (!beenhere) {
52105b261ecSmrg	beenhere = TRUE;
52205b261ecSmrg	AbortServer();
52305b261ecSmrg    } else
52405b261ecSmrg	abort();
52505b261ecSmrg    /*NOTREACHED*/
52605b261ecSmrg}
52705b261ecSmrg
52805b261ecSmrg_X_EXPORT void
52905b261ecSmrgVErrorF(const char *f, va_list args)
53005b261ecSmrg{
53105b261ecSmrg#ifdef DDXOSVERRORF
53205b261ecSmrg    if (OsVendorVErrorFProc)
53305b261ecSmrg	OsVendorVErrorFProc(f, args);
53405b261ecSmrg    else
53505b261ecSmrg	LogVWrite(-1, f, args);
53605b261ecSmrg#else
53705b261ecSmrg    LogVWrite(-1, f, args);
53805b261ecSmrg#endif
53905b261ecSmrg}
54005b261ecSmrg
54105b261ecSmrg_X_EXPORT void
54205b261ecSmrgErrorF(const char * f, ...)
54305b261ecSmrg{
54405b261ecSmrg    va_list args;
54505b261ecSmrg
54605b261ecSmrg    va_start(args, f);
54705b261ecSmrg    VErrorF(f, args);
54805b261ecSmrg    va_end(args);
54905b261ecSmrg}
55005b261ecSmrg
55105b261ecSmrg/* A perror() workalike. */
55205b261ecSmrg
55305b261ecSmrg_X_EXPORT void
55405b261ecSmrgError(char *str)
55505b261ecSmrg{
55605b261ecSmrg    char *err = NULL;
55705b261ecSmrg    int saveErrno = errno;
55805b261ecSmrg
55905b261ecSmrg    if (str) {
56005b261ecSmrg	err = malloc(strlen(strerror(saveErrno)) + strlen(str) + 2 + 1);
56105b261ecSmrg	if (!err)
56205b261ecSmrg	    return;
56305b261ecSmrg	sprintf(err, "%s: ", str);
56405b261ecSmrg	strcat(err, strerror(saveErrno));
5654642e01fSmrg	LogWrite(-1, "%s", err);
5664642e01fSmrg	free(err);
56705b261ecSmrg    } else
5684642e01fSmrg	LogWrite(-1, "%s", strerror(saveErrno));
56905b261ecSmrg}
57005b261ecSmrg
57105b261ecSmrgvoid
57205b261ecSmrgLogPrintMarkers(void)
57305b261ecSmrg{
57405b261ecSmrg    /* Show what the message marker symbols mean. */
57505b261ecSmrg    ErrorF("Markers: ");
57605b261ecSmrg    LogMessageVerb(X_PROBED, -1, "probed, ");
57705b261ecSmrg    LogMessageVerb(X_CONFIG, -1, "from config file, ");
57805b261ecSmrg    LogMessageVerb(X_DEFAULT, -1, "default setting,\n\t");
57905b261ecSmrg    LogMessageVerb(X_CMDLINE, -1, "from command line, ");
58005b261ecSmrg    LogMessageVerb(X_NOTICE, -1, "notice, ");
58105b261ecSmrg    LogMessageVerb(X_INFO, -1, "informational,\n\t");
58205b261ecSmrg    LogMessageVerb(X_WARNING, -1, "warning, ");
58305b261ecSmrg    LogMessageVerb(X_ERROR, -1, "error, ");
58405b261ecSmrg    LogMessageVerb(X_NOT_IMPLEMENTED, -1, "not implemented, ");
58505b261ecSmrg    LogMessageVerb(X_UNKNOWN, -1, "unknown.\n");
58605b261ecSmrg}
58705b261ecSmrg
588