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:
62
src/MANIFEST
Normal file
62
src/MANIFEST
Normal 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
30
src/Makefile.am
Normal 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
142
src/Makefile.old
Normal 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
95
src/README.1st
Normal 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
77
src/README.linux
Normal 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
1204
src/klogd.c
Normal file
File diff suppressed because it is too large
Load Diff
40
src/klogd.h
Normal file
40
src/klogd.h
Normal 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
948
src/ksym.c
Normal 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
621
src/ksym_mod.c
Normal 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
35
src/ksyms.h
Normal 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
51
src/module.h
Normal 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
65
src/modutils.patch
Normal 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
250
src/oops.c
Normal 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
140
src/pidfile.c
Normal 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
57
src/pidfile.h
Normal 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
0
src/syslog-tst.conf
Normal file
267
src/syslog.c
Normal file
267
src/syslog.c
Normal 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
74
src/syslog_tst.c
Normal 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
3140
src/syslogd.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user