/* ** 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 #include #include #include #include #include #include #include /* own includes */ #include "l2.h" #include "l2_p.h" /* standard include we re-implement */ #include /* 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; }