ossp-pkg/l2/l2_syslog.c
/*
** L2 - OSSP Logging Library
** Copyright (c) 2001-2002 The OSSP Project (http://www.ossp.org/)
** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/)
**
** This file is part of OSSP L2, a flexible logging library which
** can be found at http://www.ossp.org/pkg/l2/.
**
** Permission to use, copy, modify, and distribute this software for
** any purpose with or without fee is hereby granted, provided that
** the above copyright notice and this permission notice appear in all
** copies.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
**
** l2_syslog.c: syslog(3) faked API library
*/
/* standard includes we use */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
/* own includes */
#include "l2.h"
#include "l2_p.h"
/* standard include we re-implement */
#include <syslog.h>
/* default for the dedicated logfile */
#ifndef LOGFILE
#define LOGFILE "/tmp/syslog"
#endif
#ifndef LOG_PRIMASK
#define LOG_PRIMASK (LOG_EMERG|LOG_ALERT|LOG_CRIT|LOG_ERR|LOG_WARNING|LOG_NOTICE|LOG_INFO|LOG_DEBUG)
#endif
#ifndef LOG_PRI
#define LOG_PRI(p) ((p) & LOG_PRIMASK)
#endif
/* log level to string mapping */
static struct {
int level;
char *string;
} level2string[] = {
{ LOG_EMERG, "emerg" },
{ LOG_ALERT, "alert" },
{ LOG_CRIT, "crit" },
{ LOG_ERR, "err" },
{ LOG_WARNING, "warning" },
{ LOG_NOTICE, "notice" },
{ LOG_INFO, "info" },
{ LOG_DEBUG, "debug" },
{ 0, NULL }
};
/* internal context structure */
static struct {
FILE *log;
char *logfile;
const char *ident;
int logopt;
int facility;
int maskpri;
} ctx = {
NULL, LOGFILE, "unknown", 0, LOG_USER, 0xff
};
void openlog(const char *ident, int logopt, int facility)
{
/* remember parameters */
ctx.ident = ident;
ctx.logopt = logopt;
ctx.facility = facility;
/* close perhaps still open logfile */
if (ctx.log != NULL) {
fclose(ctx.log);
ctx.log = NULL;
}
/* (re-)open new logfile */
if (!(ctx.logopt & LOG_NDELAY) && ctx.log == NULL)
if ((ctx.log = fopen(ctx.logfile, "a")) == NULL)
return;
return;
}
void closelog(void)
{
/* close open logfile*/
if (ctx.log != NULL) {
fclose(ctx.log);
ctx.log = NULL;
}
return;
}
int setlogmask(int maskpri)
{
int omask;
/* remember the logging mask */
omask = ctx.maskpri;
if (maskpri != 0)
ctx.maskpri = maskpri;
return omask;
}
void syslog(int priority, const char *message, ...)
{
va_list args;
/* wrap around vsyslog(3) */
va_start(args, message);
vsyslog(priority, message, args);
va_end(args);
return;
}
#ifdef HAVE_VSYSLOG_USVALIST
void vsyslog(int priority, const char *fmt, __va_list args)
#else
void vsyslog(int priority, const char *fmt, va_list args)
#endif
{
time_t now;
int saved_errno;
char buf[2048];
char *cpBuf;
int nBuf;
char caMsg[2048];
char *cpMsg;
char *cpFmt;
int i;
char *cpTime;
char *cpLevel;
/* Check for invalid bits */
if (priority & ~(LOG_PRIMASK|LOG_FACMASK))
priority &= (LOG_PRIMASK|LOG_FACMASK);
/* stop processing if mask disabled this call */
if (!(LOG_MASK(LOG_PRI(priority)) & ctx.maskpri))
return;
/* make sure we have a reasonable default for facility */
if ((priority & LOG_FACMASK) == 0)
priority |= ctx.facility;
/* remember errno for optional %m processing below */
saved_errno = errno;
/* open logfile now (if it was delayed) */
if (ctx.log == NULL)
if ((ctx.log = fopen(ctx.logfile, "a")) == NULL)
return;
/* determine current time */
time(&now);
cpTime = ctime(&now) + 4;
/* determine logging level name */
cpLevel = "unknown";
for (i = 0; level2string[i].string != NULL; i++) {
if (LOG_PRI(priority) == level2string[i].level) {
cpLevel = level2string[i].string;
break;
}
}
/* start output generation */
cpBuf = buf;
sprintf(cpBuf, "%.15s <%s> %s", cpTime, cpLevel, ctx.ident);
nBuf = strlen(cpBuf);
/* optionally add process id */
if (ctx.logopt & LOG_PID) {
sprintf(cpBuf+nBuf, "[%d]", getpid());
nBuf += strlen(cpBuf+nBuf);
}
/* end prefix */
strcpy(cpBuf+nBuf, ": ");
nBuf += 2;
/* optionally expand %m in format string */
cpFmt = (char *)fmt;
if (strstr(cpFmt, "%m")) {
cpMsg = caMsg;
while (cpFmt[0] != '\0') {
if (cpFmt[0] == '%' && cpFmt[1] == 'm') {
strcpy(cpMsg, strerror(saved_errno));
cpMsg += strlen(cpMsg);
cpFmt += 2;
} else {
*cpMsg++ = *cpFmt++;
*cpMsg = '\0';
}
}
cpFmt = caMsg;
}
/* append message to output buffer */
vsprintf(cpBuf+nBuf, cpFmt, args);
nBuf += strlen(cpBuf+nBuf);
/* append newline if still not present */
if (cpBuf[nBuf-1] != '\n') {
cpBuf[nBuf++] = '\n';
cpBuf[nBuf] = '\0';
}
/* now finally write output buffer to logfile */
fwrite(cpBuf, nBuf, 1, ctx.log);
fflush(ctx.log);
#ifdef LOG_PERROR
/* optionally also write output buffer to stderr */
if (ctx.logopt & LOG_PERROR)
fwrite(cpBuf, nBuf, 1, stderr);
#endif
return;
}