Relocate files to man/ and src/ and change to GNU configure & build

- Relocate all source files to src/ and manual pages to man/
- Replace static Makefile with GNU configure and build system

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
Joachim Nilsson
2018-08-02 22:23:26 +02:00
parent f4110c8571
commit 880cb2aa4d
28 changed files with 117 additions and 0 deletions

62
src/MANIFEST Normal file
View File

@@ -0,0 +1,62 @@
A virgin copy of these sources should include 12 files:
MANIFEST: This file.
INSTALL: Brief installation instructions.
NEWS: Important changes.
Makefile: A makefile to generate the binaries.
README.linux: Documentation which may prove useful.
klogd.c: Source code for the kernel log daemon.
klogd.h: Global definitions required for the kernel log daemon.
ksym.c: Source module for the kernel log daemon which implements
kernel numeric address to symbol translations.
ksym_mod.c: Source module which contains functions which allow ksym.c
to resolve symbols found in loadable kernel modules.
syslogd.c: Source code for the system log daemon.
syslog.c: A slightly modified version of the syslog.c file found in
the standard libraries. This special version is needed
so that klogd will pass messages with kernel priority to
the syslogd facility.
pidfile.c: Source implementing utility functions which are useful
for managing pid files. Used by both syslogd and klogd.
pidfile.h: Include file containing global definitions for the
pid file utility functions.
version.h: An include file for setting the version and patchlevel
for the package.
syslog.conf: A sample configuration file. Note that this file uses
extensions to the BSD syntax. See the syslog.conf(5)
manpage for more details.
syslog_tst.c: A simple program to test the system log utility.
sysklogd.8: Man page documenting the general characteristics of this
package.
klogd.8: Man page documenting the kernel log daemon.
kernel.patch: A source code patch which modifies the linux kernel to
delimit addresses for symbolic translation by klogd.
oops.c: C source for a loadable kernel module which can be used
to generate a kernel protection fault. This is used to
test the address resolution capabilities of klogd.
oops_test.c: A small driver program used in conjunction with the oops
module to generate a kernel protection fault.
modules.patch: A patch to the modules-2.0.0 package which provides for
automatic signalling of klogd whenever the kernel module
state changes.

30
src/Makefile.am Normal file
View File

@@ -0,0 +1,30 @@
# Copyright (c) 2018 Joachim Nilsson <troglobit@gmail.com>
#
# This file is part of the sysklogd package, a kernel and system log daemon.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
sbin_PROGRAMS = syslogd klogd
doc_DATA = README.1st README.linux
AM_CFLAGS = -fomit-frame-pointer -fno-strength-reduce -Wno-unused-result
syslogd_SOURCES = syslogd.c pidfile.c pidfile.h
syslogd_CPPFLAGS = -DSYSV -DFSSTND -DSYSLOG_INET -DINET6 -DNO_SCCS \
-DSYSLOG_UNIXAF -DSYSLOGD_PIDNAME=\"syslogd.pid\"
klogd_SOURCES = klogd.c klogd.h syslog.c pidfile.c pidfile.h \
ksym.c ksyms.h ksym_mod.c module.h
klogd_CPPFLAGS = -DSYSV -DFSSTND

142
src/Makefile.old Normal file
View File

@@ -0,0 +1,142 @@
# Copyright (c) 1995 Dr. G.W. Wettstein <greg@wind.rmcc.com>
# Copyright (c) 2007 Martin Schulze <joey@infodrom.org>
#
# This file is part of the sysklogd package, a kernel and system log daemon.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
CC= gcc
#SKFLAGS= -g -DSYSV -Wall
#LDFLAGS= -g
SKFLAGS= $(RPM_OPT_FLAGS) -O3 -DSYSV -fomit-frame-pointer -Wall -fno-strength-reduce
# -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
# -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
# $(shell getconf LFS_SKFLAGS)
LDFLAGS= -s
# Look where your install program is.
INSTALL = /usr/bin/install
# Destination paths, set prefix=/opt if required
BINDIR = $(prefix)/usr/sbin
MANDIR = $(prefix)/usr/share/man
# There is one report that under an all ELF system there may be a need to
# explicilty link with libresolv.a. If linking syslogd fails you may wish
# to try uncommenting the following define.
# LIBS = /usr/lib/libresolv.a
# A patch was forwarded which provided support for sysklogd under
# the ALPHA. This patch included a reference to a library which may be
# specific to the ALPHA. If you are attempting to build this package under
# an ALPHA and linking fails with unresolved references please try
# uncommenting the following define.
# LIBS = ${LIBS} -linux
# Define the following to impart start-up delay in klogd. This is
# useful if klogd is started simultaneously or in close-proximity to syslogd.
# KLOGD_START_DELAY = -DKLOGD_DELAY=5
# The following define determines whether the package adheres to the
# file system standard.
FSSTND = -DFSSTND
# The following define establishes ownership for the man pages.
# Avery tells me that there is a difference between Debian and
# Slackware. Rather than choose sides I am leaving it up to the user.
MAN_USER = root
MAN_GROUP = root
MAN_PERMS = 644
# The following define establishes the name of the pid file for the
# syslogd daemon. The library include file (paths.h) defines the
# name for the syslogd pid to be syslog.pid. A number of people have
# suggested that this should be syslogd.pid. You may cast your
# ballot below.
SYSLOGD_PIDNAME = -DSYSLOGD_PIDNAME=\"syslogd.pid\"
SYSLOGD_FLAGS= -DSYSLOG_INET -DSYSLOG_UNIXAF -DINET6 -DNO_SCCS ${FSSTND} \
${SYSLOGD_PIDNAME}
SYSLOG_FLAGS= -DALLOW_KERNEL_LOGGING
KLOGD_FLAGS = ${FSSTND} ${KLOGD_START_DELAY}
DEB =
all: syslogd klogd
test: syslog_tst ksym oops.ko tsyslogd
install: install_man install_exec
syslogd: syslogd.o pidfile.o
${CC} ${LDFLAGS} -o syslogd syslogd.o pidfile.o ${LIBS}
klogd: klogd.o syslog.o pidfile.o ksym.o ksym_mod.o
${CC} ${LDFLAGS} -o klogd klogd.o syslog.o pidfile.o ksym.o \
ksym_mod.o ${LIBS}
syslog_tst: syslog_tst.o
${CC} ${LDFLAGS} -o syslog_tst syslog_tst.o
tsyslogd: syslogd.c version.h
$(CC) $(SKFLAGS) -g -DTESTING $(SYSLOGD_FLAGS) -o tsyslogd syslogd.c
tklogd: klogd.c syslog.c ksym.c ksym_mod.c version.h
$(CC) $(SKFLAGS) -g -DTESTING $(KLOGD_FLAGS) -o tklogd klogd.c syslog.c ksym.c ksym_mod.c
syslogd.o: syslogd.c version.h
${CC} ${SKFLAGS} ${SYSLOGD_FLAGS} $(DEB) -c syslogd.c
syslog.o: syslog.c
${CC} ${SKFLAGS} ${SYSLOG_FLAGS} -c syslog.c
klogd.o: klogd.c klogd.h version.h
${CC} ${SKFLAGS} ${KLOGD_FLAGS} $(DEB) -c klogd.c
ksym.o: ksym.c klogd.h ksyms.h module.h
${CC} ${SKFLAGS} ${KLOGD_FLAGS} -c ksym.c
ksym_mod.o: ksym_mod.c klogd.h ksyms.h module.h
${CC} ${SKFLAGS} ${KLOGD_FLAGS} -c ksym_mod.c
syslog_tst.o: syslog_tst.c
${CC} ${SKFLAGS} -c syslog_tst.c
ksym: ksym_test.o ksym_mod.o
${CC} ${LDFLAGS} -o ksym ksym_test.o ksym_mod.o
ksym_test.o: ksym.c
${CC} ${SKFLAGS} -DTEST -o ksym_test.o -c ksym.c
clean:
rm -f *.o *.log *~ *.orig
rm -f *.ko oops.mod.* Module.symvers
clobber: clean
rm -f syslogd klogd ksym syslog_tst oops_test TAGS tsyslogd tklogd
install_exec: syslogd klogd
${INSTALL} -m 500 -s syslogd ${BINDIR}/syslogd
${INSTALL} -m 500 -s klogd ${BINDIR}/klogd
install_man:
${INSTALL} -o ${MAN_USER} -g ${MAN_GROUP} -m ${MAN_PERMS} sysklogd.8 ${MANDIR}/man8/sysklogd.8
${INSTALL} -o ${MAN_USER} -g ${MAN_GROUP} -m ${MAN_PERMS} syslogd.8 ${MANDIR}/man8/syslogd.8
${INSTALL} -o ${MAN_USER} -g ${MAN_GROUP} -m ${MAN_PERMS} syslog.conf.5 ${MANDIR}/man5/syslog.conf.5
${INSTALL} -o ${MAN_USER} -g ${MAN_GROUP} -m ${MAN_PERMS} klogd.8 ${MANDIR}/man8/klogd.8
obj-m += oops.o
oops.ko: oops.c
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

95
src/README.1st Normal file
View File

@@ -0,0 +1,95 @@
Important information
---------------------
The included version of syslogd behaves in a slightly different manner
to the one in former releases. Please review the following important
differences:
* By default the syslog daemon doesn't accept any message from the
syslog/udp port. To enable this add "-r" to the command-line
arguments. You _have to_ add this on every host that should run as a
centralized network log server.
You also should take a look at other new command-line arguments:
"-l" and "-s".
The syslog daemon by default does not forward to a remote host any
log messages which it received from a remote host. This is an
attempt to prevent syslog loops. If you desire this behavior the
-h command-line switch can be used to enable this behavior.
* Syslogd was designed to strip off the local domain from every
message that comes from any host in the same domain. Unfortunately
this feature didn't work in every cases. This is now corrected. So
you might not get the fqdn anymore.
If you use any scripts that analyze logfiles, please bare this in
mind.
* Syslogd doesn't touch the filemode of any logfile. If it has to
create one, it will be world-readable. If you do not want this
(i.e. if auth.* is logged) you have to create the file by hand and
change permissions.
* If you notice that some of your programs make heavy use of the
syslog facility and your disks get loud you might want to turn
fsync()ing after each line off. But note that in doing so you
increase the likelihood of lost information in the event of a
system crash.
* If you're going to start klogd or syslogd by init(8), you don't have
to hack the code anymore. Instead add "-n" to the command-line
arguments.
* Klogd can now be used to decode EIP addresses if it can determine a
System.map file (command-line argument "-k"). This is a very useful
feature if your system crashes, but its usability depends on an
actual and correct System.map file.
* Both system utilities now check for and respect the existence of .pid
files. If the utilities are started by configuration scripts on
stable systems there is the potential that the process ID numbers of
the utilities will be identical from one system boot to another.
This will cause both klogd and syslogd to terminate.
Both klogd and syslogd will attempt to remove their .pid files when
they receive termination signals. The difficulty noted above
typically occurs when a system crash occurs or an uncatchable signal
(kill -9) is used to stop the daemons.
The cleanest solution to this problem is to insure that the system
configuration scripts (rc.*) provide a clean working environment for
a freshly booted system. As part of the initialization process
these scripts should remove all old .pid files found in /var/run.
This will insure that klogd and syslogd start properly even if prior
executions have been terminated harshly.
* Large file support, i.e. support to write to log files that are
larger than 2 GB is not part of syslogd, but a matter of the glibc
emitting different system calls to the kernel interface. To support
large files you'll have to compile syslogd with the compiler defines
commented out in the main Makefile so that glibc adjusts the system
calls.
Modifying the kernel console log level
--------------------------------------
There are two ways to alter the kernel console log level. This
setting controls whether log messages from the kernel should appear
on the system console or not.
In the past, klogd had to do this with the -c parameter. Using '-c
4' will set the log level of console messages to 4 and only display
warnings and errors but not regular debug or information messages.
This behaviour is deprecated and hencely not enforced anymore via
the RC script of klogd. Instead sysctl(8) should be used as
interface to various kernel variables. These can be stored
non-volatile in /etc/sysctl.conf.
The prevent the kernel to flood the system console and to achieve
the same behaviour of '-c 4' simply add the following to the
configuration file and let sysctl set this kernel parameter upon
system boot.
kernel/printk = 4 4 1 7

77
src/README.linux Normal file
View File

@@ -0,0 +1,77 @@
Welcome to the sysklogd package for Linux. All the utility
documentation has now been moved into the man pages. Please review
these carefully before proceeding.
Version 1.3 of the package is the culmination of about two years of
experience and bug reports on the 1.2 version from both the INTERNET
and our corporate Linux networks. The utilities in this package should
provide VERY reliable system logging. Klogd and syslogd have both
been stress tested in kernel development environments where literally
hundreds of megabytes of kernel messages have been blasted through
them. If either utility should fail the development team would
appreciate debug information so that the bug can be reproduced and
squashed.
Both utilities (syslogd, klogd) can be either run from init or started
as part of the rc.* sequence. Caution should be used when starting
these utilities from init since the default configuration is for both of
these utilities to auto-background themselves. Depending on the
version of init being used this could either result in the process
table being filled or at least 10 copies of the daemon being started.
If auto-backgrounding is NOT desired the command line option -n should
be used to disable the auto-fork feature.
I have found work on the sysklogd package to be an interesting example
of the powers of the INTERNET. Stephen, Juha, Shane, Martin and
myself have successfully collaborated on the development of this
package without ever having met each other, in fact we could pass on
the street without realizing it. What I have developed is a profound
respect for the personal capabilities of each one of these
individuals. Perhaps the greatest `Linux Legacy' will be that its
development/enhancement is truly an example of the powers of
international cooperation through the worldwide INTERNET.
We would be interested in keeping track of any and all bug
fixes/changes that are made. At the time that work was started on the
sysklogd package the syslog(d) sources seemed to have fallen into
neglect. This work started with and continues the believe that it is
important to maintain consistent standardized system utilities
sources. Hopefully the Linux community will find these sources to be
a useful addition to the software gene pool.
There is a mailing list covering this package and syslog in general.
The lists address is infodrom-sysklogd@lists.infodrom.org . To subscribe send a
mail to majordomo@lists.infodrom.org with a line "subscribe infodrom-sysklogd"
in the message body.
A second mailing list exists as infodrom-sysklogd-cvs@lists.infodrom.org. Only
CVS messages and diffs are distributed there. Whenever new code is added to
sysklogd, CVS generates a mail from these changes which will be sent to
this list. Discussions will take place on the first list.
The latest version of this software can be found at:
http://www.infodrom.org/projects/sysklogd/download.php3
Best regards,
Dr. Wettstein
Oncology Research Division Computing Facility
Roger Maris Cancer Center
Fargo, ND
greg@wind.enjellic.com
Stephen Tweedie
Department of Computer Science
Edinburgh University, Scotland
Juha Virtanen
jiivee@hut.fi
Shane Alderton
shane@ion.apana.org.au
Martin Schulze
Infodrom Oldenburg
joey@infodrom.org
And a number of bug reporters whose contributions cannot be underestimated.

1204
src/klogd.c Normal file

File diff suppressed because it is too large Load Diff

40
src/klogd.h Normal file
View File

@@ -0,0 +1,40 @@
/*
klogd.h - main header file for Linux kernel log daemon.
Copyright (c) 1995 Dr. G.W. Wettstein <greg@wind.rmcc.com>
This file is part of the sysklogd package, a kernel and system log daemon.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Symbols and definitions needed by klogd.
*
* Thu Nov 16 12:45:06 CST 1995: Dr. Wettstein
* Initial version.
*/
/* Useful include files. */
#include <stdio.h>
#include <syslog.h>
#include <string.h>
/* 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, ...);

948
src/ksym.c Normal file
View File

@@ -0,0 +1,948 @@
/*
ksym.c - functions for kernel address->symbol translation
Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com>
Copyright (c) 1996 Enjellic Systems Development
Copyright (c) 1997-2007 Martin Schulze <joey@infodrom.org>
This file is part of the sysklogd package, a kernel and system log daemon.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This file contains functions which handle the translation of kernel
* numeric addresses into symbols for the klogd utility.
*
* Sat Oct 28 09:00:14 CDT 1995: Dr. Wettstein
* Initial Version.
*
* Fri Nov 24 12:50:52 CST 1995: Dr. Wettstein
* Added VERBOSE_DEBUGGING define to make debugging output more
* manageable.
*
* Added support for verification of the loaded kernel symbols. If
* no version information can be be found in the mapfile a warning
* message is issued but translation will still take place. This
* will be the default case if kernel versions < 1.3.43 are used.
*
* If the symbols in the mapfile are of the same version as the kernel
* that is running an informative message is issued. If the symbols
* in the mapfile do not match the current kernel version a warning
* message is issued and translation is disabled.
*
* Wed Dec 6 16:14:11 CST 1995: Dr. Wettstein
* Added /boot/System.map to the list of symbol maps to search for.
* Also made this map the first item in the search list. I am open
* to CONSTRUCTIVE suggestions for any additions or corrections to
* the list of symbol maps to search for. Be forewarned that the
* list in use is the consensus agreement between myself, Linus and
* some package distributers. It is a given that no list will suit
* everyone's taste. If you have rabid concerns about the list
* please feel free to edit the system_maps array and compile your
* own binaries.
*
* Added support for searching of the list of symbol maps. This
* allows support for access to multiple symbol maps. The theory
* behind this is that a production kernel may have a system map in
* /boot/System.map. If a test kernel is booted this system map
* would be skipped in favor of one found in /usr/src/linux.
*
* Thu Jan 18 11:18:31 CST 1996: Dr. Wettstein
* Added patch from beta-testers to allow for reading of both
* ELF and a.out map files.
*
* Wed Aug 21 09:15:49 CDT 1996: Dr. Wettstein
* Reloading of kernel module symbols is now turned on by the
* SetParanoiaLevel function. The default behavior is to NOT reload
* the kernel module symbols when a protection fault is detected.
*
* Added support for freeing of the current kernel module symbols.
* This was necessary to support reloading of the kernel module symbols.
*
* When a matching static symbol table is loaded the kernel version
* number is printed.
*
* Mon Jun 9 17:12:42 CST 1997: Martin Schulze
* Added #1 and #2 to some error messages in order to being able
* to divide them (ulmo@Q.Net)
*
* Fri Jun 13 10:50:23 CST 1997: Martin Schulze
* Changed definition of LookupSymbol to non-static because it is
* used in klogd.c, too.
*
* Fri Jan 9 23:00:08 CET 1998: Martin Schulze <joey@infodrom.north.de>
* Fixed bug that caused klogd to die if there is no System.map available.
*
* Sun 29 Mar 18:14:07 BST 1998: Mark Simon Phillips <M.S.Phillips@nortel.co.uk>
* Switched to fgets() as gets() is not buffer overrun secure.
*
* Mon Apr 13 18:18:45 CEST 1998: Martin Schulze <joey@infodrom.north.de>
* Modified loop for detecting the correct system map. Now it won't
* stop if a file has been found but doesn't contain the correct map.
* Special thanks go go Mark Simon Phillips for the hint.
*
* Mon Oct 12 00:42:30 CEST 1998: Martin Schulze <joey@infodrom.north.de>
* Modified CheckVersion()
* . Use shift to decode the kernel version
* . Compare integers of kernel version
* . extract major.minor.patch from utsname.release via sscanf()
* The reason lays in possible use of kernel flavours which
* modify utsname.release but no the Version_ symbol.
*
* Sun Feb 21 22:27:49 EST 1999: Keith Owens <kaos@ocs.com.au>
* Fixed bug that caused klogd to die if there is no sym_array available.
*
* Tue Sep 12 23:48:12 CEST 2000: Martin Schulze <joey@infodrom.ffis.de>
* Close symbol file in InitKsyms() when an error occurred.
*
* Thu Apr 29 18:07:16 CEST 2004: Dmitry Levin <ldv@altlinux.org>
* Close file descriptor in FindSymbolFile() in order not to leak
* file descriptors.
*
* Fri Jul 16 08:32:49 CEST 2004: Ulf Härnhammar <Ulf.Harnhammar.9485@student.uu.se>
* Added boundary check for fscanf() in InitKsyms() and
* CheckMapVersion() to prevent an unintended crash when reading
* an incorrect System.map.
*
* Mon May 28 08:27:51 CEST 2007: Martin Schulze <joey@infodrom.org>
* Added back /usr/src/linux/System.map as fall-back location.
*
* Thu May 31 16:56:26 CEST 2007: Martin Schulze <joey@infodrom.org>
* Improved symbol lookup, since symbols are spread over the entire
* address space. Return the symbol that fits best instead of
* the first hit.
*/
/* Includes. */
#include <stdlib.h>
#include <malloc.h>
#include <sys/utsname.h>
#include "klogd.h"
#include "ksyms.h"
#include "module.h"
#define VERBOSE_DEBUGGING 0
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",
"/usr/src/linux/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.
*
* Arguments: (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 %511s\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.
*
* Arguments: 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... :-)
*
* Arguments: (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.
*
* Arguments: (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 %511s\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.
*
* Arguments: (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.
*
* Arguments: (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;
auto char *name;
struct symbol ksym, msym;
if (!sym_array)
return((char *) 0);
last = sym_array[0].name;
ksym.offset = 0;
ksym.size = 0;
if ( value < sym_array[0].value )
return((char *) 0);
for(lp = 0; lp <= num_syms; ++lp)
{
if ( sym_array[lp].value > value )
{
ksym.offset = value - sym_array[lp-1].value;
ksym.size = sym_array[lp].value - \
sym_array[lp-1].value;
break;
}
last = sym_array[lp].name;
}
name = LookupModuleSymbol(value, &msym);
if ( ksym.offset == 0 && msym.offset == 0 )
{
return((char *) 0);
}
if ( ksym.offset == 0 || msym.offset < 0 ||
(ksym.offset > 0 && ksym.offset < msym.offset) )
{
sym->offset = ksym.offset;
sym->size = ksym.size;
return(last);
}
else
{
sym->offset = msym.offset;
sym->size = msym.size;
return(name);
}
return((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.
*
* Arguments: 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.
*
* Arguments: (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;
sym.offset = 0;
sym.size = 0;
/*
* This is as handy a place to put this as anyplace.
*
* Since the insertion of kernel modules can occur in a somewhat
* dynamic fashion we need some mechanism to insure that the
* kernel symbol tables get read just prior to when they are
* needed.
*
* To accomplish this we look for the Oops string and use its
* presence as a signal to load the module symbols.
*
* This is not the best solution of course, especially if the
* kernel is rapidly going out to lunch. What really needs to
* be done is to somehow generate a callback from the
* kernel whenever a module is loaded or unloaded. I am
* open for patches.
*/
if ( i_am_paranoid &&
(strstr(line, "Oops:") != (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 )
{
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, "+0x%x/0x%02x", 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.
*
* Arguments: (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 <stdarg.h>
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
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* tab-width: 8
* End:
*/

621
src/ksym_mod.c Normal file
View File

@@ -0,0 +1,621 @@
/*
ksym_mod.c - functions for building symbol lookup tables for klogd
Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com>
Copyright (c) 1996 Enjellic Systems Development
Copyright (c) 1998-2007 Martin Schulze <joey@infodrom.org>
This file is part of the sysklogd package, a kernel and system log daemon.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This file implements functions which are useful for building
* a symbol lookup table based on the in kernel symbol table
* maintained by the Linux kernel.
*
* Proper logging of kernel panics generated by loadable modules
* tends to be difficult. Since the modules are loaded dynamically
* their addresses are not known at kernel load time. A general
* protection fault (Oops) cannot be properly deciphered with
* classic methods using the static symbol map produced at link time.
*
* One solution to this problem is to have klogd attempt to translate
* addresses from module when the fault occurs. By referencing the
* the kernel symbol table proper resolution of these symbols is made
* possible.
*
* At least that is the plan.
*
* Wed Aug 21 09:20:09 CDT 1996: Dr. Wettstein
* The situation where no module support has been compiled into a
* kernel is now detected. An informative message is output indicating
* that the kernel has no loadable module support whenever kernel
* module symbols are loaded.
*
* An informative message is printed indicating the number of kernel
* modules and the number of symbols loaded from these modules.
*
* Sun Jun 15 16:23:29 MET DST 1997: Michael Alan Dorman
* Some more glibc patches made by <mdorman@debian.org>.
*
* Sat Jan 10 15:00:18 CET 1998: Martin Schulze <joey@infodrom.north.de>
* Fixed problem with klogd not being able to be built on a kernel
* newer than 2.1.18. It was caused by modified structures
* inside the kernel that were included. I have worked in a
* patch from Alessandro Suardi <asuardi@uninetcom.it>.
*
* Sun Jan 25 20:57:34 CET 1998: Martin Schulze <joey@infodrom.north.de>
* Another patch for Linux/alpha by Christopher C Chimelis
* <chris@classnet.med.miami.edu>.
*
* Thu Mar 19 23:39:29 CET 1998: Manuel Rodrigues <pmanuel@cindy.fe.up.pt>
* Changed lseek() to llseek() in order to support > 2GB address
* space which provided by kernels > 2.1.70.
*
* Mon Apr 13 18:18:45 CEST 1998: Martin Schulze <joey@infodrom.north.de>
* Removed <sys/module.h> as it's no longer part of recent glibc
* versions. Added prototyp for llseek() which has been
* forgotton in <unistd.h> from glibc. Added more log
* information if problems occurred while reading a system map
* file, by submission from Mark Simon Phillips <M.S.Phillips@nortel.co.uk>.
*
* Sun Jan 3 18:38:03 CET 1999: Martin Schulze <joey@infodrom.north.de>
* Corrected return value of AddModule if /dev/kmem can't be
* loaded. This will prevent klogd from segfaulting if /dev/kmem
* is not available. Patch from Topi Miettinen <tom@medialab.sonera.net>.
*
* Tue Sep 12 23:11:13 CEST 2000: Martin Schulze <joey@infodrom.ffis.de>
* Changed llseek() to lseek64() in order to skip a libc warning.
*
* Wed Mar 31 17:35:01 CEST 2004: Martin Schulze <joey@infodrom.org>
* Removed references to <linux/module.h> since it doesn't work
* anymore with its recent content from Linux 2.4/2.6, created
* module.h locally instead.
*
* Fri May 25 20:07:30 CEST 2007: Martin Schulze <joey@infodrom.org>
* Use new query_module function rather than the old obsolete
* hack of stepping through /dev/kmem.
*
* Mon May 28 16:46:59 CEST 2007: Martin Schulze <joey@infodrom.org>
* Since Linux 2.6 query_module is depricated and no implemented
* anymore. Thus, overhauled symbol import via /proc/kallsyms
*
* Thu May 31 12:12:23 CEST 2007: Martin Schulze <joey@infodrom.org>
* Only read kernel symbols from /proc/kallsyms if no System.map
* has been read as it may contain more symbols.
*
* Thu May 31 16:56:26 CEST 2007: Martin Schulze <joey@infodrom.org>
* Improved symbol lookup, since symbols are spread over the entire
* address space. Return the symbol that fits best instead of
* the first hit.
*/
/* Includes. */
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <ctype.h>
#include <malloc.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include "module.h"
#if !defined(__GLIBC__)
#include <linux/time.h>
#endif /* __GLIBC__ */
#include <stdarg.h>
#include <paths.h>
#include <linux/version.h>
#include "klogd.h"
#include "ksyms.h"
#define KSYMS "/proc/kallsyms"
static int num_modules = 0;
struct Module *sym_array_modules = (struct Module *) 0;
static int have_modules = 0;
#if defined(TEST)
static int debugging = 1;
#else
extern int debugging;
#endif
/* Function prototypes. */
static void FreeModules(void);
static int AddSymbol(const char *);
struct Module *AddModule(const char *);
static int symsort(const void *, const void *);
/* Imported from ksym.c */
extern int num_syms;
/**************************************************************************
* Function: InitMsyms
*
* Purpose: This function is responsible for building a symbol
* table which can be used to resolve addresses for
* loadable modules.
*
* Arguments: 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;
FILE *ksyms;
char buf[128];
char *p;
/* Initialize the kernel module symbol table. */
FreeModules();
ksyms = fopen(KSYMS, "r");
if ( ksyms == NULL )
{
if ( errno == ENOENT )
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 - "
"Source: %s\n", KSYMS);
while ( fgets(buf, sizeof(buf), ksyms) != NULL )
{
if (num_syms > 0 && index(buf, '[') == NULL)
continue;
p = index(buf, ' ');
if ( p == NULL )
continue;
if ( buf[strlen(buf)-1] == '\n' )
buf[strlen(buf)-1] = '\0';
/* overlong lines will be ignored above */
AddSymbol(buf);
}
fclose(ksyms);
have_modules = 1;
/* Sort the symbol tables in each module. */
for (rtn = tmp = 0; tmp < num_modules; ++tmp)
{
rtn += sym_array_modules[tmp].num_syms;
if ( sym_array_modules[tmp].num_syms < 2 )
continue;
qsort(sym_array_modules[tmp].sym_array, \
sym_array_modules[tmp].num_syms, \
sizeof(struct sym_table), symsort);
}
if ( rtn == 0 )
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.");
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.
*
* Arguments: None specified.
*
* Return: void
**************************************************************************/
static void FreeModules()
{
auto int nmods,
nsyms;
auto struct Module *mp;
/* Check to see if the module symbol tables need to be cleared. */
have_modules = 0;
if ( num_modules == 0 )
return;
if ( sym_array_modules == NULL )
return;
for (nmods = 0; nmods < num_modules; ++nmods)
{
mp = &sym_array_modules[nmods];
if ( mp->num_syms == 0 )
continue;
for (nsyms= 0; nsyms < mp->num_syms; ++nsyms)
free(mp->sym_array[nsyms].name);
free(mp->sym_array);
if ( mp->name != NULL )
free(mp->name);
}
free(sym_array_modules);
sym_array_modules = (struct Module *) 0;
num_modules = 0;
return;
}
/**************************************************************************
* Function: AddModule
*
* Purpose: This function is responsible for adding a module to
* the list of currently loaded modules.
*
* Arguments: (const char *) module
*
* module:-> The name of the module.
*
* Return: struct Module *
**************************************************************************/
struct Module *AddModule(module)
const char *module;
{
struct Module *mp;
if ( num_modules == 0 )
{
sym_array_modules = (struct Module *)malloc(sizeof(struct Module));
if ( sym_array_modules == NULL )
{
Syslog(LOG_WARNING, "Cannot allocate Module array.\n");
return NULL;
}
mp = sym_array_modules;
}
else
{
/* Allocate space for the module. */
mp = (struct Module *) \
realloc(sym_array_modules, \
(num_modules+1) * sizeof(struct Module));
if ( mp == NULL )
{
Syslog(LOG_WARNING, "Cannot allocate Module array.\n");
return NULL;
}
sym_array_modules = mp;
mp = &sym_array_modules[num_modules];
}
num_modules++;
mp->sym_array = NULL;
mp->num_syms = 0;
if ( module != NULL )
mp->name = strdup(module);
else
mp->name = NULL;
return mp;
}
/**************************************************************************
* Function: AddSymbol
*
* Purpose: This function is responsible for adding a symbol name
* and its address to the symbol table.
*
* Arguments: (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(line)
const char *line;
{
char *module;
unsigned long address;
char *p;
static char *lastmodule = NULL;
struct Module *mp;
module = index(line, '[');
if ( module != NULL )
{
p = index(module, ']');
if ( p != NULL )
*p = '\0';
p = module++;
while ( isspace(*(--p)) );
*(++p) = '\0';
}
p = index(line, ' ');
if ( p == NULL )
return(0);
*p = '\0';
address = strtoul(line, (char **) 0, 16);
p += 3;
if ( num_modules == 0 ||
( lastmodule == NULL && module != NULL ) ||
( module == NULL && lastmodule != NULL) ||
( module != NULL && strcmp(module, lastmodule)))
{
mp = AddModule(module);
if ( mp == NULL )
return(0);
}
else
mp = &sym_array_modules[num_modules-1];
lastmodule = mp->name;
/* Allocate space for the symbol table entry. */
mp->sym_array = (struct sym_table *) realloc(mp->sym_array, \
(mp->num_syms+1) * sizeof(struct sym_table));
if ( mp->sym_array == (struct sym_table *) 0 )
return(0);
mp->sym_array[mp->num_syms].name = strdup(p);
if ( mp->sym_array[mp->num_syms].name == (char *) 0 )
return(0);
/* Stuff interesting information into the module. */
mp->sym_array[mp->num_syms].value = address;
++mp->num_syms;
return(1);
}
/**************************************************************************
* Function: LookupModuleSymbol
*
* Purpose: Find the symbol which is related to the given address from
* a kernel module.
*
* Arguments: (long int) value, (struct symbol *) sym
*
* value:-> The address to be located.
*
* sym:-> A pointer to a structure which will be
* loaded with the symbol's parameters.
*
* Return: (char *)
*
* If a match cannot be found a diagnostic string is printed.
* If a match is found the pointer to the symbolic name most
* closely matching the address is returned.
**************************************************************************/
extern char * LookupModuleSymbol(value, sym)
unsigned long value;
struct symbol *sym;
{
auto int nmod,
nsym;
auto struct sym_table *last;
auto struct Module *mp;
static char ret[100];
sym->size = 0;
sym->offset = 0;
if ( num_modules == 0 )
return((char *) 0);
for (nmod = 0; nmod < num_modules; ++nmod)
{
mp = &sym_array_modules[nmod];
/*
* Run through the list of symbols in this module and
* see if the address can be resolved.
*/
for(nsym = 1, last = &mp->sym_array[0];
nsym < mp->num_syms;
++nsym)
{
if ( mp->sym_array[nsym].value > value )
{
if ( sym->size == 0 ||
(value - last->value) < sym->offset ||
( (sym->offset == (value - last->value)) &&
(mp->sym_array[nsym].value-last->value) < sym->size ) )
{
sym->offset = value - last->value;
sym->size = mp->sym_array[nsym].value - \
last->value;
ret[sizeof(ret)-1] = '\0';
if ( mp->name == NULL )
snprintf(ret, sizeof(ret)-1,
"%s", last->name);
else
snprintf(ret, sizeof(ret)-1,
"%s:%s", mp->name, last->name);
}
break;
}
last = &mp->sym_array[nsym];
}
}
if ( sym->size > 0 )
return(ret);
/* It has been a hopeless exercise. */
return((char *) 0);
}
/*
* 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 <stdarg.h>
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 == NULL
?"kernel space"
: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
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* tab-width: 8
* End:
*/

35
src/ksyms.h Normal file
View File

@@ -0,0 +1,35 @@
/*
ksym.h - Definitions for symbol table utilities.
Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com>
Copyright (c) 1996 Enjellic Systems Development
This file is part of the sysklogd package, a kernel and system log daemon.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* 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 *);

51
src/module.h Normal file
View File

@@ -0,0 +1,51 @@
/*
module.h - Miscellaneous module definitions
Copyright (c) 1996 Richard Henderson <rth@tamu.edu>
Copyright (c) 2004-7 Martin Schulze <joey@infodrom.org>
This file is part of the sysklogd package.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* ChangeLog:
*
* Wed Mar 31 17:35:01 CEST 2004: Martin Schulze <joey@infodrom.org>
* Created local copy of module.h based on the content of Linux
* 2.2 since <linux/module.h> doesn't work anymore with its
* recent content from Linux 2.4/2.6.
*
* Thu May 25 09:14:33 CEST 2006: Martin Schulze <joey@infodrom.org>
* Removed asm/atomic.h since it is not needed anymore.
*
* Mon May 28 16:46:59 CEST 2007: Martin Schulze <joey@infodrom.org>
* Removed several structs not used anymore. Moved structs from
* ksym_mod.c over here.
*/
struct sym_table
{
unsigned long value;
char *name;
};
struct Module
{
struct sym_table *sym_array;
int num_syms;
char *name;
};

65
src/modutils.patch Normal file
View File

@@ -0,0 +1,65 @@
diff -u --new-file --recursive base/modules-2.0.0/depmod/modprobe.c ./modules-2.0.0/depmod/modprobe.c
--- base/modules-2.0.0/depmod/modprobe.c Mon Jun 10 05:29:08 1996
+++ ./modules-2.0.0/depmod/modprobe.c Thu Aug 29 09:58:01 1996
@@ -233,6 +233,13 @@
verbose ("\r\t%s\n\t\t",cmd);
int ret = system(cmd);
#endif
+ if ( fork() == 0 )
+ {
+ /* Child process. */
+ if ( execlp("klogd", "klogd", "-i", (char *) 0) < 0 )
+ fprintf(stderr, "Failure in signaling klogd.\n");
+ exit(0);
+ }
return ret;
}
/*
diff -u --new-file --recursive base/modules-2.0.0/insmod/insmod.c ./modules-2.0.0/insmod/insmod.c
--- base/modules-2.0.0/insmod/insmod.c Mon Jun 10 06:42:25 1996
+++ ./modules-2.0.0/insmod/insmod.c Thu Aug 29 09:56:53 1996
@@ -253,6 +253,18 @@
++n_stringpatches;
}
+
+void signal_klogd() {
+ if ( fork() == 0 )
+ {
+ if ( execlp("klogd", "klogd", "-i", (char *) 0) < 0 )
+ fprintf(stderr, "Failure in signaling klogd.\n");
+ exit(0);
+ }
+ return;
+}
+
+
int main(int argc, char **argv)
{
FILE *fp;
@@ -983,6 +995,8 @@
symvalue(sp) + addr, symtype, symname(sp));
}
+ signal_klogd();
+
if (nksyms > 0)
free(ksymtab); /* it has done its job */
@@ -1292,6 +1306,7 @@
--argc;
++argv;
}
+ signal_klogd();
return errors;
}
/* else recursive removal */
@@ -1353,6 +1368,8 @@
break;
}
}
+
+ signal_klogd();
return errors;
}

250
src/oops.c Normal file
View File

@@ -0,0 +1,250 @@
/*
oops.c - Dummy loadable module for testing klogd.
Copyright (c) 2007 Martin Schulze <joey@infodrom.org>
This file is part of the sysklogd package, a kernel and system log daemon.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Helpful documentation: http://www.tldp.org/LDP/lkmpg/2.6/html/
SYNOPSIS
echo TEXT > /proc/oops Emits TEXT via printk at log level
[<address+delta>] triggers klogd address decoding
echo level: info > /proc/oops Sets the log level to 'info'
echo oops > /proc/oops Creates a real oops, kills executing shell
cat /proc/oops Display current log level and last oops time
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/time.h>
#define MODNAME "oops"
#define PROCNAME "oops"
MODULE_AUTHOR("Martin Schulze <joey@infodrom.org>");
MODULE_DESCRIPTION("Oops module from klogd");
MODULE_LICENSE("GPL");
static DEFINE_MUTEX(oops_lock);
struct oops_t {
unsigned long lastoops;
int loglevel;
};
static struct oops_t oops_data;
static int procflag = 0;
struct code {
char *name;
int level;
};
struct code priorities[] = {
{"emerg", 0},
{"panic", 0}, /* DEPRECATED */
{"alert", 1},
{"crit", 2},
{"err", 3},
{"error", 3}, /* DEPRECATED */
{"warning", 4},
{"warn", 4}, /* DEPRECATED */
{"notice", 5},
{"info", 6},
{"debug", 7},
{NULL, -1}
};
void oops_decode_level (char *line)
{
char *p;
struct code *prio;
if (strncmp(line, "level:", 6))
return;
for (p = (char *)(line) + 6;*p == ' ' || *p == '\t';p++);
for (prio = priorities; prio->name; prio++)
if (!strcmp(p, prio->name)) {
oops_data.loglevel = prio->level;
return;
}
}
/*
* This routine will create a real and ugly oops
*/
static void oops(void)
{
auto unsigned long *p = (unsigned long *) 828282828;
*p = 5;
return;
}
static int oops_proc_open (struct inode *inode, struct file *file)
{
#ifdef DEBUG
printk (KERN_DEBUG "oops_proc_open().\n");
#endif
return 0;
}
static ssize_t
oops_proc_read (struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
char s[70];
int size;
struct code *prio;
char *level = NULL;
#ifdef DEBUG
printk (KERN_DEBUG "oops_proc_read(%d).\n",nbytes);
#endif
if (procflag) {
procflag = 0;
return 0;
}
for (prio = priorities;
prio->name && prio->level != oops_data.loglevel;
prio++);
level = prio->name;
if (oops_data.lastoops == 0)
size = sprintf (s, "Log level: %s\nLast oops: none\n", level);
else {
unsigned long now = get_seconds();
unsigned long delta = now - oops_data.lastoops;
size = sprintf (s, "Log level: %s\nLast oops: %lu (%lu second%s ago)\n",
level, oops_data.lastoops,
delta, delta == 1 ? "" : "s");
}
if (size < nbytes)
nbytes = size;
if (copy_to_user(buf, s, nbytes))
return -EFAULT;
*ppos += nbytes;
procflag++;
return nbytes;
}
static int
oops_proc_release(struct inode *inode, struct file *filp)
{
#ifdef DEBUG
printk (KERN_DEBUG "oops_proc_release().\n");
#endif
return 0;
}
static ssize_t
oops_proc_write(struct file *file, const char __user *buf,
size_t nbytes, loff_t *ppos)
{
char input[100];
int len;
#ifdef DEBUG
printk (KERN_DEBUG "oops_proc_write(%d).\n", nbytes);
#endif
len = nbytes >= sizeof(input) ? sizeof(input)-1 : nbytes;
if (copy_from_user(input, buf, len))
return -EFAULT;
input[len] = '\0';
if (input[len-1] == '\n')
input[len-1] = '\0';
if (!strncmp(input, "level:", 6))
oops_decode_level(input);
else if (!strcmp(input, "oops")) {
oops_data.lastoops = get_seconds();
oops();
} else
printk ("<%d>%s\n", oops_data.loglevel, input);
return nbytes;
}
static const struct file_operations oops_proc_operations = {
.read = oops_proc_read,
.release = oops_proc_release,
.write = oops_proc_write,
.open = oops_proc_open,
};
void oops_proc_add (void)
{
struct proc_dir_entry *entry;
mutex_lock (&oops_lock);
entry = create_proc_entry (PROCNAME, 0, NULL);
if (entry) {
entry->proc_fops = &oops_proc_operations;
}
mutex_unlock (&oops_lock);
}
void oops_proc_remove (void)
{
mutex_lock (&oops_lock);
remove_proc_entry(PROCNAME, NULL);
mutex_unlock(&oops_lock);
}
int oops_init (void)
{
printk (KERN_INFO "Loading module " MODNAME ".\n");
oops_data.lastoops = 0;
oops_data.loglevel = 5;
oops_proc_add();
return 0;
}
void oops_cleanup (void)
{
oops_proc_remove();
printk (KERN_INFO "Removing module " MODNAME ".\n");
}
module_init(oops_init);
module_exit(oops_cleanup);

140
src/pidfile.c Normal file
View File

@@ -0,0 +1,140 @@
/*
pidfile.c - interact with pidfiles
Copyright (c) 1995 Martin Schulze <Martin.Schulze@Linux.DE>
This file is part of the sysklogd package, a kernel and system log daemon.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA
*/
/*
* Sat Aug 19 13:24:33 MET DST 1995: Martin Schulze
* First version (v0.2) released
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
/* read_pid
*
* Reads the specified pidfile and returns the read pid.
* 0 is returned if either there's no pidfile, it's empty
* or no pid can be read.
*/
int read_pid (char *pidfile)
{
FILE *f;
int pid;
if (!(f=fopen(pidfile,"r")))
return 0;
fscanf(f,"%d", &pid);
fclose(f);
return pid;
}
/* check_pid
*
* Reads the pid using read_pid and looks up the pid in the process
* table (using /proc) to determine if the process already exists. If
* so 1 is returned, otherwise 0.
*/
int check_pid (char *pidfile)
{
int pid = read_pid(pidfile);
/* Amazing ! _I_ am already holding the pid file... */
if ((!pid) || (pid == getpid ()))
return 0;
/*
* The 'standard' method of doing this is to try and do a 'fake' kill
* of the process. If an ESRCH error is returned the process cannot
* be found -- GW
*/
/* But... errno is usually changed only on error.. */
if (kill(pid, 0) && errno == ESRCH)
return(0);
return pid;
}
/* write_pid
*
* Writes the pid to the specified file. If that fails 0 is
* returned, otherwise the pid.
*/
int write_pid (char *pidfile)
{
FILE *f;
int fd;
int pid;
if ( ((fd = open(pidfile, O_RDWR|O_CREAT|O_TRUNC, 0644)) == -1)
|| ((f = fdopen(fd, "r+")) == NULL) ) {
fprintf(stderr, "Can't open or create %s.\n", pidfile);
return 0;
}
if (flock(fd, LOCK_EX|LOCK_NB) == -1) {
fscanf(f, "%d", &pid);
fclose(f);
printf("Can't lock, lock is held by pid %d.\n", pid);
return 0;
}
pid = getpid();
if (!fprintf(f,"%d\n", pid)) {
printf("Can't write pid , %s.\n", strerror(errno));
close(fd);
return 0;
}
fflush(f);
if (flock(fd, LOCK_UN) == -1) {
printf("Can't unlock pidfile %s, %s.\n", pidfile, strerror(errno));
close(fd);
return 0;
}
close(fd);
return pid;
}
/* touch_pid
*
* Touches the specified pidfile f.ex. when receiving a SIGHUP
* The result from utimensat() is returned
*/
int touch_pid (char *pidfile)
{
return utimensat(0, pidfile, NULL, 0);
}
/* remove_pid
*
* Remove the the specified file. The result from unlink(2)
* is returned
*/
int remove_pid (char *pidfile)
{
return unlink (pidfile);
}

57
src/pidfile.h Normal file
View File

@@ -0,0 +1,57 @@
/*
pidfile.h - interact with pidfiles
Copyright (c) 1995 Martin Schulze <Martin.Schulze@Linux.DE>
This file is part of the sysklogd package, a kernel and system log daemon.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
/* read_pid
*
* Reads the specified pidfile and returns the read pid.
* 0 is returned if either there's no pidfile, it's empty
* or no pid can be read.
*/
int read_pid (char *pidfile);
/* check_pid
*
* Reads the pid using read_pid and looks up the pid in the process
* table (using /proc) to determine if the process already exists. If
* so 1 is returned, otherwise 0.
*/
int check_pid (char *pidfile);
/* write_pid
*
* Writes the pid to the specified file. If that fails 0 is
* returned, otherwise the pid.
*/
int write_pid (char *pidfile);
/* touch_pid
*
* Touches the specified pidfile f.ex. when receiving a SIGHUP
* The result from utimensat() is returned
*/
int touch_pid (char *pidfile);
/* remove_pid
*
* Remove the the specified file. The result from unlink(2)
* is returned
*/
int remove_pid (char *pidfile);

0
src/syslog-tst.conf Normal file
View File

267
src/syslog.c Normal file
View File

@@ -0,0 +1,267 @@
/*
* Copyright (c) 1983, 1988 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted provided
* that: (1) source distributions retain this entire copyright notice and
* comment, and (2) distributions including binaries display the following
* acknowledgement: ``This product includes software developed by the
* University of California, Berkeley and its contributors'' in the
* documentation or other materials provided with the distribution and in
* all advertising materials mentioning features or use of this software.
* Neither the name of the University nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)syslog.c 5.28 (Berkeley) 6/27/90";
#endif /* LIBC_SCCS and not lint */
/*
* SYSLOG -- print message on log file
*
* This routine looks a lot like printf, except that it outputs to the
* log file instead of the standard output. Also:
* adds a timestamp,
* prints the module name in front of the message,
* has some other formatting types (or will sometime),
* adds a newline on the end of the message.
*
* The output of this routine is intended to be read by syslogd(8).
*
* Author: Eric Allman
* Modified to use UNIX domain IPC by Ralph Campbell
*
* Sat Dec 11 11:58:31 CST 1993: Dr. Wettstein
* Changes to allow compilation with no complains under -Wall.
*
* Thu Jan 18 11:16:11 CST 1996: Dr. Wettstein
* Added patch to close potential security hole. This is the same
* patch which was announced in the linux-security mailing lists
* and incorporated into the libc version of syslog.c.
*
* Sun Mar 11 20:23:44 CET 2001: Martin Schulze <joey@infodrom.ffis.de>
* Use SOCK_DGRAM for loggin, renables it to work.
*
* Wed Aug 27 17:48:16 CEST 2003: Martin Schulze <joey@Infodrom.org>
* Improved patch by Michael Pomraning <mjp@securepipe.com> to
* reconnect klogd to the logger after it went away.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/signal.h>
#include <sys/syslog.h>
#if 0
#include "syslog.h"
#include "pathnames.h"
#endif
#include <sys/uio.h>
#include <sys/wait.h>
#include <netdb.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include <paths.h>
#include <stdio.h>
#define _PATH_LOGNAME "/dev/log"
static int LogFile = -1; /* fd for log */
static int connected; /* have done connect */
static int LogStat = 0; /* status bits, set by openlog() */
static const char *LogTag = "syslog"; /* string to tag the entry with */
static int LogFacility = LOG_USER; /* default facility code */
void
syslog(int pri, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsyslog(pri, fmt, ap);
va_end(ap);
}
void
vsyslog(pri, fmt, ap)
int pri;
const char *fmt;
va_list ap;
{
register int cnt;
register char *p;
time_t now;
int fd, saved_errno;
int result;
char tbuf[2048], fmt_cpy[1024], *stdp = (char *) 0;
saved_errno = errno;
/* see if we should just throw out this message */
if (!LOG_MASK(LOG_PRI(pri)) || (pri &~ (LOG_PRIMASK|LOG_FACMASK)))
return;
if (LogFile < 0 || !connected)
openlog(LogTag, LogStat | LOG_NDELAY, LogFacility);
/* set default facility if none specified */
if ((pri & LOG_FACMASK) == 0)
pri |= LogFacility;
/* build the message */
(void)time(&now);
(void)sprintf(tbuf, "<%d>%.15s ", pri, ctime(&now) + 4);
for (p = tbuf; *p; ++p);
if (LogStat & LOG_PERROR)
stdp = p;
if (LogTag) {
(void)strcpy(p, LogTag);
for (; *p; ++p);
}
if (LogStat & LOG_PID) {
(void)sprintf(p, "[%d]", getpid());
for (; *p; ++p);
}
if (LogTag) {
*p++ = ':';
*p++ = ' ';
}
/* substitute error message for %m */
{
register char ch, *t1, *t2;
char *strerror();
for (t1 = fmt_cpy;
(ch = *fmt) != '\0' && t1<fmt_cpy+sizeof(fmt_cpy);
++fmt)
if (ch == '%' && fmt[1] == 'm') {
++fmt;
for (t2 = strerror(saved_errno);
(*t1 = *t2++); ++t1);
}
else
*t1++ = ch;
*t1 = '\0';
}
(void)vsprintf(p, fmt_cpy, ap);
cnt = strlen(tbuf);
/* output to stderr if requested */
if (LogStat & LOG_PERROR) {
struct iovec iov[2];
register struct iovec *v = iov;
v->iov_base = stdp;
v->iov_len = cnt - (stdp - tbuf);
++v;
v->iov_base = "\n";
v->iov_len = 1;
(void)writev(2, iov, 2);
}
/* output the message to the local logger */
result = write(LogFile, tbuf, cnt + 1);
if (result == -1
&& (errno == ECONNRESET || errno == ENOTCONN || errno == ECONNREFUSED)) {
closelog();
openlog(LogTag, LogStat | LOG_NDELAY, LogFacility);
result = write(LogFile, tbuf, cnt + 1);
}
if (result >= 0 || !(LogStat&LOG_CONS))
return;
/*
* output the message to the console; don't worry about
* blocking, if console blocks everything will.
*/
if ((fd = open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY, 0)) < 0)
return;
(void)strcat(tbuf, "\r\n");
cnt += 2;
p = index(tbuf, '>') + 1;
(void)write(fd, p, cnt - (p - tbuf));
(void)close(fd);
}
#ifndef TESTING
static struct sockaddr SyslogAddr; /* AF_UNIX address of local logger */
#endif
/*
* OPENLOG -- open system log
*/
void
openlog(ident, logstat, logfac)
const char *ident;
int logstat, logfac;
{
if (ident != NULL)
LogTag = ident;
LogStat = logstat;
#ifdef ALLOW_KERNEL_LOGGING
if ((logfac &~ LOG_FACMASK) == 0)
#else
if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
#endif
LogFacility = logfac;
#ifndef TESTING
if (LogFile == -1) {
SyslogAddr.sa_family = AF_UNIX;
strncpy(SyslogAddr.sa_data, _PATH_LOGNAME,
sizeof(SyslogAddr.sa_data));
if (LogStat & LOG_NDELAY) {
LogFile = socket(AF_UNIX, SOCK_DGRAM, 0);
/* fcntl(LogFile, F_SETFD, 1); */
}
}
if (LogFile != -1 && !connected &&
connect(LogFile, &SyslogAddr, sizeof(SyslogAddr.sa_family)+
strlen(SyslogAddr.sa_data)) != -1)
#else
LogFile = fileno(stdout);
#endif
connected = 1;
}
/*
* CLOSELOG -- close the system log
*/
void
closelog()
{
#ifndef TESTING
(void) close(LogFile);
#endif
LogFile = -1;
connected = 0;
}
static int LogMask = 0xff; /* mask of priorities to be logged */
/*
* SETLOGMASK -- set the log mask level
*/
int
setlogmask(pmask)
int pmask;
{
int omask;
omask = LogMask;
if (pmask != 0)
LogMask = pmask;
return (omask);
}

74
src/syslog_tst.c Normal file
View File

@@ -0,0 +1,74 @@
/* Program to test daemon logging. */
/*
* Sat Dec 11 12:07:50 CST 1993: Dr. Wettstein
* Compiles clean with -Wall. Renamed for first public distribution.
* Use this freely but if you make a ton of money with it I
* expect a cut... :-)
*
* Thu Jan 6 11:52:10 CST 1994: Dr. Wettstein
* Added support for reading getting log input from the standard
* input. To activate this use a - as the single arguement to the
* the program. Note that there is a hack in the code to pause
* after each 1K has been written. This eliminates what appears
* to be a problem with overrunning a UNIX domain socket with
* excessive amounts of input.
*/
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/param.h>
extern int main(int, char **);
int main(int argc, char *argv[])
{
auto char *nl,
bufr[512];
auto int logged = 0;
openlog("DOTEST", LOG_PID, LOG_DAEMON);
if (argc > 1)
{
if ( (*argv[1] == '-') && (*(argv[1]+1) == '\0') )
{
while (!feof(stdin))
if ( fgets(bufr, sizeof(bufr), stdin) != \
(char *) 0 )
{
if ( (nl = strrchr(bufr, '\n')) != \
(char *) 0)
*nl = '\0';
syslog(LOG_INFO, "%s", bufr);
logged += strlen(bufr);
if ( logged > 1024 )
{
sleep(1);
logged = 0;
}
}
}
else
while (argc-- > 1)
syslog(LOG_INFO, "%s", argv++[1]);
}
else
{
syslog(LOG_EMERG, "EMERG log.");
syslog(LOG_ALERT, "Alert log.");
syslog(LOG_CRIT, "Critical log.");
syslog(LOG_ERR, "Error log.");
syslog(LOG_WARNING, "Warning log.");
syslog(LOG_NOTICE, "Notice log.");
syslog(LOG_INFO, "Info log.");
syslog(LOG_DEBUG, "Debug log.");
closelog();
return(0);
}
return(0);
}

3140
src/syslogd.c Normal file

File diff suppressed because it is too large Load Diff