/* 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
*
* Copyright (C) 2007 Rainer Gerhards
*
* This file is part of rsyslog.
*
* Rsyslog 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 3 of the License, or
* (at your option) any later version.
*
* Rsyslog 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.
*
* You should have received a copy of the GNU General Public License
* along with Rsyslog. If not, see .
*
* A copy of the GPL can be found in the file "COPYING" in this distribution.
*/
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#define PATH_LOGNAME "/dev/log" /* be sure you know what you do if you change this! */
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 */
/* 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)
{
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;
}
/* Close the log file if it is currently open.
*/
static void klogCloselog(void)
{
if(fdLog != -1)
close(fdLog);
fdLog = -1;
connected = 0;
}
/* 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 */
assert(szFmt != NULL);
if (fdLog < 0 || !connected)
klogOpenlog();
/* build the message */
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);
iChars = vsnprintf(msgBuf + iLen, sizeof(msgBuf) / sizeof(char) - iLen, szFmt, va);
if(iChars > (int)(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 */
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);
}
return(iWritten);
}
/* And now the same with variable arguments */
int writeSyslog(int iPRI, const char *szFmt, ...)
{
int iRet;
va_list va;
assert(szFmt != NULL);
va_start(va, szFmt);
iRet = writeSyslogV(iPRI, szFmt, va);
va_end(va);
return(iRet);
}
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
* End:
* vi:set ai:
*/