From 9088ee33893803cc47a69ba671ebfe10cc09c95b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 17 Dec 2007 11:52:10 +0000 Subject: begun imklog, replacing klogd.c (finally we get rid of it...) --- Makefile.am | 17 +- configure.ac | 3 +- klogd.c | 1201 -------------------------------------------- klogd.h | 45 -- ksym.c | 986 ------------------------------------ ksym_mod.c | 704 -------------------------- ksyms.h | 38 -- module-template.h | 7 +- plugins/imklog/.cvsignore | 6 + plugins/imklog/Makefile.am | 8 + plugins/imklog/imklog.c | 753 +++++++++++++++++++++++++++ plugins/imklog/ksym.c | 986 ++++++++++++++++++++++++++++++++++++ plugins/imklog/ksym_mod.c | 704 ++++++++++++++++++++++++++ plugins/imklog/ksyms.h | 38 ++ plugins/imklog/module.h | 81 +++ plugins/immark/immark.c | 4 +- syslog.c | 141 ------ syslogd.c | 2 - syslogd.h | 2 + 19 files changed, 2592 insertions(+), 3134 deletions(-) delete mode 100644 klogd.c delete mode 100644 klogd.h delete mode 100644 ksym.c delete mode 100644 ksym_mod.c delete mode 100644 ksyms.h create mode 100644 plugins/imklog/.cvsignore create mode 100644 plugins/imklog/Makefile.am create mode 100644 plugins/imklog/imklog.c create mode 100644 plugins/imklog/ksym.c create mode 100644 plugins/imklog/ksym_mod.c create mode 100644 plugins/imklog/ksyms.h create mode 100644 plugins/imklog/module.h delete mode 100644 syslog.c diff --git a/Makefile.am b/Makefile.am index 7e738f18..c9053f24 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,15 +1,4 @@ -sbin_PROGRAMS = rklogd rfc3195d rsyslogd - -rklogd_SOURCES = \ - klogd.c \ - klogd.h \ - syslog.c \ - pidfile.c \ - pidfile.h \ - ksym.c \ - ksyms.h \ - ksym_mod.c \ - module.h +sbin_PROGRAMS = rfc3195d rsyslogd rfc3195d_SOURCES = rfc3195d.c rsyslog.h @@ -87,6 +76,10 @@ SUBDIRS = doc SUBDIRS += plugins/immark +if ENABLE_IMKLOGD +SUBDIRS += plugins/imklog +endif + if ENABLE_MYSQL SUBDIRS += plugins/ommysql endif diff --git a/configure.ac b/configure.ac index ef5353d9..2cf912ec 100644 --- a/configure.ac +++ b/configure.ac @@ -204,6 +204,7 @@ AC_ARG_ENABLE(klogd, if test "$enable_klogd" = "yes"; then AC_DEFINE(FEATURE_KLOGD, 1, [klogd functionality is integrated.]) fi +AM_CONDITIONAL(ENABLE_IMKLOGD, test x$enable_klogd = xyes) # # SYSLOG_UNIXAF @@ -348,7 +349,7 @@ AC_SUBST(pgsql_libs) -AC_CONFIG_FILES([Makefile doc/Makefile plugins/immark/Makefile plugins/ommysql/Makefile plugins/ompgsql/Makefile]) +AC_CONFIG_FILES([Makefile doc/Makefile plugins/immark/Makefile plugins/imklog/Makefile plugins/ommysql/Makefile plugins/ompgsql/Makefile]) AC_OUTPUT echo "****************************************************" diff --git a/klogd.c b/klogd.c deleted file mode 100644 index e2e9df21..00000000 --- a/klogd.c +++ /dev/null @@ -1,1201 +0,0 @@ -/* - klogd.c - main program for Linux kernel log daemon. - Copyright (c) 1995 Dr. G.W. Wettstein - * - * 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" - -#ifdef FEATURE_KLOGD -/* - * Steve Lord (lord@cray.com) 7th Nov 92 - * - * Modified to check for kernel info by Dr. G.W. Wettstein 02/17/93. - * - * Fri Mar 12 16:53:56 CST 1993: Dr. Wettstein - * Modified LogLine to use a newline as the line separator in - * the kernel message buffer. - * - * Added debugging code to dump the contents of the kernel message - * buffer at the start of the LogLine function. - * - * Thu Jul 29 11:40:32 CDT 1993: Dr. Wettstein - * Added syscalls to turn off logging of kernel messages to the - * console when klogd becomes responsible for kernel messages. - * - * klogd now catches SIGTERM and SIGKILL signals. Receipt of these - * signals cases the clean_up function to be called which shuts down - * kernel logging and re-enables logging of messages to the console. - * - * Sat Dec 11 11:54:22 CST 1993: Dr. Wettstein - * Added fixes to allow compilation with no complaints with -Wall. - * - * When the daemon catches a fatal signal (SIGTERM, SIGKILL) a - * message is output to the logfile advising that the daemon is - * going to terminate. - * - * Thu Jan 6 11:54:10 CST 1994: Dr. Wettstein - * Major re-write/re-organization of the code. - * - * Klogd now assigns kernel messages to priority levels when output - * to the syslog facility is requested. The priority level is - * determined by decoding the prioritization sequence which is - * tagged onto the start of the kernel messages. - * - * Added the following program options: -f arg -c arg -s -o -d - * - * The -f switch can be used to specify that output should - * be written to the named file. - * - * The -c switch is used to specify the level of kernel - * messages which are to be directed to the console. - * - * The -s switch causes the program to use the syscall - * interface to the kernel message facility. This can be - * used to override the presence of the /proc filesystem. - * - * The -o switch causes the program to operate in 'one-shot' - * mode. A single call will be made to read the complete - * kernel buffer. The contents of the buffer will be - * output and the program will terminate. - * - * The -d switch causes 'debug' mode to be activated. This - * will cause the daemon to generate LOTS of output to stderr. - * - * The buffer decomposition function (LogLine) was re-written to - * squash a bug which was causing only partial kernel messages to - * be written to the syslog facility. - * - * The signal handling code was modified to properly differentiate - * between the STOP and TSTP signals. - * - * Added pid saving when the daemon detaches into the background. Thank - * you to Juha Virtanen (jiivee@hut.fi) for providing this patch. - * - * Mon Feb 6 07:31:29 CST 1995: Dr. Wettstein - * Significant re-organization of the signal handling code. The - * signal handlers now only set variables. Not earth shaking by any - * means but aesthetically pleasing to the code purists in the group. - * - * Patch to make things more compliant with the file system standards. - * Thanks to Chris Metcalf for prompting this helpful change. - * - * The routines responsible for reading the kernel log sources now - * initialize the buffers before reading. I think that this will - * solve problems with non-terminated kernel messages producing - * output of the form: new old old old - * - * This may also help influence the occassional reports of klogd - * failing under significant load. I think that the jury may still - * be out on this one though. My thanks to Joerg Ahrens for initially - * tipping me off to the source of this problem. Also thanks to - * Michael O'Reilly for tipping me off to the best fix for this problem. - * And last but not least Mark Lord for prompting me to try this as - * a means of attacking the stability problem. - * - * Specifying a - as the arguement to the -f switch will cause output - * to be directed to stdout rather than a filename of -. Thanks to - * Randy Appleton for a patch which prompted me to do this. - * - * Wed Feb 22 15:37:37 CST 1995: Dr. Wettstein - * Added version information to logging startup messages. - * - * Wed Jul 26 18:57:23 MET DST 1995: Martin Schulze - * Added an commandline argument "-n" to avoid forking. This obsoletes - * the compiler define NO_FORK. It's more useful to have this as an - * argument as there are many binary versions and one doesn't need to - * recompile the daemon. - * - * Thu Aug 10 19:01:08 MET DST 1995: Martin Schulze - * Added my pidfile.[ch] to it to perform a better handling with pidfiles. - * Now both, syslogd and klogd, can only be started once. They check the - * pidfile. - * - * Fri Nov 17 15:05:43 CST 1995: Dr. Wettstein - * Added support for kernel address translation. This required moving - * some definitions and includes to the new klogd.h file. Some small - * code cleanups and modifications. - * - * Mon Nov 20 10:03:39 MET 1995 - * Added -v option to print the version and exit. - * - * Thu Jan 18 11:19:46 CST 1996: Dr. Wettstein - * Added suggested patches from beta-testers. These address two - * two problems. The first is segmentation faults which occur with - * the ELF libraries. This was caused by passing a null pointer to - * the strcmp function. - * - * Added a second patch to remove the pidfile as part of the - * termination cleanup sequence. This minimizes the potential for - * conflicting pidfiles causing immediate termination at boot time. - * - * Wed Aug 21 09:13:03 CDT 1996: Dr. Wettstein - * Added ability to reload static symbols and kernel module symbols - * under control of SIGUSR1 and SIGUSR2 signals. - * - * Added -p switch to select 'paranoid' behavior with respect to the - * loading of kernel module symbols. - * - * Informative line now printed whenever a state change occurs due - * to signal reception by the daemon. - * - * Added the -i and -I command line switches to signal the currently - * executing daemon. - * - * Tue Nov 19 10:15:36 PST 1996: Leland Olds - * Corrected vulnerability to buffer overruns by rewriting LogLine - * routine. Obscenely long kernel messages will now be broken up - * into lines no longer than LOG_LINE_LENGTH. - * - * The last version of LogLine was vulnerable to buffer overruns: - * - Kernel messages longer than LOG_LINE_LENGTH caused a buffer - * overrun. - * - If a line was determined to be shorter than LOG_LINE_LENGTH, - * the routine "ExpandKadds" could cause the line grow by - * an unknown amount and overrun a buffer. - * I turned these routines into a little parsing state machine that - * should not have these problems. - * - * Sun Jun 15 16:23:29 MET DST 1997: Michael Alan Dorman - * Some more glibc patches made by . - * - * Thu Aug 21 12:11:27 MET DST 1997: Martin Schulze - * Fixed little mistake which prevented klogd from accepting a - * console log - * - * Fri Jan 9 00:39:52 CET 1998: Martin Schulze - * Changed the behaviour of klogd when receiving a terminate - * signal. Now the program terminates immediately instead of - * completing the receipt of a kernel message, i.e the read() - * call. The old behaveiour could result in klogd being - * recognized as being undead, because it'll only die after a - * message has been received. - * - * Fri Jan 9 11:03:48 CET 1998: Martin Schulze - * Corrected some code that caused klogd to dump core when - * receiving messages containing '%', some of them exist in - * 2.1.78. Thanks to Chu-yeon Park for - * informing me. - * - * Fri Jan 9 23:38:19 CET 1998: Florian La Roche - * Added -x switch to omit EIP translation and System.map evaluation. - * - * Sun Jan 25 20:47:46 CET 1998: Martin Schulze - * As the bug covering the %'s introduced a problem with - * unevaluated priorities I've worked out a real fix that strips - * %'s to an even number which is harmless for printf. - * - * Sat Oct 10 20:01:48 CEST 1998: Martin Schulze - * Added support for TESTING define which will turn klogd into - * stdio-mode used for debugging. - * - * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze - * Modified System.map read function to try all possible map - * files until a file with matching version is found. Added support for - * Debian release. - * - * Mon Oct 12 13:01:27 MET DST 1998: Martin Schulze - * Used unsigned long and strtoul() to resolve kernel oops symbols. - * - * Sun Jan 3 18:38:03 CET 1999: Martin Schulze - * Shortened LOG_LINE_LENGTH in order to get long lines splitted - * up earlier and syslogd has a better chance concatenating them - * together again. - * - * Sat Aug 21 12:27:02 CEST 1999: Martin Schulze - * Skip newline when reading in messages. - * - * Tue Sep 12 22:14:33 CEST 2000: Martin Schulze - * Don't feed a buffer directly to a printf-type routine, use - * "%s" as format string instead. Thanks to Jouko Pynnönen - * for pointing this out. - * - * Tue Sep 12 22:44:57 CEST 2000: Martin Schulze - * Commandline option `-2': When symbols are expanded, print the - * line twice. Once with addresses converted to symbols, once with the - * raw text. Allows external programs such as ksymoops do their own - * processing on the original data. Thanks to Keith Owens - * for the patch. - * - * Mon Sep 18 09:32:27 CEST 2000: Martin Schulze - * Added patch to fix priority decoding after moving kernel - * messgages into "%s". Thanks to Solar Designer - * for the patch. - * - * Sun Mar 11 20:23:44 CET 2001: Martin Schulze - * Stop LogLine() from being called with wrong argument when a - * former calculation failed already. Thanks to Thomas Roessler - * for providing a patch. - * - * Ignore zero bytes, no busy loop is entered anymore. Several - * people have submitted patches: Troels Walsted Hansen - * , Wolfgang Oertl - * and Thomas Roessler. - */ - - -/* Includes. */ -#include -#include -#include -#include -#include -#if !defined(__GLIBC__) -#include -#endif /* __GLIBC__ */ -#include -#include -#include -#include "klogd.h" -#include "ksyms.h" -#ifndef TESTING -#include "pidfile.h" -#endif - -#define __LIBRARY__ -#include -#if !defined(__GLIBC__) -# define __NR_ksyslog __NR_syslog -_syscall3(int,ksyslog,int, type, char *, buf, int, len); -#else -#include -#define ksyslog klogctl -#endif -extern int writeSyslogV(int pri, const char *szFmt, va_list va); -extern int writeSyslog(int iPri, const char *szFmt, ...); - -#ifndef _PATH_KLOG -#define _PATH_KLOG "/proc/kmsg" -#endif - -#define LOG_BUFFER_SIZE 4096 -#define LOG_LINE_LENGTH 1000 - -#ifndef TESTING -#if defined(FSSTND) -static char *PidFile = _PATH_VARRUN "rklogd.pid"; -#else -static char *PidFile = "/etc/rklogd.pid"; -#endif -#endif - -static int kmsg, - change_state = 0, - terminate = 0, - caught_TSTP = 0, - reload_symbols = 0, - console_log_level = -1; - -static int use_syscall = 0, - one_shot = 0, - symbol_lookup = 1, - no_fork = 0; /* don't fork - don't run in daemon mode */ - -static char *symfile = (char *) 0, - log_buffer[LOG_BUFFER_SIZE]; - -static FILE *output_file = (FILE *) 0; - -static enum LOGSRC {none, proc, kernel} logsrc; - -int debugging = 0; -int symbols_twice = 0; - - -/* Function prototypes. */ -extern int ksyslog(int type, char *buf, int len); -static void CloseLogSrc(void); -extern void restart(int sig); -extern void stop_logging(int sig); -extern void stop_daemon(int sig); -extern void reload_daemon(int sig); -static void Terminate(void); -static void SignalDaemon(int); -static void ReloadSymbols(void); -static void ChangeLogging(void); -static enum LOGSRC GetKernelLogSrc(void); -static void LogLine(char *ptr, int len); -static void LogKernelLine(void); -static void LogProcLine(void); -extern int main(int argc, char *argv[]); - - -extern void Syslog(int priority, char *fmt, ...) __attribute__((format(printf,2, 3))); -extern void Syslog(int priority, char *fmt, ...) -{ - va_list ap; - char *argl; - - if(debugging) - { - fputs("Logging line:\n", stderr); - fprintf(stderr, "\tLine: %s\n", fmt); - fprintf(stderr, "\tPriority: %d\n", priority); - } - - /* Handle output to a file. */ - if ( output_file != (FILE *) 0 ) { - va_start(ap, fmt); - vfprintf(output_file, fmt, ap); - va_end(ap); - fputc('\n', output_file); - fflush(output_file); - if (!one_shot) - fsync(fileno(output_file)); - return; - } - - /* Output using syslog. */ - if (!strcmp(fmt, "%s")) { - va_start(ap, fmt); - argl = va_arg(ap, char *); - if (argl[0] == '<' && argl[1] && argl[2] == '>') { - switch ( argl[1] ) - { - case '0': - priority = LOG_EMERG; - break; - case '1': - priority = LOG_ALERT; - break; - case '2': - priority = LOG_CRIT; - break; - case '3': - priority = LOG_ERR; - break; - case '4': - priority = LOG_WARNING; - break; - case '5': - priority = LOG_NOTICE; - break; - case '6': - priority = LOG_INFO; - break; - case '7': - default: - priority = LOG_DEBUG; - } - argl += 3; - } - writeSyslog(priority, fmt, argl); - va_end(ap); -#ifdef TESTING - putchar('\n'); -#endif - return; - } - - va_start(ap, fmt); - writeSyslogV(priority, fmt, ap); - va_end(ap); -#ifdef TESTING - printf ("\n"); -#endif - - return; -} - - -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); - Syslog(LOG_INFO, "Kernel logging (ksyslog) stopped."); - break; - case proc: - close(kmsg); - Syslog(LOG_INFO, "Kernel logging (proc) stopped."); - break; - case none: - break; - } - - if ( output_file != (FILE *) 0 ) - fflush(output_file); - return; -} - - -void restart(int __attribute__((unused)) sig) -{ - change_state = 1; - caught_TSTP = 0; - return; -} - - -void stop_logging(int __attribute__((unused)) sig) -{ - change_state = 1; - caught_TSTP = 1; - return; -} - - -void stop_daemon(int __attribute__((unused)) sig) -{ - change_state = 1; - terminate = 1; - return; -} - - -void reload_daemon(int sig) -{ - change_state = 1; - reload_symbols = 1; - - if ( sig == SIGUSR2 ) - { - ++reload_symbols; - } - - return; -} - - -static void Terminate(void) -{ - CloseLogSrc(); - Syslog(LOG_INFO, "Kernel log daemon terminating."); - sleep(1); - if ( output_file != (FILE *) 0 ) - fclose(output_file); - closelog(); -#ifndef TESTING - (void) remove_pid(PidFile); -#endif - exit(1); -} - -static void SignalDaemon(int sig) -{ -#ifndef TESTING - auto int pid = check_pid(PidFile); - - kill(pid, sig); -#else - kill(getpid(), sig); -#endif - return; -} - - -static void ReloadSymbols(void) -{ - if (symbol_lookup) { - if ( reload_symbols > 1 ) - InitKsyms(symfile); - InitMsyms(); - } - reload_symbols = change_state = 0; - return; -} - - -static void ChangeLogging(void) -{ - /* Terminate kernel logging. */ - if ( terminate == 1 ) - Terminate(); - - /* Indicate that something is happening. */ - Syslog(LOG_INFO, "rklogd %s, ---------- state change ----------\n", \ - VERSION); - - /* Reload symbols. */ - if ( reload_symbols > 0 ) - { - ReloadSymbols(); - return; - } - - /* Stop kernel logging. */ - if ( caught_TSTP == 1 ) - { - CloseLogSrc(); - logsrc = none; - change_state = 0; - return; - } - - /* - * The rest of this function is responsible for restarting - * kernel logging after it was stopped. - * - * In the following section we make a decision based on the - * kernel log state as to what is causing us to restart. Somewhat - * groady but it keeps us from creating another static variable. - */ - if ( logsrc != none ) - { - Syslog(LOG_INFO, "Kernel logging re-started after SIGSTOP."); - change_state = 0; - return; - } - - /* Restart logging. */ - logsrc = GetKernelLogSrc(); - change_state = 0; - 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. - */ - Syslog(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); -#ifdef DEBRELEASE - Syslog(LOG_INFO, "rklogd %s#%s, log source = ksyslog " - "started.", VERSION, DEBRELEASE); -#else - Syslog(LOG_INFO, "rklogd %s, log source = ksyslog " - "started.", VERSION); -#endif - return(kernel); - } - -#ifndef TESTING - if ( (kmsg = open(_PATH_KLOG, O_RDONLY)) < 0 ) - { - fprintf(stderr, "rklogd: Cannot open proc file system, " \ - "%d - %s.\n", errno, strerror(errno)); - ksyslog(7, NULL, 0); - exit(1); - } -#else - kmsg = fileno(stdin); -#endif - -#ifdef DEBRELEASE - Syslog(LOG_INFO, "rklogd %ss#%s, log source = %s started.", \ - VERSION, DEBRELEASE, _PATH_KLOG); -#else - Syslog(LOG_INFO, "rklogd %s, log source = %s started.", \ - VERSION, _PATH_KLOG); -#endif - 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( char *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]", - * 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 char line_buff[LOG_LINE_LENGTH]; - - static char *line =line_buff; - static enum parse_state_enum parse_state = PARSING_TEXT; - static int space = sizeof(line_buff)-1; - - static char *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 */ - - if ( debugging ) - { - fputs("Line buffer full:\n", stderr); - fprintf(stderr, "\tLine: %s\n", line); - } - - Syslog( LOG_INFO, "%s", 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, "%s", 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(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; - } - - delta = sprintf( 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 ) - { - if ( errno == EINTR ) - return; - fprintf(stderr, "rklogd: Error return from sys_sycall: " \ - "%d - %s\n", errno, strerror(errno)); - } - 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; - Syslog(LOG_ERR, "Cannot read proc file system: %d - %s.", \ - errno, strerror(errno)); - } - else - LogLine(log_buffer, rdcnt); - - return; -} - - -/* helper routine to spit out an error message and terminate - * klogd when setting a signal error fails. - */ -void sigactionErrAbort() -{ - fprintf(stderr, "rklogd: could net set a signal handler - terminating. Error: %s\n", - strerror(errno)); - exit(1); -} - - -int main(int argc, char *argv[]) -{ - int ch, - use_output = 0; - - char *log_level = (char *) 0, - *output = (char *) 0; - struct sigaction sigAct; - -#ifndef TESTING - chdir ("/"); -#endif - /* Parse the command-line. */ - while ((ch = getopt(argc, argv, "c:df:iIk:nopsvx2")) != EOF) - switch((char)ch) - { - case '2': /* Print lines with symbols twice. */ - symbols_twice = 1; - break; - case 'c': /* Set console message level. */ - log_level = optarg; - break; - case 'd': /* Activity debug mode. */ - debugging = 1; - break; - case 'f': /* Define an output file. */ - output = optarg; - use_output++; - break; - case 'i': /* Reload module symbols. */ - SignalDaemon(SIGUSR1); - return(0); - case 'I': - SignalDaemon(SIGUSR2); - return(0); - case 'k': /* Kernel symbol file. */ - symfile = optarg; - break; - case 'n': /* don't fork */ - no_fork++; - break; - case 'o': /* One-shot mode. */ - one_shot = 1; - break; - case 'p': - SetParanoiaLevel(1); /* Load symbols on oops. */ - break; - case 's': /* Use syscall interface. */ - use_syscall = 1; - break; - case 'v': - printf("rklogd %s\n", VERSION); - exit (1); - case 'x': - symbol_lookup = 0; - break; - } - - - /* Set console logging level. */ - if ( log_level != (char *) 0 ) - { - if ( (strlen(log_level) > 1) || \ - (strchr("12345678", *log_level) == (char *) 0) ) - { - fprintf(stderr, "rklogd: Invalid console logging " - "level <%s> specified.\n", log_level); - return(1); - } - console_log_level = *log_level - '0'; - } - - -#ifndef TESTING - /* - * The following code allows klogd to auto-background itself. - * What happens is that the program forks and the parent quits. - * The child closes all its open file descriptors, and issues a - * call to setsid to establish itself as an independent session - * immune from control signals. - * - * fork() is only called if it should run in daemon mode, fork is - * not disabled with the command line argument and there's no - * such process running. - */ - if ( (!one_shot) && (!no_fork) ) - { - if (!check_pid(PidFile)) - { - if ( fork() == 0 ) - { - auto int fl; - int num_fds = getdtablesize(); - - /* This is the child closing its file descriptors. */ - for (fl= 0; fl <= num_fds; ++fl) - { - if ( fileno(stdout) == fl && use_output ) - if ( strcmp(output, "-") == 0 ) - continue; - close(fl); - } - - setsid(); - } - else - exit(0); - } - else - { - fputs("rklogd: Already running.\n", stderr); - exit(1); - } - } - - - /* tuck my process id away */ - if (!check_pid(PidFile)) - { - if (!write_pid(PidFile)) - Terminate(); - } - else - { - fputs("rklogd: Already running.\n", stderr); - Terminate(); - } -#endif - - /* Signal setups. - * Please note that the "original" klogd in sysklogd tries to - * handle SIGKILL and SIGSTOP. That does not work - but as the - * original klogd had no error checking, nobody ever noticed. We - * do now have error checking and consequently those ever-failing - * calls are now removed. - */ - sigemptyset(&sigAct.sa_mask); - sigAct.sa_flags = 0; - - /* first, set all signals to ignore - * In this loop, we try blindly to ignore all signals. I am leaving - * intentionally out all error checking. If we can ignore the signal, - * that's nice, but if we can't ... well, so be it ;) - * RGerhards, 2007-06-15 - */ - sigAct.sa_handler = SIG_IGN; - for (ch= 1; ch < NSIG ; ++ch) - { - if(ch != SIGKILL && ch != SIGSTOP) - sigaction(ch, &sigAct, NULL); - } - - /* Now specific handlers (one after another) */ - sigAct.sa_handler = stop_daemon; - if(sigaction(SIGINT, &sigAct, NULL) != 0) sigactionErrAbort(); - if(sigaction(SIGTERM, &sigAct, NULL) != 0) sigactionErrAbort(); - if(sigaction(SIGHUP, &sigAct, NULL) != 0) sigactionErrAbort(); - - sigAct.sa_handler = stop_daemon; - if(sigaction(SIGTSTP, &sigAct, NULL) != 0) sigactionErrAbort(); - - sigAct.sa_handler = restart; - if(sigaction(SIGCONT, &sigAct, NULL) != 0) sigactionErrAbort(); - - sigAct.sa_handler = reload_daemon; - if(sigaction(SIGUSR1, &sigAct, NULL) != 0) sigactionErrAbort(); - if(sigaction(SIGUSR2, &sigAct, NULL) != 0) sigactionErrAbort(); - - - /* Open outputs. */ - if ( use_output ) - { - if ( strcmp(output, "-") == 0 ) - output_file = stdout; - else if ( (output_file = fopen(output, "w")) == (FILE *) 0 ) - { - fprintf(stderr, "rklogd: Cannot open output file " \ - "%s - %s\n", output, strerror(errno)); - return(1); - } - } - - /* Handle one-shot logging. */ - if ( one_shot ) - { - if (symbol_lookup) { - symbol_lookup = (InitKsyms(symfile) == 1); - symbol_lookup |= InitMsyms(); - if (symbol_lookup == 0) { - Syslog(LOG_WARNING, "cannot find any symbols, turning off symbol lookups\n"); - } - } - if ( (logsrc = GetKernelLogSrc()) == kernel ) - LogKernelLine(); - else - LogProcLine(); - Terminate(); - } - - /* Determine where kernel logging information is to come from. */ -#if defined(KLOGD_DELAY) - sleep(KLOGD_DELAY); -#endif - logsrc = GetKernelLogSrc(); - if (symbol_lookup) { - symbol_lookup = (InitKsyms(symfile) == 1); - symbol_lookup |= InitMsyms(); - if (symbol_lookup == 0) { - Syslog(LOG_WARNING, "cannot find any symbols, turning off symbol lookups\n"); - } - } - - /* The main loop. */ - /* The main loop will be broken by a signal handler which set the - * terminate variable. That is then cheked in ChangeLogging(), which - * will then terminate klogd. - * RGerhards, 2007-06-15 - */ - while(1) - { - if ( change_state ) - ChangeLogging(); - switch ( logsrc ) - { - case kernel: - LogKernelLine(); - break; - case proc: - LogProcLine(); - break; - case none: - pause(); - break; - } - } -} -#else /* #ifdef FEATURE_KLOGD */ -#include -int main() -{ - fprintf(stderr, "FEATURE_KLOGD was disabled during make, so rklogd is not available.\n"); - return(1); -} -#endif /* #ifdef WITH_KLOGD */ -/* - * Local variables: - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - * vi:set ai: - */ diff --git a/klogd.h b/klogd.h deleted file mode 100644 index b9261caf..00000000 --- a/klogd.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - klogd.h - main header file for Linux kernel log daemon. - Copyright (c) 1995 Dr. G.W. Wettstein - - * 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. -*/ - -/* - * Symbols and definitions needed by klogd. - * - * Thu Nov 16 12:45:06 CST 1995: Dr. Wettstein - * Initial version. - */ - -/* Useful include files. */ -#include -#include -#include -#include -#undef syslog -#undef vsyslog - -/* Function prototypes. */ -extern int InitKsyms(char *); -extern int InitMsyms(void); -extern char * ExpandKadds(char *, char *); -extern void SetParanoiaLevel(int); -extern void Syslog(int priority, char *fmt, ...); -extern void vsyslog(int pri, const char *fmt, va_list ap); -extern void openlog(const char *ident, int logstat, int logfac); diff --git a/ksym.c b/ksym.c deleted file mode 100644 index baee2c05..00000000 --- a/ksym.c +++ /dev/null @@ -1,986 +0,0 @@ -#include "config.h" - -#ifdef FEATURE_KLOGD -/* - ksym.c - functions for kernel address->symbol translation - Copyright (c) 1995, 1996 Dr. G.W. Wettstein - Copyright (c) 1996 Enjellic Systems Development - - * 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. -*/ - -/* - * 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 - * 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 - * Switched to fgets() as gets() is not buffer overrun secure. - * - * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze - * 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 - * 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 - * Fixed bug that caused klogd to die if there is no sym_array available. - * - * Tue Sep 12 23:48:12 CEST 2000: Martin Schulze - * Close symbol file in InitKsyms() when an error occurred. - */ - - -/* Includes. */ -#include -#include -#include -#include "klogd.h" -#include "ksyms.h" - -#define VERBOSE_DEBUGGING 0 - - -/* Variables static to this module. */ -struct sym_table -{ - unsigned long value; - char *name; -}; - -static 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", -#if defined(TEST) - "./System.map", -#endif - (char *) 0 -}; - - -#if defined(TEST) -int debugging; -#else -extern int debugging; -#endif - - -/* 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(mapfile) - - char *mapfile; - -{ - auto char type, - sym[512]; - - auto int version = 0; - - auto unsigned long int address; - - auto FILE *sym_file; - - - /* 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 != (char *) 0 ) - { - if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 ) - { - Syslog(LOG_WARNING, "Cannot open map file: %s.", \ - mapfile); - return(0); - } - } - else - { - if ( (mapfile = FindSymbolFile()) == (char *) 0 ) - { - Syslog(LOG_WARNING, "Cannot find map file."); - if ( debugging ) - fputs("Cannot find map file.\n", stderr); - return(0); - } - - if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 ) - { - Syslog(LOG_WARNING, "Cannot open map file."); - if ( debugging ) - fputs("Cannot open map file.\n", stderr); - 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 ) - { - Syslog(LOG_ERR, "Error in symbol table input (#1)."); - fclose(sym_file); - return(0); - } - if ( VERBOSE_DEBUGGING && debugging ) - fprintf(stderr, "Address: %lx, Type: %c, Symbol: %s\n", - address, type, sym); - - if ( AddSymbol(address, sym) == 0 ) - { - Syslog(LOG_ERR, "Error adding symbol - %s.", sym); - fclose(sym_file); - return(0); - } - - if ( version == 0 ) - version = CheckVersion(sym); - } - - - Syslog(LOG_INFO, "Loaded %d symbols from %s.", num_syms, mapfile); - switch ( version ) - { - case -1: - Syslog(LOG_WARNING, "Symbols do not match kernel version."); - num_syms = 0; - break; - - case 0: - Syslog(LOG_WARNING, "Cannot verify that symbols match " \ - "kernel version."); - break; - - case 1: - Syslog(LOG_INFO, "Symbols match kernel version %s.", vstring); - break; - } - - fclose(sym_file); - return(1); -} - - -/************************************************************************** - * 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() - -{ - auto char *file = (char *) 0, - **mf = system_maps; - - auto struct utsname utsname; - static char symfile[100]; - - auto FILE *sym_file = (FILE *) 0; - - if ( uname(&utsname) < 0 ) - { - Syslog(LOG_ERR, "Cannot get kernel version information."); - return(0); - } - - if ( debugging ) - fputs("Searching for symbol map.\n", stderr); - - for (mf = system_maps; *mf != (char *) 0 && file == (char *) 0; ++mf) - { - - sprintf (symfile, "%s-%s", *mf, utsname.release); - if ( debugging ) - fprintf(stderr, "Trying %s.\n", symfile); - if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) { - if (CheckMapVersion(symfile) == 1) - file = symfile; - fclose(sym_file); - } - if (sym_file == (FILE *) 0 || file == (char *) 0) { - sprintf (symfile, "%s", *mf); - if ( debugging ) - fprintf(stderr, "Trying %s.\n", symfile); - if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) { - if (CheckMapVersion(symfile) == 1) - file = symfile; - fclose(sym_file); - } - } - - } - - /* - * At this stage of the game we are at the end of the symbol - * tables. - */ - if ( debugging ) - fprintf(stderr, "End of search list encountered.\n"); - 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(version) - - char *version; - - -{ - auto int vnum, - major, - minor, - patch; - -#ifndef TESTING - int kvnum; - auto struct utsname utsname; -#endif - - 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; - if ( debugging ) - fprintf(stderr, "Version string = %s, Major = %d, " \ - "Minor = %d, Patch = %d.\n", version + - strlen(prefix), major, minor, \ - patch); - sprintf(vstring, "%d.%d.%d", major, minor, patch); - -#ifndef TESTING - /* - * 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 ) - { - Syslog(LOG_ERR, "Cannot get kernel version information."); - return(0); - } - if ( debugging ) - fprintf(stderr, "Comparing kernel %s with symbol table %s.\n",\ - utsname.release, vstring); - - if ( sscanf (utsname.release, "%d.%d.%d", &major, &minor, &patch) < 3 ) - { - Syslog(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. */ -#endif - 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(fname) - - char *fname; - - -{ - int version; - FILE *sym_file; - auto unsigned long int address; - auto char type, - sym[512]; - - if ( (sym_file = fopen(fname, "r")) != (FILE *) 0 ) { - /* - * At this point a map file was successfully opened. We - * now need to search this file and look for version - * information. - */ - Syslog(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 ) - { - Syslog(LOG_ERR, "Error in symbol table input (#2)."); - fclose(sym_file); - return(0); - } - if ( VERBOSE_DEBUGGING && debugging ) - fprintf(stderr, "Address: %lx, Type: %c, " \ - "Symbol: %s\n", address, type, sym); - - version = CheckVersion(sym); - } - fclose(sym_file); - - switch ( version ) - { - case -1: - Syslog(LOG_ERR, "Symbol table has incorrect " \ - "version number.\n"); - break; - - case 0: - if ( debugging ) - fprintf(stderr, "No version information " \ - "found.\n"); - break; - case 1: - if ( debugging ) - fprintf(stderr, "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(address, symbol) - - 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 == (char *) 0 ) - 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(value, sym) - - unsigned long value; - - struct symbol *sym; - -{ - auto int lp; - - auto char *last; - - if (!sym_array) - return((char *) 0); - - last = sym_array[0].name; - sym->offset = 0; - sym->size = 0; - if ( value < sym_array[0].value ) - return((char *) 0); - - for(lp= 0; lp <= num_syms; ++lp) - { - if ( sym_array[lp].value > value ) - { - sym->offset = value - sym_array[lp-1].value; - sym->size = sym_array[lp].value - \ - sym_array[lp-1].value; - return(last); - } - last = sym_array[lp].name; - } - - if ( (last = LookupModuleSymbol(value, sym)) != (char *) 0 ) - return(last); - - return((char *) 0); -} - - -/************************************************************************** - * 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() - -{ - 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(line, el) - - 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; - - - /* - * 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:") != (char *) 0) && !InitMsyms() ) - Syslog(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, "[<")) == (char *) 0 ) - { -#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, ">]")) == (char *) 0 ) - { - 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)) == (char *) 0 ) - symbol = sl; - - strcat(elp, symbol); - elp += strlen(symbol); - if ( debugging ) - fprintf(stderr, "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, "+%x/%d", sym.offset, sym.size); - } - strncat(elp, kp, value); - elp += value; - sl = kp + value; - if ( (kp = strstr(sl, "[<")) == (char *) 0 ) - strcat(elp, sl); - } - while ( kp != (char *) 0); - - if ( debugging ) - fprintf(stderr, "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(level) - - int level; - -{ - i_am_paranoid = level; - return; -} - - -/* - * Setting the -DTEST define enables the following code fragment to - * be compiled. This produces a small standalone program which will - * echo the standard input of the process to stdout while translating - * all numeric kernel addresses into their symbolic equivalent. - */ -#if defined(TEST) - -#include - -extern int main(int, char **); - - -extern int main(int argc, char *argv[]) -{ - auto char line[1024], eline[2048]; - - debugging = 1; - - - if ( !InitKsyms((char *) 0) ) - { - fputs("ksym: Error loading system map.\n", stderr); - return(1); - } - - while ( !feof(stdin) ) - { - fgets(line, sizeof(line), stdin); - if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0'; /* Trash NL char */ - memset(eline, '\0', sizeof(eline)); - ExpandKadds(line, eline); - fprintf(stdout, "%s\n", eline); - } - - - return(0); -} - -extern void Syslog(int priority, char *fmt, ...) - -{ - va_list ap; - - va_start(ap, fmt); - fprintf(stdout, "Pr: %d, ", priority); - vfprintf(stdout, fmt, ap); - va_end(ap); - fputc('\n', stdout); - - return; -} -#endif -#endif /* #ifdef FEATURE_KLOGD */ diff --git a/ksym_mod.c b/ksym_mod.c deleted file mode 100644 index 51ca2fb8..00000000 --- a/ksym_mod.c +++ /dev/null @@ -1,704 +0,0 @@ -#include "config.h" - -#ifdef FEATURE_KLOGD -/* - ksym_mod.c - functions for building symbol lookup tables for klogd - Copyright (c) 1995, 1996 Dr. G.W. Wettstein - Copyright (c) 1996 Enjellic Systems Development - - * 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. -*/ - -/* - * 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 . - * - * Sat Jan 10 15:00:18 CET 1998: Martin Schulze - * 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 . - * - * Sun Jan 25 20:57:34 CET 1998: Martin Schulze - * Another patch for Linux/alpha by Christopher C Chimelis - * . - * - * Thu Mar 19 23:39:29 CET 1998: Manuel Rodrigues - * 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 - * Removed as it's no longer part of recent glibc - * versions. Added prototyp for llseek() which has been - * forgotton in from glibc. Added more log - * information if problems occurred while reading a system map - * file, by submission from Mark Simon Phillips . - * - * Sun Jan 3 18:38:03 CET 1999: Martin Schulze - * 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 . - * - * Tue Sep 12 23:11:13 CEST 2000: Martin Schulze - * Changed llseek() to lseek64() in order to skip a libc warning. - */ - - -/* Includes. */ -#include -#include -#include -#include -#include -#include -#if !defined(__GLIBC__) -#include -#include -#else /* __GLIBC__ */ -#include "module.h" -extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence)); -extern int get_kernel_syms __P ((struct kernel_sym *__table)); -#endif /* __GLIBC__ */ -#include -#include -#include - -#include "klogd.h" -#include "ksyms.h" - - -#if !defined(__GLIBC__) -/* - * The following bit uses some kernel/library magic to product what - * looks like a function call to user level code. This function is - * actually a system call in disguise. The purpose of the getsyms - * call is to return a current copy of the in-kernel symbol table. - */ -#define __LIBRARY__ -#include -#define __NR_getsyms __NR_get_kernel_syms -_syscall1(int, getsyms, struct kernel_sym *, syms); -#undef __LIBRARY__ -extern int getsyms(struct kernel_sym *); -#else /* __GLIBC__ */ -#define getsyms get_kernel_syms -#endif /* __GLIBC__ */ - -/* Variables static to this module. */ -struct sym_table -{ - unsigned long value; - char *name; -}; - -struct Module -{ - struct sym_table *sym_array; - int num_syms; - - char *name; - struct module module; -#if LINUX_VERSION_CODE >= 0x20112 - struct module_info module_info; -#endif -}; - -static int num_modules = 0; -struct Module *sym_array_modules = (struct Module *) 0; - -static int have_modules = 0; - -#if defined(TEST) -static int debugging = 1; -#else -extern int debugging; -#endif - - -/* Function prototypes. */ -static void FreeModules(void); -static int AddSymbol(struct Module *mp, unsigned long, char *); -static int AddModule(unsigned long, char *); -static int symsort(const void *, const void *); - - -/************************************************************************** - * 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() - -{ - auto int rtn, - tmp; - - auto struct kernel_sym *ksym_table, - *p; - - - /* Initialize the kernel module symbol table. */ - FreeModules(); - - - /* - * The system call which returns the kernel symbol table has - * essentialy two modes of operation. Called with a null pointer - * the system call returns the number of symbols defined in the - * the table. - * - * The second mode of operation is to pass a valid pointer to - * the call which will then load the current symbol table into - * the memory provided. - * - * Returning the symbol table is essentially an all or nothing - * proposition so we need to pre-allocate enough memory for the - * complete table regardless of how many symbols we need. - * - * Bummer. - */ - if ( (rtn = getsyms((struct kernel_sym *) 0)) < 0 ) - { - if ( errno == ENOSYS ) - Syslog(LOG_INFO, "No module symbols loaded - " - "kernel modules not enabled.\n"); - else - Syslog(LOG_ERR, "Error loading kernel symbols " \ - "- %s\n", strerror(errno)); - return(0); - } - if ( debugging ) - fprintf(stderr, "Loading kernel module symbols - " - "Size of table: %d\n", rtn); - - ksym_table = (struct kernel_sym *) malloc(rtn * \ - sizeof(struct kernel_sym)); - if ( ksym_table == (struct kernel_sym *) 0 ) - { - Syslog(LOG_WARNING, " Failed memory allocation for kernel " \ - "symbol table.\n"); - return(0); - } - if ( (rtn = getsyms(ksym_table)) < 0 ) - { - Syslog(LOG_WARNING, "Error reading kernel symbols - %s\n", \ - strerror(errno)); - return(0); - } - - - /* - * Build a symbol table compatible with the other one used by - * klogd. - */ - tmp = rtn; - p = ksym_table; - while ( tmp-- ) - { - if ( !AddModule(p->value, p->name) ) - { - Syslog(LOG_WARNING, "Error adding kernel module table " - "entry.\n"); - free(ksym_table); - return(0); - } - ++p; - } - - /* 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 ) - Syslog(LOG_INFO, "No module symbols loaded."); - else - Syslog(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \ - (rtn == 1) ? "symbol" : "symbols", \ - num_modules, (num_modules == 1) ? "." : "s."); - free(ksym_table); - return(1); -} - - -static int symsort(p1, p2) - - 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); -} - - -/************************************************************************** - * 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; - - - 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); - } - - 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. - * - * Arguements: (unsigned long) address, (char *) symbol - * - * address:-> The address of the module. - * - * symbol:-> The name of the module. - * - * Return: int - **************************************************************************/ - -static int AddModule(address, symbol) - - unsigned long address; - - char *symbol; - -{ - auto int memfd; - - auto struct Module *mp; - - - /* Return if we have loaded the modules. */ - if ( have_modules ) - return(1); - - /* - * The following section of code is responsible for determining - * whether or not we are done reading the list of modules. - */ - if ( symbol[0] == '#' ) - { - - if ( symbol[1] == '\0' ) - { - /* - * A symbol which consists of a # sign only - * signifies a a resident kernel segment. When we - * hit one of these we are done reading the - * module list. - */ - have_modules = 1; - return(1); - } - /* Allocate space for the module. */ - sym_array_modules = (struct Module *) \ - realloc(sym_array_modules, \ - (num_modules+1) * sizeof(struct Module)); - if ( sym_array_modules == (struct Module *) 0 ) - { - Syslog(LOG_WARNING, "Cannot allocate Module array.\n"); - return(0); - } - mp = &sym_array_modules[num_modules]; - - if ( (memfd = open("/dev/kmem", O_RDONLY)) < 0 ) - { - Syslog(LOG_WARNING, "Error opening /dev/kmem\n"); - return(0); - } - if ( lseek64(memfd, address, SEEK_SET) < 0 ) - { - Syslog(LOG_WARNING, "Error seeking in /dev/kmem\n"); - Syslog(LOG_WARNING, "Symbol %s, value %08x\n", symbol, address); - return(0); - } - if ( read(memfd, \ - (char *)&sym_array_modules[num_modules].module, \ - sizeof(struct module)) < 0 ) - { - Syslog(LOG_WARNING, "Error reading module " - "descriptor.\n"); - return(0); - } - close(memfd); - - /* Save the module name. */ - mp->name = (char *) malloc(strlen(&symbol[1]) + 1); - if ( mp->name == (char *) 0 ) - return(0); - strcpy(mp->name, &symbol[1]); - - mp->num_syms = 0; - mp->sym_array = (struct sym_table *) 0; - ++num_modules; - return(1); - } - else - { - if (num_modules > 0) - mp = &sym_array_modules[num_modules - 1]; - else - mp = &sym_array_modules[0]; - AddSymbol(mp, address, symbol); - } - - - return(1); -} - - -/************************************************************************** - * Function: AddSymbol - * - * Purpose: This function is responsible for adding a symbol name - * and its address to the symbol table. - * - * Arguements: (struct Module *) mp, (unsigned long) address, (char *) symbol - * - * mp:-> A pointer to the module which the symbol is - * to be added to. - * - * address:-> The address of the symbol. - * - * symbol:-> The name of the symbol. - * - * Return: int - * - * A boolean value is assumed. True if the addition is - * successful. False if not. - **************************************************************************/ - -static int AddSymbol(mp, address, symbol) - - struct Module *mp; - - unsigned long address; - - char *symbol; - -{ - auto int tmp; - - - /* 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); - - /* Then the space for the symbol. */ - tmp = strlen(symbol); - tmp += (strlen(mp->name) + 1); - mp->sym_array[mp->num_syms].name = (char *) malloc(tmp + 1); - if ( mp->sym_array[mp->num_syms].name == (char *) 0 ) - return(0); - memset(mp->sym_array[mp->num_syms].name, '\0', tmp + 1); - - /* Stuff interesting information into the module. */ - mp->sym_array[mp->num_syms].value = address; - strcpy(mp->sym_array[mp->num_syms].name, mp->name); - strcat(mp->sym_array[mp->num_syms].name, ":"); - strcat(mp->sym_array[mp->num_syms].name, symbol); - ++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; - - - 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 ) - { - sym->offset = value - last->value; - sym->size = mp->sym_array[nsym].value - \ - last->value; - return(last->name); - } - last = &mp->sym_array[nsym]; - } - - - /* - * At this stage of the game we still cannot give up the - * ghost. There is the possibility that the address is - * from a module which has no symbols registered with - * the kernel. The solution is to compare the address - * against the starting address and extant of the module - * If it is in this range we can at least return the - * name of the module. - */ -#if LINUX_VERSION_CODE < 0x20112 - if ( (void *) value >= mp->module.addr && - (void *) value <= (mp->module.addr + \ - mp->module.size * 4096) ) -#else - if ( value >= mp->module_info.addr && - value <= (mp->module_info.addr + \ - mp->module.size * 4096) ) -#endif - { - /* - * A special case needs to be checked for. The above - * conditional tells us that we are within the - * extant of this module but symbol lookup has - * failed. - * - * We need to check to see if any symbols have - * been defined in this module. If there have been - * symbols defined the assumption must be made that - * the faulting address lies somewhere beyond the - * last symbol. About the only thing we can do - * at this point is use an offset from this - * symbol. - */ - if ( mp->num_syms > 0 ) - { - last = &mp->sym_array[mp->num_syms - 1]; -#if LINUX_VERSION_CODE < 0x20112 - sym->size = (int) mp->module.addr + \ - (mp->module.size * 4096) - value; -#else - sym->size = (int) mp->module_info.addr + \ - (mp->module.size * 4096) - value; -#endif - sym->offset = value - last->value; - return(last->name); - } - - /* - * There were no symbols defined for this module. - * Return the module name and the offset of the - * faulting address in the module. - */ - sym->size = mp->module.size * 4096; -#if LINUX_VERSION_CODE < 0x20112 - sym->offset = (void *) value - mp->module.addr; -#else - sym->offset = value - mp->module_info.addr; -#endif - return(mp->name); - } - } - - /* It has been a hopeless exercise. */ - return((char *) 0); -} - - -/* - * Setting the -DTEST define enables the following code fragment to - * be compiled. This produces a small standalone program which will - * dump the current kernel symbol table. - */ -#if defined(TEST) - -#include - - -extern int main(int, char **); - - -int main(argc, argv) - - int argc; - - char *argv[]; - -{ - auto int lp, syms; - - - if ( !InitMsyms() ) - { - fprintf(stderr, "Cannot load module symbols.\n"); - return(1); - } - - printf("Number of modules: %d\n\n", num_modules); - - for(lp= 0; lp < num_modules; ++lp) - { - printf("Module #%d = %s, Number of symbols = %d\n", lp + 1, \ - sym_array_modules[lp].name, \ - sym_array_modules[lp].num_syms); - - for (syms= 0; syms < sym_array_modules[lp].num_syms; ++syms) - { - printf("\tSymbol #%d\n", syms + 1); - printf("\tName: %s\n", \ - sym_array_modules[lp].sym_array[syms].name); - printf("\tAddress: %lx\n\n", \ - sym_array_modules[lp].sym_array[syms].value); - } - } - - FreeModules(); - return(0); -} - -extern void Syslog(int priority, char *fmt, ...) - -{ - va_list ap; - - va_start(ap, fmt); - fprintf(stdout, "Pr: %d, ", priority); - vfprintf(stdout, fmt, ap); - va_end(ap); - fputc('\n', stdout); - - return; -} - -#endif -#endif /* #ifdef FEATURE_KLOGD */ diff --git a/ksyms.h b/ksyms.h deleted file mode 100644 index 316950a0..00000000 --- a/ksyms.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - ksym.h - Definitions for symbol table utilities. - Copyright (c) 1995, 1996 Dr. G.W. Wettstein - Copyright (c) 1996 Enjellic Systems Development - - This file is part of the sysklogd package, a kernel and system log daemon. - - * 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. -*/ - -/* 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/module-template.h b/module-template.h index 4dbb5a2c..96af4d83 100644 --- a/module-template.h +++ b/module-template.h @@ -32,8 +32,13 @@ /* macro to define standard output-module static data members */ -#define DEF_OMOD_STATIC_DATA \ +#define DEF_MOD_STATIC_DATA \ static rsRetVal (*omsdRegCFSLineHdlr)(); +#define DEF_OMOD_STATIC_DATA \ + DEF_MOD_STATIC_DATA +#define DEF_IMOD_STATIC_DATA \ + DEF_MOD_STATIC_DATA + /* Macro to define the module type. Each module can only have a single type. If * a module provides multiple types, several separate modules must be created which diff --git a/plugins/imklog/.cvsignore b/plugins/imklog/.cvsignore new file mode 100644 index 00000000..f43c5593 --- /dev/null +++ b/plugins/imklog/.cvsignore @@ -0,0 +1,6 @@ +.deps +.libs +Makefile +Makefile.in +imklog.la +immklog-ommysql.lo diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am new file mode 100644 index 00000000..23530758 --- /dev/null +++ b/plugins/imklog/Makefile.am @@ -0,0 +1,8 @@ +pkglib_LTLIBRARIES = imklog.la + +imklog_la_SOURCES = imklog.c module.h ksym.c ksyms.h ksym_mod.c ../../module-template.h +imklog_la_CPPFLAGS = -I$(srcdir)/../.. $(pthreads_cflags) +imklog_la_LDFLAGS = -module -avoid-version +imklog_la_LIBADD = + +EXTRA_DIST = diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c new file mode 100644 index 00000000..a6e2a856 --- /dev/null +++ b/plugins/imklog/imklog.c @@ -0,0 +1,753 @@ +/* The kernel log input module for Linux. This file heavily + * borrows from the klogd daemon provided by the sysklogd project. + * Many thanks for this piece of software. + * + * Please note that this file replaces the klogd daemon that was + * also present in pre-v3 versions of rsyslog. + * + * I have begun to convert this to an input module on 2007-12-17. + * IMPORTANT: more than a single instance is currently not supported. This + * needs to be revisited once the config file and input module interface + * supports multiple instances! + * + * 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 "rsyslog.h" +#include +#include +#include +#include +#include +#include +#include "syslogd.h" +#include "cfsysline.h" +#include "template.h" +#include "msg.h" +#include "module-template.h" + +MODULE_TYPE_INPUT +TERM_SYNC_TYPE(eTermSync_SIGNAL) + +/* defines */ +#define DEFAULT_MARK_PERIOD (20 * 60) + +/* Module static data */ +DEF_IMOD_STATIC_DATA +typedef struct _instanceData { +} instanceData; + + +/* Includes. */ +#include +#include +#include +#include +#if !defined(__GLIBC__) +#include +#endif /* __GLIBC__ */ +#include +#include +#include "ksyms.h" + +#define __LIBRARY__ +#include +#if !defined(__GLIBC__) +# define __NR_ksyslog __NR_syslog +_syscall3(int,ksyslog,int, type, char *, buf, int, len); +#else +#include +#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, + console_log_level = -1; + +static int use_syscall = 0, + symbol_lookup = 1; + +static char *symfile = (char *) 0, + log_buffer[LOG_BUFFER_SIZE]; + +static enum LOGSRC {none, proc, kernel} logsrc; + +int debugging = 0; +int symbols_twice = 0; + + +/* Function prototypes. */ +extern int ksyslog(int type, char *buf, int len); +static enum LOGSRC GetKernelLogSrc(void); +static void LogLine(char *ptr, int len); +static void LogKernelLine(void); +static void LogProcLine(void); + + + +/* Write a message to the message queue. + * returns -1 if it fails, something else otherwise + */ +static rsRetVal writeSyslogV(int iPRI, const char *szFmt, va_list va)// __attribute__((format(printf,2, 3))); +{ + DEFiRet; + int iChars; + int iLen; + time_t tNow; + char msgBuf[2048]; /* we use the same size as sysklogd to remain compatible */ + msg_t *pMsg; + + assert(szFmt != NULL); + + /* 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); + + /* here we must create our message object and supply it to the message queue + */ + if((pMsg = MsgConstruct()) == NULL){ + /* There is not much we can do in this case - we discard the message + * then. + */ + dbgprintf("Memory shortage in imklogd: could not construct Msg object.\n"); + return RS_RET_OUT_OF_MEMORY; + } + +dbgprintf("klogd logging Raw: '%s',\nmsg: '%s'\n", msgBuf, msgBuf + iLen); + MsgSetUxTradMsg(pMsg, msgBuf); + MsgSetRawMsg(pMsg, msgBuf); + MsgSetMSG(pMsg, (msgBuf + iLen)); + MsgSetHOSTNAME(pMsg, LocalHostName); + MsgSetTAG(pMsg, "kernel:"); + pMsg->iFacility = LOG_FAC(LOG_KERN); + pMsg->iSeverity = LOG_PRI(iPRI); + pMsg->bParseHOSTNAME = 0; + getCurrTime(&(pMsg->tTIMESTAMP)); /* use the current time! */ + + /* provide message to the queue engine */ + logmsg(iPRI, pMsg, INTERNAL_MSG); + + return iRet; +} + +/* And now the same with variable arguments */ +static 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); +} + +rsRetVal Syslog(int priority, char *fmt, ...) __attribute__((format(printf,2, 3))); +rsRetVal Syslog(int priority, char *fmt, ...) +{ + DEFiRet; + va_list ap; + char *argl; + + /* Output using syslog. */ + if (!strcmp(fmt, "%s")) { + va_start(ap, fmt); + argl = va_arg(ap, char *); + if (argl[0] == '<' && argl[1] && argl[2] == '>') { + switch ( argl[1] ) + { + case '0': + priority = LOG_EMERG; + break; + case '1': + priority = LOG_ALERT; + break; + case '2': + priority = LOG_CRIT; + break; + case '3': + priority = LOG_ERR; + break; + case '4': + priority = LOG_WARNING; + break; + case '5': + priority = LOG_NOTICE; + break; + case '6': + priority = LOG_INFO; + break; + case '7': + default: + priority = LOG_DEBUG; + } + argl += 3; + } + iRet = writeSyslog(priority, fmt, argl); + va_end(ap); + } else { + va_start(ap, fmt); + iRet = writeSyslogV(priority, fmt, ap); + va_end(ap); + } + + return iRet; +} + + +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); + Syslog(LOG_INFO, "Kernel logging (ksyslog) stopped."); + break; + case proc: + close(kmsg); + Syslog(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. + */ + Syslog(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); + Syslog(LOG_INFO, "imklogd %s, log source = ksyslog " + "started.", VERSION); + return(kernel); + } + + if ( (kmsg = open(_PATH_KLOG, O_RDONLY)) < 0 ) + { + fprintf(stderr, "rklogd: Cannot open proc file system, " \ + "%d - %s.\n", errno, strerror(errno)); + ksyslog(7, NULL, 0); + exit(1); + } + + Syslog(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( char *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]", + * 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 char line_buff[LOG_LINE_LENGTH]; + + static char *line =line_buff; + static enum parse_state_enum parse_state = PARSING_TEXT; + static int space = sizeof(line_buff)-1; + + static char *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 */ + + if ( debugging ) + { + fputs("Line buffer full:\n", stderr); + fprintf(stderr, "\tLine: %s\n", line); + } + + Syslog( LOG_INFO, "%s", 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, "%s", 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(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; + } + + delta = sprintf( 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 ) + { + if ( errno == EINTR ) + return; + fprintf(stderr, "rklogd: Error return from sys_sycall: " \ + "%d - %s\n", errno, strerror(errno)); + } + 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; + Syslog(LOG_ERR, "Cannot read proc file system: %d - %s.", \ + errno, strerror(errno)); + } + else + LogLine(log_buffer, rdcnt); + + return; +} + + +#if 0 +int main(int argc, char *argv[]) +{ + int ch, + use_output = 0; + + char *log_level = (char *) 0, + *output = (char *) 0; + + /* Parse the command-line. */ + while ((ch = getopt(argc, argv, "c:df:iIk:nopsvx2")) != EOF) + switch((char)ch) + { + case '2': /* Print lines with symbols twice. */ + symbols_twice = 1; + break; + case 'c': /* Set console message level. */ + log_level = optarg; + break; + case 'd': /* Activity debug mode. */ + debugging = 1; + break; + case 'f': /* Define an output file. */ + output = optarg; + use_output++; + break; + case 'k': /* Kernel symbol file. */ + symfile = optarg; + break; + case 'p': + SetParanoiaLevel(1); /* Load symbols on oops. */ + break; + case 's': /* Use syscall interface. */ + use_syscall = 1; + break; + case 'x': + symbol_lookup = 0; + break; + } + + + /* Set console logging level. */ + if ( log_level != (char *) 0 ) + { + if ( (strlen(log_level) > 1) || \ + (strchr("12345678", *log_level) == (char *) 0) ) + { + fprintf(stderr, "rklogd: Invalid console logging " + "level <%s> specified.\n", log_level); + return(1); + } + console_log_level = *log_level - '0'; + } +} +#endif + +BEGINrunInput +CODESTARTrunInput + /* Determine where kernel logging information is to come from. */ + logsrc = GetKernelLogSrc(); + if (symbol_lookup) { + symbol_lookup = (InitKsyms(symfile) == 1); + symbol_lookup |= InitMsyms(); + if (symbol_lookup == 0) { + Syslog(LOG_WARNING, "cannot find any symbols, turning off symbol lookups\n"); + } + } + + /* 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) { + /* we do not need to handle the RS_RET_TERMINATE_NOW case any + * special because we just need to terminate. This may be different + * if a cleanup is needed. But for now, we can just use CHKiRet(). + * rgerhards, 2007-12-17 + */ + switch ( logsrc ) + { + case kernel: + LogKernelLine(); + break; + case proc: + LogProcLine(); + break; + case none: + pause(); + break; + } +// CHKiRet(thrdSleep(pThrd, iMarkMessagePeriod, 0)); /* seconds, micro seconds */ + } +finalize_it: + /* cleanup here */ + CloseLogSrc(); + + return iRet; +ENDrunInput + + +BEGINwillRun +CODESTARTwillRun +ENDwillRun + + +BEGINfreeInstance +CODESTARTfreeInstance +ENDfreeInstance + + +BEGINdbgPrintInstInfo +CODESTARTdbgPrintInstInfo +ENDdbgPrintInstInfo + + +BEGINmodExit +CODESTARTmodExit +ENDmodExit + + +BEGINqueryEtryPt +CODESTARTqueryEtryPt +CODEqueryEtryPt_STD_IMOD_QUERIES +ENDqueryEtryPt + +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +{ + + return RS_RET_OK; +} + +BEGINmodInit() +CODESTARTmodInit + *ipIFVersProvided = 1; /* so far, we only support the initial definition */ +CODEmodInit_QueryRegCFSLineHdlr + //CHKiRet(omsdRegCFSLineHdlr((uchar *)"markmessageperiod", 0, eCmdHdlrInt, NULL, &iMarkMessagePeriod, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); +ENDmodInit +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + * vi:set ai: + */ diff --git a/plugins/imklog/ksym.c b/plugins/imklog/ksym.c new file mode 100644 index 00000000..baee2c05 --- /dev/null +++ b/plugins/imklog/ksym.c @@ -0,0 +1,986 @@ +#include "config.h" + +#ifdef FEATURE_KLOGD +/* + ksym.c - functions for kernel address->symbol translation + Copyright (c) 1995, 1996 Dr. G.W. Wettstein + Copyright (c) 1996 Enjellic Systems Development + + * 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. +*/ + +/* + * 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 + * 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 + * Switched to fgets() as gets() is not buffer overrun secure. + * + * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze + * 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 + * 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 + * Fixed bug that caused klogd to die if there is no sym_array available. + * + * Tue Sep 12 23:48:12 CEST 2000: Martin Schulze + * Close symbol file in InitKsyms() when an error occurred. + */ + + +/* Includes. */ +#include +#include +#include +#include "klogd.h" +#include "ksyms.h" + +#define VERBOSE_DEBUGGING 0 + + +/* Variables static to this module. */ +struct sym_table +{ + unsigned long value; + char *name; +}; + +static 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", +#if defined(TEST) + "./System.map", +#endif + (char *) 0 +}; + + +#if defined(TEST) +int debugging; +#else +extern int debugging; +#endif + + +/* 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(mapfile) + + char *mapfile; + +{ + auto char type, + sym[512]; + + auto int version = 0; + + auto unsigned long int address; + + auto FILE *sym_file; + + + /* 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 != (char *) 0 ) + { + if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 ) + { + Syslog(LOG_WARNING, "Cannot open map file: %s.", \ + mapfile); + return(0); + } + } + else + { + if ( (mapfile = FindSymbolFile()) == (char *) 0 ) + { + Syslog(LOG_WARNING, "Cannot find map file."); + if ( debugging ) + fputs("Cannot find map file.\n", stderr); + return(0); + } + + if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 ) + { + Syslog(LOG_WARNING, "Cannot open map file."); + if ( debugging ) + fputs("Cannot open map file.\n", stderr); + 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 ) + { + Syslog(LOG_ERR, "Error in symbol table input (#1)."); + fclose(sym_file); + return(0); + } + if ( VERBOSE_DEBUGGING && debugging ) + fprintf(stderr, "Address: %lx, Type: %c, Symbol: %s\n", + address, type, sym); + + if ( AddSymbol(address, sym) == 0 ) + { + Syslog(LOG_ERR, "Error adding symbol - %s.", sym); + fclose(sym_file); + return(0); + } + + if ( version == 0 ) + version = CheckVersion(sym); + } + + + Syslog(LOG_INFO, "Loaded %d symbols from %s.", num_syms, mapfile); + switch ( version ) + { + case -1: + Syslog(LOG_WARNING, "Symbols do not match kernel version."); + num_syms = 0; + break; + + case 0: + Syslog(LOG_WARNING, "Cannot verify that symbols match " \ + "kernel version."); + break; + + case 1: + Syslog(LOG_INFO, "Symbols match kernel version %s.", vstring); + break; + } + + fclose(sym_file); + return(1); +} + + +/************************************************************************** + * 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() + +{ + auto char *file = (char *) 0, + **mf = system_maps; + + auto struct utsname utsname; + static char symfile[100]; + + auto FILE *sym_file = (FILE *) 0; + + if ( uname(&utsname) < 0 ) + { + Syslog(LOG_ERR, "Cannot get kernel version information."); + return(0); + } + + if ( debugging ) + fputs("Searching for symbol map.\n", stderr); + + for (mf = system_maps; *mf != (char *) 0 && file == (char *) 0; ++mf) + { + + sprintf (symfile, "%s-%s", *mf, utsname.release); + if ( debugging ) + fprintf(stderr, "Trying %s.\n", symfile); + if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) { + if (CheckMapVersion(symfile) == 1) + file = symfile; + fclose(sym_file); + } + if (sym_file == (FILE *) 0 || file == (char *) 0) { + sprintf (symfile, "%s", *mf); + if ( debugging ) + fprintf(stderr, "Trying %s.\n", symfile); + if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) { + if (CheckMapVersion(symfile) == 1) + file = symfile; + fclose(sym_file); + } + } + + } + + /* + * At this stage of the game we are at the end of the symbol + * tables. + */ + if ( debugging ) + fprintf(stderr, "End of search list encountered.\n"); + 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(version) + + char *version; + + +{ + auto int vnum, + major, + minor, + patch; + +#ifndef TESTING + int kvnum; + auto struct utsname utsname; +#endif + + 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; + if ( debugging ) + fprintf(stderr, "Version string = %s, Major = %d, " \ + "Minor = %d, Patch = %d.\n", version + + strlen(prefix), major, minor, \ + patch); + sprintf(vstring, "%d.%d.%d", major, minor, patch); + +#ifndef TESTING + /* + * 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 ) + { + Syslog(LOG_ERR, "Cannot get kernel version information."); + return(0); + } + if ( debugging ) + fprintf(stderr, "Comparing kernel %s with symbol table %s.\n",\ + utsname.release, vstring); + + if ( sscanf (utsname.release, "%d.%d.%d", &major, &minor, &patch) < 3 ) + { + Syslog(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. */ +#endif + 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(fname) + + char *fname; + + +{ + int version; + FILE *sym_file; + auto unsigned long int address; + auto char type, + sym[512]; + + if ( (sym_file = fopen(fname, "r")) != (FILE *) 0 ) { + /* + * At this point a map file was successfully opened. We + * now need to search this file and look for version + * information. + */ + Syslog(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 ) + { + Syslog(LOG_ERR, "Error in symbol table input (#2)."); + fclose(sym_file); + return(0); + } + if ( VERBOSE_DEBUGGING && debugging ) + fprintf(stderr, "Address: %lx, Type: %c, " \ + "Symbol: %s\n", address, type, sym); + + version = CheckVersion(sym); + } + fclose(sym_file); + + switch ( version ) + { + case -1: + Syslog(LOG_ERR, "Symbol table has incorrect " \ + "version number.\n"); + break; + + case 0: + if ( debugging ) + fprintf(stderr, "No version information " \ + "found.\n"); + break; + case 1: + if ( debugging ) + fprintf(stderr, "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(address, symbol) + + 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 == (char *) 0 ) + 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(value, sym) + + unsigned long value; + + struct symbol *sym; + +{ + auto int lp; + + auto char *last; + + if (!sym_array) + return((char *) 0); + + last = sym_array[0].name; + sym->offset = 0; + sym->size = 0; + if ( value < sym_array[0].value ) + return((char *) 0); + + for(lp= 0; lp <= num_syms; ++lp) + { + if ( sym_array[lp].value > value ) + { + sym->offset = value - sym_array[lp-1].value; + sym->size = sym_array[lp].value - \ + sym_array[lp-1].value; + return(last); + } + last = sym_array[lp].name; + } + + if ( (last = LookupModuleSymbol(value, sym)) != (char *) 0 ) + return(last); + + return((char *) 0); +} + + +/************************************************************************** + * 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() + +{ + 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(line, el) + + 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; + + + /* + * 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:") != (char *) 0) && !InitMsyms() ) + Syslog(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, "[<")) == (char *) 0 ) + { +#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, ">]")) == (char *) 0 ) + { + 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)) == (char *) 0 ) + symbol = sl; + + strcat(elp, symbol); + elp += strlen(symbol); + if ( debugging ) + fprintf(stderr, "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, "+%x/%d", sym.offset, sym.size); + } + strncat(elp, kp, value); + elp += value; + sl = kp + value; + if ( (kp = strstr(sl, "[<")) == (char *) 0 ) + strcat(elp, sl); + } + while ( kp != (char *) 0); + + if ( debugging ) + fprintf(stderr, "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(level) + + int level; + +{ + i_am_paranoid = level; + return; +} + + +/* + * Setting the -DTEST define enables the following code fragment to + * be compiled. This produces a small standalone program which will + * echo the standard input of the process to stdout while translating + * all numeric kernel addresses into their symbolic equivalent. + */ +#if defined(TEST) + +#include + +extern int main(int, char **); + + +extern int main(int argc, char *argv[]) +{ + auto char line[1024], eline[2048]; + + debugging = 1; + + + if ( !InitKsyms((char *) 0) ) + { + fputs("ksym: Error loading system map.\n", stderr); + return(1); + } + + while ( !feof(stdin) ) + { + fgets(line, sizeof(line), stdin); + if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0'; /* Trash NL char */ + memset(eline, '\0', sizeof(eline)); + ExpandKadds(line, eline); + fprintf(stdout, "%s\n", eline); + } + + + return(0); +} + +extern void Syslog(int priority, char *fmt, ...) + +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stdout, "Pr: %d, ", priority); + vfprintf(stdout, fmt, ap); + va_end(ap); + fputc('\n', stdout); + + return; +} +#endif +#endif /* #ifdef FEATURE_KLOGD */ diff --git a/plugins/imklog/ksym_mod.c b/plugins/imklog/ksym_mod.c new file mode 100644 index 00000000..51ca2fb8 --- /dev/null +++ b/plugins/imklog/ksym_mod.c @@ -0,0 +1,704 @@ +#include "config.h" + +#ifdef FEATURE_KLOGD +/* + ksym_mod.c - functions for building symbol lookup tables for klogd + Copyright (c) 1995, 1996 Dr. G.W. Wettstein + Copyright (c) 1996 Enjellic Systems Development + + * 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. +*/ + +/* + * 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 . + * + * Sat Jan 10 15:00:18 CET 1998: Martin Schulze + * 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 . + * + * Sun Jan 25 20:57:34 CET 1998: Martin Schulze + * Another patch for Linux/alpha by Christopher C Chimelis + * . + * + * Thu Mar 19 23:39:29 CET 1998: Manuel Rodrigues + * 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 + * Removed as it's no longer part of recent glibc + * versions. Added prototyp for llseek() which has been + * forgotton in from glibc. Added more log + * information if problems occurred while reading a system map + * file, by submission from Mark Simon Phillips . + * + * Sun Jan 3 18:38:03 CET 1999: Martin Schulze + * 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 . + * + * Tue Sep 12 23:11:13 CEST 2000: Martin Schulze + * Changed llseek() to lseek64() in order to skip a libc warning. + */ + + +/* Includes. */ +#include +#include +#include +#include +#include +#include +#if !defined(__GLIBC__) +#include +#include +#else /* __GLIBC__ */ +#include "module.h" +extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence)); +extern int get_kernel_syms __P ((struct kernel_sym *__table)); +#endif /* __GLIBC__ */ +#include +#include +#include + +#include "klogd.h" +#include "ksyms.h" + + +#if !defined(__GLIBC__) +/* + * The following bit uses some kernel/library magic to product what + * looks like a function call to user level code. This function is + * actually a system call in disguise. The purpose of the getsyms + * call is to return a current copy of the in-kernel symbol table. + */ +#define __LIBRARY__ +#include +#define __NR_getsyms __NR_get_kernel_syms +_syscall1(int, getsyms, struct kernel_sym *, syms); +#undef __LIBRARY__ +extern int getsyms(struct kernel_sym *); +#else /* __GLIBC__ */ +#define getsyms get_kernel_syms +#endif /* __GLIBC__ */ + +/* Variables static to this module. */ +struct sym_table +{ + unsigned long value; + char *name; +}; + +struct Module +{ + struct sym_table *sym_array; + int num_syms; + + char *name; + struct module module; +#if LINUX_VERSION_CODE >= 0x20112 + struct module_info module_info; +#endif +}; + +static int num_modules = 0; +struct Module *sym_array_modules = (struct Module *) 0; + +static int have_modules = 0; + +#if defined(TEST) +static int debugging = 1; +#else +extern int debugging; +#endif + + +/* Function prototypes. */ +static void FreeModules(void); +static int AddSymbol(struct Module *mp, unsigned long, char *); +static int AddModule(unsigned long, char *); +static int symsort(const void *, const void *); + + +/************************************************************************** + * 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() + +{ + auto int rtn, + tmp; + + auto struct kernel_sym *ksym_table, + *p; + + + /* Initialize the kernel module symbol table. */ + FreeModules(); + + + /* + * The system call which returns the kernel symbol table has + * essentialy two modes of operation. Called with a null pointer + * the system call returns the number of symbols defined in the + * the table. + * + * The second mode of operation is to pass a valid pointer to + * the call which will then load the current symbol table into + * the memory provided. + * + * Returning the symbol table is essentially an all or nothing + * proposition so we need to pre-allocate enough memory for the + * complete table regardless of how many symbols we need. + * + * Bummer. + */ + if ( (rtn = getsyms((struct kernel_sym *) 0)) < 0 ) + { + if ( errno == ENOSYS ) + Syslog(LOG_INFO, "No module symbols loaded - " + "kernel modules not enabled.\n"); + else + Syslog(LOG_ERR, "Error loading kernel symbols " \ + "- %s\n", strerror(errno)); + return(0); + } + if ( debugging ) + fprintf(stderr, "Loading kernel module symbols - " + "Size of table: %d\n", rtn); + + ksym_table = (struct kernel_sym *) malloc(rtn * \ + sizeof(struct kernel_sym)); + if ( ksym_table == (struct kernel_sym *) 0 ) + { + Syslog(LOG_WARNING, " Failed memory allocation for kernel " \ + "symbol table.\n"); + return(0); + } + if ( (rtn = getsyms(ksym_table)) < 0 ) + { + Syslog(LOG_WARNING, "Error reading kernel symbols - %s\n", \ + strerror(errno)); + return(0); + } + + + /* + * Build a symbol table compatible with the other one used by + * klogd. + */ + tmp = rtn; + p = ksym_table; + while ( tmp-- ) + { + if ( !AddModule(p->value, p->name) ) + { + Syslog(LOG_WARNING, "Error adding kernel module table " + "entry.\n"); + free(ksym_table); + return(0); + } + ++p; + } + + /* 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 ) + Syslog(LOG_INFO, "No module symbols loaded."); + else + Syslog(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \ + (rtn == 1) ? "symbol" : "symbols", \ + num_modules, (num_modules == 1) ? "." : "s."); + free(ksym_table); + return(1); +} + + +static int symsort(p1, p2) + + 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); +} + + +/************************************************************************** + * 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; + + + 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); + } + + 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. + * + * Arguements: (unsigned long) address, (char *) symbol + * + * address:-> The address of the module. + * + * symbol:-> The name of the module. + * + * Return: int + **************************************************************************/ + +static int AddModule(address, symbol) + + unsigned long address; + + char *symbol; + +{ + auto int memfd; + + auto struct Module *mp; + + + /* Return if we have loaded the modules. */ + if ( have_modules ) + return(1); + + /* + * The following section of code is responsible for determining + * whether or not we are done reading the list of modules. + */ + if ( symbol[0] == '#' ) + { + + if ( symbol[1] == '\0' ) + { + /* + * A symbol which consists of a # sign only + * signifies a a resident kernel segment. When we + * hit one of these we are done reading the + * module list. + */ + have_modules = 1; + return(1); + } + /* Allocate space for the module. */ + sym_array_modules = (struct Module *) \ + realloc(sym_array_modules, \ + (num_modules+1) * sizeof(struct Module)); + if ( sym_array_modules == (struct Module *) 0 ) + { + Syslog(LOG_WARNING, "Cannot allocate Module array.\n"); + return(0); + } + mp = &sym_array_modules[num_modules]; + + if ( (memfd = open("/dev/kmem", O_RDONLY)) < 0 ) + { + Syslog(LOG_WARNING, "Error opening /dev/kmem\n"); + return(0); + } + if ( lseek64(memfd, address, SEEK_SET) < 0 ) + { + Syslog(LOG_WARNING, "Error seeking in /dev/kmem\n"); + Syslog(LOG_WARNING, "Symbol %s, value %08x\n", symbol, address); + return(0); + } + if ( read(memfd, \ + (char *)&sym_array_modules[num_modules].module, \ + sizeof(struct module)) < 0 ) + { + Syslog(LOG_WARNING, "Error reading module " + "descriptor.\n"); + return(0); + } + close(memfd); + + /* Save the module name. */ + mp->name = (char *) malloc(strlen(&symbol[1]) + 1); + if ( mp->name == (char *) 0 ) + return(0); + strcpy(mp->name, &symbol[1]); + + mp->num_syms = 0; + mp->sym_array = (struct sym_table *) 0; + ++num_modules; + return(1); + } + else + { + if (num_modules > 0) + mp = &sym_array_modules[num_modules - 1]; + else + mp = &sym_array_modules[0]; + AddSymbol(mp, address, symbol); + } + + + return(1); +} + + +/************************************************************************** + * Function: AddSymbol + * + * Purpose: This function is responsible for adding a symbol name + * and its address to the symbol table. + * + * Arguements: (struct Module *) mp, (unsigned long) address, (char *) symbol + * + * mp:-> A pointer to the module which the symbol is + * to be added to. + * + * address:-> The address of the symbol. + * + * symbol:-> The name of the symbol. + * + * Return: int + * + * A boolean value is assumed. True if the addition is + * successful. False if not. + **************************************************************************/ + +static int AddSymbol(mp, address, symbol) + + struct Module *mp; + + unsigned long address; + + char *symbol; + +{ + auto int tmp; + + + /* 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); + + /* Then the space for the symbol. */ + tmp = strlen(symbol); + tmp += (strlen(mp->name) + 1); + mp->sym_array[mp->num_syms].name = (char *) malloc(tmp + 1); + if ( mp->sym_array[mp->num_syms].name == (char *) 0 ) + return(0); + memset(mp->sym_array[mp->num_syms].name, '\0', tmp + 1); + + /* Stuff interesting information into the module. */ + mp->sym_array[mp->num_syms].value = address; + strcpy(mp->sym_array[mp->num_syms].name, mp->name); + strcat(mp->sym_array[mp->num_syms].name, ":"); + strcat(mp->sym_array[mp->num_syms].name, symbol); + ++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; + + + 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 ) + { + sym->offset = value - last->value; + sym->size = mp->sym_array[nsym].value - \ + last->value; + return(last->name); + } + last = &mp->sym_array[nsym]; + } + + + /* + * At this stage of the game we still cannot give up the + * ghost. There is the possibility that the address is + * from a module which has no symbols registered with + * the kernel. The solution is to compare the address + * against the starting address and extant of the module + * If it is in this range we can at least return the + * name of the module. + */ +#if LINUX_VERSION_CODE < 0x20112 + if ( (void *) value >= mp->module.addr && + (void *) value <= (mp->module.addr + \ + mp->module.size * 4096) ) +#else + if ( value >= mp->module_info.addr && + value <= (mp->module_info.addr + \ + mp->module.size * 4096) ) +#endif + { + /* + * A special case needs to be checked for. The above + * conditional tells us that we are within the + * extant of this module but symbol lookup has + * failed. + * + * We need to check to see if any symbols have + * been defined in this module. If there have been + * symbols defined the assumption must be made that + * the faulting address lies somewhere beyond the + * last symbol. About the only thing we can do + * at this point is use an offset from this + * symbol. + */ + if ( mp->num_syms > 0 ) + { + last = &mp->sym_array[mp->num_syms - 1]; +#if LINUX_VERSION_CODE < 0x20112 + sym->size = (int) mp->module.addr + \ + (mp->module.size * 4096) - value; +#else + sym->size = (int) mp->module_info.addr + \ + (mp->module.size * 4096) - value; +#endif + sym->offset = value - last->value; + return(last->name); + } + + /* + * There were no symbols defined for this module. + * Return the module name and the offset of the + * faulting address in the module. + */ + sym->size = mp->module.size * 4096; +#if LINUX_VERSION_CODE < 0x20112 + sym->offset = (void *) value - mp->module.addr; +#else + sym->offset = value - mp->module_info.addr; +#endif + return(mp->name); + } + } + + /* It has been a hopeless exercise. */ + return((char *) 0); +} + + +/* + * Setting the -DTEST define enables the following code fragment to + * be compiled. This produces a small standalone program which will + * dump the current kernel symbol table. + */ +#if defined(TEST) + +#include + + +extern int main(int, char **); + + +int main(argc, argv) + + int argc; + + char *argv[]; + +{ + auto int lp, syms; + + + if ( !InitMsyms() ) + { + fprintf(stderr, "Cannot load module symbols.\n"); + return(1); + } + + printf("Number of modules: %d\n\n", num_modules); + + for(lp= 0; lp < num_modules; ++lp) + { + printf("Module #%d = %s, Number of symbols = %d\n", lp + 1, \ + sym_array_modules[lp].name, \ + sym_array_modules[lp].num_syms); + + for (syms= 0; syms < sym_array_modules[lp].num_syms; ++syms) + { + printf("\tSymbol #%d\n", syms + 1); + printf("\tName: %s\n", \ + sym_array_modules[lp].sym_array[syms].name); + printf("\tAddress: %lx\n\n", \ + sym_array_modules[lp].sym_array[syms].value); + } + } + + FreeModules(); + return(0); +} + +extern void Syslog(int priority, char *fmt, ...) + +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stdout, "Pr: %d, ", priority); + vfprintf(stdout, fmt, ap); + va_end(ap); + fputc('\n', stdout); + + return; +} + +#endif +#endif /* #ifdef FEATURE_KLOGD */ diff --git a/plugins/imklog/ksyms.h b/plugins/imklog/ksyms.h new file mode 100644 index 00000000..316950a0 --- /dev/null +++ b/plugins/imklog/ksyms.h @@ -0,0 +1,38 @@ +/* + ksym.h - Definitions for symbol table utilities. + Copyright (c) 1995, 1996 Dr. G.W. Wettstein + Copyright (c) 1996 Enjellic Systems Development + + This file is part of the sysklogd package, a kernel and system log daemon. + + * 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. +*/ + +/* 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/module.h b/plugins/imklog/module.h new file mode 100644 index 00000000..71eac2c4 --- /dev/null +++ b/plugins/imklog/module.h @@ -0,0 +1,81 @@ +/* Module definitions for klogd's module support + * + * Copyright 2007 by Rainer Gerhards and others + * + * 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. + */ +struct kernel_sym +{ + unsigned long value; + char name[60]; +}; + +struct module_symbol +{ + unsigned long value; + const char *name; +}; + +struct module_ref +{ + struct module *dep; /* "parent" pointer */ + struct module *ref; /* "child" pointer */ + struct module_ref *next_ref; +}; + +struct module_info +{ + unsigned long addr; + unsigned long size; + unsigned long flags; + long usecount; +}; + + +typedef struct { volatile int counter; } atomic_t; + +struct module +{ + unsigned long size_of_struct; /* == sizeof(module) */ + struct module *next; + const char *name; + unsigned long size; + + union + { + atomic_t usecount; + long pad; + } uc; /* Needs to keep its size - so says rth */ + + unsigned long flags; /* AUTOCLEAN et al */ + + unsigned nsyms; + unsigned ndeps; + + struct module_symbol *syms; + struct module_ref *deps; + struct module_ref *refs; + int (*init)(void); + void (*cleanup)(void); + const struct exception_table_entry *ex_table_start; + const struct exception_table_entry *ex_table_end; +#ifdef __alpha__ + unsigned long gp; +#endif +}; + diff --git a/plugins/immark/immark.c b/plugins/immark/immark.c index fa603260..78adcbac 100644 --- a/plugins/immark/immark.c +++ b/plugins/immark/immark.c @@ -30,7 +30,6 @@ * A copy of the GPL can be found in the file "COPYING" in this distribution. */ #include "config.h" -#if 1 /* IMMARK */ #include "rsyslog.h" #include #include @@ -49,7 +48,7 @@ TERM_SYNC_TYPE(eTermSync_SIGNAL) #define DEFAULT_MARK_PERIOD (20 * 60) /* Module static data */ -DEF_OMOD_STATIC_DATA +DEF_IMOD_STATIC_DATA static int iMarkMessagePeriod = DEFAULT_MARK_PERIOD; typedef struct _instanceData { @@ -129,7 +128,6 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(omsdRegCFSLineHdlr((uchar *)"markmessageperiod", 0, eCmdHdlrInt, NULL, &iMarkMessagePeriod, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit -#endif /* #if 0 */ /* * vi:set ai: */ diff --git a/syslog.c b/syslog.c deleted file mode 100644 index 111a37f9..00000000 --- a/syslog.c +++ /dev/null @@ -1,141 +0,0 @@ -/* 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: - */ diff --git a/syslogd.c b/syslogd.c index e24a4029..f3b3042f 100644 --- a/syslogd.c +++ b/syslogd.c @@ -492,7 +492,6 @@ static char *LogPort = "514"; /* port number for INET connections */ static int MarkInterval = 20 * 60; /* interval between marks in seconds - read-only after startup */ int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both), set via cmdline */ int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */ -static int MarkSeq = 0; /* mark sequence number - modified in domark() only */ static int NoFork = 0; /* don't fork - don't run in daemon mode - read-only after startup */ static int AcceptRemote = 0;/* receive messages that come via UDP - read-only after startup */ int ACLAddHostnameOnFail = 0; /* add hostname to acl when DNS resolving has failed */ @@ -650,7 +649,6 @@ static void *singleWorker(); /* REMOVEME later 2005-10-24 */ /* Function prototypes. */ static char **crunch_list(char *list); static void printline(char *hname, char *msg, int iSource); -static void logmsg(int pri, msg_t*, int flags); static rsRetVal fprintlog(action_t *pAction); static void reapchild(); static void debug_switch(); diff --git a/syslogd.h b/syslogd.h index 1ad52d5c..b94f6970 100644 --- a/syslogd.h +++ b/syslogd.h @@ -23,6 +23,7 @@ #include "syslogd-types.h" #include "objomsr.h" +#include "template.h" #ifdef USE_NETZIP #include @@ -71,6 +72,7 @@ int getSubString(uchar **ppSrc, char *pDst, size_t DstSize, char cSep); * module interface -- rgerhards, 2007-12-12 */ void logmsgInternal(int pri, char *msg, int flags); +void logmsg(int pri, msg_t *pMsg, int flags); extern int bFinished; /* used by termination signal handler, read-only except there */ extern int glblHadMemShortage; /* indicates if we had memory shortage some time during the run */ -- cgit