ossp-pkg/fsl/fsl.c
1.2
/*
** OSSP fsl - Faking Syslog Library
** Copyright (c) 2002 Ralf S. Engelschall <rse@engelschall.com>
** Copyright (c) 2002 The OSSP Project <http://www.ossp.org/>
** Copyright (c) 2002 Cable & Wireless Deutschland <http://www.cw.com/de/>
**
** This file is part of OSSP fsl, a syslog(3) API faking library which
** can be found at http://www.ossp.org/pkg/lib/fsl/.
**
** 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.
**
** fsl.c: OSSP fsl 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>
/* 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;
}
/* ------------------------------------------------------------------ */
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h> /* strerror() */
#include <dirent.h>
#include "config.h"
#define FSL_PREFIX "l2."
#define STMT(stuff) do { stuff } while (0)
#define CU(returncode) STMT( rc = returncode; goto CUS; )
#define VCU STMT( goto CUS; )
typedef struct {
char *base;
int used;
int size;
} buf_t;
/* general return codes */
typedef enum {
FSL_OK = 0, /* everything ok */
FSL_ERR_ARG, /* invalid argument */
FSL_ERR_USE, /* invalid use */
FSL_ERR_MEM, /* no more memory available */
FSL_ERR_SYS /* operating system error, see errno */
//FSL_ERR_FMT, /* formatting error */
//FSL_ERR_INT, /* internal error */
//FSL_ERR_SYN, /* syntax error */
} fsl_rc_t;
fsl_rc_t readfileorallfiles(buf_t *, const char *);
fsl_rc_t readfile (buf_t *, const char *);
fsl_rc_t readallfiles (buf_t *);
fsl_rc_t appendfiletobuffer(buf_t *, const char *);
int main(int argc, char **argv)
{
buf_t buf;
fsl_rc_t rv;
buf.base = NULL;
buf.used = 0;
buf.size = 0;
if ((rv = readfileorallfiles(&buf, "config.log")) != FSL_OK)
fprintf(stderr, "DEBUG: error#%d, system#%s(%d)\n", rv, strerror(errno), errno);
return 0;
}
fsl_rc_t readfileorallfiles(buf_t *buffer, const char *ident)
{
fsl_rc_t rv;
if ((rv = readfile(buffer, ident)) == FSL_OK)
return FSL_OK;
if (rv != FSL_ERR_SYS || errno != ENOENT)
return rv;
if ((rv = readallfiles(buffer)) != FSL_OK)
return rv;
return FSL_OK;
}
fsl_rc_t readfile(buf_t *buffer, const char *ident)
{
fsl_rc_t rc;
char *filename = NULL;
if (ident == NULL || buffer == NULL)
CU(FSL_ERR_ARG);
if ((filename = (char *)malloc(strlen(FSL_CFGDIR) + 1 + strlen(FSL_PREFIX) + strlen(ident) + 1)) == NULL)
CU(FSL_ERR_MEM);
filename[0] = '\0';
strcat(filename, FSL_CFGDIR);
strcat(filename, "/");
strcat(filename, FSL_PREFIX);
strcat(filename, ident);
CU(appendfiletobuffer(buffer, filename));
CUS:
if (filename != NULL)
free(filename);
return rc;
}
fsl_rc_t readallfiles(buf_t *buffer)
{
fsl_rc_t rc;
DIR *dp;
struct dirent *de;
char *filename = NULL;
if (buffer == NULL)
CU(FSL_ERR_ARG);
if ((dp = opendir(FSL_CFGDIR)) == NULL)
CU(FSL_ERR_SYS);
while ((de = readdir(dp)) != NULL) {
if ( (de->d_type == DT_REG)
&& (de->d_namlen >= strlen(FSL_PREFIX))
&& (strncmp(de->d_name, FSL_PREFIX, strlen(FSL_PREFIX)) == 0)
) {
if ((filename = (char *)malloc(strlen(FSL_CFGDIR) + 1 + de->d_namlen + 1)) == NULL)
CU(FSL_ERR_MEM);
filename[0] = '\0';
strcat(filename, FSL_CFGDIR);
strcat(filename, "/");
strncat(filename, de->d_name, de->d_namlen);
(void /*FIXME*/)appendfiletobuffer(buffer, filename);
free(filename);
filename = NULL;
}
}
(void)closedir(dp);
CU(FSL_OK);
CUS:
if (filename != NULL)
free(filename);
return rc;
}
fsl_rc_t appendfiletobuffer(buf_t *buffer, const char *filename)
{
fsl_rc_t rc;
int fd = -1;
int filesize;
int fileread;
int bufferneed;
if (filename == NULL || buffer == NULL)
CU(FSL_ERR_ARG);
if ((fd = open(filename, O_RDONLY)) == -1)
CU(FSL_ERR_SYS);
if ((filesize = (int)lseek(fd, 0, SEEK_END)) == -1)
CU(FSL_ERR_SYS);
bufferneed = buffer->used + filesize;
if (bufferneed > buffer->size) {
if (buffer->base == NULL) {
if ((buffer->base = (char *)malloc(bufferneed)) == NULL)
CU(FSL_ERR_MEM);
buffer->size = bufferneed;
buffer->used = 0;
}
else {
if ((buffer->base = (char *)realloc(buffer->base, bufferneed)) == NULL)
CU(FSL_ERR_MEM);
buffer->size = bufferneed;
}
}
if (lseek(fd, 0, SEEK_SET) == -1)
CU(FSL_ERR_SYS);
if ((fileread = (int)read(fd, buffer->base + buffer->used, (size_t)filesize)) == -1)
CU(FSL_ERR_SYS);
if (fileread != filesize)
CU(FSL_ERR_USE);
buffer->used += filesize;
CU(FSL_OK);
CUS:
if (fd != -1)
close(fd);
return rc;
}