diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2007-06-14 13:07:32 +0000 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2007-06-14 13:07:32 +0000 |
commit | 2112ef22ae40b421279221f77140f90e09308c39 (patch) | |
tree | 1e704e1ca6784ddd436963f39f71746e75253278 /syslog.c | |
parent | f925aba4ad669c6b96b348c0761ed0531c6f41b4 (diff) | |
download | rsyslog-2112ef22ae40b421279221f77140f90e09308c39.tar.gz rsyslog-2112ef22ae40b421279221f77140f90e09308c39.tar.xz rsyslog-2112ef22ae40b421279221f77140f90e09308c39.zip |
re-wrote syslog.c from scratch to solve a license compatibility issue,
provide some bug fixes and performance enhancemnts. Also required
changes to klogd.c to support the new interface.
Diffstat (limited to 'syslog.c')
-rw-r--r-- | syslog.c | 322 |
1 files changed, 104 insertions, 218 deletions
@@ -1,252 +1,138 @@ -/* - * Copyright (c) 1983, 1988 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted provided - * that: (1) source distributions retain this entire copyright notice and - * comment, and (2) distributions including binaries display the following - * acknowledgement: ``This product includes software developed by the - * University of California, Berkeley and its contributors'' in the - * documentation or other materials provided with the distribution and in - * all advertising materials mentioning features or use of this software. - * Neither the name of the University nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - */ - -/* - * SYSLOG -- print message on log file - * - * This routine looks a lot like printf, except that it outputs to the - * log file instead of the standard output. Also: - * adds a timestamp, - * prints the module name in front of the message, - * has some other formatting types (or will sometime), - * adds a newline on the end of the message. +/* logger.c + * Helper routines for klogd. It replaces the regular glibc syslog() + * call. The reason is that the glibc version does not support + * logging with the kernel facility. This file is a re-implementation + * of the functions with only the functionality required for klogd. + * So it can NOT be used as a general-purpose replacment. + * Thanks to being special, this version is deemed to be considerable + * faster than its glibc counterpart. + * To avoid confusion, the syslog() replacement is named writeSyslog(). + * all other functions are just helpers to it. + * RGerhards, 2007-06-14 * - * The output of this routine is intended to be read by syslogd(8). + * Copyright (C) 2007 Rainer Gerhards * - * Author: Eric Allman - * Modified to use UNIX domain IPC by Ralph Campbell + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * - * Sat Dec 11 11:58:31 CST 1993: Dr. Wettstein - * Changes to allow compilation with no complains under -Wall. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * Thu Jan 18 11:16:11 CST 1996: Dr. Wettstein - * Added patch to close potential security hole. This is the same - * patch which was announced in the linux-security mailing lists - * and incorporated into the libc version of syslog.c. - * - * Sun Mar 11 20:23:44 CET 2001: Martin Schulze <joey@infodrom.ffis.de> - * Use SOCK_DGRAM for loggin, renables it to work. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * A copy of the GPL can be found in the file "COPYING" in this distribution. */ - -#include <sys/types.h> +#include <stdio.h> +#include <assert.h> #include <sys/socket.h> -#include <sys/file.h> -#include <sys/signal.h> -#include <sys/syslog.h> -#undef syslog -#undef vsyslog -#if 0 -#include "syslog.h" -#include "pathnames.h" -#endif - -#include <sys/uio.h> -#include <sys/wait.h> -#include <netdb.h> #include <string.h> #include <time.h> -#include <unistd.h> -#include <errno.h> #include <stdarg.h> -#include <paths.h> -#include <stdio.h> +#include <unistd.h> -#define _PATH_LOGNAME "/dev/log" +#define PATH_LOGNAME "/dev/log" /* be sure you know what you do if you change this! */ -static int LogFile = -1; /* fd for log */ -static int connected; /* have done connect */ -static int LogStat = 0; /* status bits, set by openlog() */ -static const char *LogTag = "syslog"; /* string to tag the entry with */ -static int LogFacility = LOG_USER; /* default facility code */ +static struct sockaddr LoggerAddr; /* AF_UNIX address of local logger */ +static int connected; /* have done connect */ +static int fdLog = -1; /* fd for log - -1 if closed */ -void -syslog(int pri, const char *fmt, ...) +/* klogOpenLog + * opens the system log for writing. The log is opened immediately. + * If it is already open, no action is taken) + */ +static void klogOpenlog(void) { - va_list ap; - - va_start(ap, fmt); - vsyslog(pri, fmt, ap); - va_end(ap); + if (fdLog == -1) { + LoggerAddr.sa_family = AF_UNIX; + strncpy(LoggerAddr.sa_data, PATH_LOGNAME, sizeof(LoggerAddr.sa_data)); + fdLog = socket(AF_UNIX, SOCK_DGRAM, 0); + } + if (fdLog != -1 && !connected) + if(connect(fdLog, &LoggerAddr, sizeof(LoggerAddr.sa_family) + + sizeof(PATH_LOGNAME) - 1 /* for \0 byte!*/ ) != -1) + connected = 1; } -void -vsyslog(pri, fmt, ap) - int pri; - const char *fmt; - va_list ap; +/* Close the log file if it is currently open. + */ +static void klogCloselog(void) { - register int cnt; - register char *p; - time_t now; - int fd, saved_errno; - char tbuf[2048], fmt_cpy[1024], *stdp = (char *) 0; + if(fdLog != -1) + close(fdLog); + fdLog = -1; + connected = 0; +} - saved_errno = errno; +/* Write a message to the syslogd. + * returns -1 if it fails, something else otherwise + */ +int writeSyslogV(int iPRI, const char *szFmt, va_list va) +{ + int iChars; + int iLen; + time_t tNow; + int iWritten; /* number of bytes written */ + char msgBuf[2048]; /* we use the same size as sysklogd to remain compatible */ - /* see if we should just throw out this message */ - if (!LOG_MASK(LOG_PRI(pri)) || (pri &~ (LOG_PRIMASK|LOG_FACMASK))) - return; - if (LogFile < 0 || !connected) - openlog(LogTag, LogStat | LOG_NDELAY, LogFacility); + assert(szFmt != NULL); - /* set default facility if none specified */ - if ((pri & LOG_FACMASK) == 0) - pri |= LogFacility; + if (fdLog < 0 || !connected) + klogOpenlog(); /* build the message */ - (void)time(&now); - (void)sprintf(tbuf, "<%d>%.15s ", pri, ctime(&now) + 4); - for (p = tbuf; *p; ++p); - if (LogStat & LOG_PERROR) - stdp = p; - if (LogTag) { - (void)strcpy(p, LogTag); - for (; *p; ++p); - } - if (LogStat & LOG_PID) { - (void)sprintf(p, "[%d]", getpid()); - for (; *p; ++p); - } - if (LogTag) { - *p++ = ':'; - *p++ = ' '; - } - - /* substitute error message for %m */ - { - register char ch, *t1, *t2; - char *strerror(); - - for (t1 = fmt_cpy; - (ch = *fmt) != '\0' && t1<fmt_cpy+sizeof(fmt_cpy); - ++fmt) - if (ch == '%' && fmt[1] == 'm') { - ++fmt; - for (t2 = strerror(saved_errno); - (*t1 = *t2++); ++t1); - } - else - *t1++ = ch; - *t1 = '\0'; - } - - (void)vsprintf(p, fmt_cpy, ap); - - cnt = strlen(tbuf); - - /* output to stderr if requested */ - if (LogStat & LOG_PERROR) { - struct iovec iov[2]; - register struct iovec *v = iov; + time(&tNow); + /* we can use sprintf safely below, because we know the size of the constants. + * By doing so, we save some cpu cycles and code complexity (for unnecessary + * error checking). + */ + iLen = sprintf(msgBuf, "<%d>%.15s kernel: ", iPRI, ctime(&tNow) + 4); - v->iov_base = stdp; - v->iov_len = cnt - (stdp - tbuf); - ++v; - v->iov_base = "\n"; - v->iov_len = 1; - (void)writev(2, iov, 2); - } + iChars = vsnprintf(msgBuf + iLen, sizeof(msgBuf) / sizeof(char) - iLen, szFmt, va); + if(iChars > sizeof(msgBuf) / sizeof(char) - iLen) + iLen = sizeof(msgBuf) / sizeof(char) - 1; /* full buffer siz minus \0 byte */ + else + iLen += iChars; /* output the message to the local logger */ - if (write(LogFile, tbuf, cnt + 1) >= 0 || !(LogStat&LOG_CONS)) - return; + iWritten = write(fdLog, msgBuf, iLen); + /* Debug aid below - uncomment to use + printf("wrote to log(%d): '%s'\n", iWritten, msgBuf); */ + + if(iWritten == -1) { + /* retry */ + klogCloselog(); + klogOpenlog(); + iWritten = write(fdLog, msgBuf, iLen); + } - /* - * output the message to the console; don't worry about - * blocking, if console blocks everything will. - */ - if ((fd = open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY, 0)) < 0) - return; - (void)strcat(tbuf, "\r\n"); - cnt += 2; - p = index(tbuf, '>') + 1; - (void)write(fd, p, cnt - (p - tbuf)); - (void)close(fd); + return(iWritten); } -#ifndef TESTING -static struct sockaddr SyslogAddr; /* AF_UNIX address of local logger */ -#endif -/* - * OPENLOG -- open system log - */ -void -openlog(ident, logstat, logfac) - const char *ident; - int logstat, logfac; +/* And now the same with variable arguments */ +int writeSyslog(int iPRI, const char *szFmt, ...) { - if (ident != NULL) - LogTag = ident; - LogStat = logstat; - -#ifdef ALLOW_KERNEL_LOGGING - if ((logfac &~ LOG_FACMASK) == 0) -#else - if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) -#endif - LogFacility = logfac; - -#ifndef TESTING - if (LogFile == -1) { - SyslogAddr.sa_family = AF_UNIX; - strncpy(SyslogAddr.sa_data, _PATH_LOGNAME, - sizeof(SyslogAddr.sa_data)); - if (LogStat & LOG_NDELAY) { - LogFile = socket(AF_UNIX, SOCK_DGRAM, 0); -/* fcntl(LogFile, F_SETFD, 1); */ - } - } - if (LogFile != -1 && !connected && - connect(LogFile, &SyslogAddr, sizeof(SyslogAddr.sa_family)+ - strlen(SyslogAddr.sa_data)) != -1) -#else - LogFile = fileno(stdout); -#endif - connected = 1; -} + int iRet; + va_list va; -/* - * CLOSELOG -- close the system log - */ -void -closelog() -{ -#ifndef TESTING - (void) close(LogFile); -#endif - LogFile = -1; - connected = 0; + assert(szFmt != NULL); + va_start(va, szFmt); + iRet = writeSyslogV(iPRI, szFmt, va); + va_end(va); + + return(iRet); } -static int LogMask = 0xff; /* mask of priorities to be logged */ /* - * SETLOGMASK -- set the log mask level + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vi:set ai: */ -int -setlogmask(pmask) - int pmask; -{ - int omask; - - omask = LogMask; - if (pmask != 0) - LogMask = pmask; - return (omask); -} |