diff options
Diffstat (limited to 'plugins/imklog')
-rw-r--r-- | plugins/imklog/.cvsignore | 6 | ||||
-rw-r--r-- | plugins/imklog/Makefile.am | 16 | ||||
-rw-r--r-- | plugins/imklog/bsd.c | 181 | ||||
-rw-r--r-- | plugins/imklog/imklog.c | 267 | ||||
-rw-r--r-- | plugins/imklog/imklog.h | 70 | ||||
-rw-r--r-- | plugins/imklog/ksym.c | 833 | ||||
-rw-r--r-- | plugins/imklog/ksym_mod.c | 482 | ||||
-rw-r--r-- | plugins/imklog/ksyms.h | 37 | ||||
-rw-r--r-- | plugins/imklog/linux.c | 544 | ||||
-rw-r--r-- | plugins/imklog/module.h | 35 |
10 files changed, 2471 insertions, 0 deletions
diff --git a/plugins/imklog/.cvsignore b/plugins/imklog/.cvsignore new file mode 100644 index 00000000..9730646f --- /dev/null +++ b/plugins/imklog/.cvsignore @@ -0,0 +1,6 @@ +.deps +.libs +Makefile +Makefile.in +*.la +*.lo diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am new file mode 100644 index 00000000..246b3306 --- /dev/null +++ b/plugins/imklog/Makefile.am @@ -0,0 +1,16 @@ +pkglib_LTLIBRARIES = imklog.la + +imklog_la_SOURCES = imklog.c imklog.h + +# select klog "driver" +if ENABLE_IMKLOG_BSD +imklog_la_SOURCES += bsd.c +endif + +if ENABLE_IMKLOG_LINUX +imklog_la_SOURCES += linux.c module.h ksym.c ksyms.h ksym_mod.c +endif + +imklog_la_CPPFLAGS = -I$(top_srcdir) $(pthreads_cflags) +imklog_la_LDFLAGS = -module -avoid-version +imklog_la_LIBADD = diff --git a/plugins/imklog/bsd.c b/plugins/imklog/bsd.c new file mode 100644 index 00000000..39b644c0 --- /dev/null +++ b/plugins/imklog/bsd.c @@ -0,0 +1,181 @@ +/* klog for BSD, based on the FreeBSD syslogd implementation. + * + * This contains OS-specific functionality to read the BSD + * kernel log. For a general overview, see head comment in + * imklog.c. + * + * Copyright (C) 2008 by Rainer Gerhards for the modifications of + * the original FreeBSD sources. + * + * I would like to express my gratitude to those folks which + * layed an important foundation for rsyslog to build on. + * + * 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 <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * + * This file is based on earlier work included in the FreeBSD sources. We + * integrated it into the rsyslog project. The copyright below applies, and + * I also reproduce the original license under which we aquired the code: + * + * Copyright (c) 1983, 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS 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 REGENTS OR 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. + * + * If you would like to use the code under the BSD license, you should + * aquire your own copy of BSD's syslogd, from which we have taken it. The + * code in this file is modified and may only be used under the terms of + * the GPLv3+ as specified above. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> + +#include "rsyslog.h" +#include "imklog.h" + +/* globals */ +static int fklog = -1; /* /dev/klog */ + +#ifndef _PATH_KLOG +# define _PATH_KLOG "/dev/klog" +#endif + +/* open the kernel log - will be called inside the willRun() imklog + * entry point. -- rgerhards, 2008-04-09 + */ +rsRetVal +klogWillRun(void) +{ + DEFiRet; + + fklog = open(_PATH_KLOG, O_RDONLY, 0); + if (fklog < 0) { + dbgprintf("can't open %s (%d)\n", _PATH_KLOG, errno); + iRet = RS_RET_ERR; // TODO: better error code + } + + RETiRet; +} + + +/* Read /dev/klog while data are available, split into lines. + * Contrary to standard BSD syslogd, we do a blocking read. We can + * afford this as imklog is running on its own threads. So if we have + * a single file, it really doesn't matter if we wait inside a 1-file + * select or the read() directly. + */ +static void +readklog(void) +{ + char *p, *q, line[MAXLINE + 1]; + int len, i; + + len = 0; + for (;;) { + dbgprintf("----------imklog waiting for kernel log line\n"); + i = read(fklog, line + len, MAXLINE - 1 - len); + if (i > 0) { + line[i + len] = '\0'; + } else { + if (i < 0 && errno != EINTR && errno != EAGAIN) { + imklogLogIntMsg(LOG_ERR, + "imklog error %d reading kernel log - shutting down imklog", + errno); + fklog = -1; + } + break; + } + + for (p = line; (q = strchr(p, '\n')) != NULL; p = q + 1) { + *q = '\0'; + Syslog(LOG_INFO, (uchar*) p); + } + len = strlen(p); + if (len >= MAXLINE - 1) { + Syslog(LOG_INFO, (uchar*)p); + len = 0; + } + if (len > 0) + memmove(line, p, len + 1); + } + if (len > 0) + Syslog(LOG_INFO, (uchar*)line); +} + + +/* to be called in the module's AfterRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogAfterRun(void) +{ + DEFiRet; + if(fklog != -1) + close(fklog); + RETiRet; +} + + + +/* to be called in the module's WillRun entry point, this is the main + * "message pull" mechanism. + * rgerhards, 2008-04-09 + */ +rsRetVal klogLogKMsg(void) +{ + DEFiRet; + readklog(); + RETiRet; +} + + +/* provide the (system-specific) default facility for internal messages + * rgerhards, 2008-04-14 + */ +int +klogFacilIntMsg(void) +{ + return LOG_SYSLOG; +} diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c new file mode 100644 index 00000000..f7aee5b1 --- /dev/null +++ b/plugins/imklog/imklog.c @@ -0,0 +1,267 @@ +/* The kernel log module. + * + * This is an abstracted module. As Linux and BSD kernel log is conceptually the + * same, we do not do different input plugins for them but use + * imklog in both cases, just with different "backend drivers" for + * the different platforms. This also enables a rsyslog.conf to + * be used on multiple platforms without the need to take care of + * what the kernel log is coming from. + * + * See platform-specific files (e.g. linux.c, bsd.c) in the plugin's + * working directory. For other systems with similar kernel logging + * functionality, no new input plugin shall be written but rather a + * driver be developed for imklog. Please note that imklog itself is + * mostly concerned with handling the interface. Any real action happens + * in the drivers, as things may be pretty different on different + * platforms. + * + * Please note that this file replaces the klogd daemon that was + * also present in pre-v3 versions of rsyslog. + * + * Copyright (C) 2008 by Rainer Gerhards and Adiscon GmbH + * + * 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 <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. +*/ +#include "config.h" +#include "rsyslog.h" +#include <stdio.h> +#include <assert.h> +#include <string.h> +#include <stdarg.h> +#include <ctype.h> + +#include "syslogd.h" +#include "cfsysline.h" +#include "obj.h" +#include "msg.h" +#include "module-template.h" +#include "datetime.h" +#include "imklog.h" + +MODULE_TYPE_INPUT + +/* Module static data */ +DEF_IMOD_STATIC_DATA +DEFobjCurrIf(datetime) + +/* configuration settings TODO: move to instance data? */ +int dbgPrintSymbols = 0; /* this one is extern so the helpers can access it! */ +int symbols_twice = 0; +int use_syscall = 0; +int symbol_lookup = 0; /* on recent kernels > 2.6, the kernel does this */ +int bPermitNonKernel = 0; /* permit logging of messages not having LOG_KERN facility */ +int iFacilIntMsg; /* the facility to use for internal messages (set by driver) */ +/* TODO: configuration for the following directives must be implemented. It + * was not done yet because we either do not yet have a config handler for + * that type or I thought it was acceptable to push it to a later stage when + * I gained more handson experience with the input module interface (and the + * changes resulting from that). -- rgerhards, 2007-12-20 + */ +char *symfile = NULL; +int console_log_level = -1; + + +/* enqueue the the kernel message into the message queue. + * The provided msg string is not freed - thus must be done + * by the caller. + * rgerhards, 2008-04-12 + */ +static rsRetVal +enqMsg(uchar *msg, uchar* pszTag, int iFacility, int iSeverity) +{ + DEFiRet; + msg_t *pMsg; + + assert(msg != NULL); + assert(pszTag != NULL); + + CHKiRet(msgConstruct(&pMsg)); + MsgSetFlowControlType(pMsg, eFLOWCTL_LIGHT_DELAY); + MsgSetUxTradMsg(pMsg, (char*)msg); + MsgSetRawMsg(pMsg, (char*)msg); + MsgSetMSG(pMsg, (char*)msg); + MsgSetHOSTNAME(pMsg, (char*)LocalHostName); + MsgSetTAG(pMsg, (char*)pszTag); + pMsg->iFacility = LOG_FAC(iFacility); + pMsg->iSeverity = LOG_PRI(iSeverity); + pMsg->bParseHOSTNAME = 0; + datetime.getCurrTime(&(pMsg->tTIMESTAMP)); /* use the current time! */ + CHKiRet(submitMsg(pMsg)); + +finalize_it: + RETiRet; +} + +/* parse the PRI from a kernel message. At least BSD seems to have + * non-kernel messages inside the kernel log... + * Expected format: "<pri>". piPri is only valid if the function + * successfully returns. If there was a proper pri ppSz is advanced to the + * position right after ">". + * rgerhards, 2008-04-14 + */ +static rsRetVal +parsePRI(uchar **ppSz, int *piPri) +{ + DEFiRet; + int i; + uchar *pSz; + + assert(ppSz != NULL); + pSz = *ppSz; + assert(pSz != NULL); + assert(piPri != NULL); + + if(*pSz != '<' || !isdigit(*(pSz+1))) + ABORT_FINALIZE(RS_RET_INVALID_PRI); + + ++pSz; + i = 0; + while(isdigit(*pSz)) { + i = i * 10 + *pSz++ - '0'; + } + + if(*pSz != '>') + ABORT_FINALIZE(RS_RET_INVALID_PRI); + + /* OK, we have a valid PRI */ + *piPri = i; + *ppSz = pSz + 1; /* update msg ptr to position after PRI */ + +finalize_it: + RETiRet; +} + + +/* log an imklog-internal message + * rgerhards, 2008-04-14 + */ +rsRetVal imklogLogIntMsg(int priority, char *fmt, ...) +{ + DEFiRet; + va_list ap; + uchar msgBuf[2048]; /* we use the same size as sysklogd to remain compatible */ + uchar *pLogMsg; + + va_start(ap, fmt); + vsnprintf((char*)msgBuf, sizeof(msgBuf) / sizeof(char), fmt, ap); + pLogMsg = msgBuf; + va_end(ap); + + iRet = enqMsg((uchar*)pLogMsg, (uchar*) ((iFacilIntMsg == LOG_KERN) ? "kernel:" : "imklog:"), + iFacilIntMsg, LOG_PRI(priority)); + + RETiRet; +} + + +/* log a kernel message + * rgerhards, 2008-04-14 + */ +rsRetVal Syslog(int priority, uchar *pMsg) +{ + DEFiRet; + rsRetVal localRet; + + /* Output using syslog */ + localRet = parsePRI(&pMsg, &priority); + if(localRet != RS_RET_INVALID_PRI && localRet != RS_RET_OK) + FINALIZE; + /* if we don't get the pri, we use whatever we were supplied */ + + /* ignore non-kernel messages if not permitted */ + if(bPermitNonKernel == 0 && LOG_FAC(priority) != LOG_KERN) + FINALIZE; /* silently ignore */ + + iRet = enqMsg((uchar*)pMsg, (uchar*) "kernel:", LOG_FAC(priority), LOG_PRI(priority)); + +finalize_it: + RETiRet; +} + + +BEGINrunInput +CODESTARTrunInput + /* this is an endless loop - it is terminated when the thread is + * signalled to do so. This, however, is handled by the framework, + * right into the sleep below. + */ + while(!pThrd->bShallStop) { + /* klogLogKMsg() waits for the next kernel message, obtains it + * and then submits it to the rsyslog main queue. + * rgerhards, 2008-04-09 + */ + CHKiRet(klogLogKMsg()); + } +finalize_it: +ENDrunInput + + +BEGINwillRun +CODESTARTwillRun + iRet = klogWillRun(); +ENDwillRun + + +BEGINafterRun +CODESTARTafterRun + iRet = klogAfterRun(); +ENDafterRun + + +BEGINmodExit +CODESTARTmodExit + /* release objects we used */ + objRelease(datetime, CORE_COMPONENT); +ENDmodExit + + +BEGINqueryEtryPt +CODESTARTqueryEtryPt +CODEqueryEtryPt_STD_IMOD_QUERIES +ENDqueryEtryPt + +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +{ + dbgPrintSymbols = 0; + symbols_twice = 0; + use_syscall = 0; + symfile = NULL; + symbol_lookup = 0; + bPermitNonKernel = 0; + iFacilIntMsg = klogFacilIntMsg(); + return RS_RET_OK; +} + +BEGINmodInit() +CODESTARTmodInit + *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ +CODEmodInit_QueryRegCFSLineHdlr + CHKiRet(objUse(datetime, CORE_COMPONENT)); + + iFacilIntMsg = klogFacilIntMsg(); + + CHKiRet(omsdRegCFSLineHdlr((uchar *)"debugprintkernelsymbols", 0, eCmdHdlrBinary, NULL, &dbgPrintSymbols, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbollookup", 0, eCmdHdlrBinary, NULL, &symbol_lookup, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbolstwice", 0, eCmdHdlrBinary, NULL, &symbols_twice, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogusesyscallinterface", 0, eCmdHdlrBinary, NULL, &use_syscall, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogpermitnonkernelfacility", 0, eCmdHdlrBinary, NULL, &bPermitNonKernel, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"kloginternalmsgfacility", 0, eCmdHdlrFacility, NULL, &iFacilIntMsg, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); +ENDmodInit +/* vim:set ai: + */ diff --git a/plugins/imklog/imklog.h b/plugins/imklog/imklog.h new file mode 100644 index 00000000..a37ecc9e --- /dev/null +++ b/plugins/imklog/imklog.h @@ -0,0 +1,70 @@ +/* imklog.h + * These are the definitions for the klog message generation module. + * + * File begun on 2007-12-17 by RGerhards + * Major change: 2008-04-09: switched to a driver interface for + * several platforms + * + * Copyright 2007-2008 Rainer Gerhards and Adiscon GmbH. + * + * 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 <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#ifndef IMKLOG_H_INCLUDED +#define IMKLOG_H_INCLUDED 1 + +#include "rsyslog.h" +#include "syslogd.h" + +/* interface to "drivers" + * the platform specific drivers must implement these entry points. Only one + * driver may be active at any given time, thus we simply rely on the linker + * to resolve the addresses. + * rgerhards, 2008-04-09 + */ +rsRetVal klogLogKMsg(void); +rsRetVal klogWillRun(void); +rsRetVal klogAfterRun(void); +int klogFacilIntMsg(void); + +/* the following data members may be accessed by the "drivers" + * I admit this is not the cleanest way to doing things, but I honestly + * believe it is appropriate for the job that needs to be done. + * rgerhards, 2008-04-09 + */ +extern int symbols_twice; +extern int use_syscall; +extern int symbol_lookup; +extern char *symfile; +extern int console_log_level; +extern int dbgPrintSymbols; + +/* the functions below may be called by the drivers */ +rsRetVal imklogLogIntMsg(int priority, char *fmt, ...) __attribute__((format(printf,2, 3))); +rsRetVal Syslog(int priority, uchar *msg); + +/* prototypes */ +extern int InitKsyms(char *); +extern void DeinitKsyms(void); +extern int InitMsyms(void); +extern void DeinitMsyms(void); +extern char * ExpandKadds(char *, char *); +extern void SetParanoiaLevel(int); + +#endif /* #ifndef IMKLOG_H_INCLUDED */ +/* vi:set ai: + */ diff --git a/plugins/imklog/ksym.c b/plugins/imklog/ksym.c new file mode 100644 index 00000000..f636a7bb --- /dev/null +++ b/plugins/imklog/ksym.c @@ -0,0 +1,833 @@ +/* ksym.c - functions for kernel address->symbol translation + * Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com> + * Copyright (c) 1996 Enjellic Systems Development + * Copyright (c) 1998-2007 Martin Schulze <joey@infodrom.org> + * Copyright (C) 2007-2008 Rainer Gerhards <rgerhards@adiscon.com> + * + * 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 <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. +*/ + +/* + * This file contains functions which handle the translation of kernel + * numeric addresses into symbols for the klogd utility. + * + * Sat Oct 28 09:00:14 CDT 1995: Dr. Wettstein + * Initial Version. + * + * Fri Nov 24 12:50:52 CST 1995: Dr. Wettstein + * Added VERBOSE_DEBUGGING define to make debugging output more + * manageable. + * + * Added support for verification of the loaded kernel symbols. If + * no version information can be be found in the mapfile a warning + * message is issued but translation will still take place. This + * will be the default case if kernel versions < 1.3.43 are used. + * + * If the symbols in the mapfile are of the same version as the kernel + * that is running an informative message is issued. If the symbols + * in the mapfile do not match the current kernel version a warning + * message is issued and translation is disabled. + * + * Wed Dec 6 16:14:11 CST 1995: Dr. Wettstein + * Added /boot/System.map to the list of symbol maps to search for. + * Also made this map the first item in the search list. I am open + * to CONSTRUCTIVE suggestions for any additions or corrections to + * the list of symbol maps to search for. Be forewarned that the + * list in use is the consensus agreement between myself, Linus and + * some package distributers. It is a given that no list will suit + * everyone's taste. If you have rabid concerns about the list + * please feel free to edit the system_maps array and compile your + * own binaries. + * + * Added support for searching of the list of symbol maps. This + * allows support for access to multiple symbol maps. The theory + * behind this is that a production kernel may have a system map in + * /boot/System.map. If a test kernel is booted this system map + * would be skipped in favor of one found in /usr/src/linux. + * + * Thu Jan 18 11:18:31 CST 1996: Dr. Wettstein + * Added patch from beta-testers to allow for reading of both + * ELF and a.out map files. + * + * Wed Aug 21 09:15:49 CDT 1996: Dr. Wettstein + * Reloading of kernel module symbols is now turned on by the + * SetParanoiaLevel function. The default behavior is to NOT reload + * the kernel module symbols when a protection fault is detected. + * + * Added support for freeing of the current kernel module symbols. + * This was necessary to support reloading of the kernel module symbols. + * + * When a matching static symbol table is loaded the kernel version + * number is printed. + * + * Mon Jun 9 17:12:42 CST 1997: Martin Schulze + * Added #1 and #2 to some error messages in order to being able + * to divide them (ulmo@Q.Net) + * + * Fri Jun 13 10:50:23 CST 1997: Martin Schulze + * Changed definition of LookupSymbol to non-static because it is + * used in klogd.c, too. + * + * Fri Jan 9 23:00:08 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Fixed bug that caused klogd to die if there is no System.map available. + * + * Sun 29 Mar 18:14:07 BST 1998: Mark Simon Phillips <M.S.Phillips@nortel.co.uk> + * Switched to fgets() as gets() is not buffer overrun secure. + * + * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Modified loop for detecting the correct system map. Now it won't + * stop if a file has been found but doesn't contain the correct map. + * Special thanks go go Mark Simon Phillips for the hint. + * + * Mon Oct 12 00:42:30 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Modified CheckVersion() + * . Use shift to decode the kernel version + * . Compare integers of kernel version + * . extract major.minor.patch from utsname.release via sscanf() + * The reason lays in possible use of kernel flavours which + * modify utsname.release but no the Version_ symbol. + * + * Sun Feb 21 22:27:49 EST 1999: Keith Owens <kaos@ocs.com.au> + * Fixed bug that caused klogd to die if there is no sym_array available. + * + * Tue Sep 12 23:48:12 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> + * Close symbol file in InitKsyms() when an error occurred. + */ + + +/* Includes. */ +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <sys/utsname.h> +#include <ctype.h> +#include <stdarg.h> +#include <string.h> +#include <syslog.h> +#include "imklog.h" +#include "ksyms.h" +#include "module.h" + + +int num_syms = 0; +static int i_am_paranoid = 0; +static char vstring[12]; +static struct sym_table *sym_array = (struct sym_table *) 0; + +static char *system_maps[] = +{ + "/boot/System.map", + "/System.map", + NULL +}; + + +/* Function prototypes. */ +static char *FindSymbolFile(void); +static int AddSymbol(unsigned long, char*); +static void FreeSymbols(void); +static int CheckVersion(char *); +static int CheckMapVersion(char *); + + +/************************************************************************* + * Function: InitKsyms + * + * Purpose: This function is responsible for initializing and loading + * the data tables used by the kernel address translations. + * + * Arguements: (char *) mapfile + * + * mapfile:-> A pointer to a complete path + * specification of the file containing + * the kernel map to use. + * + * Return: int + * + * A boolean style context is returned. The return value will + * be true if initialization was successful. False if not. + **************************************************************************/ +extern int InitKsyms(char *mapfile) +{ + auto char type, + sym[512]; + + auto int version = 0; + + auto unsigned long int address; + + auto FILE *sym_file; + + BEGINfunc + + /* Check and make sure that we are starting with a clean slate. */ + if ( num_syms > 0 ) + FreeSymbols(); + + + /* Search for and open the file containing the kernel symbols. */ + if ( mapfile != NULL ) { + if ( (sym_file = fopen(mapfile, "r")) == NULL ) + { + imklogLogIntMsg(LOG_WARNING, "Cannot open map file: %s.", mapfile); + return(0); + } + } else { + if ( (mapfile = FindSymbolFile()) == NULL ) { + imklogLogIntMsg(LOG_WARNING, "Cannot find map file."); + dbgprintf("Cannot find map file.\n"); + return(0); + } + + if ( (sym_file = fopen(mapfile, "r")) == NULL ) { + imklogLogIntMsg(LOG_WARNING, "Cannot open map file."); + dbgprintf("Cannot open map file.\n"); + return(0); + } + } + + + /* Read the kernel symbol table file and add entries for each + * line. I suspect that the use of fscanf is not really in vogue + * but it was quick and dirty and IMHO suitable for fixed format + * data such as this. If anybody doesn't agree with this please + * e-mail me a diff containing a parser with suitable political + * correctness -- GW. + */ + while ( !feof(sym_file) ) { + if ( fscanf(sym_file, "%lx %c %s\n", &address, &type, sym) != 3 ) { + imklogLogIntMsg(LOG_ERR, "Error in symbol table input (#1)."); + fclose(sym_file); + return(0); + } + if(dbgPrintSymbols) + dbgprintf("Address: %lx, Type: %c, Symbol: %s\n", address, type, sym); + + if ( AddSymbol(address, sym) == 0 ) { + imklogLogIntMsg(LOG_ERR, "Error adding symbol - %s.", sym); + fclose(sym_file); + return(0); + } + + if ( version == 0 ) + version = CheckVersion(sym); + } + + + imklogLogIntMsg(LOG_INFO, "Loaded %d symbols from %s.", num_syms, mapfile); + switch(version) { + case -1: + imklogLogIntMsg(LOG_WARNING, "Symbols do not match kernel version."); + num_syms = 0; + break; + + case 0: + imklogLogIntMsg(LOG_WARNING, "Cannot verify that symbols match kernel version."); + break; + + case 1: + imklogLogIntMsg(LOG_INFO, "Symbols match kernel version %s.", vstring); + break; + } + + fclose(sym_file); + ENDfunc + return(1); +} + + +extern void DeinitKsyms(void) +{ + FreeSymbols(); +} + + +/************************************************************************** + * Function: FindSymbolFile + * + * Purpose: This function is responsible for encapsulating the search + * for a valid symbol file. Encapsulating the search for + * the map file in this function allows an intelligent search + * process to be implemented. + * + * The list of symbol files will be searched until either a + * symbol file is found whose version matches the currently + * executing kernel or the end of the list is encountered. If + * the end of the list is encountered the first available + * symbol file is returned to the caller. + * + * This strategy allows klogd to locate valid symbol files + * for both a production and an experimental kernel. For + * example a map for a production kernel could be installed + * in /boot. If an experimental kernel is loaded the map + * in /boot will be skipped and the map in /usr/src/linux would + * be used if its version number matches the executing kernel. + * + * Arguements: None specified. + * + * Return: char * + * + * If a valid system map cannot be located a null pointer + * is returned to the caller. + * + * If the search is succesful a pointer is returned to the + * caller which points to the name of the file containing + * the symbol table to be used. + **************************************************************************/ +static char *FindSymbolFile(void) +{ + auto char *file = NULL, + **mf = system_maps; + auto struct utsname utsname; + static char mysymfile[100]; + auto FILE *sym_file = NULL; + BEGINfunc + + if(uname(&utsname) < 0) { + imklogLogIntMsg(LOG_ERR, "Cannot get kernel version information."); + return(0); + } + + dbgprintf("Searching for symbol map.\n"); + + for(mf = system_maps; *mf != NULL && file == NULL; ++mf) { + snprintf(mysymfile, sizeof(mysymfile), "%s-%s", *mf, utsname.release); + dbgprintf("Trying %s.\n", mysymfile); + if((sym_file = fopen(mysymfile, "r")) != NULL) { + if(CheckMapVersion(mysymfile) == 1) + file = mysymfile; + fclose(sym_file); + } + if(sym_file == NULL || file == NULL) { + sprintf (mysymfile, "%s", *mf); + dbgprintf("Trying %s.\n", mysymfile); + if((sym_file = fopen(mysymfile, "r")) != NULL ) { + if (CheckMapVersion(mysymfile) == 1) + file = mysymfile; + fclose(sym_file); + } + } + } + + /* At this stage of the game we are at the end of the symbol tables. */ + dbgprintf("End of search list encountered.\n"); + ENDfunc + return(file); +} + + +/************************************************************************** + * Function: CheckVersion + * + * Purpose: This function is responsible for determining whether or + * the system map being loaded matches the version of the + * currently running kernel. + * + * The kernel version is checked by examing a variable which + * is of the form: _Version_66347 (a.out) or Version_66437 (ELF). + * + * The suffix of this variable is the current kernel version + * of the kernel encoded in base 256. For example the + * above variable would be decoded as: + * + * (66347 = 1*65536 + 3*256 + 43 = 1.3.43) + * + * (Insert appropriate deities here) help us if Linus ever + * needs more than 255 patch levels to get a kernel out the + * door... :-) + * + * Arguements: (char *) version + * + * version:-> A pointer to the string which + * is to be decoded as a kernel + * version variable. + * + * Return: int + * + * -1:-> The currently running kernel version does + * not match this version string. + * + * 0:-> The string is not a kernel version variable. + * + * 1:-> The executing kernel is of the same version + * as the version string. + **************************************************************************/ +static int CheckVersion(char *version) +{ + auto int vnum, + major, + minor, + patch; + int kvnum; + auto struct utsname utsname; + + static char *prefix = { "Version_" }; + + + /* Early return if there is no hope. */ + if ( strncmp(version, prefix, strlen(prefix)) == 0 /* ELF */ || + (*version == '_' && + strncmp(++version, prefix, strlen(prefix)) == 0 ) /* a.out */ ) + ; + else + return(0); + + + /* Since the symbol looks like a kernel version we can start + * things out by decoding the version string into its component + * parts. + */ + vnum = atoi(version + strlen(prefix)); + patch = vnum & 0x000000FF; + minor = (vnum >> 8) & 0x000000FF; + major = (vnum >> 16) & 0x000000FF; + dbgprintf("Version string = %s, Major = %d, Minor = %d, Patch = %d.\n", version + + strlen(prefix), major, minor, patch); + sprintf(vstring, "%d.%d.%d", major, minor, patch); + + /* We should now have the version string in the vstring variable in + * the same format that it is stored in by the kernel. We now + * ask the kernel for its version information and compare the two + * values to determine if our system map matches the kernel + * version level. + */ + if ( uname(&utsname) < 0 ) { + imklogLogIntMsg(LOG_ERR, "Cannot get kernel version information."); + return(0); + } + dbgprintf("Comparing kernel %s with symbol table %s.\n", utsname.release, vstring); + + if ( sscanf (utsname.release, "%d.%d.%d", &major, &minor, &patch) < 3 ) { + imklogLogIntMsg(LOG_ERR, "Kernel send bogus release string `%s'.", utsname.release); + return(0); + } + + /* Compute the version code from data sent by the kernel */ + kvnum = (major << 16) | (minor << 8) | patch; + + /* Failure. */ + if ( vnum != kvnum ) + return(-1); + + /* Success. */ + return(1); +} + + +/************************************************************************** + * Function: CheckMapVersion + * + * Purpose: This function is responsible for determining whether or + * the system map being loaded matches the version of the + * currently running kernel. It uses CheckVersion as + * backend. + * + * Arguements: (char *) fname + * + * fname:-> A pointer to the string which + * references the system map file to + * be used. + * + * Return: int + * + * -1:-> The currently running kernel version does + * not match the version in the given file. + * + * 0:-> No system map file or no version information. + * + * 1:-> The executing kernel is of the same version + * as the version of the map file. + **************************************************************************/ +static int CheckMapVersion(char *fname) +{ + int version; + FILE *sym_file; + auto unsigned long int address; + auto char type, + sym[512]; + + if ( (sym_file = fopen(fname, "r")) != NULL ) { + /* + * At this point a map file was successfully opened. We + * now need to search this file and look for version + * information. + */ + imklogLogIntMsg(LOG_INFO, "Inspecting %s", fname); + + version = 0; + while ( !feof(sym_file) && (version == 0) ) { + if ( fscanf(sym_file, "%lx %c %s\n", &address, &type, sym) != 3 ) { + imklogLogIntMsg(LOG_ERR, "Error in symbol table input (#2)."); + fclose(sym_file); + return(0); + } + if(dbgPrintSymbols) + dbgprintf("Address: %lx, Type: %c, Symbol: %s\n", address, type, sym); + version = CheckVersion(sym); + } + fclose(sym_file); + + switch ( version ) { + case -1: + imklogLogIntMsg(LOG_ERR, "Symbol table has incorrect version number.\n"); + break; + case 0: + dbgprintf("No version information found.\n"); + break; + case 1: + dbgprintf("Found table with matching version number.\n"); + break; + } + + return(version); + } + + return(0); +} + + +/************************************************************************** + * Function: AddSymbol + * + * Purpose: This function is responsible for adding a symbol name + * and its address to the symbol table. + * + * Arguements: (unsigned long) address, (char *) symbol + * + * Return: int + * + * A boolean value is assumed. True if the addition is + * successful. False if not. + **************************************************************************/ +static int AddSymbol(unsigned long address, char *symbol) +{ + /* Allocate the the symbol table entry. */ + sym_array = (struct sym_table *) realloc(sym_array, (num_syms+1) * + sizeof(struct sym_table)); + if ( sym_array == (struct sym_table *) 0 ) + return(0); + + /* Then the space for the symbol. */ + sym_array[num_syms].name = (char *) malloc(strlen(symbol)*sizeof(char) + 1); + if ( sym_array[num_syms].name == NULL ) + return(0); + + sym_array[num_syms].value = address; + strcpy(sym_array[num_syms].name, symbol); + ++num_syms; + return(1); +} + + +/************************************************************************** + * Function: LookupSymbol + * + * Purpose: Find the symbol which is related to the given kernel + * address. + * + * Arguements: (long int) value, (struct symbol *) sym + * + * value:-> The address to be located. + * + * sym:-> A pointer to a structure which will be + * loaded with the symbol's parameters. + * + * Return: (char *) + * + * If a match cannot be found a diagnostic string is printed. + * If a match is found the pointer to the symbolic name most + * closely matching the address is returned. + **************************************************************************/ +char * LookupSymbol(unsigned long value, struct symbol *sym) +{ + auto int lp; + + auto char *last; + auto char *name; + + struct symbol ksym, msym; + + if (!sym_array) + return(NULL); + + last = sym_array[0].name; + ksym.offset = 0; + ksym.size = 0; + if ( value < sym_array[0].value ) + return(NULL); + + for(lp = 0; lp <= num_syms; ++lp) { + if ( sym_array[lp].value > value ) { + ksym.offset = value - sym_array[lp-1].value; + ksym.size = sym_array[lp].value - \ + sym_array[lp-1].value; + break; + } + last = sym_array[lp].name; + } + + name = LookupModuleSymbol(value, &msym); + + if ( ksym.offset == 0 && msym.offset == 0 ) { + return(NULL); + } + + if ( ksym.offset == 0 || msym.offset < 0 || + (ksym.offset > 0 && ksym.offset < msym.offset) ) { + sym->offset = ksym.offset; + sym->size = ksym.size; + return(last); + } else { + sym->offset = msym.offset; + sym->size = msym.size; + return(name); + } + + + return(NULL); +} + +/************************************************************************** + * Function: FreeSymbols + * + * Purpose: This function is responsible for freeing all memory which + * has been allocated to hold the static symbol table. It + * also initializes the symbol count and in general prepares + * for a re-read of a static symbol table. + * + * Arguements: void + * + * Return: void + **************************************************************************/ +static void FreeSymbols(void) +{ + auto int lp; + + /* Free each piece of memory allocated for symbol names. */ + for(lp= 0; lp < num_syms; ++lp) + free(sym_array[lp].name); + + /* Whack the entire array and initialize everything. */ + free(sym_array); + sym_array = (struct sym_table *) 0; + num_syms = 0; + + return; +} + + +/************************************************************************** + * Function: LogExpanded + * + * Purpose: This function is responsible for logging a kernel message + * line after all potential numeric kernel addresses have + * been resolved symolically. + * + * Arguements: (char *) line, (char *) el + * + * line:-> A pointer to the buffer containing the kernel + * message to be expanded and logged. + * + * el:-> A pointer to the buffer into which the expanded + * kernel line will be written. + * + * Return: void + **************************************************************************/ +extern char *ExpandKadds(char *line, char *el) +{ + auto char dlm, + *kp, + *sl = line, + *elp = el, + *symbol; + char num[15]; + auto unsigned long int value; + auto struct symbol sym; + + sym.offset = 0; + sym.size = 0; + + /* + * This is as handy a place to put this as anyplace. + * + * Since the insertion of kernel modules can occur in a somewhat + * dynamic fashion we need some mechanism to insure that the + * kernel symbol tables get read just prior to when they are + * needed. + * + * To accomplish this we look for the Oops string and use its + * presence as a signal to load the module symbols. + * + * This is not the best solution of course, especially if the + * kernel is rapidly going out to lunch. What really needs to + * be done is to somehow generate a callback from the + * kernel whenever a module is loaded or unloaded. I am + * open for patches. + */ + if ( i_am_paranoid && + (strstr(line, "Oops:") != NULL) && !InitMsyms() ) + imklogLogIntMsg(LOG_WARNING, "Cannot load kernel module symbols.\n"); + + + /* + * Early return if there do not appear to be any kernel + * messages in this line. + */ + if ( (num_syms == 0) || + (kp = strstr(line, "[<")) == NULL ) { +#ifdef __sparc__ + if (num_syms) { + /* On SPARC, register dumps do not have the [< >] characters in it. + */ + static struct sparc_tests { + char *str; + int len; + } tests[] = { { "PC: ", 4 }, + { " o7: ", 5 }, + { " ret_pc: ", 9 }, + { " i7: ", 5 }, + { "Caller[", 7 } + }; + int i, j, ndigits; + char *kp2; + for (i = 0; i < 5; i++) { + kp = strstr(line, tests[i].str); + if (!kp) continue; + kp2 = kp + tests[i].len; + if (!isxdigit(*kp2)) continue; + for (ndigits = 1; isxdigit(kp2[ndigits]); ndigits++); + if (ndigits != 8 && ndigits != 16) continue; + /* On sparc64, all kernel addresses are in first 4GB */ + if (ndigits == 16) { + if (strncmp (kp2, "00000000", 8)) continue; + kp2 += 8; + } + if (!i) { + char *kp3; + if (ndigits == 16 && kp > line && kp[-1L] != 'T') continue; + kp3 = kp2 + 8; + if (ndigits == 16) { + if (strncmp (kp3, " TNPC: 00000000", 15) || !isxdigit(kp3[15])) + continue; + kp3 += 15; + } else { + if (strncmp (kp3, " NPC: ", 6) || !isxdigit(kp3[6])) + continue; + kp3 += 6; + } + for (j = 0; isxdigit(kp3[j]); j++); + if (j != 8) continue; + strncpy(elp, line, kp2 + 8 - line); + elp += kp2 + 8 - line; + value = strtol(kp2, (char **) 0, 16); + if ( (symbol = LookupSymbol(value, &sym)) ) { + if (sym.size) + elp += sprintf(elp, " (%s+%d/%d)", symbol, sym.offset, sym.size); + else + elp += sprintf(elp, " (%s)", symbol); + } + strncpy(elp, kp2 + 8, kp3 - kp2); + elp += kp3 - kp2; + value = strtol(kp3, (char **) 0, 16); + if ( (symbol = LookupSymbol(value, &sym)) ) { + if (sym.size) + elp += sprintf(elp, " (%s+%d/%d)", symbol, sym.offset, sym.size); + else + elp += sprintf(elp, " (%s)", symbol); + } + strcpy(elp, kp3 + 8); + } else { + strncpy(elp, line, kp2 + 8 - line); + elp += kp2 + 8 - line; + value = strtol(kp2, (char **) 0, 16); + if ( (symbol = LookupSymbol(value, &sym)) ) { + if (sym.size) + elp += sprintf(elp, " (%s+%d/%d)", symbol, sym.offset, sym.size); + else + elp += sprintf(elp, " (%s)", symbol); + } + strcpy(elp, kp2 + 8); + } + return el; + } + } +#endif + strcpy(el, line); + return(el); + } + + /* Loop through and expand all kernel messages. */ + do { + while ( sl < kp+1 ) + *elp++ = *sl++; + + /* Now poised at a kernel delimiter. */ + if ( (kp = strstr(sl, ">]")) == NULL ) { + strcpy(el, sl); + return(el); + } + dlm = *kp; + strncpy(num,sl+1,kp-sl-1); + num[kp-sl-1] = '\0'; + value = strtoul(num, (char **) 0, 16); + if ( (symbol = LookupSymbol(value, &sym)) == NULL ) + symbol = sl; + + strcat(elp, symbol); + elp += strlen(symbol); + dbgprintf("Symbol: %s = %lx = %s, %x/%d\n", sl+1, value, + (sym.size==0) ? symbol+1 : symbol, sym.offset, sym.size); + + value = 2; + if ( sym.size != 0 ) { + --value; + ++kp; + elp += sprintf(elp, "+0x%x/0x%02x", sym.offset, sym.size); + } + strncat(elp, kp, value); + elp += value; + sl = kp + value; + if ( (kp = strstr(sl, "[<")) == NULL ) + strcat(elp, sl); + } + while ( kp != NULL); + + dbgprintf("Expanded line: %s\n", el); + return(el); +} + + +/************************************************************************** + * Function: SetParanoiaLevel + * + * Purpose: This function is an interface function for setting the + * mode of loadable module symbol lookups. Probably overkill + * but it does slay another global variable. + * + * Arguements: (int) level + * + * level:-> The amount of paranoia which is to be + * present when resolving kernel exceptions. + * Return: void + **************************************************************************/ +extern void SetParanoiaLevel(int level) +{ + i_am_paranoid = level; + return; +} + diff --git a/plugins/imklog/ksym_mod.c b/plugins/imklog/ksym_mod.c new file mode 100644 index 00000000..6e48e89e --- /dev/null +++ b/plugins/imklog/ksym_mod.c @@ -0,0 +1,482 @@ +/* + * ksym_mod.c - functions for building symbol lookup tables for klogd + * Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com> + * Copyright (c) 1996 Enjellic Systems Development + * Copyright (c) 1998-2007 Martin Schulze <joey@infodrom.org> + * Copyright (C) 2007-2008 Rainer Gerhards <rgerhards@adiscon.com> + * + * 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 <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. +*/ + +/* + * This file implements functions which are useful for building + * a symbol lookup table based on the in kernel symbol table + * maintained by the Linux kernel. + * + * Proper logging of kernel panics generated by loadable modules + * tends to be difficult. Since the modules are loaded dynamically + * their addresses are not known at kernel load time. A general + * protection fault (Oops) cannot be properly deciphered with + * classic methods using the static symbol map produced at link time. + * + * One solution to this problem is to have klogd attempt to translate + * addresses from module when the fault occurs. By referencing the + * the kernel symbol table proper resolution of these symbols is made + * possible. + * + * At least that is the plan. + * + * Wed Aug 21 09:20:09 CDT 1996: Dr. Wettstein + * The situation where no module support has been compiled into a + * kernel is now detected. An informative message is output indicating + * that the kernel has no loadable module support whenever kernel + * module symbols are loaded. + * + * An informative message is printed indicating the number of kernel + * modules and the number of symbols loaded from these modules. + * + * Sun Jun 15 16:23:29 MET DST 1997: Michael Alan Dorman + * Some more glibc patches made by <mdorman@debian.org>. + * + * Sat Jan 10 15:00:18 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Fixed problem with klogd not being able to be built on a kernel + * newer than 2.1.18. It was caused by modified structures + * inside the kernel that were included. I have worked in a + * patch from Alessandro Suardi <asuardi@uninetcom.it>. + * + * Sun Jan 25 20:57:34 CET 1998: Martin Schulze <joey@infodrom.north.de> + * Another patch for Linux/alpha by Christopher C Chimelis + * <chris@classnet.med.miami.edu>. + * + * Thu Mar 19 23:39:29 CET 1998: Manuel Rodrigues <pmanuel@cindy.fe.up.pt> + * Changed lseek() to llseek() in order to support > 2GB address + * space which provided by kernels > 2.1.70. + * + * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze <joey@infodrom.north.de> + * Removed <sys/module.h> as it's no longer part of recent glibc + * versions. Added prototyp for llseek() which has been + * forgotton in <unistd.h> from glibc. Added more log + * information if problems occurred while reading a system map + * file, by submission from Mark Simon Phillips <M.S.Phillips@nortel.co.uk>. + * + * Sun Jan 3 18:38:03 CET 1999: Martin Schulze <joey@infodrom.north.de> + * Corrected return value of AddModule if /dev/kmem can't be + * loaded. This will prevent klogd from segfaulting if /dev/kmem + * is not available. Patch from Topi Miettinen <tom@medialab.sonera.net>. + * + * Tue Sep 12 23:11:13 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> + * Changed llseek() to lseek64() in order to skip a libc warning. + */ + + +/* Includes. */ +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <errno.h> +#include <sys/fcntl.h> +#include <sys/stat.h> +#if !defined(__GLIBC__) +#include <linux/time.h> +#include <linux/module.h> +#else /* __GLIBC__ */ +#include "module.h" +#endif /* __GLIBC__ */ +#include <stdarg.h> +#include <paths.h> +#include <linux/version.h> + +#include "rsyslog.h" +#include "imklog.h" +#include "ksyms.h" + +#define KSYMS "/proc/kallsyms" + +static int num_modules = 0; +struct Module *sym_array_modules = (struct Module *) 0; + +static int have_modules = 0; + + +/* Function prototypes. */ +static void FreeModules(void); +static int AddSymbol(const char *); +struct Module *AddModule(const char *); +static int symsort(const void *, const void *); + +/* Imported from ksym.c */ +extern int num_syms; + + +/************************************************************************** + * Function: InitMsyms + * + * Purpose: This function is responsible for building a symbol + * table which can be used to resolve addresses for + * loadable modules. + * + * Arguements: Void + * + * Return: A boolean return value is assumed. + * + * A false value indicates that something went wrong. + * + * True if loading is successful. + **************************************************************************/ +extern int InitMsyms(void) +{ + + auto int rtn, + tmp; + FILE *ksyms; + char buf[128]; + char *p; + + /* Initialize the kernel module symbol table. */ + FreeModules(); + + ksyms = fopen(KSYMS, "r"); + + if ( ksyms == NULL ) { + if ( errno == ENOENT ) + imklogLogIntMsg(LOG_INFO, "No module symbols loaded - " + "kernel modules not enabled.\n"); + else + imklogLogIntMsg(LOG_ERR, "Error loading kernel symbols " \ + "- %s\n", strerror(errno)); + return(0); + } + + dbgprintf("Loading kernel module symbols - Source: %s\n", KSYMS); + + while ( fgets(buf, sizeof(buf), ksyms) != NULL ) { + if (num_syms > 0 && index(buf, '[') == NULL) + continue; + + p = index(buf, ' '); + + if ( p == NULL ) + continue; + + if ( buf[strlen(buf)-1] == '\n' ) + buf[strlen(buf)-1] = '\0'; + /* overlong lines will be ignored above */ + + AddSymbol(buf); + } + + if(ksyms != NULL) + fclose(ksyms); + + have_modules = 1; + + /* Sort the symbol tables in each module. */ + for (rtn = tmp = 0; tmp < num_modules; ++tmp) { + rtn += sym_array_modules[tmp].num_syms; + if ( sym_array_modules[tmp].num_syms < 2 ) + continue; + qsort(sym_array_modules[tmp].sym_array, \ + sym_array_modules[tmp].num_syms, \ + sizeof(struct sym_table), symsort); + } + + if ( rtn == 0 ) + imklogLogIntMsg(LOG_INFO, "No module symbols loaded."); + else + imklogLogIntMsg(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \ + (rtn == 1) ? "symbol" : "symbols", \ + num_modules, (num_modules == 1) ? "." : "s."); + + return(1); +} + + +static int symsort(const void *p1, const void *p2) +{ + auto const struct sym_table *sym1 = p1, + *sym2 = p2; + + if ( sym1->value < sym2->value ) + return(-1); + if ( sym1->value == sym2->value ) + return(0); + return(1); +} + + +extern void DeinitMsyms(void) +{ + FreeModules(); +} + + +/************************************************************************** + * Function: FreeModules + * + * Purpose: This function is used to free all memory which has been + * allocated for the modules and their symbols. + * + * Arguements: None specified. + * + * Return: void + **************************************************************************/ +static void FreeModules() +{ + auto int nmods, + nsyms; + auto struct Module *mp; + + /* Check to see if the module symbol tables need to be cleared. */ + have_modules = 0; + if ( num_modules == 0 ) + return; + + if ( sym_array_modules == NULL ) + return; + + for (nmods = 0; nmods < num_modules; ++nmods) { + mp = &sym_array_modules[nmods]; + if ( mp->num_syms == 0 ) + continue; + + for (nsyms= 0; nsyms < mp->num_syms; ++nsyms) + free(mp->sym_array[nsyms].name); + free(mp->sym_array); + if ( mp->name != NULL ) + free(mp->name); + } + + free(sym_array_modules); + sym_array_modules = (struct Module *) 0; + num_modules = 0; + return; +} + + +/************************************************************************** + * Function: AddModule + * + * Purpose: This function is responsible for adding a module to + * the list of currently loaded modules. + * + * Arguments: (const char *) module + * + * module:-> The name of the module. + * + * Return: struct Module * + **************************************************************************/ + +struct Module *AddModule(module) + const char *module; +{ + struct Module *mp; + + if ( num_modules == 0 ) { + sym_array_modules = (struct Module *)malloc(sizeof(struct Module)); + + if ( sym_array_modules == NULL ) + { + imklogLogIntMsg(LOG_WARNING, "Cannot allocate Module array.\n"); + return NULL; + } + mp = sym_array_modules; + } else { + /* Allocate space for the module. */ + mp = (struct Module *) \ + realloc(sym_array_modules, \ + (num_modules+1) * sizeof(struct Module)); + + if ( mp == NULL ) + { + imklogLogIntMsg(LOG_WARNING, "Cannot allocate Module array.\n"); + return NULL; + } + + sym_array_modules = mp; + mp = &sym_array_modules[num_modules]; + } + + num_modules++; + mp->sym_array = NULL; + mp->num_syms = 0; + + if ( module != NULL ) + mp->name = strdup(module); + else + mp->name = NULL; + + return mp; +} + + +/************************************************************************** + * Function: AddSymbol + * + * Purpose: This function is responsible for adding a symbol name + * and its address to the symbol table. + * + * Arguements: const char * + * + * Return: int + * + * A boolean value is assumed. True if the addition is + * successful. False if not. + **************************************************************************/ +static int AddSymbol(line) + const char *line; +{ + char *module; + unsigned long address; + char *p; + static char *lastmodule = NULL; + struct Module *mp; + + module = index(line, '['); + + if ( module != NULL ) { + p = index(module, ']'); + if ( p != NULL ) + *p = '\0'; + p = module++; + while ( isspace(*(--p)) ) + /*SKIP*/; + *(++p) = '\0'; + } + + p = index(line, ' '); + + if ( p == NULL ) + return(0); + + *p = '\0'; + + address = strtoul(line, (char **) 0, 16); + + p += 3; + + if ( num_modules == 0 || + ( lastmodule == NULL && module != NULL ) || + ( module == NULL && lastmodule != NULL) || + ( module != NULL && strcmp(module, lastmodule))) { + mp = AddModule(module); + + if ( mp == NULL ) + return(0); + } else + mp = &sym_array_modules[num_modules-1]; + + lastmodule = mp->name; + + /* Allocate space for the symbol table entry. */ + mp->sym_array = (struct sym_table *) realloc(mp->sym_array, \ + (mp->num_syms+1) * sizeof(struct sym_table)); + + if ( mp->sym_array == (struct sym_table *) 0 ) + return(0); + + mp->sym_array[mp->num_syms].name = strdup(p); + if ( mp->sym_array[mp->num_syms].name == (char *) 0 ) + return(0); + + /* Stuff interesting information into the module. */ + mp->sym_array[mp->num_syms].value = address; + ++mp->num_syms; + + return(1); +} + + + +/************************************************************************** + * Function: LookupModuleSymbol + * + * Purpose: Find the symbol which is related to the given address from + * a kernel module. + * + * Arguements: (long int) value, (struct symbol *) sym + * + * value:-> The address to be located. + * + * sym:-> A pointer to a structure which will be + * loaded with the symbol's parameters. + * + * Return: (char *) + * + * If a match cannot be found a diagnostic string is printed. + * If a match is found the pointer to the symbolic name most + * closely matching the address is returned. + **************************************************************************/ +extern char * LookupModuleSymbol(value, sym) + unsigned long value; + struct symbol *sym; +{ + auto int nmod, + nsym; + auto struct sym_table *last; + auto struct Module *mp; + static char ret[100]; + + sym->size = 0; + sym->offset = 0; + if ( num_modules == 0 ) + return((char *) 0); + + for (nmod = 0; nmod < num_modules; ++nmod) { + mp = &sym_array_modules[nmod]; + + /* + * Run through the list of symbols in this module and + * see if the address can be resolved. + */ + for(nsym = 1, last = &mp->sym_array[0]; + nsym < mp->num_syms; + ++nsym) { + if ( mp->sym_array[nsym].value > value ) + { + if ( sym->size == 0 || + (value - last->value) < sym->offset || + ( (sym->offset == (value - last->value)) && + (mp->sym_array[nsym].value-last->value) < sym->size ) ) + { + sym->offset = value - last->value; + sym->size = mp->sym_array[nsym].value - \ + last->value; + ret[sizeof(ret)-1] = '\0'; + if ( mp->name == NULL ) + snprintf(ret, sizeof(ret)-1, + "%s", last->name); + else + snprintf(ret, sizeof(ret)-1, + "%s:%s", mp->name, last->name); + } + break; + } + last = &mp->sym_array[nsym]; + } + } + + if ( sym->size > 0 ) + return(ret); + + /* It has been a hopeless exercise. */ + return((char *) 0); +} diff --git a/plugins/imklog/ksyms.h b/plugins/imklog/ksyms.h new file mode 100644 index 00000000..b5362ff3 --- /dev/null +++ b/plugins/imklog/ksyms.h @@ -0,0 +1,37 @@ +/* ksym.h - Definitions for symbol table utilities. + * Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com> + * Copyright (c) 1996 Enjellic Systems Development + * Copyright (c) 2004-7 Martin Schulze <joey@infodrom.org> + * Copyright (c) 2007-2008 Rainer Gerhards <rgerhards@adiscon.com> + * + * 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 <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ + +/* Variables, structures and type definitions static to this module. */ + +struct symbol +{ + char *name; + int size; + int offset; +}; + + +/* Function prototypes. */ +extern char * LookupSymbol(unsigned long, struct symbol *); +extern char * LookupModuleSymbol(unsigned long int, struct symbol *); diff --git a/plugins/imklog/linux.c b/plugins/imklog/linux.c new file mode 100644 index 00000000..faf20134 --- /dev/null +++ b/plugins/imklog/linux.c @@ -0,0 +1,544 @@ +/* klog for linux, based on the FreeBSD syslogd implementation. + * + * This contains OS-specific functionality to read the BSD + * kernel log. For a general overview, see head comment in + * imklog.c. + * + * This file heavily borrows from the klogd daemon provided by + * the sysklogd project. Many thanks for this piece of software. + * + * 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 <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. +*/ +#include "config.h" +#include "rsyslog.h" +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <signal.h> +#include <string.h> +#include <pthread.h> +#include "syslogd.h" +#include "cfsysline.h" +#include "template.h" +#include "msg.h" +#include "module-template.h" +#include "imklog.h" + + +/* Includes. */ +#include <unistd.h> +#include <errno.h> +#include <sys/fcntl.h> +#include <sys/stat.h> + +#if HAVE_TIME_H +# include <time.h> +#endif + +#include <stdarg.h> +#include <paths.h> +#include "ksyms.h" + +#define __LIBRARY__ +#include <unistd.h> + + +#if !defined(__GLIBC__) +# define __NR_ksyslog __NR_syslog +_syscall3(int,ksyslog,int, type, char *, buf, int, len); +#else +#include <sys/klog.h> +#define ksyslog klogctl +#endif + + + +#ifndef _PATH_KLOG +#define _PATH_KLOG "/proc/kmsg" +#endif + +#define LOG_BUFFER_SIZE 4096 +#define LOG_LINE_LENGTH 1000 + +static int kmsg; +static char log_buffer[LOG_BUFFER_SIZE]; + +static enum LOGSRC {none, proc, kernel} logsrc; + + +/* Function prototypes. */ +extern int ksyslog(int type, char *buf, int len); + + +static void CloseLogSrc(void) +{ + /* Turn on logging of messages to console, but only if we had the -c + * option -- rgerhards, 2007-08-01 + */ + if (console_log_level != -1) + ksyslog(7, NULL, 0); + + /* Shutdown the log sources. */ + switch ( logsrc ) + { + case kernel: + ksyslog(0, 0, 0); + imklogLogIntMsg(LOG_INFO, "Kernel logging (ksyslog) stopped."); + break; + case proc: + close(kmsg); + imklogLogIntMsg(LOG_INFO, "Kernel logging (proc) stopped."); + break; + case none: + break; + } + + return; +} + + +static enum LOGSRC GetKernelLogSrc(void) +{ + auto struct stat sb; + + /* Set level of kernel console messaging.. */ + if ( (console_log_level != -1) && + (ksyslog(8, NULL, console_log_level) < 0) && + (errno == EINVAL) ) + { + /* + * An invalid arguement error probably indicates that + * a pre-0.14 kernel is being run. At this point we + * issue an error message and simply shut-off console + * logging completely. + */ + imklogLogIntMsg(LOG_WARNING, "Cannot set console log level - disabling " + "console output."); + } + + /* + * First do a stat to determine whether or not the proc based + * file system is available to get kernel messages from. + */ + if ( use_syscall || + ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)) ) + { + /* Initialize kernel logging. */ + ksyslog(1, NULL, 0); + imklogLogIntMsg(LOG_INFO, "imklog %s, log source = ksyslog " + "started.", VERSION); + return(kernel); + } + + if ( (kmsg = open(_PATH_KLOG, O_RDONLY)) < 0 ) + { + char sz[512]; + snprintf(sz, sizeof(sz), "imklog: Cannot open proc file system, %d - %s.\n", errno, strerror(errno)); + logmsgInternal(LOG_SYSLOG|LOG_ERR, sz, ADDDATE); + ksyslog(7, NULL, 0); /* TODO: check this, implement more */ + return(none); + } + + imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, _PATH_KLOG); + return(proc); +} + + +/* Copy characters from ptr to line until a char in the delim + * string is encountered or until min( space, len ) chars have + * been copied. + * + * Returns the actual number of chars copied. + */ +static int copyin( uchar *line, int space, + const char *ptr, int len, + const char *delim ) +{ + auto int i; + auto int count; + + count = len < space ? len : space; + + for(i=0; i<count && !strchr(delim, *ptr); i++ ) { + *line++ = *ptr++; + } + + return(i); +} + +/* + * Messages are separated by "\n". Messages longer than + * LOG_LINE_LENGTH are broken up. + * + * Kernel symbols show up in the input buffer as : "[<aaaaaa>]", + * where "aaaaaa" is the address. These are replaced with + * "[symbolname+offset/size]" in the output line - symbolname, + * offset, and size come from the kernel symbol table. + * + * If a kernel symbol happens to fall at the end of a message close + * in length to LOG_LINE_LENGTH, the symbol will not be expanded. + * (This should never happen, since the kernel should never generate + * messages that long. + * + * To preserve the original addresses, lines containing kernel symbols + * are output twice. Once with the symbols converted and again with the + * original text. Just in case somebody wants to run their own Oops + * analysis on the syslog, e.g. ksymoops. + */ +static void LogLine(char *ptr, int len) +{ + enum parse_state_enum { + PARSING_TEXT, + PARSING_SYMSTART, /* at < */ + PARSING_SYMBOL, + PARSING_SYMEND /* at ] */ + }; + + static uchar line_buff[LOG_LINE_LENGTH]; + + static uchar *line =line_buff; + static enum parse_state_enum parse_state = PARSING_TEXT; + static int space = sizeof(line_buff)-1; + + static uchar *sym_start; /* points at the '<' of a symbol */ + + auto int delta = 0; /* number of chars copied */ + auto int symbols_expanded = 0; /* 1 if symbols were expanded */ + auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */ + auto char *save_ptr = ptr; /* save start of input line */ + auto int save_len = len; /* save length at start of input line */ + + while( len > 0 ) + { + if( space == 0 ) /* line buffer is full */ + { + /* + ** Line too long. Start a new line. + */ + *line = 0; /* force null terminator */ + + //dbgprintf("Line buffer full:\n"); + //dbgprintf("\tLine: %s\n", line); + + Syslog(LOG_INFO, line_buff); + line = line_buff; + space = sizeof(line_buff)-1; + parse_state = PARSING_TEXT; + symbols_expanded = 0; + skip_symbol_lookup = 0; + save_ptr = ptr; + save_len = len; + } + + switch( parse_state ) + { + case PARSING_TEXT: + delta = copyin(line, space, ptr, len, "\n[" ); + line += delta; + ptr += delta; + space -= delta; + len -= delta; + + if( space == 0 || len == 0 ) + { + break; /* full line_buff or end of input buffer */ + } + + if( *ptr == '\0' ) /* zero byte */ + { + ptr++; /* skip zero byte */ + space -= 1; + len -= 1; + + break; + } + + if( *ptr == '\n' ) /* newline */ + { + ptr++; /* skip newline */ + space -= 1; + len -= 1; + + *line = 0; /* force null terminator */ + Syslog(LOG_INFO, line_buff); + line = line_buff; + space = sizeof(line_buff)-1; + if (symbols_twice) { + if (symbols_expanded) { + /* reprint this line without symbol lookup */ + symbols_expanded = 0; + skip_symbol_lookup = 1; + ptr = save_ptr; + len = save_len; + } + else + { + skip_symbol_lookup = 0; + save_ptr = ptr; + save_len = len; + } + } + break; + } + if( *ptr == '[' ) /* possible kernel symbol */ + { + *line++ = *ptr++; + space -= 1; + len -= 1; + if (!skip_symbol_lookup) + parse_state = PARSING_SYMSTART; /* at < */ + break; + } + /* Now that line_buff is no longer fed to *printf as format + * string, '%'s are no longer "dangerous". + */ + break; + + case PARSING_SYMSTART: + if( *ptr != '<' ) + { + parse_state = PARSING_TEXT; /* not a symbol */ + break; + } + + /* + ** Save this character for now. If this turns out to + ** be a valid symbol, this char will be replaced later. + ** If not, we'll just leave it there. + */ + + sym_start = line; /* this will point at the '<' */ + + *line++ = *ptr++; + space -= 1; + len -= 1; + parse_state = PARSING_SYMBOL; /* symbol... */ + break; + + case PARSING_SYMBOL: + delta = copyin( line, space, ptr, len, ">\n[" ); + line += delta; + ptr += delta; + space -= delta; + len -= delta; + if( space == 0 || len == 0 ) + { + break; /* full line_buff or end of input buffer */ + } + if( *ptr != '>' ) + { + parse_state = PARSING_TEXT; + break; + } + + *line++ = *ptr++; /* copy the '>' */ + space -= 1; + len -= 1; + + parse_state = PARSING_SYMEND; + + break; + + case PARSING_SYMEND: + if( *ptr != ']' ) + { + parse_state = PARSING_TEXT; /* not a symbol */ + break; + } + + /* + ** It's really a symbol! Replace address with the + ** symbol text. + */ + { + auto int sym_space; + + unsigned long value; + auto struct symbol sym; + auto char *symbol; + + *(line-1) = 0; /* null terminate the address string */ + value = strtoul((char*)(sym_start+1), (char **) 0, 16); + *(line-1) = '>'; /* put back delim */ + + if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 ) + { + parse_state = PARSING_TEXT; + break; + } + + /* + ** verify there is room in the line buffer + */ + sym_space = space + ( line - sym_start ); + if( (unsigned) sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/ + { + parse_state = PARSING_TEXT; /* not enough space */ + break; + } + + // TODO: sprintf!!!! + delta = sprintf( (char*) sym_start, "%s+%d/%d]", + symbol, sym.offset, sym.size ); + + space = sym_space + delta; + line = sym_start + delta; + symbols_expanded = 1; + } + ptr++; + len--; + parse_state = PARSING_TEXT; + break; + + default: /* Can't get here! */ + parse_state = PARSING_TEXT; + + } + } + + return; +} + + +static void LogKernelLine(void) +{ + auto int rdcnt; + + /* + * Zero-fill the log buffer. This should cure a multitude of + * problems with klogd logging the tail end of the message buffer + * which will contain old messages. Then read the kernel log + * messages into this fresh buffer. + */ + memset(log_buffer, '\0', sizeof(log_buffer)); + if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer)-1)) < 0 ) + { + char sz[512]; + if(errno == EINTR) + return; + snprintf(sz, sizeof(sz), "imklog: Error return from sys_sycall: %d - %s\n", errno, strerror(errno)); + logmsgInternal(LOG_SYSLOG|LOG_ERR, sz, ADDDATE); + } + else + LogLine(log_buffer, rdcnt); + return; +} + + +static void LogProcLine(void) +{ + auto int rdcnt; + + /* + * Zero-fill the log buffer. This should cure a multitude of + * problems with klogd logging the tail end of the message buffer + * which will contain old messages. Then read the kernel messages + * from the message pseudo-file into this fresh buffer. + */ + memset(log_buffer, '\0', sizeof(log_buffer)); + if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 ) { + if ( errno == EINTR ) + return; + imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno)); + } else { + LogLine(log_buffer, rdcnt); + } + + return; +} + + +/* to be called in the module's WillRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogLogKMsg(void) +{ + DEFiRet; + switch(logsrc) { + case kernel: + LogKernelLine(); + break; + case proc: + LogProcLine(); + break; + case none: + /* TODO: We need to handle this case here somewhat more intelligent + * This is now at least partly done - code should never reach this point + * as willRun() already checked for the "none" status -- rgerhards, 2007-12-17 + */ + pause(); + break; + } + RETiRet; +} + + +/* to be called in the module's WillRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogWillRun(void) +{ + DEFiRet; + /* Initialize this module. If that fails, we tell the engine we don't like to run */ + /* Determine where kernel logging information is to come from. */ + logsrc = GetKernelLogSrc(); + if(logsrc == none) { + iRet = RS_RET_NO_KERNEL_LOGSRC; + } else { + if (symbol_lookup) { + symbol_lookup = (InitKsyms(symfile) == 1); + symbol_lookup |= InitMsyms(); + if (symbol_lookup == 0) { + imklogLogIntMsg(LOG_WARNING, "cannot find any symbols, turning off symbol lookups"); + } + } + } + + RETiRet; +} + + +/* to be called in the module's AfterRun entry point + * rgerhards, 2008-04-09 + */ +rsRetVal klogAfterRun(void) +{ + DEFiRet; + /* cleanup here */ + if(logsrc != none) + CloseLogSrc(); + + DeinitKsyms(); + DeinitMsyms(); + + RETiRet; +} + + +/* provide the (system-specific) default facility for internal messages + * rgerhards, 2008-04-14 + */ +int +klogFacilIntMsg(void) +{ + return LOG_KERN; +} + + +/* vi:set ai: + */ diff --git a/plugins/imklog/module.h b/plugins/imklog/module.h new file mode 100644 index 00000000..38a26fea --- /dev/null +++ b/plugins/imklog/module.h @@ -0,0 +1,35 @@ +/* module.h - Miscellaneous module definitions + * Copyright (c) 1996 Richard Henderson <rth@tamu.edu> + * Copyright (c) 2004-7 Martin Schulze <joey@infodrom.org> + * Copyright (c) 2007-2008 Rainer Gerhards <rgerhards@adiscon.com> + * + * 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 <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +struct sym_table +{ + unsigned long value; + char *name; +}; + +struct Module +{ + struct sym_table *sym_array; + int num_syms; + + char *name; +}; |