summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ANNOUNCE62
-rw-r--r--CHANGES32
-rw-r--r--COPYING339
-rw-r--r--INSTALL37
-rw-r--r--MANIFEST62
-rw-r--r--Makefile122
-rw-r--r--NEWS170
-rw-r--r--README.1st65
-rw-r--r--README.linux72
-rw-r--r--klogd.8441
-rw-r--r--klogd.c1191
-rw-r--r--klogd.h40
-rw-r--r--ksym.c901
-rw-r--r--ksym_mod.c700
-rw-r--r--ksyms.h35
-rw-r--r--modutils.patch65
-rw-r--r--oops.c118
-rw-r--r--oops_test.c52
-rw-r--r--pidfile.c130
-rw-r--r--pidfile.h50
-rw-r--r--sysklogd.8607
-rw-r--r--syslog-tst.conf0
-rw-r--r--syslog.c254
-rw-r--r--syslog.conf46
-rw-r--r--syslog.conf.5397
-rw-r--r--syslog_tst.c74
-rw-r--r--syslogd.81
-rw-r--r--syslogd.c2803
-rw-r--r--version.h2
29 files changed, 8868 insertions, 0 deletions
diff --git a/ANNOUNCE b/ANNOUNCE
new file mode 100644
index 00000000..aba171e7
--- /dev/null
+++ b/ANNOUNCE
@@ -0,0 +1,62 @@
+On behalf of the beta-testers and other members of the Linux INTERNET
+community who have helped shape and debug this package I am pleased to
+announce version 1.3-pl3 of the sysklogd package.
+
+This package implements two system log daemons. The syslogd daemon is
+an enhanced version of the standard Berkeley utility program. This
+daemon is responsible for providing logging of messages received from
+programs and facilities on the local host as well as from remote
+hosts. The klogd daemon listens to kernel message sources and is
+responsible for prioritizing and processing operating system
+messages. The klogd daemon can run as a client of syslogd or
+optionally as a standalone program.
+
+This 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 I would appreciate a report and debug information
+so that the bug can be reproduced and squashed.
+
+This package includes some major improvements. Some of them are listed
+here:
+
+ * klogd supports on-the-fly kernel address to symbol
+ translations. This requires that a valid kernel symbol map be
+ found at execution.
+
+ * klogd also supports debugging of protection faults which occur
+ in kernel loadable modules.
+
+ * syslogd has better handling of remote logging capabilities.
+
+ * both klogd and syslogd can be controlled through commandline
+ options and signals.
+
+ * both daemons are now FSSTND conform.
+
+ * a syslog.conf(5) manpage is now available.
+
+ * Spaces are now accepted in the syslog configuration
+ file. This should be a real crowd pleaser.
+
+ * Syslogd now uses dynamic allocation of logging output
+ descriptors. There is no longer a static limit on the number
+ of log destinations that can be defined.
+
+ * Numerous bug fixes and code cleanups.
+
+The new release can be obtained from either tsx-11.mit.edu or
+sunsite.unc.edu.
+
+Thanks again to everyone who has contributed ideas, patches and bug
+reports. Linux has a superior set of logging utilities thanks to
+contributions from the entire community.
+
+
+Dr. Greg Wettstein
+Oncology Research Division Computing Facility
+Roger Maris Cancer Center
+greg@wind.enjellic.com
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 00000000..25a50edc
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,32 @@
+Version 1.4.1
+
+ . klogd will set the console log level only if `-c' is given on the
+ commandline, not overwriting local settings in `/etc/sysctl.conf'.
+ . Bugfix: klogd will use SOCK_DGRM as well, re-enables kernel logging
+ . Bugfix: Don't make syslogd fail with broken `-a'
+ . Bugfix: klogd will skip zero bytes and not enter a busy loop anymore
+ . Thomas Roessler <roessler@does-not-exist.org>
+ - Patch to prevent LogLine() from being invoked with a negative
+ counter as an argument.
+
+Version 1.4
+
+ . Skip newline when reading in klog messages
+ . Use lseek64() instead of llseek() which is deprecated these days
+ . Close symbol file before returning with 0 when an error occurred
+ while reading it. This will enable systems to umount that
+ partition with no open file descriptor left over.
+ . Solar Designer <solar@false.com>
+ - printline() fixes
+ - priority decoding fix
+ . Daniel Jacobowitz <dan@debian.org>
+ - printchopped() fix
+ . Keith Owens <kaos@ocs.com.au>
+ - Fixed bug that caused klogd to die if there is no sym_array available.
+ - When symbols are expanded, print the line twice. Once with
+ addresses converted to symbols, once with the raw text. Allows
+ external programs such as ksymoops do their own processing on the
+ original data.
+ . Olaf Kirch <okir@caldera.de>
+ - Remove Unix Domain Sockets and switch to Datagram Unix Sockets
+ . Several bugfixes and improvements, please refer to the .c files
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..a43ea212
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 00000000..c7a0ad9e
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,37 @@
+1.) READ the README.linux file and the accompanying man pages. It will
+ save you some frustration.
+
+2.) Edit the Makefile for your installation. NOTE that if you have not
+ carried out step 1 you may make choices which could render your
+ system and/or these utilities unusable. Compile the utilities.
+ Compilation has been tested with versions 2.5.8, 2.6.3 and 2.7.0 of
+ the gcc compiler and libc versions 4.5.26 and 4.6.27.
+
+3.) The FSSTND makes suggestions as to appropriate locations for
+ system binaries. Since not everyone agrees with standards it is
+ up to the system administrator installing the utilities to choose
+ the most appropriate locations for the binaries and their
+ configuration files. By default the package will compile and
+ install following the FSSTND recommendations. If a decision is
+ made to change this behavior consult the makefile and the sources.
+ The FSSTND define controls selection of values which may be
+ influenced by the choice of conformance with the FSSTND or site
+ preferences.
+
+4.) For proper functioning both of these utilities are best run as root.
+ This is probably not much of a problem since they will probably be
+ started either by init or as part of the rc.* startup process. There
+ may be security concerns with running syslogd as root. Please repeat
+ step 1 if you are unsure of why this may be the case.
+
+5.) If kernel address to symbol translation is desired there is the
+ possibility that a new kernel will need to be compiled. The patches
+ to delimit kernel addresses requiring translation were added to
+ kernel 1.3.43. If this kernel or a newer kernel is used there is
+ no need to modify the kernel sources.
+
+ If a kernel earlier than this is used the kernel sources will have to
+ be patched. The patch to delimit addresses for translation is included
+ with the sysklogd sources. The necessary modifications are quite
+ generic and should require little modification over a wide range of
+ kernel sources.
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 00000000..be0cb61e
--- /dev/null
+++ b/MANIFEST
@@ -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.
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..6507e0a0
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,122 @@
+# Makefile for syslogd and klogd daemons.
+
+CC= gcc
+#CFLAGS= -g -DSYSV -Wall
+#LDFLAGS= -g
+CFLAGS= $(RPM_OPT_FLAGS) -O3 -DSYSV -fomit-frame-pointer -Wall -fno-strength-reduce
+LDFLAGS= -s
+
+# Look where your install program is.
+INSTALL = /usr/bin/install
+BINDIR = /usr/sbin
+MANDIR = /usr/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_OWNER = root
+# MAN_OWNER = man
+
+# 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 -DNO_SCCS ${FSSTND} \
+ ${SYSLOGD_PIDNAME}
+SYSLOG_FLAGS= -DALLOW_KERNEL_LOGGING
+KLOGD_FLAGS = ${FSSTND} ${KLOGD_START_DELAY}
+DEB =
+
+.c.o:
+ ${CC} ${CFLAGS} -c $*.c
+
+all: syslogd klogd
+
+test: syslog_tst ksym oops_test 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) $(CFLAGS) -g -DTESTING $(SYSLOGD_FLAGS) -o tsyslogd syslogd.c
+
+tklogd: klogd.c syslog.c ksym.c ksym_mod.c version.h
+ $(CC) $(CFLAGS) -g -DTESTING $(KLOGD_FLAGS) -o tklogd klogd.c syslog.c ksym.c ksym_mod.c
+
+syslogd.o: syslogd.c version.h
+ ${CC} ${CFLAGS} ${SYSLOGD_FLAGS} $(DEB) -c syslogd.c
+
+syslog.o: syslog.c
+ ${CC} ${CFLAGS} ${SYSLOG_FLAGS} -c syslog.c
+
+klogd.o: klogd.c klogd.h version.h
+ ${CC} ${CFLAGS} ${KLOGD_FLAGS} $(DEB) -c klogd.c
+
+ksym.o: ksym.c klogd.h
+ ${CC} ${CFLAGS} ${KLOGD_FLAGS} -c ksym.c
+
+ksym_mod.o: ksym_mod.c klogd.h
+ ${CC} ${CFLAGS} ${KLOGD_FLAGS} -c ksym_mod.c
+
+syslog_tst.o: syslog_tst.c
+ ${CC} ${CFLAGS} -c syslog_tst.c
+
+oops_test: oops.o
+ ${CC} ${CFLAGS} -o oops_test oops_test.c
+
+oops.o: oops.c
+ ${CC} ${CFLAGS} -D__KERNEL__ -DMODULE -c oops.c
+
+ksym: ksym_test.o ksym_mod.o
+ ${CC} ${LDFLAGS} -o ksym ksym_test.o ksym_mod.o
+
+ksym_test.o: ksym.c
+ ${CC} ${CFLAGS} -DTEST -o ksym_test.o -c ksym.c
+
+clean:
+ rm -f *.o *.log *~ *.orig
+
+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_OWNER} -g ${MAN_OWNER} -m 644 sysklogd.8 ${MANDIR}/man8/sysklogd.8
+ ${INSTALL} -o ${MAN_OWNER} -g ${MAN_OWNER} -m 644 syslogd.8 ${MANDIR}/man8/syslogd.8
+ ${INSTALL} -o ${MAN_OWNER} -g ${MAN_OWNER} -m 644 syslog.conf.5 ${MANDIR}/man5/syslog.conf.5
+ ${INSTALL} -o ${MAN_OWNER} -g ${MAN_OWNER} -m 644 klogd.8 ${MANDIR}/man8/klogd.8
diff --git a/NEWS b/NEWS
new file mode 100644
index 00000000..94d281c5
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,170 @@
+Version 1.3 Patch Level 3
+
+General. ------------------------------------------------------------------
+Update to documentation including klogd.8 manpage to reflect new features.
+
+Included patch for modules-2.0.0 package to provide support for signalling
+klogd of changes in kernel module status.
+
+klogd ---------------------------------------------------------------------
+Provided support for signalling klogd to reload static and kernel module
+symbol information via SIGUSR1 and SIGUSR2.
+
+Implemented -p switch to cause a reload of kernel module symbol information
+whenever a protection fault is detected.
+
+Informative message is printed whenever klogd state change occurs.
+
+Added -i and -I switches to signal the currently executing klogd daemon
+to reload symbold information.
+
+
+Version 1.3 Patch Level 2
+
+General. ------------------------------------------------------------------
+Added oops.c and oops_test.c. Oops.c implements a kernel loadable module
+which will generate a general protection fault. The oops_test.c program
+generates a test program for exercising the loadable module.
+
+syslogd ------------------------------------------------------------------
+Fixed bug resulting in file descriptors being orphaned when syslogd was
+initialized via signal handler.
+
+klogd ---------------------------------------------------------------------
+Bug fix to prevent errors when reading symbol tables with 64 bit addresses.
+
+Added support for debugging of protection faults occuring in kernel
+loadable modules.
+
+
+Version 1.3 Patch Level 1
+
+General. ------------------------------------------------------------------
+Cleanups in the Makefile.
+
+Patches to support compilation in the ALPHA environment. I have not
+been able to test these personally so if anyone has any feedback I
+would be interested in hearing from the Linux ALPHA community.
+
+Spelling and grammar corrections in the man pages.
+
+syslogd ------------------------------------------------------------------
+Patch to fix parsing of hostnames in syslogd.c.
+
+The return value of gethostbyname is now properly checked. This should
+fix the problems with core dumps when name resolution failed.
+
+Bounds error fixed when setting the file descriptors for UNIX domain
+sockets.
+
+klogd ---------------------------------------------------------------------
+Error checking and reporting enhanced. I have a couple of reports
+that klogd is experiencing errors when reading the /proc filesystem.
+Any additional information would be appreciated.
+
+The sys_syslog function has been renamed to ksyslog. This was in a
+set patches for ALPHA support so I am assuming that this is necessary
+for that environment
+
+
+Version 1.3
+
+Numerous changes, performance enhancements, code cleanups and bug fixes.
+Too many to individually summarize. Have a look at the top of each
+source file for more information.
+
+** Default behavior of sysklogd is not to accept any message that
+is sent via syslog/udp. To allow remote reception add -r to the
+command-line arguments.
+
+** Spaces are now accepted in the syslog configuration file. This
+should be a real crowd pleaser.
+
+syslogd now uses dynamic allocation of logging output descriptors.
+There is no longer a static limit on the number of log destinations
+that can be defined.
+
+klogd supports on-the-fly kernel address to symbol translations.
+This requires that a valid kernel symbol map be found at execution.
+
+** The default level for console log messages was changed to 6. This
+means that kernel messages with a priority less than or equal to 5
+(KERN_NOTICE) will be logged to the console.
+
+ This item has been flagged because it results in a behavior
+ change which will be different if version 1.3 replaces an
+ existing 1.2 binary. Linus strongly suggested that this
+ behavior be changed and in the 1.3.3x kernels Linus in fact
+ made it impossible to set the console log level lower than
+ about 5.
+
+ There were good reasons from his perspective for doing so.
+ The most troublesome being that user's of packaged
+ distributions were not able to generate register dumps with
+ the kernel debugging keys, most notably altgr-SCRLCK.
+
+ If a kernels prior to 1.3.3x are being used the klogd daemon
+ invocation must be changed to something like: klogd -c 1
+
+ This will turn off logging of kernel messages to the console.
+ If you understand the ramifications of this the 1.3.3x kernels
+ can be patched to allow the suppression of console log
+ messages. It is important to be cognizant of the effects of
+ these changes. None the least of which is that Linus and Alan
+ will yell at you if you complain about not being able to
+ generate kernel debugging information.. :-)
+
+---------------------------------------------------------------------------
+Version 1.2
+Fixes to both klogd and syslogd so that the package will compile without
+errors due to the vararg procedures.
+
+Modified pid files produced so that the names of the files are
+klogd.pid and syslogd.pid respectively.
+
+Fixed bug in klogd which prevented output from being directed to a file
+when the program was compiled to auto-background itself. In the
+auto-backgrounding configuration the forked process was closing all its
+file descriptors which was causing the errant behavior.
+
+Modified signal handling in klogd so that all signal are set to ignored
+before establishing specific signal handlers.
+
+Fixed bug in syslogd which was causing a delay in opening of the /dev/log
+UNIX domain socket. This should correct the race condition which was
+preventing klogd from properly logging kernel messages when the two
+daemons were started in rapid succession.
+
+Modified the closing/opening of file descriptors when syslogd was
+compiled with auto-backgrounding support. Closes the potential for
+a somewhat obscure bug caused by the /dev/log socket being opened on
+fd 0.
+
+Changed the names of the man pages from an extension of 1 to 8.
+---------------------------------------------------------------------------
+Version 1.1
+Extensive changes and additional functionality added to klogd. Please
+see sources and man-pages for documentation.
+
+Fixed bugs in both syslogd and klogd with respect to fragmented
+message re-assembly. Bootup messages should now be display properly.
+
+Fixed bug in syslogd which prevented proper logging of messages with
+priority classes of none and emerg.
+
+Fixed bug which caused core dump when messages were logged to users.
+Also fixed bug with messages to login type of LOGIN.
+
+Fixed problem with zombies being left when messages were logged to
+multiple users.
+
+Enhanced functionality of syslog_tst program.
+
+Added man-pages.
+---------------------------------------------------------------------------
+
+---------------------------------------------------------------------------
+Version 1.0
+
+Initial release.
+---------------------------------------------------------------------------
diff --git a/README.1st b/README.1st
new file mode 100644
index 00000000..39467563
--- /dev/null
+++ b/README.1st
@@ -0,0 +1,65 @@
+Very important information before using version 1.3
+---------------------------------------------------
+
+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.
diff --git a/README.linux b/README.linux
new file mode 100644
index 00000000..bfebf53e
--- /dev/null
+++ b/README.linux
@@ -0,0 +1,72 @@
+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 sysklogd@Infodrom.North.DE . To subscribe send a
+mail to Majordomo@Infodrom.North.DE with a line "subscribe sysklogd"
+in the message body.
+
+New versions of this package will be available at Joey's ftp server.
+ftp://ftp.infodrom.north.de/pub/people/joey/sysklogd/
+
+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@linux.de
+
+And a host of bug reporters whose contributions cannot be underestimated.
diff --git a/klogd.8 b/klogd.8
new file mode 100644
index 00000000..02949dad
--- /dev/null
+++ b/klogd.8
@@ -0,0 +1,441 @@
+.\" Copyright 1994 Dr. Greg Wettstein, Enjellic Systems Development.
+.\" May be distributed under the GNU General Public License
+.\" Sun Jul 30 01:35:55 MET: Martin Schulze: Updates
+.\" Sun Nov 19 23:22:21 MET: Martin Schulze: Updates
+.\" Mon Aug 19 09:42:08 CDT 1996: Dr. G.W. Wettstein: Updates
+.\"
+.TH KLOGD 8 "21 August, 1999" "Version 1.4" "Linux System Administration"
+.SH NAME
+klogd \- Kernel Log Daemon
+.LP
+.SH SYNOPSIS
+.B klogd
+.RB [ " \-c "
+.I n
+]
+.RB [ " \-d " ]
+.RB [ " \-f "
+.I fname
+]
+.RB [ " \-iI " ]
+.RB [ " \-n " ]
+.RB [ " \-o " ]
+.RB [ " \-p " ]
+.RB [ " \-s " ]
+.RB [ " \-k "
+.I fname
+]
+.RB [ " \-v " ]
+.RB [ " \-x " ]
+.RB [ " \-2 " ]
+.LP
+.SH DESCRIPTION
+.B klogd
+is a system daemon which intercepts and logs Linux kernel
+messages.
+.LP
+.SH OPTIONS
+.TP
+.BI "\-c " n
+Sets the default log level of console messages to \fIn\fR.
+.TP
+.B "\-d"
+Enable debugging mode. This will generate \fBLOTS\fR of output to
+stderr.
+.TP
+.BI "\-f " file
+Log messages to the specified filename rather than to the syslog facility.
+.TP
+.BI "\-i \-I"
+Signal the currently executing klogd daemon. Both of these switches control
+the loading/reloading of symbol information. The \-i switch signals the
+daemon to reload the kernel module symbols. The \-I switch signals for a
+reload of both the static kernel symbols and the kernel module symbols.
+.TP
+.B "\-n"
+Avoid auto-backgrounding. This is needed especially if the
+.B klogd
+is started and controlled by
+.BR init (8).
+.TP
+.B "-o"
+Execute in 'one\-shot' mode. This causes \fBklogd\fP to read and log
+all the messages that are found in the kernel message buffers. After
+a single read and log cycle the daemon exits.
+.TP
+.B "-p"
+Enable paranoia. This option controls when klogd loads kernel module symbol
+information. Setting this switch causes klogd to load the kernel module
+symbol information whenever an Oops string is detected in the kernel message
+stream.
+.TP
+.B "-s"
+Force \fBklogd\fP to use the system call interface to the kernel message
+buffers.
+.TP
+.BI "\-k " file
+Use the specified file as the source of kernel symbol information.
+.TP
+.B "\-v"
+Print version and exit.
+.TP
+.B "\-x"
+Omits EIP translation and therefore doesn't read the System.map file.
+.TP
+.B "\-2"
+When symbols are expanded, print the line twice. Once with addresses
+converted to symbols, once with the raw text. This allows external
+programs such as ksymoops do their own processing on the original
+data.
+.LP
+.SH OVERVIEW
+The functionality of klogd has been typically incorporated into other
+versions of syslogd but this seems to be a poor place for it. In the
+modern Linux kernel a number of kernel messaging issues such as
+sourcing, prioritization and resolution of kernel addresses must be
+addressed. Incorporating kernel logging into a separate process
+offers a cleaner separation of services.
+
+In Linux there are two potential sources of kernel log information: the
+.I /proc
+file system and the syscall (sys_syslog) interface, although
+ultimately they are one and the same. Klogd is designed to choose
+whichever source of information is the most appropriate. It does this
+by first checking for the presence of a mounted
+.I /proc
+file system. If this is found the
+.I /proc/kmsg
+file is used as the source of kernel log
+information. If the proc file system is not mounted
+.B klogd
+uses a
+system call to obtain kernel messages. The command line switch
+.RB ( "\-s" )
+can be used to force klogd to use the system call interface as its
+messaging source.
+
+If kernel messages are directed through the
+.BR syslogd " daemon the " klogd
+daemon, as of version 1.1, has the ability to properly prioritize
+kernel messages. Prioritization of the kernel messages was added to it
+at approximately version 0.99pl13 of the kernel. The raw kernel messages
+are of the form:
+.IP
+\<[0\-7]\>Something said by the kernel.
+.PP
+The priority of the kernel message is encoded as a single numeric
+digit enclosed inside the <> pair. The definitions of these values is
+given in the kernel include file kernel.h. When a message is received
+from the kernel the klogd daemon reads this priority level and assigns
+the appropriate priority level to the syslog message. If file output
+(\fB-f\fR) is used the prioritization sequence is left pre\-pended to the
+kernel message.
+
+The
+.B klogd
+daemon also allows the ability to alter the presentation of
+kernel messages to the system console. Consequent with the
+prioritization of kernel messages was the inclusion of default
+messaging levels for the kernel. In a stock kernel the the default
+console log level is set to 7. Any messages with a priority level
+numerically lower than 7 (higher priority) appear on the console.
+
+Messages of priority level 7 are considered to be 'debug' messages and
+will thus not appear on the console. Many administrators,
+particularly in a multi\-user environment, prefer that all kernel
+messages be handled by klogd and either directed to a file or to
+the syslogd daemon. This prevents 'nuisance' messages such as line
+printer out of paper or disk change detected from cluttering the
+console.
+
+When
+.B \-c
+is given on the commandline the
+.B klogd
+daemon will execute a system call to inhibit all kernel messages from
+being displayed on the console. Former versions always issued this
+system call and defaulted to all kernel messages except for panics.
+This is handled differently nowardays so
+.B klogd
+doesn't need to set this value anymore. The
+argument given to the \fB\-c\fR switch specifies the priority level of
+messages which will be directed to the console. Note that messages of
+a priority value LOWER than the indicated number will be directed to
+the console.
+.IP
+For example, to have the kernel display all messages with a
+priority level of 3
+.BR "" ( KERN_ERR )
+or more severe the following
+command would be executed:
+.IP
+.nf
+ klogd \-c 4
+.fi
+.PP
+The definitions of the numeric values for kernel messages are given in
+the file
+.IR kernel.h " which can be found in the " /usr/include/linux
+directory if the kernel sources are installed. These values parallel
+the syslog priority values which are defined in the file
+.IR syslog.h " found in the " /usr/include/sys " sub\-directory."
+
+The klogd daemon can also be used in a 'one\-shot' mode for reading the
+kernel message buffers. One shot mode is selected by specifying the
+\fB\-o\fR switch on the command line. Output will be directed to either the
+syslogd daemon or to an alternate file specified by the \fB-f\fR switch.
+.IP
+For example, to read all the kernel messages after a system
+boot and record them in a file called krnl.msg the following
+command would be given.
+.IP
+.nf
+ klogd -o -f ./krnl.msg
+.fi
+.PP
+.SH KERNEL ADDRESS RESOLUTION
+If the kernel detects an internal error condition a general protection
+fault will be triggered. As part of the GPF handling procedure the
+kernel prints out a status report indicating the state of the
+processor at the time of the fault. Included in this display are the
+contents of the microprocessor's registers, the contents of the kernel
+stack and a tracing of what functions were being executed at the time
+of the fault.
+
+This information is
+.B EXTREMELY IMPORTANT
+in determining what caused the internal error condition. The
+difficulty comes when a kernel developer attempts to analyze this
+information. The raw numeric information present in the protection
+fault printout is of very little use to the developers. This is due
+to the fact that kernels are not identical and the addresses of
+variable locations or functions will not be the same in all kernels.
+In order to correctly diagnose the cause of failure a kernel developer
+needs to know what specific kernel functions or variable locations
+were involved in the error.
+
+As part of the kernel compilation process a listing is created which
+specified the address locations of important variables and function in
+the kernel being compiled. This listing is saved in a file called
+System.map in the top of the kernel directory source tree. Using this
+listing a kernel developer can determine exactly what the kernel was
+doing when the error condition occurred.
+
+The process of resolving the numeric addresses from the protection
+fault printout can be done manually or by using the
+.B ksymoops
+program which is included in the kernel sources.
+
+As a convenience
+.B klogd
+will attempt to resolve kernel numeric addresses to their symbolic
+forms if a kernel symbol table is available at execution time. If you
+require the original address of the symbol, use the
+.B -2
+switch to preserve the numeric address. A
+symbol table may be specified by using the \fB\-k\fR switch on the
+command line. If a symbol file is not explicitly specified the
+following filenames will be tried:
+
+.nf
+.I /boot/System.map
+.I /System.map
+.I /usr/src/linux/System.map
+.fi
+
+Version information is supplied in the system maps as of kernel
+1.3.43. This version information is used to direct an intelligent
+search of the list of symbol tables. This feature is useful since it
+provides support for both production and experimental kernels.
+
+For example a production kernel may have its map file stored in
+/boot/System.map. If an experimental or test kernel is compiled with
+the sources in the 'standard' location of /usr/src/linux the system
+map will be found in /usr/src/linux/System.map. When klogd starts
+under the experimental kernel the map in /boot/System.map will be
+bypassed in favor of the map in /usr/src/linux/System.map.
+
+Modern kernels as of 1.3.43 properly format important kernel addresses
+so that they will be recognized and translated by klogd. Earlier
+kernels require a source code patch be applied to the kernel sources.
+This patch is supplied with the sysklogd sources.
+
+The process of analyzing kernel protections faults works very well
+with a static kernel. Additional difficulties are encountered when
+attempting to diagnose errors which occur in loadable kernel modules.
+Loadable kernel modules are used to implement kernel functionality in
+a form which can be loaded or unloaded at will. The use of loadable
+modules is useful from a debugging standpoint and can also be useful
+in decreasing the amount of memory required by a kernel.
+
+The difficulty with diagnosing errors in loadable modules is due to
+the dynamic nature of the kernel modules. When a module is loaded the
+kernel will allocate memory to hold the module, when the module is
+unloaded this memory will be returned back to the kernel. This
+dynamic memory allocation makes it impossible to produce a map file
+which details the addresses of the variable and functions in a kernel
+loadable module. Without this location map it is not possible for a
+kernel developer to determine what went wrong if a protection fault
+involves a kernel module.
+
+.B klogd
+has support for dealing with the problem of diagnosing protection
+faults in kernel loadable modules. At program start time or in
+response to a signal the daemon will interrogate the kernel for a
+listing of all modules loaded and the addresses in memory they are
+loaded at. Individual modules can also register the locations of
+important functions when the module is loaded. The addresses of these
+exported symbols are also determined during this interrogation
+process.
+
+When a protection fault occurs an attempt will be made to resolve
+kernel addresses from the static symbol table. If this fails the
+symbols from the currently loaded modules are examined in an attempt
+to resolve the addresses. At the very minimum this allows klogd to
+indicate which loadable module was responsible for generating the
+protection fault. Additional information may be available if the
+module developer chose to export symbol information from the module.
+
+Proper and accurate resolution of addresses in kernel modules requires
+that
+.B klogd
+be informed whenever the kernel module status changes. The
+.B \-i
+and
+.B \-I
+switches can be used to signal the currently executing daemon that
+symbol information be reloaded. Of most importance to proper
+resolution of module symbols is the
+.B \-i
+switch. Each time a kernel module is loaded or removed from the
+kernel the following command should be executed:
+
+.nf
+.I klogd \-i
+.fi
+
+The
+.B \-p
+switch can also be used to insure that module symbol information is up
+to date. This switch instructs
+.B klogd
+to reload the module symbol information whenever a protection fault
+is detected. Caution should be used before invoking the program in
+\'paranoid\' mode. The stability of the kernel and the operating
+environment is always under question when a protection fault occurs.
+Since the klogd daemon must execute system calls in order to read the
+module symbol information there is the possibility that the system may
+be too unstable to capture useful information. A much better policy
+is to insure that klogd is updated whenever a module is loaded or
+unloaded. Having uptodate symbol information loaded increases the
+probability of properly resolving a protection fault if it should occur.
+
+Included in the sysklogd source distribution is a patch to the
+modules-2.0.0 package which allows the
+.B insmod,
+.B rmmod
+and
+.B modprobe
+utilities to automatically signal
+.B klogd
+whenever a module is inserted or removed from the kernel. Using this
+patch will insure that the symbol information maintained in klogd is
+always consistent with the current kernel state.
+.PP
+.SH SIGNAL HANDLING
+The
+.B klogd
+will respond to eight signals:
+.BR SIGHUP ", " SIGINT ", " SIGKILL ", " SIGTERM ", " SIGTSTP ", "
+.BR SIGUSR1 ", "SIGUSR2 " and " SIGCONT ". The"
+.BR SIGINT ", " SIGKILL ", " SIGTERM " and " SIGHUP
+signals will cause the daemon to close its kernel log sources and
+terminate gracefully.
+
+The
+.BR SIGTSTP " and " SIGCONT
+signals are used to start and stop kernel logging. Upon receipt of a
+.B SIGTSTP
+signal the daemon will close its
+log sources and spin in an idle loop. Subsequent receipt of a
+.B SIGCONT
+signal will cause the daemon to go through its initialization sequence
+and re-choose an input source. Using
+.BR SIGSTOP " and " SIGCONT
+in combination the kernel log input can be re-chosen without stopping and
+restarting the daemon. For example if the \fI/proc\fR file system is to be
+un-mounted the following command sequence should be used:
+.PP
+.PD 0
+.TP
+ # kill -TSTP pid
+.TP
+ # umount /proc
+.TP
+ # kill -CONT pid
+.PD
+.PP
+Notations will be made in the system logs with
+.B LOG_INFO
+priority
+documenting the start/stop of logging.
+
+The
+.BR SIGUSR1 " and " SIGUSR2
+signals are used to initiate loading/reloading of kernel symbol information.
+Receipt of the
+.B SIGUSR1
+signal will cause the kernel module symbols to be reloaded. Signaling the
+daemon with
+.B SIGUSR2
+will cause both the static kernel symbols and the kernel module symbols to
+be reloaded.
+
+Provided that the System.map file is placed in an appropriate location the
+signal of generally greatest usefulness is the
+.B SIGUSR1
+signal. This signal is designed to be used to signal the daemon when kernel
+modules are loaded/unloaded. Sending this signal to the daemon after a
+kernel module state change will insure that proper resolution of symbols will
+occur if a protection fault occurs in the address space occupied by a kernel
+module.
+.LP
+.SH FILES
+.PD 0
+.TP
+.I /proc/kmsg
+One Source for kernel messages
+.B klogd
+.TP
+.I /var/run/klogd.pid
+The file containing the process id of
+.B klogd
+.TP
+.I /boot/System.map, /System.map, /usr/src/linux/System.map
+Default locations for kernel system maps.
+.PD
+.SH BUGS
+Probably numerous. Well formed context diffs appreciated.
+.LP
+.SH AUTHOR
+The
+.B klogd
+was originally written by Steve Lord (lord@cray.com), Greg Wettstein
+made major improvements.
+
+.PD 0
+.TP
+Dr. Greg Wettstein (greg@wind.enjellic.com)
+.TP
+Enjellic Systems Development
+.PD
+.PP
+.PD 0
+.TP
+Oncology Research Divsion Computing Facility
+.TP
+Roger Maris Cancer Center
+.TP
+Fargo, ND 58122
+.PD
+.zZ
diff --git a/klogd.c b/klogd.c
new file mode 100644
index 00000000..2c8e765e
--- /dev/null
+++ b/klogd.c
@@ -0,0 +1,1191 @@
+/*
+ klogd.c - main program 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.
+*/
+
+/*
+ * Steve Lord (lord@cray.com) 7th Nov 92
+ *
+ * Modified to check for kernel info by Dr. G.W. Wettstein 02/17/93.
+ *
+ * Fri Mar 12 16:53:56 CST 1993: Dr. Wettstein
+ * Modified LogLine to use a newline as the line separator in
+ * the kernel message buffer.
+ *
+ * Added debugging code to dump the contents of the kernel message
+ * buffer at the start of the LogLine function.
+ *
+ * Thu Jul 29 11:40:32 CDT 1993: Dr. Wettstein
+ * Added syscalls to turn off logging of kernel messages to the
+ * console when klogd becomes responsible for kernel messages.
+ *
+ * klogd now catches SIGTERM and SIGKILL signals. Receipt of these
+ * signals cases the clean_up function to be called which shuts down
+ * kernel logging and re-enables logging of messages to the console.
+ *
+ * Sat Dec 11 11:54:22 CST 1993: Dr. Wettstein
+ * Added fixes to allow compilation with no complaints with -Wall.
+ *
+ * When the daemon catches a fatal signal (SIGTERM, SIGKILL) a
+ * message is output to the logfile advising that the daemon is
+ * going to terminate.
+ *
+ * Thu Jan 6 11:54:10 CST 1994: Dr. Wettstein
+ * Major re-write/re-organization of the code.
+ *
+ * Klogd now assigns kernel messages to priority levels when output
+ * to the syslog facility is requested. The priority level is
+ * determined by decoding the prioritization sequence which is
+ * tagged onto the start of the kernel messages.
+ *
+ * Added the following program options: -f arg -c arg -s -o -d
+ *
+ * The -f switch can be used to specify that output should
+ * be written to the named file.
+ *
+ * The -c switch is used to specify the level of kernel
+ * messages which are to be directed to the console.
+ *
+ * The -s switch causes the program to use the syscall
+ * interface to the kernel message facility. This can be
+ * used to override the presence of the /proc filesystem.
+ *
+ * The -o switch causes the program to operate in 'one-shot'
+ * mode. A single call will be made to read the complete
+ * kernel buffer. The contents of the buffer will be
+ * output and the program will terminate.
+ *
+ * The -d switch causes 'debug' mode to be activated. This
+ * will cause the daemon to generate LOTS of output to stderr.
+ *
+ * The buffer decomposition function (LogLine) was re-written to
+ * squash a bug which was causing only partial kernel messages to
+ * be written to the syslog facility.
+ *
+ * The signal handling code was modified to properly differentiate
+ * between the STOP and TSTP signals.
+ *
+ * Added pid saving when the daemon detaches into the background. Thank
+ * you to Juha Virtanen (jiivee@hut.fi) for providing this patch.
+ *
+ * Mon Feb 6 07:31:29 CST 1995: Dr. Wettstein
+ * Significant re-organization of the signal handling code. The
+ * signal handlers now only set variables. Not earth shaking by any
+ * means but aesthetically pleasing to the code purists in the group.
+ *
+ * Patch to make things more compliant with the file system standards.
+ * Thanks to Chris Metcalf for prompting this helpful change.
+ *
+ * The routines responsible for reading the kernel log sources now
+ * initialize the buffers before reading. I think that this will
+ * solve problems with non-terminated kernel messages producing
+ * output of the form: new old old old
+ *
+ * This may also help influence the occassional reports of klogd
+ * failing under significant load. I think that the jury may still
+ * be out on this one though. My thanks to Joerg Ahrens for initially
+ * tipping me off to the source of this problem. Also thanks to
+ * Michael O'Reilly for tipping me off to the best fix for this problem.
+ * And last but not least Mark Lord for prompting me to try this as
+ * a means of attacking the stability problem.
+ *
+ * Specifying a - as the arguement to the -f switch will cause output
+ * to be directed to stdout rather than a filename of -. Thanks to
+ * Randy Appleton for a patch which prompted me to do this.
+ *
+ * Wed Feb 22 15:37:37 CST 1995: Dr. Wettstein
+ * Added version information to logging startup messages.
+ *
+ * Wed Jul 26 18:57:23 MET DST 1995: Martin Schulze
+ * Added an commandline argument "-n" to avoid forking. This obsoletes
+ * the compiler define NO_FORK. It's more useful to have this as an
+ * argument as there are many binary versions and one doesn't need to
+ * recompile the daemon.
+ *
+ * Thu Aug 10 19:01:08 MET DST 1995: Martin Schulze
+ * Added my pidfile.[ch] to it to perform a better handling with pidfiles.
+ * Now both, syslogd and klogd, can only be started once. They check the
+ * pidfile.
+ *
+ * Fri Nov 17 15:05:43 CST 1995: Dr. Wettstein
+ * Added support for kernel address translation. This required moving
+ * some definitions and includes to the new klogd.h file. Some small
+ * code cleanups and modifications.
+ *
+ * Mon Nov 20 10:03:39 MET 1995
+ * Added -v option to print the version and exit.
+ *
+ * Thu Jan 18 11:19:46 CST 1996: Dr. Wettstein
+ * Added suggested patches from beta-testers. These address two
+ * two problems. The first is segmentation faults which occur with
+ * the ELF libraries. This was caused by passing a null pointer to
+ * the strcmp function.
+ *
+ * Added a second patch to remove the pidfile as part of the
+ * termination cleanup sequence. This minimizes the potential for
+ * conflicting pidfiles causing immediate termination at boot time.
+ *
+ * Wed Aug 21 09:13:03 CDT 1996: Dr. Wettstein
+ * Added ability to reload static symbols and kernel module symbols
+ * under control of SIGUSR1 and SIGUSR2 signals.
+ *
+ * Added -p switch to select 'paranoid' behavior with respect to the
+ * loading of kernel module symbols.
+ *
+ * Informative line now printed whenever a state change occurs due
+ * to signal reception by the daemon.
+ *
+ * Added the -i and -I command line switches to signal the currently
+ * executing daemon.
+ *
+ * Tue Nov 19 10:15:36 PST 1996: Leland Olds <olds@eskimo.com>
+ * Corrected vulnerability to buffer overruns by rewriting LogLine
+ * routine. Obscenely long kernel messages will now be broken up
+ * into lines no longer than LOG_LINE_LENGTH.
+ *
+ * The last version of LogLine was vulnerable to buffer overruns:
+ * - Kernel messages longer than LOG_LINE_LENGTH caused a buffer
+ * overrun.
+ * - If a line was determined to be shorter than LOG_LINE_LENGTH,
+ * the routine "ExpandKadds" could cause the line grow by
+ * an unknown amount and overrun a buffer.
+ * I turned these routines into a little parsing state machine that
+ * should not have these problems.
+ *
+ * Sun Jun 15 16:23:29 MET DST 1997: Michael Alan Dorman
+ * Some more glibc patches made by <mdorman@debian.org>.
+ *
+ * Thu Aug 21 12:11:27 MET DST 1997: Martin Schulze <joey@infodrom.north.de>
+ * Fixed little mistake which prevented klogd from accepting a
+ * console log
+ *
+ * Fri Jan 9 00:39:52 CET 1998: Martin Schulze <joey@infodrom.north.de>
+ * Changed the behaviour of klogd when receiving a terminate
+ * signal. Now the program terminates immediately instead of
+ * completing the receipt of a kernel message, i.e the read()
+ * call. The old behaveiour could result in klogd being
+ * recognized as being undead, because it'll only die after a
+ * message has been received.
+ *
+ * Fri Jan 9 11:03:48 CET 1998: Martin Schulze <joey@infodrom.north.de>
+ * Corrected some code that caused klogd to dump core when
+ * receiving messages containing '%', some of them exist in
+ * 2.1.78. Thanks to Chu-yeon Park <kokids@doit.ajou.ac.kr> for
+ * informing me.
+ *
+ * Fri Jan 9 23:38:19 CET 1998: Florian La Roche <florian@knorke.saar.de>
+ * Added -x switch to omit EIP translation and System.map evaluation.
+ *
+ * Sun Jan 25 20:47:46 CET 1998: Martin Schulze <joey@infodrom.north.de>
+ * As the bug covering the %'s introduced a problem with
+ * unevaluated priorities I've worked out a real fix that strips
+ * %'s to an even number which is harmless for printf.
+ *
+ * Sat Oct 10 20:01:48 CEST 1998: Martin Schulze <joey@infodrom.north.de>
+ * Added support for TESTING define which will turn klogd into
+ * stdio-mode used for debugging.
+ *
+ * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze <joey@infodrom.north.de>
+ * Modified System.map read function to try all possible map
+ * files until a file with matching version is found. Added support for
+ * Debian release.
+ *
+ * Mon Oct 12 13:01:27 MET DST 1998: Martin Schulze <joey@infodrom.north.de>
+ * Used unsigned long and strtoul() to resolve kernel oops symbols.
+ *
+ * Sun Jan 3 18:38:03 CET 1999: Martin Schulze <joey@infodrom.north.de>
+ * Shortened LOG_LINE_LENGTH in order to get long lines splitted
+ * up earlier and syslogd has a better chance concatenating them
+ * together again.
+ *
+ * Sat Aug 21 12:27:02 CEST 1999: Martin Schulze <joey@infodrom.north.de>
+ * Skip newline when reading in messages.
+ *
+ * Tue Sep 12 22:14:33 CEST 2000: Martin Schulze <joey@infodrom.ffis.de>
+ * Don't feed a buffer directly to a printf-type routine, use
+ * "%s" as format string instead. Thanks to Jouko Pynnönen
+ * <jouko@solutions.fi> for pointing this out.
+ *
+ * Tue Sep 12 22:44:57 CEST 2000: Martin Schulze <joey@infodrom.ffis.de>
+ * Commandline option `-2': When symbols are expanded, print the
+ * line twice. Once with addresses converted to symbols, once with the
+ * raw text. Allows external programs such as ksymoops do their own
+ * processing on the original data. Thanks to Keith Owens
+ * <kaos@ocs.com.au> for the patch.
+ *
+ * Mon Sep 18 09:32:27 CEST 2000: Martin Schulze <joey@infodrom.ffis.de>
+ * Added patch to fix priority decoding after moving kernel
+ * messgages into "%s". Thanks to Solar Designer
+ * <solar@false.com> for the patch.
+ *
+ * Sun Mar 11 20:23:44 CET 2001: Martin Schulze <joey@infodrom.ffis.de>
+ * Stop LogLine() from being called with wrong argument when a
+ * former calculation failed already. Thanks to Thomas Roessler
+ * <roessler@does-not-exist.org> for providing a patch.
+ *
+ * Ignore zero bytes, no busy loop is entered anymore. Several
+ * people have submitted patches: Troels Walsted Hansen
+ * <troels@thule.no>, Wolfgang Oertl <Wolfgang.Oertl@uibk.ac.at>
+ * and Thomas Roessler.
+ */
+
+
+/* Includes. */
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#if !defined(__GLIBC__)
+#include <linux/time.h>
+#endif /* __GLIBC__ */
+#include <stdarg.h>
+#include <paths.h>
+#include <stdlib.h>
+#include "klogd.h"
+#include "ksyms.h"
+#ifndef TESTING
+#include "pidfile.h"
+#endif
+#include "version.h"
+
+#define __LIBRARY__
+#include <linux/unistd.h>
+#if !defined(__GLIBC__)
+# define __NR_ksyslog __NR_syslog
+_syscall3(int,ksyslog,int, type, char *, buf, int, len);
+#else
+#include <sys/klog.h>
+#define ksyslog klogctl
+#endif
+
+#define LOG_BUFFER_SIZE 4096
+#define LOG_LINE_LENGTH 1000
+
+#ifndef TESTING
+#if defined(FSSTND)
+static char *PidFile = _PATH_VARRUN "klogd.pid";
+#else
+static char *PidFile = "/etc/klogd.pid";
+#endif
+#endif
+
+static int kmsg,
+ change_state = 0,
+ terminate = 0,
+ caught_TSTP = 0,
+ reload_symbols = 0,
+ console_log_level = -1;
+
+static int use_syscall = 0,
+ one_shot = 0,
+ symbol_lookup = 1,
+ no_fork = 0; /* don't fork - don't run in daemon mode */
+
+static char *symfile = (char *) 0,
+ log_buffer[LOG_BUFFER_SIZE];
+
+static FILE *output_file = (FILE *) 0;
+
+static enum LOGSRC {none, proc, kernel} logsrc;
+
+int debugging = 0;
+int symbols_twice = 0;
+
+
+/* Function prototypes. */
+extern int ksyslog(int type, char *buf, int len);
+static void CloseLogSrc(void);
+extern void restart(int sig);
+extern void stop_logging(int sig);
+extern void stop_daemon(int sig);
+extern void reload_daemon(int sig);
+static void Terminate(void);
+static void SignalDaemon(int);
+static void ReloadSymbols(void);
+static void ChangeLogging(void);
+static enum LOGSRC GetKernelLogSrc(void);
+static void LogLine(char *ptr, int len);
+static void LogKernelLine(void);
+static void LogProcLine(void);
+extern int main(int argc, char *argv[]);
+
+
+static void CloseLogSrc()
+
+{
+ /* Turn on logging of messages to console. */
+ ksyslog(7, NULL, 0);
+
+ /* Shutdown the log sources. */
+ switch ( logsrc )
+ {
+ case kernel:
+ ksyslog(0, 0, 0);
+ Syslog(LOG_INFO, "Kernel logging (ksyslog) stopped.");
+ break;
+ case proc:
+ close(kmsg);
+ Syslog(LOG_INFO, "Kernel logging (proc) stopped.");
+ break;
+ case none:
+ break;
+ }
+
+ if ( output_file != (FILE *) 0 )
+ fflush(output_file);
+ return;
+}
+
+
+void restart(sig)
+
+ int sig;
+
+{
+ signal(SIGCONT, restart);
+ change_state = 1;
+ caught_TSTP = 0;
+ return;
+}
+
+
+void stop_logging(sig)
+
+ int sig;
+
+{
+ signal(SIGTSTP, stop_logging);
+ change_state = 1;
+ caught_TSTP = 1;
+ return;
+}
+
+
+void stop_daemon(sig)
+
+ int sig;
+
+{
+ Terminate();
+ return;
+}
+
+
+void reload_daemon(sig)
+
+ int sig;
+
+{
+ change_state = 1;
+ reload_symbols = 1;
+
+
+ if ( sig == SIGUSR2 )
+ {
+ ++reload_symbols;
+ signal(SIGUSR2, reload_daemon);
+ }
+ else
+ signal(SIGUSR1, reload_daemon);
+
+ return;
+}
+
+
+static void Terminate()
+
+{
+ CloseLogSrc();
+ Syslog(LOG_INFO, "Kernel log daemon terminating.");
+ sleep(1);
+ if ( output_file != (FILE *) 0 )
+ fclose(output_file);
+ closelog();
+#ifndef TESTING
+ (void) remove_pid(PidFile);
+#endif
+ exit(1);
+}
+
+static void SignalDaemon(sig)
+
+ int sig;
+
+{
+#ifndef TESTING
+ auto int pid = check_pid(PidFile);
+
+ kill(pid, sig);
+#else
+ kill(getpid(), sig);
+#endif
+ return;
+}
+
+
+static void ReloadSymbols()
+
+{
+ if (symbol_lookup) {
+ if ( reload_symbols > 1 )
+ InitKsyms(symfile);
+ InitMsyms();
+ }
+ reload_symbols = change_state = 0;
+ return;
+}
+
+
+static void ChangeLogging(void)
+
+{
+ /* Terminate kernel logging. */
+ if ( terminate == 1 )
+ Terminate();
+
+ /* Indicate that something is happening. */
+ Syslog(LOG_INFO, "klogd %s.%s, ---------- state change ----------\n", \
+ VERSION, PATCHLEVEL);
+
+ /* Reload symbols. */
+ if ( reload_symbols > 0 )
+ {
+ ReloadSymbols();
+ return;
+ }
+
+ /* Stop kernel logging. */
+ if ( caught_TSTP == 1 )
+ {
+ CloseLogSrc();
+ logsrc = none;
+ change_state = 0;
+ return;
+ }
+
+ /*
+ * The rest of this function is responsible for restarting
+ * kernel logging after it was stopped.
+ *
+ * In the following section we make a decision based on the
+ * kernel log state as to what is causing us to restart. Somewhat
+ * groady but it keeps us from creating another static variable.
+ */
+ if ( logsrc != none )
+ {
+ Syslog(LOG_INFO, "Kernel logging re-started after SIGSTOP.");
+ change_state = 0;
+ return;
+ }
+
+ /* Restart logging. */
+ logsrc = GetKernelLogSrc();
+ change_state = 0;
+ return;
+}
+
+
+static enum LOGSRC GetKernelLogSrc(void)
+
+{
+ auto struct stat sb;
+
+
+ /* Set level of kernel console messaging.. */
+ if ( (console_log_level != -1)
+ && (ksyslog(8, NULL, console_log_level) < 0) && \
+ (errno == EINVAL) )
+ {
+ /*
+ * An invalid arguement error probably indicates that
+ * a pre-0.14 kernel is being run. At this point we
+ * issue an error message and simply shut-off console
+ * logging completely.
+ */
+ Syslog(LOG_WARNING, "Cannot set console log level - disabling "
+ "console output.");
+ ksyslog(6, NULL, 0);
+ }
+
+ /*
+ * First do a stat to determine whether or not the proc based
+ * file system is available to get kernel messages from.
+ */
+ if ( use_syscall ||
+ ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)) )
+ {
+ /* Initialize kernel logging. */
+ ksyslog(1, NULL, 0);
+#ifdef DEBRELEASE
+ Syslog(LOG_INFO, "klogd %s.%s#%s, log source = ksyslog "
+ "started.", VERSION, PATCHLEVEL, DEBRELEASE);
+#else
+ Syslog(LOG_INFO, "klogd %s.%s, log source = ksyslog "
+ "started.", VERSION, PATCHLEVEL);
+#endif
+ return(kernel);
+ }
+
+#ifndef TESTING
+ if ( (kmsg = open(_PATH_KLOG, O_RDONLY)) < 0 )
+ {
+ fprintf(stderr, "klogd: Cannot open proc file system, " \
+ "%d - %s.\n", errno, strerror(errno));
+ ksyslog(7, NULL, 0);
+ exit(1);
+ }
+#else
+ kmsg = fileno(stdin);
+#endif
+
+#ifdef DEBRELEASE
+ Syslog(LOG_INFO, "klogd %s.%s#%s, log source = %s started.", \
+ VERSION, PATCHLEVEL, DEBRELEASE, _PATH_KLOG);
+#else
+ Syslog(LOG_INFO, "klogd %s.%s, log source = %s started.", \
+ VERSION, PATCHLEVEL, _PATH_KLOG);
+#endif
+ return(proc);
+}
+
+
+extern void Syslog(int priority, char *fmt, ...)
+
+{
+ va_list ap;
+ char *argl;
+
+ if ( debugging )
+ {
+ fputs("Logging line:\n", stderr);
+ fprintf(stderr, "\tLine: %s\n", fmt);
+ fprintf(stderr, "\tPriority: %d\n", priority);
+ }
+
+ /* Handle output to a file. */
+ if ( output_file != (FILE *) 0 )
+ {
+ va_start(ap, fmt);
+ vfprintf(output_file, fmt, ap);
+ va_end(ap);
+ fputc('\n', output_file);
+ fflush(output_file);
+ if (!one_shot)
+ fsync(fileno(output_file));
+ return;
+ }
+
+ /* Output using syslog. */
+ if (!strcmp(fmt, "%s"))
+ {
+ va_start(ap, fmt);
+ argl = va_arg(ap, char *);
+ if (argl[0] == '<' && argl[1] && argl[2] == '>')
+ {
+ switch ( argl[1] )
+ {
+ case '0':
+ priority = LOG_EMERG;
+ break;
+ case '1':
+ priority = LOG_ALERT;
+ break;
+ case '2':
+ priority = LOG_CRIT;
+ break;
+ case '3':
+ priority = LOG_ERR;
+ break;
+ case '4':
+ priority = LOG_WARNING;
+ break;
+ case '5':
+ priority = LOG_NOTICE;
+ break;
+ case '6':
+ priority = LOG_INFO;
+ break;
+ case '7':
+ default:
+ priority = LOG_DEBUG;
+ }
+ argl += 3;
+ }
+ syslog(priority, fmt, argl);
+ va_end(ap);
+#ifdef TESTING
+ putchar('\n');
+#endif
+ return;
+ }
+
+ va_start(ap, fmt);
+ vsyslog(priority, fmt, ap);
+ va_end(ap);
+#ifdef TESTING
+ printf ("\n");
+#endif
+
+ return;
+}
+
+
+/*
+ * Copy characters from ptr to line until a char in the delim
+ * string is encountered or until min( space, len ) chars have
+ * been copied.
+ *
+ * Returns the actual number of chars copied.
+ */
+static int copyin( char *line, int space,
+ const char *ptr, int len,
+ const char *delim )
+{
+ auto int i;
+ auto int count;
+
+ count = len < space ? len : space;
+
+ for(i=0; i<count && !strchr(delim, *ptr); i++ ) { *line++ = *ptr++; }
+
+ return( i );
+}
+
+/*
+ * Messages are separated by "\n". Messages longer than
+ * LOG_LINE_LENGTH are broken up.
+ *
+ * Kernel symbols show up in the input buffer as : "[<aaaaaa>]",
+ * where "aaaaaa" is the address. These are replaced with
+ * "[symbolname+offset/size]" in the output line - symbolname,
+ * offset, and size come from the kernel symbol table.
+ *
+ * If a kernel symbol happens to fall at the end of a message close
+ * in length to LOG_LINE_LENGTH, the symbol will not be expanded.
+ * (This should never happen, since the kernel should never generate
+ * messages that long.
+ *
+ * To preserve the original addresses, lines containing kernel symbols
+ * are output twice. Once with the symbols converted and again with the
+ * original text. Just in case somebody wants to run their own Oops
+ * analysis on the syslog, e.g. ksymoops.
+ */
+static void LogLine(char *ptr, int len)
+{
+ enum parse_state_enum {
+ PARSING_TEXT,
+ PARSING_SYMSTART, /* at < */
+ PARSING_SYMBOL,
+ PARSING_SYMEND /* at ] */
+ };
+
+ static char line_buff[LOG_LINE_LENGTH];
+
+ static char *line =line_buff;
+ static enum parse_state_enum parse_state = PARSING_TEXT;
+ static int space = sizeof(line_buff)-1;
+
+ static char *sym_start; /* points at the '<' of a symbol */
+
+ auto int delta = 0; /* number of chars copied */
+ auto int symbols_expanded = 0; /* 1 if symbols were expanded */
+ auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */
+ auto char *save_ptr = ptr; /* save start of input line */
+ auto int save_len = len; /* save length at start of input line */
+
+ while( len > 0 )
+ {
+ if( space == 0 ) /* line buffer is full */
+ {
+ /*
+ ** Line too long. Start a new line.
+ */
+ *line = 0; /* force null terminator */
+
+ if ( debugging )
+ {
+ fputs("Line buffer full:\n", stderr);
+ fprintf(stderr, "\tLine: %s\n", line);
+ }
+
+ Syslog( LOG_INFO, "%s", line_buff );
+ line = line_buff;
+ space = sizeof(line_buff)-1;
+ parse_state = PARSING_TEXT;
+ symbols_expanded = 0;
+ skip_symbol_lookup = 0;
+ save_ptr = ptr;
+ save_len = len;
+ }
+
+ switch( parse_state )
+ {
+ case PARSING_TEXT:
+ delta = copyin( line, space, ptr, len, "\n[%" );
+ line += delta;
+ ptr += delta;
+ space -= delta;
+ len -= delta;
+
+ if( space == 0 || len == 0 )
+ {
+ break; /* full line_buff or end of input buffer */
+ }
+
+ if( *ptr == '\0' ) /* zero byte */
+ {
+ ptr++; /* skip zero byte */
+ space -= 1;
+ len -= 1;
+
+ break;
+ }
+
+ if( *ptr == '\n' ) /* newline */
+ {
+ ptr++; /* skip newline */
+ space -= 1;
+ len -= 1;
+
+ *line = 0; /* force null terminator */
+ Syslog( LOG_INFO, "%s", line_buff );
+ line = line_buff;
+ space = sizeof(line_buff)-1;
+ if (symbols_twice) {
+ if (symbols_expanded) {
+ /* reprint this line without symbol lookup */
+ symbols_expanded = 0;
+ skip_symbol_lookup = 1;
+ ptr = save_ptr;
+ len = save_len;
+ }
+ else
+ {
+ skip_symbol_lookup = 0;
+ save_ptr = ptr;
+ save_len = len;
+ }
+ }
+ break;
+ }
+ if( *ptr == '[' ) /* possible kernel symbol */
+ {
+ *line++ = *ptr++;
+ space -= 1;
+ len -= 1;
+ if (!skip_symbol_lookup)
+ parse_state = PARSING_SYMSTART; /* at < */
+ break;
+ }
+ if( *ptr == '%' ) /* dangerous printf marker */
+ {
+ delta = 0;
+ while (len && *ptr == '%')
+ {
+ *line++ = *ptr++; /* copy it in */
+ space -= 1;
+ len -= 1;
+ delta++;
+ }
+ if (delta % 2) /* odd amount of %'s */
+ {
+ if (space)
+ {
+ *line++ = '%'; /* so simply add one */
+ space -= 1;
+ }
+ else
+ {
+ *line++ = '\0'; /* remove the last one / terminate the string */
+ }
+
+ }
+ }
+ break;
+
+ case PARSING_SYMSTART:
+ if( *ptr != '<' )
+ {
+ parse_state = PARSING_TEXT; /* not a symbol */
+ break;
+ }
+
+ /*
+ ** Save this character for now. If this turns out to
+ ** be a valid symbol, this char will be replaced later.
+ ** If not, we'll just leave it there.
+ */
+
+ sym_start = line; /* this will point at the '<' */
+
+ *line++ = *ptr++;
+ space -= 1;
+ len -= 1;
+ parse_state = PARSING_SYMBOL; /* symbol... */
+ break;
+
+ case PARSING_SYMBOL:
+ delta = copyin( line, space, ptr, len, ">\n[" );
+ line += delta;
+ ptr += delta;
+ space -= delta;
+ len -= delta;
+ if( space == 0 || len == 0 )
+ {
+ break; /* full line_buff or end of input buffer */
+ }
+ if( *ptr != '>' )
+ {
+ parse_state = PARSING_TEXT;
+ break;
+ }
+
+ *line++ = *ptr++; /* copy the '>' */
+ space -= 1;
+ len -= 1;
+
+ parse_state = PARSING_SYMEND;
+
+ break;
+
+ case PARSING_SYMEND:
+ if( *ptr != ']' )
+ {
+ parse_state = PARSING_TEXT; /* not a symbol */
+ break;
+ }
+
+ /*
+ ** It's really a symbol! Replace address with the
+ ** symbol text.
+ */
+ {
+ auto int sym_space;
+
+ unsigned long value;
+ auto struct symbol sym;
+ auto char *symbol;
+
+ *(line-1) = 0; /* null terminate the address string */
+ value = strtoul(sym_start+1, (char **) 0, 16);
+ *(line-1) = '>'; /* put back delim */
+
+ symbol = LookupSymbol(value, &sym);
+ if ( !symbol_lookup || symbol == (char *) 0 )
+ {
+ parse_state = PARSING_TEXT;
+ break;
+ }
+
+ /*
+ ** verify there is room in the line buffer
+ */
+ sym_space = space + ( line - sym_start );
+ if( sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/
+ {
+ parse_state = PARSING_TEXT; /* not enough space */
+ break;
+ }
+
+ delta = sprintf( sym_start, "%s+%d/%d]",
+ symbol, sym.offset, sym.size );
+
+ space = sym_space + delta;
+ line = sym_start + delta;
+ symbols_expanded = 1;
+ }
+ ptr++;
+ len--;
+ parse_state = PARSING_TEXT;
+ break;
+
+ default: /* Can't get here! */
+ parse_state = PARSING_TEXT;
+
+ }
+ }
+
+ return;
+}
+
+
+static void LogKernelLine(void)
+
+{
+ auto int rdcnt;
+
+ /*
+ * Zero-fill the log buffer. This should cure a multitude of
+ * problems with klogd logging the tail end of the message buffer
+ * which will contain old messages. Then read the kernel log
+ * messages into this fresh buffer.
+ */
+ memset(log_buffer, '\0', sizeof(log_buffer));
+ if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer))) < 0 )
+ {
+ if ( errno == EINTR )
+ return;
+ fprintf(stderr, "klogd: Error return from sys_sycall: " \
+ "%d - %s\n", errno, strerror(errno));
+ }
+ else
+ LogLine(log_buffer, rdcnt);
+ return;
+}
+
+
+static void LogProcLine(void)
+
+{
+ auto int rdcnt;
+
+ /*
+ * Zero-fill the log buffer. This should cure a multitude of
+ * problems with klogd logging the tail end of the message buffer
+ * which will contain old messages. Then read the kernel messages
+ * from the message pseudo-file into this fresh buffer.
+ */
+ memset(log_buffer, '\0', sizeof(log_buffer));
+ if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 )
+ {
+ if ( errno == EINTR )
+ return;
+ Syslog(LOG_ERR, "Cannot read proc file system: %d - %s.", \
+ errno, strerror(errno));
+ }
+ else
+ LogLine(log_buffer, rdcnt);
+
+ return;
+}
+
+
+int main(argc, argv)
+
+ int argc;
+
+ char *argv[];
+
+{
+ auto int ch,
+ use_output = 0;
+
+ auto char *log_level = (char *) 0,
+ *output = (char *) 0;
+
+#ifndef TESTING
+ chdir ("/");
+#endif
+ /* Parse the command-line. */
+ while ((ch = getopt(argc, argv, "c:df:iIk:nopsvx2")) != EOF)
+ switch((char)ch)
+ {
+ case '2': /* Print lines with symbols twice. */
+ symbols_twice = 1;
+ break;
+ case 'c': /* Set console message level. */
+ log_level = optarg;
+ break;
+ case 'd': /* Activity debug mode. */
+ debugging = 1;
+ break;
+ case 'f': /* Define an output file. */
+ output = optarg;
+ use_output++;
+ break;
+ case 'i': /* Reload module symbols. */
+ SignalDaemon(SIGUSR1);
+ return(0);
+ case 'I':
+ SignalDaemon(SIGUSR2);
+ return(0);
+ case 'k': /* Kernel symbol file. */
+ symfile = optarg;
+ break;
+ case 'n': /* don't fork */
+ no_fork++;
+ break;
+ case 'o': /* One-shot mode. */
+ one_shot = 1;
+ break;
+ case 'p':
+ SetParanoiaLevel(1); /* Load symbols on oops. */
+ break;
+ case 's': /* Use syscall interface. */
+ use_syscall = 1;
+ break;
+ case 'v':
+ printf("klogd %s.%s\n", VERSION, PATCHLEVEL);
+ exit (1);
+ case 'x':
+ symbol_lookup = 0;
+ break;
+ }
+
+
+ /* Set console logging level. */
+ if ( log_level != (char *) 0 )
+ {
+ if ( (strlen(log_level) > 1) || \
+ (strchr("12345678", *log_level) == (char *) 0) )
+ {
+ fprintf(stderr, "klogd: Invalid console logging "
+ "level <%s> specified.\n", log_level);
+ return(1);
+ }
+ console_log_level = *log_level - '0';
+ }
+
+
+#ifndef TESTING
+ /*
+ * The following code allows klogd to auto-background itself.
+ * What happens is that the program forks and the parent quits.
+ * The child closes all its open file descriptors, and issues a
+ * call to setsid to establish itself as an independent session
+ * immune from control signals.
+ *
+ * fork() is only called if it should run in daemon mode, fork is
+ * not disabled with the command line argument and there's no
+ * such process running.
+ */
+ if ( (!one_shot) && (!no_fork) )
+ {
+ if (!check_pid(PidFile))
+ {
+ if ( fork() == 0 )
+ {
+ auto int fl;
+ int num_fds = getdtablesize();
+
+ /* This is the child closing its file descriptors. */
+ for (fl= 0; fl <= num_fds; ++fl)
+ {
+ if ( fileno(stdout) == fl && use_output )
+ if ( strcmp(output, "-") == 0 )
+ continue;
+ close(fl);
+ }
+
+ setsid();
+ }
+ else
+ exit(0);
+ }
+ else
+ {
+ fputs("klogd: Already running.\n", stderr);
+ exit(1);
+ }
+ }
+
+
+ /* tuck my process id away */
+ if (!check_pid(PidFile))
+ {
+ if (!write_pid(PidFile))
+ Terminate();
+ }
+ else
+ {
+ fputs("klogd: Already running.\n", stderr);
+ Terminate();
+ }
+#endif
+
+ /* Signal setups. */
+ for (ch= 1; ch < NSIG; ++ch)
+ signal(ch, SIG_IGN);
+ signal(SIGINT, stop_daemon);
+ signal(SIGKILL, stop_daemon);
+ signal(SIGTERM, stop_daemon);
+ signal(SIGHUP, stop_daemon);
+ signal(SIGTSTP, stop_logging);
+ signal(SIGCONT, restart);
+ signal(SIGUSR1, reload_daemon);
+ signal(SIGUSR2, reload_daemon);
+
+
+ /* Open outputs. */
+ if ( use_output )
+ {
+ if ( strcmp(output, "-") == 0 )
+ output_file = stdout;
+ else if ( (output_file = fopen(output, "w")) == (FILE *) 0 )
+ {
+ fprintf(stderr, "klogd: Cannot open output file " \
+ "%s - %s\n", output, strerror(errno));
+ return(1);
+ }
+ }
+ else
+ openlog("kernel", 0, LOG_KERN);
+
+
+ /* Handle one-shot logging. */
+ if ( one_shot )
+ {
+ if (symbol_lookup) {
+ InitKsyms(symfile);
+ InitMsyms();
+ }
+ if ( (logsrc = GetKernelLogSrc()) == kernel )
+ LogKernelLine();
+ else
+ LogProcLine();
+ Terminate();
+ }
+
+ /* Determine where kernel logging information is to come from. */
+#if defined(KLOGD_DELAY)
+ sleep(KLOGD_DELAY);
+#endif
+ logsrc = GetKernelLogSrc();
+ if (symbol_lookup) {
+ InitKsyms(symfile);
+ InitMsyms();
+ }
+
+ /* The main loop. */
+ while (1)
+ {
+ if ( change_state )
+ ChangeLogging();
+ switch ( logsrc )
+ {
+ case kernel:
+ LogKernelLine();
+ break;
+ case proc:
+ LogProcLine();
+ break;
+ case none:
+ pause();
+ break;
+ }
+ }
+}
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/klogd.h b/klogd.h
new file mode 100644
index 00000000..ef60f088
--- /dev/null
+++ b/klogd.h
@@ -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, ...);
diff --git a/ksym.c b/ksym.c
new file mode 100644
index 00000000..0a6d7151
--- /dev/null
+++ b/ksym.c
@@ -0,0 +1,901 @@
+/*
+ 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
+
+ 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.
+ */
+
+
+/* Includes. */
+#include <stdlib.h>
+#include <malloc.h>
+#include <sys/utsname.h>
+#include "klogd.h"
+#include "ksyms.h"
+
+#define VERBOSE_DEBUGGING 0
+
+
+/* Variables static to this module. */
+struct sym_table
+{
+ unsigned long value;
+ char *name;
+};
+
+static int num_syms = 0;
+static int i_am_paranoid = 0;
+static char vstring[12];
+static struct sym_table *sym_array = (struct sym_table *) 0;
+
+static char *system_maps[] =
+{
+ "/boot/System.map",
+ "/System.map",
+#if defined(TEST)
+ "./System.map",
+#endif
+ (char *) 0
+};
+
+
+#if defined(TEST)
+int debugging;
+#else
+extern int debugging;
+#endif
+
+
+/* Function prototypes. */
+static char * FindSymbolFile(void);
+static int AddSymbol(unsigned long, char*);
+static void FreeSymbols(void);
+static int CheckVersion(char *);
+static int CheckMapVersion(char *);
+
+
+/**************************************************************************
+ * Function: InitKsyms
+ *
+ * Purpose: This function is responsible for initializing and loading
+ * the data tables used by the kernel address translations.
+ *
+ * Arguements: (char *) mapfile
+ *
+ * mapfile:-> A pointer to a complete path
+ * specification of the file containing
+ * the kernel map to use.
+ *
+ * Return: int
+ *
+ * A boolean style context is returned. The return value will
+ * be true if initialization was successful. False if not.
+ **************************************************************************/
+
+extern int InitKsyms(mapfile)
+
+ char *mapfile;
+
+{
+ auto char type,
+ sym[512];
+
+ auto int version = 0;
+
+ auto unsigned long int address;
+
+ auto FILE *sym_file;
+
+
+ /* Check and make sure that we are starting with a clean slate. */
+ if ( num_syms > 0 )
+ FreeSymbols();
+
+
+ /*
+ * Search for and open the file containing the kernel symbols.
+ */
+ if ( mapfile != (char *) 0 )
+ {
+ if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 )
+ {
+ Syslog(LOG_WARNING, "Cannot open map file: %s.", \
+ mapfile);
+ return(0);
+ }
+ }
+ else
+ {
+ if ( (mapfile = FindSymbolFile()) == (char *) 0 )
+ {
+ Syslog(LOG_WARNING, "Cannot find map file.");
+ if ( debugging )
+ fputs("Cannot find map file.\n", stderr);
+ return(0);
+ }
+
+ if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 )
+ {
+ Syslog(LOG_WARNING, "Cannot open map file.");
+ if ( debugging )
+ fputs("Cannot open map file.\n", stderr);
+ return(0);
+ }
+ }
+
+
+ /*
+ * Read the kernel symbol table file and add entries for each
+ * line. I suspect that the use of fscanf is not really in vogue
+ * but it was quick and dirty and IMHO suitable for fixed format
+ * data such as this. If anybody doesn't agree with this please
+ * e-mail me a diff containing a parser with suitable political
+ * correctness -- GW.
+ */
+ while ( !feof(sym_file) )
+ {
+ if ( fscanf(sym_file, "%lx %c %s\n", &address, &type, sym)
+ != 3 )
+ {
+ Syslog(LOG_ERR, "Error in symbol table input (#1).");
+ fclose(sym_file);
+ return(0);
+ }
+ if ( VERBOSE_DEBUGGING && debugging )
+ fprintf(stderr, "Address: %lx, Type: %c, Symbol: %s\n",
+ address, type, sym);
+
+ if ( AddSymbol(address, sym) == 0 )
+ {
+ Syslog(LOG_ERR, "Error adding symbol - %s.", sym);
+ fclose(sym_file);
+ return(0);
+ }
+
+ if ( version == 0 )
+ version = CheckVersion(sym);
+ }
+
+
+ Syslog(LOG_INFO, "Loaded %d symbols from %s.", num_syms, mapfile);
+ switch ( version )
+ {
+ case -1:
+ Syslog(LOG_WARNING, "Symbols do not match kernel version.");
+ num_syms = 0;
+ break;
+
+ case 0:
+ Syslog(LOG_WARNING, "Cannot verify that symbols match " \
+ "kernel version.");
+ break;
+
+ case 1:
+ Syslog(LOG_INFO, "Symbols match kernel version %s.", vstring);
+ break;
+ }
+
+ fclose(sym_file);
+ return(1);
+}
+
+
+/**************************************************************************
+ * Function: FindSymbolFile
+ *
+ * Purpose: This function is responsible for encapsulating the search
+ * for a valid symbol file. Encapsulating the search for
+ * the map file in this function allows an intelligent search
+ * process to be implemented.
+ *
+ * The list of symbol files will be searched until either a
+ * symbol file is found whose version matches the currently
+ * executing kernel or the end of the list is encountered. If
+ * the end of the list is encountered the first available
+ * symbol file is returned to the caller.
+ *
+ * This strategy allows klogd to locate valid symbol files
+ * for both a production and an experimental kernel. For
+ * example a map for a production kernel could be installed
+ * in /boot. If an experimental kernel is loaded the map
+ * in /boot will be skipped and the map in /usr/src/linux would
+ * be used if its version number matches the executing kernel.
+ *
+ * Arguements: None specified.
+ *
+ * Return: char *
+ *
+ * If a valid system map cannot be located a null pointer
+ * is returned to the caller.
+ *
+ * If the search is succesful a pointer is returned to the
+ * caller which points to the name of the file containing
+ * the symbol table to be used.
+ **************************************************************************/
+
+static char * FindSymbolFile()
+
+{
+ auto char *file = (char *) 0,
+ **mf = system_maps;
+
+ auto struct utsname utsname;
+ static char symfile[100];
+
+ auto FILE *sym_file = (FILE *) 0;
+
+ if ( uname(&utsname) < 0 )
+ {
+ Syslog(LOG_ERR, "Cannot get kernel version information.");
+ return(0);
+ }
+
+ if ( debugging )
+ fputs("Searching for symbol map.\n", stderr);
+
+ for (mf = system_maps; *mf != (char *) 0 && file == (char *) 0; ++mf)
+ {
+
+ sprintf (symfile, "%s-%s", *mf, utsname.release);
+ if ( debugging )
+ fprintf(stderr, "Trying %s.\n", symfile);
+ if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) {
+ if (CheckMapVersion(symfile) == 1)
+ file = symfile;
+ }
+ 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;
+ }
+ }
+
+ }
+
+ /*
+ * At this stage of the game we are at the end of the symbol
+ * tables.
+ */
+ if ( debugging )
+ fprintf(stderr, "End of search list encountered.\n");
+ return(file);
+}
+
+
+/**************************************************************************
+ * Function: CheckVersion
+ *
+ * Purpose: This function is responsible for determining whether or
+ * the system map being loaded matches the version of the
+ * currently running kernel.
+ *
+ * The kernel version is checked by examing a variable which
+ * is of the form: _Version_66347 (a.out) or Version_66437 (ELF).
+ *
+ * The suffix of this variable is the current kernel version
+ * of the kernel encoded in base 256. For example the
+ * above variable would be decoded as:
+ *
+ * (66347 = 1*65536 + 3*256 + 43 = 1.3.43)
+ *
+ * (Insert appropriate deities here) help us if Linus ever
+ * needs more than 255 patch levels to get a kernel out the
+ * door... :-)
+ *
+ * Arguements: (char *) version
+ *
+ * version:-> A pointer to the string which
+ * is to be decoded as a kernel
+ * version variable.
+ *
+ * Return: int
+ *
+ * -1:-> The currently running kernel version does
+ * not match this version string.
+ *
+ * 0:-> The string is not a kernel version variable.
+ *
+ * 1:-> The executing kernel is of the same version
+ * as the version string.
+ **************************************************************************/
+
+static int CheckVersion(version)
+
+ char *version;
+
+
+{
+ auto int vnum,
+ major,
+ minor,
+ patch;
+
+#ifndef TESTING
+ int kvnum;
+ auto struct utsname utsname;
+#endif
+
+ static char *prefix = { "Version_" };
+
+
+ /* Early return if there is no hope. */
+ if ( strncmp(version, prefix, strlen(prefix)) == 0 /* ELF */ ||
+ (*version == '_' &&
+ strncmp(++version, prefix, strlen(prefix)) == 0 ) /* a.out */ )
+ ;
+ else
+ return(0);
+
+
+ /*
+ * Since the symbol looks like a kernel version we can start
+ * things out by decoding the version string into its component
+ * parts.
+ */
+ vnum = atoi(version + strlen(prefix));
+ patch = vnum & 0x000000FF;
+ minor = (vnum >> 8) & 0x000000FF;
+ major = (vnum >> 16) & 0x000000FF;
+ if ( debugging )
+ fprintf(stderr, "Version string = %s, Major = %d, " \
+ "Minor = %d, Patch = %d.\n", version +
+ strlen(prefix), major, minor, \
+ patch);
+ sprintf(vstring, "%d.%d.%d", major, minor, patch);
+
+#ifndef TESTING
+ /*
+ * We should now have the version string in the vstring variable in
+ * the same format that it is stored in by the kernel. We now
+ * ask the kernel for its version information and compare the two
+ * values to determine if our system map matches the kernel
+ * version level.
+ */
+ if ( uname(&utsname) < 0 )
+ {
+ Syslog(LOG_ERR, "Cannot get kernel version information.");
+ return(0);
+ }
+ if ( debugging )
+ fprintf(stderr, "Comparing kernel %s with symbol table %s.\n",\
+ utsname.release, vstring);
+
+ if ( sscanf (utsname.release, "%d.%d.%d", &major, &minor, &patch) < 3 )
+ {
+ Syslog(LOG_ERR, "Kernel send bogus release string `%s'.",
+ utsname.release);
+ return(0);
+ }
+
+ /* Compute the version code from data sent by the kernel */
+ kvnum = (major << 16) | (minor << 8) | patch;
+
+ /* Failure. */
+ if ( vnum != kvnum )
+ return(-1);
+
+ /* Success. */
+#endif
+ return(1);
+}
+
+
+/**************************************************************************
+ * Function: CheckMapVersion
+ *
+ * Purpose: This function is responsible for determining whether or
+ * the system map being loaded matches the version of the
+ * currently running kernel. It uses CheckVersion as
+ * backend.
+ *
+ * Arguements: (char *) fname
+ *
+ * fname:-> A pointer to the string which
+ * references the system map file to
+ * be used.
+ *
+ * Return: int
+ *
+ * -1:-> The currently running kernel version does
+ * not match the version in the given file.
+ *
+ * 0:-> No system map file or no version information.
+ *
+ * 1:-> The executing kernel is of the same version
+ * as the version of the map file.
+ **************************************************************************/
+
+static int CheckMapVersion(fname)
+
+ char *fname;
+
+
+{
+ int version;
+ FILE *sym_file;
+ auto unsigned long int address;
+ auto char type,
+ sym[512];
+
+ if ( (sym_file = fopen(fname, "r")) != (FILE *) 0 ) {
+ /*
+ * At this point a map file was successfully opened. We
+ * now need to search this file and look for version
+ * information.
+ */
+ Syslog(LOG_INFO, "Inspecting %s", fname);
+
+ version = 0;
+ while ( !feof(sym_file) && (version == 0) )
+ {
+ if ( fscanf(sym_file, "%lx %c %s\n", &address, \
+ &type, sym) != 3 )
+ {
+ Syslog(LOG_ERR, "Error in symbol table input (#2).");
+ fclose(sym_file);
+ return(0);
+ }
+ if ( VERBOSE_DEBUGGING && debugging )
+ fprintf(stderr, "Address: %lx, Type: %c, " \
+ "Symbol: %s\n", address, type, sym);
+
+ version = CheckVersion(sym);
+ }
+ fclose(sym_file);
+
+ switch ( version )
+ {
+ case -1:
+ Syslog(LOG_ERR, "Symbol table has incorrect " \
+ "version number.\n");
+ break;
+
+ case 0:
+ if ( debugging )
+ fprintf(stderr, "No version information " \
+ "found.\n");
+ break;
+ case 1:
+ if ( debugging )
+ fprintf(stderr, "Found table with " \
+ "matching version number.\n");
+ break;
+ }
+
+ return(version);
+ }
+
+ return(0);
+}
+
+
+/**************************************************************************
+ * Function: AddSymbol
+ *
+ * Purpose: This function is responsible for adding a symbol name
+ * and its address to the symbol table.
+ *
+ * Arguements: (unsigned long) address, (char *) symbol
+ *
+ * Return: int
+ *
+ * A boolean value is assumed. True if the addition is
+ * successful. False if not.
+ **************************************************************************/
+
+static int AddSymbol(address, symbol)
+
+ unsigned long address;
+
+ char *symbol;
+
+{
+ /* Allocate the the symbol table entry. */
+ sym_array = (struct sym_table *) realloc(sym_array, (num_syms+1) * \
+ sizeof(struct sym_table));
+ if ( sym_array == (struct sym_table *) 0 )
+ return(0);
+
+ /* Then the space for the symbol. */
+ sym_array[num_syms].name = (char *) malloc(strlen(symbol)*sizeof(char)\
+ + 1);
+ if ( sym_array[num_syms].name == (char *) 0 )
+ return(0);
+
+ sym_array[num_syms].value = address;
+ strcpy(sym_array[num_syms].name, symbol);
+ ++num_syms;
+ return(1);
+}
+
+
+/**************************************************************************
+ * Function: LookupSymbol
+ *
+ * Purpose: Find the symbol which is related to the given kernel
+ * address.
+ *
+ * Arguements: (long int) value, (struct symbol *) sym
+ *
+ * value:-> The address to be located.
+ *
+ * sym:-> A pointer to a structure which will be
+ * loaded with the symbol's parameters.
+ *
+ * Return: (char *)
+ *
+ * If a match cannot be found a diagnostic string is printed.
+ * If a match is found the pointer to the symbolic name most
+ * closely matching the address is returned.
+ **************************************************************************/
+
+char * LookupSymbol(value, sym)
+
+ unsigned long value;
+
+ struct symbol *sym;
+
+{
+ auto int lp;
+
+ auto char *last;
+
+ if (!sym_array)
+ return((char *) 0);
+
+ last = sym_array[0].name;
+ sym->offset = 0;
+ sym->size = 0;
+ if ( value < sym_array[0].value )
+ return((char *) 0);
+
+ for(lp= 0; lp <= num_syms; ++lp)
+ {
+ if ( sym_array[lp].value > value )
+ {
+ sym->offset = value - sym_array[lp-1].value;
+ sym->size = sym_array[lp].value - \
+ sym_array[lp-1].value;
+ return(last);
+ }
+ last = sym_array[lp].name;
+ }
+
+ if ( (last = LookupModuleSymbol(value, sym)) != (char *) 0 )
+ return(last);
+
+ return((char *) 0);
+}
+
+
+/**************************************************************************
+ * Function: FreeSymbols
+ *
+ * Purpose: This function is responsible for freeing all memory which
+ * has been allocated to hold the static symbol table. It
+ * also initializes the symbol count and in general prepares
+ * for a re-read of a static symbol table.
+ *
+ * Arguements: void
+ *
+ * Return: void
+ **************************************************************************/
+
+static void FreeSymbols()
+
+{
+ auto int lp;
+
+ /* Free each piece of memory allocated for symbol names. */
+ for(lp= 0; lp < num_syms; ++lp)
+ free(sym_array[lp].name);
+
+ /* Whack the entire array and initialize everything. */
+ free(sym_array);
+ sym_array = (struct sym_table *) 0;
+ num_syms = 0;
+
+ return;
+}
+
+
+/**************************************************************************
+ * Function: LogExpanded
+ *
+ * Purpose: This function is responsible for logging a kernel message
+ * line after all potential numeric kernel addresses have
+ * been resolved symolically.
+ *
+ * Arguements: (char *) line, (char *) el
+ *
+ * line:-> A pointer to the buffer containing the kernel
+ * message to be expanded and logged.
+ *
+ * el:-> A pointer to the buffer into which the expanded
+ * kernel line will be written.
+ *
+ * Return: void
+ **************************************************************************/
+
+extern char * ExpandKadds(line, el)
+
+ char *line;
+
+ char *el;
+
+{
+ auto char dlm,
+ *kp,
+ *sl = line,
+ *elp = el,
+ *symbol;
+
+ char num[15];
+ auto unsigned long int value;
+
+ auto struct symbol sym;
+
+
+ /*
+ * This is as handy a place to put this as anyplace.
+ *
+ * Since the insertion of kernel modules can occur in a somewhat
+ * dynamic fashion we need some mechanism to insure that the
+ * kernel symbol tables get read just prior to when they are
+ * needed.
+ *
+ * To accomplish this we look for the Oops string and use its
+ * presence as a signal to load the module symbols.
+ *
+ * This is not the best solution of course, especially if the
+ * kernel is rapidly going out to lunch. What really needs to
+ * be done is to somehow generate a callback from the
+ * kernel whenever a module is loaded or unloaded. I am
+ * open for patches.
+ */
+ if ( i_am_paranoid &&
+ (strstr(line, "Oops:") != (char *) 0) && !InitMsyms() )
+ Syslog(LOG_WARNING, "Cannot load kernel module symbols.\n");
+
+
+ /*
+ * Early return if there do not appear to be any kernel
+ * messages in this line.
+ */
+ if ( (num_syms == 0) ||
+ (kp = strstr(line, "[<")) == (char *) 0 )
+ {
+ strcpy(el, line);
+ return(el);
+ }
+
+ /* Loop through and expand all kernel messages. */
+ do
+ {
+ while ( sl < kp+1 )
+ *elp++ = *sl++;
+
+ /* Now poised at a kernel delimiter. */
+ if ( (kp = strstr(sl, ">]")) == (char *) 0 )
+ {
+ strcpy(el, sl);
+ return(el);
+ }
+ dlm = *kp;
+ strncpy(num,sl+1,kp-sl-1);
+ num[kp-sl-1] = '\0';
+ value = strtoul(num, (char **) 0, 16);
+ if ( (symbol = LookupSymbol(value, &sym)) == (char *) 0 )
+ symbol = sl;
+
+ strcat(elp, symbol);
+ elp += strlen(symbol);
+ if ( debugging )
+ fprintf(stderr, "Symbol: %s = %lx = %s, %x/%d\n", \
+ sl+1, value, \
+ (sym.size==0) ? symbol+1 : symbol, \
+ sym.offset, sym.size);
+
+ value = 2;
+ if ( sym.size != 0 )
+ {
+ --value;
+ ++kp;
+ elp += sprintf(elp, "+%x/%d", sym.offset, sym.size);
+ }
+ strncat(elp, kp, value);
+ elp += value;
+ sl = kp + value;
+ if ( (kp = strstr(sl, "[<")) == (char *) 0 )
+ strcat(elp, sl);
+ }
+ while ( kp != (char *) 0);
+
+ if ( debugging )
+ fprintf(stderr, "Expanded line: %s\n", el);
+ return(el);
+}
+
+
+/**************************************************************************
+ * Function: SetParanoiaLevel
+ *
+ * Purpose: This function is an interface function for setting the
+ * mode of loadable module symbol lookups. Probably overkill
+ * but it does slay another global variable.
+ *
+ * Arguements: (int) level
+ *
+ * level:-> The amount of paranoia which is to be
+ * present when resolving kernel exceptions.
+ * Return: void
+ **************************************************************************/
+
+extern void SetParanoiaLevel(level)
+
+ int level;
+
+{
+ i_am_paranoid = level;
+ return;
+}
+
+
+/*
+ * Setting the -DTEST define enables the following code fragment to
+ * be compiled. This produces a small standalone program which will
+ * echo the standard input of the process to stdout while translating
+ * all numeric kernel addresses into their symbolic equivalent.
+ */
+#if defined(TEST)
+
+#include <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
diff --git a/ksym_mod.c b/ksym_mod.c
new file mode 100644
index 00000000..344963b2
--- /dev/null
+++ b/ksym_mod.c
@@ -0,0 +1,700 @@
+/*
+ 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
+
+ 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.
+ */
+
+
+/* Includes. */
+#include <stdlib.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#if !defined(__GLIBC__)
+#include <linux/time.h>
+#include <linux/module.h>
+#else /* __GLIBC__ */
+#include <linux/module.h>
+extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
+extern int get_kernel_syms __P ((struct kernel_sym *__table));
+#endif /* __GLIBC__ */
+#include <stdarg.h>
+#include <paths.h>
+#include <linux/version.h>
+
+#include "klogd.h"
+#include "ksyms.h"
+
+
+#if !defined(__GLIBC__)
+/*
+ * The following bit uses some kernel/library magic to product what
+ * looks like a function call to user level code. This function is
+ * actually a system call in disguise. The purpose of the getsyms
+ * call is to return a current copy of the in-kernel symbol table.
+ */
+#define __LIBRARY__
+#include <linux/unistd.h>
+#define __NR_getsyms __NR_get_kernel_syms
+_syscall1(int, getsyms, struct kernel_sym *, syms);
+#undef __LIBRARY__
+extern int getsyms(struct kernel_sym *);
+#else /* __GLIBC__ */
+#define getsyms get_kernel_syms
+#endif /* __GLIBC__ */
+
+/* Variables static to this module. */
+struct sym_table
+{
+ unsigned long value;
+ char *name;
+};
+
+struct Module
+{
+ struct sym_table *sym_array;
+ int num_syms;
+
+ char *name;
+ struct module module;
+#if LINUX_VERSION_CODE >= 0x20112
+ struct module_info module_info;
+#endif
+};
+
+static int num_modules = 0;
+struct Module *sym_array_modules = (struct Module *) 0;
+
+static int have_modules = 0;
+
+#if defined(TEST)
+static int debugging = 1;
+#else
+extern int debugging;
+#endif
+
+
+/* Function prototypes. */
+static void FreeModules(void);
+static int AddSymbol(struct Module *mp, unsigned long, char *);
+static int AddModule(unsigned long, char *);
+static int symsort(const void *, const void *);
+
+
+/**************************************************************************
+ * Function: InitMsyms
+ *
+ * Purpose: This function is responsible for building a symbol
+ * table which can be used to resolve addresses for
+ * loadable modules.
+ *
+ * Arguements: Void
+ *
+ * Return: A boolean return value is assumed.
+ *
+ * A false value indicates that something went wrong.
+ *
+ * True if loading is successful.
+ **************************************************************************/
+
+extern int InitMsyms()
+
+{
+ auto int rtn,
+ tmp;
+
+ auto struct kernel_sym *ksym_table,
+ *p;
+
+
+ /* Initialize the kernel module symbol table. */
+ FreeModules();
+
+
+ /*
+ * The system call which returns the kernel symbol table has
+ * essentialy two modes of operation. Called with a null pointer
+ * the system call returns the number of symbols defined in the
+ * the table.
+ *
+ * The second mode of operation is to pass a valid pointer to
+ * the call which will then load the current symbol table into
+ * the memory provided.
+ *
+ * Returning the symbol table is essentially an all or nothing
+ * proposition so we need to pre-allocate enough memory for the
+ * complete table regardless of how many symbols we need.
+ *
+ * Bummer.
+ */
+ if ( (rtn = getsyms((struct kernel_sym *) 0)) < 0 )
+ {
+ if ( errno == ENOSYS )
+ Syslog(LOG_INFO, "No module symbols loaded - "
+ "kernel modules not enabled.\n");
+ else
+ Syslog(LOG_ERR, "Error loading kernel symbols " \
+ "- %s\n", strerror(errno));
+ return(0);
+ }
+ if ( debugging )
+ fprintf(stderr, "Loading kernel module symbols - "
+ "Size of table: %d\n", rtn);
+
+ ksym_table = (struct kernel_sym *) malloc(rtn * \
+ sizeof(struct kernel_sym));
+ if ( ksym_table == (struct kernel_sym *) 0 )
+ {
+ Syslog(LOG_WARNING, " Failed memory allocation for kernel " \
+ "symbol table.\n");
+ return(0);
+ }
+ if ( (rtn = getsyms(ksym_table)) < 0 )
+ {
+ Syslog(LOG_WARNING, "Error reading kernel symbols - %s\n", \
+ strerror(errno));
+ return(0);
+ }
+
+
+ /*
+ * Build a symbol table compatible with the other one used by
+ * klogd.
+ */
+ tmp = rtn;
+ p = ksym_table;
+ while ( tmp-- )
+ {
+ if ( !AddModule(p->value, p->name) )
+ {
+ Syslog(LOG_WARNING, "Error adding kernel module table "
+ "entry.\n");
+ free(ksym_table);
+ return(0);
+ }
+ ++p;
+ }
+
+ /* Sort the symbol tables in each module. */
+ for (rtn = tmp= 0; tmp < num_modules; ++tmp)
+ {
+ rtn += sym_array_modules[tmp].num_syms;
+ if ( sym_array_modules[tmp].num_syms < 2 )
+ continue;
+ qsort(sym_array_modules[tmp].sym_array, \
+ sym_array_modules[tmp].num_syms, \
+ sizeof(struct sym_table), symsort);
+ }
+
+ if ( rtn == 0 )
+ Syslog(LOG_INFO, "No module symbols loaded.");
+ else
+ Syslog(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \
+ (rtn == 1) ? "symbol" : "symbols", \
+ num_modules, (num_modules == 1) ? "." : "s.");
+ free(ksym_table);
+ return(1);
+}
+
+
+static int symsort(p1, p2)
+
+ const void *p1;
+
+ const void *p2;
+
+{
+ auto const struct sym_table *sym1 = p1,
+ *sym2 = p2;
+
+ if ( sym1->value < sym2->value )
+ return(-1);
+ if ( sym1->value == sym2->value )
+ return(0);
+ return(1);
+}
+
+
+/**************************************************************************
+ * Function: FreeModules
+ *
+ * Purpose: This function is used to free all memory which has been
+ * allocated for the modules and their symbols.
+ *
+ * Arguements: None specified.
+ *
+ * Return: void
+ **************************************************************************/
+
+static void FreeModules()
+
+{
+ auto int nmods,
+ nsyms;
+
+ auto struct Module *mp;
+
+
+ /* Check to see if the module symbol tables need to be cleared. */
+ have_modules = 0;
+ if ( num_modules == 0 )
+ return;
+
+
+ for (nmods= 0; nmods < num_modules; ++nmods)
+ {
+ mp = &sym_array_modules[nmods];
+ if ( mp->num_syms == 0 )
+ continue;
+
+ for (nsyms= 0; nsyms < mp->num_syms; ++nsyms)
+ free(mp->sym_array[nsyms].name);
+ free(mp->sym_array);
+ }
+
+ free(sym_array_modules);
+ sym_array_modules = (struct Module *) 0;
+ num_modules = 0;
+ return;
+}
+
+
+/**************************************************************************
+ * Function: AddModule
+ *
+ * Purpose: This function is responsible for adding a module to
+ * the list of currently loaded modules.
+ *
+ * Arguements: (unsigned long) address, (char *) symbol
+ *
+ * address:-> The address of the module.
+ *
+ * symbol:-> The name of the module.
+ *
+ * Return: int
+ **************************************************************************/
+
+static int AddModule(address, symbol)
+
+ unsigned long address;
+
+ char *symbol;
+
+{
+ auto int memfd;
+
+ auto struct Module *mp;
+
+
+ /* Return if we have loaded the modules. */
+ if ( have_modules )
+ return(1);
+
+ /*
+ * The following section of code is responsible for determining
+ * whether or not we are done reading the list of modules.
+ */
+ if ( symbol[0] == '#' )
+ {
+
+ if ( symbol[1] == '\0' )
+ {
+ /*
+ * A symbol which consists of a # sign only
+ * signifies a a resident kernel segment. When we
+ * hit one of these we are done reading the
+ * module list.
+ */
+ have_modules = 1;
+ return(1);
+ }
+ /* Allocate space for the module. */
+ sym_array_modules = (struct Module *) \
+ realloc(sym_array_modules, \
+ (num_modules+1) * sizeof(struct Module));
+ if ( sym_array_modules == (struct Module *) 0 )
+ {
+ Syslog(LOG_WARNING, "Cannot allocate Module array.\n");
+ return(0);
+ }
+ mp = &sym_array_modules[num_modules];
+
+ if ( (memfd = open("/dev/kmem", O_RDONLY)) < 0 )
+ {
+ Syslog(LOG_WARNING, "Error opening /dev/kmem\n");
+ return(0);
+ }
+ if ( lseek64(memfd, address, SEEK_SET) < 0 )
+ {
+ Syslog(LOG_WARNING, "Error seeking in /dev/kmem\n");
+ Syslog(LOG_WARNING, "Symbol %s, value %08x\n", symbol, address);
+ return(0);
+ }
+ if ( read(memfd, \
+ (char *)&sym_array_modules[num_modules].module, \
+ sizeof(struct module)) < 0 )
+ {
+ Syslog(LOG_WARNING, "Error reading module "
+ "descriptor.\n");
+ return(0);
+ }
+ close(memfd);
+
+ /* Save the module name. */
+ mp->name = (char *) malloc(strlen(&symbol[1]) + 1);
+ if ( mp->name == (char *) 0 )
+ return(0);
+ strcpy(mp->name, &symbol[1]);
+
+ mp->num_syms = 0;
+ mp->sym_array = (struct sym_table *) 0;
+ ++num_modules;
+ return(1);
+ }
+ else
+ {
+ if (num_modules > 0)
+ mp = &sym_array_modules[num_modules - 1];
+ else
+ mp = &sym_array_modules[0];
+ AddSymbol(mp, address, symbol);
+ }
+
+
+ return(1);
+}
+
+
+/**************************************************************************
+ * Function: AddSymbol
+ *
+ * Purpose: This function is responsible for adding a symbol name
+ * and its address to the symbol table.
+ *
+ * Arguements: (struct Module *) mp, (unsigned long) address, (char *) symbol
+ *
+ * mp:-> A pointer to the module which the symbol is
+ * to be added to.
+ *
+ * address:-> The address of the symbol.
+ *
+ * symbol:-> The name of the symbol.
+ *
+ * Return: int
+ *
+ * A boolean value is assumed. True if the addition is
+ * successful. False if not.
+ **************************************************************************/
+
+static int AddSymbol(mp, address, symbol)
+
+ struct Module *mp;
+
+ unsigned long address;
+
+ char *symbol;
+
+{
+ auto int tmp;
+
+
+ /* Allocate space for the symbol table entry. */
+ mp->sym_array = (struct sym_table *) realloc(mp->sym_array, \
+ (mp->num_syms+1) * sizeof(struct sym_table));
+ if ( mp->sym_array == (struct sym_table *) 0 )
+ return(0);
+
+ /* Then the space for the symbol. */
+ tmp = strlen(symbol);
+ tmp += (strlen(mp->name) + 1);
+ mp->sym_array[mp->num_syms].name = (char *) malloc(tmp + 1);
+ if ( mp->sym_array[mp->num_syms].name == (char *) 0 )
+ return(0);
+ memset(mp->sym_array[mp->num_syms].name, '\0', tmp + 1);
+
+ /* Stuff interesting information into the module. */
+ mp->sym_array[mp->num_syms].value = address;
+ strcpy(mp->sym_array[mp->num_syms].name, mp->name);
+ strcat(mp->sym_array[mp->num_syms].name, ":");
+ strcat(mp->sym_array[mp->num_syms].name, symbol);
+ ++mp->num_syms;
+
+ return(1);
+}
+
+
+/**************************************************************************
+ * Function: LookupModuleSymbol
+ *
+ * Purpose: Find the symbol which is related to the given address from
+ * a kernel module.
+ *
+ * Arguements: (long int) value, (struct symbol *) sym
+ *
+ * value:-> The address to be located.
+ *
+ * sym:-> A pointer to a structure which will be
+ * loaded with the symbol's parameters.
+ *
+ * Return: (char *)
+ *
+ * If a match cannot be found a diagnostic string is printed.
+ * If a match is found the pointer to the symbolic name most
+ * closely matching the address is returned.
+ **************************************************************************/
+
+extern char * LookupModuleSymbol(value, sym)
+
+ unsigned long value;
+
+ struct symbol *sym;
+
+{
+ auto int nmod,
+ nsym;
+
+ auto struct sym_table *last;
+
+ auto struct Module *mp;
+
+
+ sym->size = 0;
+ sym->offset = 0;
+ if ( num_modules == 0 )
+ return((char *) 0);
+
+ for(nmod= 0; nmod < num_modules; ++nmod)
+ {
+ mp = &sym_array_modules[nmod];
+
+ /*
+ * Run through the list of symbols in this module and
+ * see if the address can be resolved.
+ */
+ for(nsym= 1, last = &mp->sym_array[0];
+ nsym < mp->num_syms;
+ ++nsym)
+ {
+ if ( mp->sym_array[nsym].value > value )
+ {
+ sym->offset = value - last->value;
+ sym->size = mp->sym_array[nsym].value - \
+ last->value;
+ return(last->name);
+ }
+ last = &mp->sym_array[nsym];
+ }
+
+
+ /*
+ * At this stage of the game we still cannot give up the
+ * ghost. There is the possibility that the address is
+ * from a module which has no symbols registered with
+ * the kernel. The solution is to compare the address
+ * against the starting address and extant of the module
+ * If it is in this range we can at least return the
+ * name of the module.
+ */
+#if LINUX_VERSION_CODE < 0x20112
+ if ( (void *) value >= mp->module.addr &&
+ (void *) value <= (mp->module.addr + \
+ mp->module.size * 4096) )
+#else
+ if ( value >= mp->module_info.addr &&
+ value <= (mp->module_info.addr + \
+ mp->module.size * 4096) )
+#endif
+ {
+ /*
+ * A special case needs to be checked for. The above
+ * conditional tells us that we are within the
+ * extant of this module but symbol lookup has
+ * failed.
+ *
+ * We need to check to see if any symbols have
+ * been defined in this module. If there have been
+ * symbols defined the assumption must be made that
+ * the faulting address lies somewhere beyond the
+ * last symbol. About the only thing we can do
+ * at this point is use an offset from this
+ * symbol.
+ */
+ if ( mp->num_syms > 0 )
+ {
+ last = &mp->sym_array[mp->num_syms - 1];
+#if LINUX_VERSION_CODE < 0x20112
+ sym->size = (int) mp->module.addr + \
+ (mp->module.size * 4096) - value;
+#else
+ sym->size = (int) mp->module_info.addr + \
+ (mp->module.size * 4096) - value;
+#endif
+ sym->offset = value - last->value;
+ return(last->name);
+ }
+
+ /*
+ * There were no symbols defined for this module.
+ * Return the module name and the offset of the
+ * faulting address in the module.
+ */
+ sym->size = mp->module.size * 4096;
+#if LINUX_VERSION_CODE < 0x20112
+ sym->offset = (void *) value - mp->module.addr;
+#else
+ sym->offset = value - mp->module_info.addr;
+#endif
+ return(mp->name);
+ }
+ }
+
+ /* It has been a hopeless exercise. */
+ return((char *) 0);
+}
+
+
+/*
+ * Setting the -DTEST define enables the following code fragment to
+ * be compiled. This produces a small standalone program which will
+ * dump the current kernel symbol table.
+ */
+#if defined(TEST)
+
+#include <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, \
+ 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
diff --git a/ksyms.h b/ksyms.h
new file mode 100644
index 00000000..4e70ba05
--- /dev/null
+++ b/ksyms.h
@@ -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 *);
diff --git a/modutils.patch b/modutils.patch
new file mode 100644
index 00000000..4dff7f35
--- /dev/null
+++ b/modutils.patch
@@ -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;
+ }
diff --git a/oops.c b/oops.c
new file mode 100644
index 00000000..14573f0f
--- /dev/null
+++ b/oops.c
@@ -0,0 +1,118 @@
+/*
+ * Loadable driver which provides the ability to generate a kernel
+ * protection fault. Mainly useful for testing the address translation
+ * capabilities of klogd.
+ *
+ * Fri Oct 27 14:34:27 CDT 1995: Dr. Wettstein
+ *
+ * Initial version.
+ */
+
+#define NEW_MODULES
+
+/* Kernel includes. */
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+
+/* Standard module stuff. */
+#if defined(NEW_MODULES)
+#include <linux/module.h>
+#else
+#include <linux/module.h>
+#include <linux/version.h>
+char kernel_version[] = UTS_RELEASE;
+#endif
+
+
+static int major = 32;
+
+
+#ifdef MODULE
+static int oops_ioctl(struct inode *, struct file *, unsigned int cmd, unsigned long arg);
+static int oops_open(struct inode * node, struct file * file);
+static void oops(void);
+
+static struct symbol_table these_symbols = {
+#include <linux/symtab_begin.h>
+ X(oops_open),
+ X(oops_ioctl),
+ X(oops),
+#include <linux/symtab_end.h>
+};
+
+/* driver specific module definitions */
+static struct file_operations oops_fops1 = {
+ NULL, /* hw_lseek */
+ NULL, /* hw_read */
+ NULL, /* write */
+ NULL, /* hw_readdir */
+ NULL, /* hw_select */
+ oops_ioctl, /* hw_ioctl */
+ NULL, /* mmap */
+ oops_open, /* hw_open */
+ NULL, /* hw_release */
+ NULL /* fsync */
+};
+
+static int oops_open(struct inode * node, struct file * file)
+{
+ printk("Called oops_open.\n");
+ return(0);
+}
+
+
+static int oops_ioctl(struct inode * node, struct file * file, \
+ unsigned int cmd, unsigned long arg)
+{
+
+ printk("Called oops_ioctl.\n");
+ printk("Cmd: %d, Arg: %ld\n", cmd, arg);
+ if ( cmd == 1 )
+ {
+ oops();
+ }
+
+ return(0);
+}
+
+static void oops()
+
+{
+ auto unsigned long *p = (unsigned long *) 828282828;
+ *p = 5;
+ return;
+}
+
+
+int
+init_module(void)
+{
+ printk("oops: Module initilization.\n");
+ if (register_chrdev(major, "oops", &oops_fops1)) {
+ printk("register_chrdev failed.");
+ return -EIO;
+ }
+
+ printk("oops: Registering symbols.\n");
+ register_symtab(&these_symbols);
+
+ return 0;
+}
+
+
+void
+cleanup_module(void)
+{
+ /* driver specific cleanups, ususally "unregister_*()" */
+ printk("oops: Module unloadeding.\n");
+ if (unregister_chrdev(major, "oops") != 0)
+ printk("cleanup_module failed\n");
+ else
+ printk("cleanup_module succeeded\n");
+
+ return;
+
+}
+#endif /* MODULE */
diff --git a/oops_test.c b/oops_test.c
new file mode 100644
index 00000000..f710d4cd
--- /dev/null
+++ b/oops_test.c
@@ -0,0 +1,52 @@
+/*
+ * This is a small test program for generating a kernel protection fault
+ * using the oops loadable module.
+ *
+ * Fri Apr 26 12:52:43 CDT 1996: Dr. Wettstein
+ * Initial version.
+ */
+
+
+/* Includes. */
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+
+/* Function prototypes. */
+extern int main(int, char **);
+
+
+extern int main(argc, argv)
+
+ int argc;
+
+ char *argv[];
+
+{
+ auto int fd;
+
+ if ( argc != 2 )
+ {
+ fprintf(stderr, "No oops device specified.\n");
+ return(1);
+ }
+
+ if ( (fd = open(argv[1], O_RDONLY)) < 0 )
+ {
+ fprintf(stderr, "Cannot open device: %s.\n", argv[1]);
+ return(1);
+ }
+
+ if ( ioctl(fd, 1, 0) < 0 )
+ {
+ fprintf(stderr, "Failed on oops.\n");
+ return(1);
+ }
+
+ printf("OOoops\n");
+
+ close(fd);
+ return(0);
+}
diff --git a/pidfile.c b/pidfile.c
new file mode 100644
index 00000000..08520293
--- /dev/null
+++ b/pidfile.c
@@ -0,0 +1,130 @@
+/*
+ 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, 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;
+}
+
+/* remove_pid
+ *
+ * Remove the the specified file. The result from unlink(2)
+ * is returned
+ */
+int remove_pid (char *pidfile)
+{
+ return unlink (pidfile);
+}
+
diff --git a/pidfile.h b/pidfile.h
new file mode 100644
index 00000000..19d19c16
--- /dev/null
+++ b/pidfile.h
@@ -0,0 +1,50 @@
+/*
+ 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);
+
+/* remove_pid
+ *
+ * Remove the the specified file. The result from unlink(2)
+ * is returned
+ */
+int remove_pid (char *pidfile);
diff --git a/sysklogd.8 b/sysklogd.8
new file mode 100644
index 00000000..ccf1e654
--- /dev/null
+++ b/sysklogd.8
@@ -0,0 +1,607 @@
+.\" Copyright 1994 Dr. Greg Wettstein, Enjellic Systems Development.
+.\" May be distributed under the GNU General Public License
+.\" Sun Aug 30 11:35:55 MET: Martin Schulze: Updates
+.\"
+.TH SYSKLOGD 8 "12 October 1998" "Version 1.3" "Linux System Administration"
+.SH NAME
+sysklogd \- Linux system logging utilities.
+.SH SYNOPSIS
+.B syslogd
+.RB [ " \-a "
+.I socket
+]
+.RB [ " \-d " ]
+.RB [ " \-f "
+.I config file
+]
+.RB [ " \-h " ]
+.RB [ " \-l "
+.I hostlist
+]
+.RB [ " \-m "
+.I interval
+]
+.RB [ " \-n " ]
+.RB [ " \-p"
+.IB socket
+]
+.RB [ " \-r " ]
+.RB [ " \-s "
+.I domainlist
+]
+.RB [ " \-v " ]
+.LP
+.SH DESCRIPTION
+.B Sysklogd
+provides two system utilities which provide support for
+system logging and kernel message trapping. Support of both internet and
+unix domain sockets enables this utility package to support both local
+and remote logging.
+
+System logging is provided by a version of
+.BR syslogd (8)
+derived from the
+stock BSD sources. Support for kernel logging is provided by the
+.BR klogd (8)
+utility which allows kernel logging to be conducted in either a
+standalone fashion or as a client of syslogd.
+
+.B Syslogd
+provides a kind of logging that many modern programs use. Every logged
+message contains at least a time and a hostname field, normally a
+program name field, too, but that depends on how trusty the logging
+program is.
+
+While the
+.B syslogd
+sources have been heavily modified a couple of notes
+are in order. First of all there has been a systematic attempt to
+insure that syslogd follows its default, standard BSD behavior.
+The second important concept to note is that this version of syslogd
+interacts transparently with the version of syslog found in the
+standard libraries. If a binary linked to the standard shared
+libraries fails to function correctly we would like an example of the
+anomalous behavior.
+
+The main configuration file
+.I /etc/syslog.conf
+or an alternative file, given with the
+.B "\-f"
+option, is read at startup. Any lines that begin with the hash mark
+(``#'') and empty lines are ignored. If an error occurs during parsing
+the whole line is ignored.
+
+.LP
+.SH OPTIONS
+.TP
+.BI "\-a " "socket"
+Using this argument you can specify additional sockets from that
+.B syslogd
+has to listen to. This is needed if you're going to let some daemon
+run within a chroot() environment. You can use up to 19 additional
+sockets. If your environment needs even more, you have to increase
+the symbol
+.B MAXFUNIX
+within the syslogd.c source file. An example for a chroot() daemon is
+described by the people from OpenBSD at
+http://www.psionic.com/papers/dns.html.
+.TP
+.B "\-d"
+Turns on debug mode. Using this the daemon will not proceed a
+.BR fork (2)
+to set itself in the background, but opposite to that stay in the
+foreground and write much debug information on the current tty. See the
+DEBUGGING section for more information.
+.TP
+.BI "\-f " "config file"
+Specify an alternative configuration file instead of
+.IR /etc/syslog.conf ","
+which is the default.
+.TP
+.BI "\-h "
+By default syslogd will not forward messages it receives from remote hosts.
+Specifying this switch on the command line will cause the log daemon to
+forward any remote messages it receives to forwarding hosts which have been
+defined.
+.TP
+.BI "\-l " "hostlist"
+Specify a hostname that should be logged only with its simple hostname
+and not the fqdn. Multiple hosts may be specified using the colon
+(``:'') separator.
+.TP
+.BI "\-m " "interval"
+The
+.B syslogd
+logs a mark timestamp regularly. The default
+.I interval
+between two \fI-- MARK --\fR lines is 20 minutes. This can be changed
+with this option. Setting the
+.I interval
+to zero turns it off entirely.
+.TP
+.B "\-n"
+Avoid auto-backgrounding. This is needed especially if the
+.B syslogd
+is started and controlled by
+.BR init (8).
+.TP
+.BI "\-p " "socket"
+You can specify an alternative unix domain socket instead of
+.IR /dev/log "."
+.TP
+.B "\-r"
+This option will enable the facility to receive message from the
+network using an internet domain socket with the syslog service (see
+.BR services (5)).
+The default is to not receive any messages from the network.
+
+This option is introduced in version 1.3 of the sysklogd
+package. Please note that the default behavior is the opposite of
+how older versions behave, so you might have to turn this on.
+.TP
+.BI "\-s " "domainlist"
+Specify a domainname that should be stripped off before
+logging. Multiple domains may be specified using the colon (``:'')
+separator.
+Please be advised that no sub-domains may be specified but only entire
+domains. For example if
+.B "\-s north.de"
+is specified and the host logging resolves to satu.infodrom.north.de
+no domain would be cut, you will have to specify two domains like:
+.BR "\-s north.de:infodrom.north.de" .
+.TP
+.B "\-v"
+Print version and exit.
+.LP
+.SH SIGNALS
+.B Syslogd
+reacts to a set of signals. You may easily send a signal to
+.B syslogd
+using the following:
+.IP
+.nf
+kill -SIGNAL `cat /var/run/syslogd.pid`
+.fi
+.PP
+.TP
+.B SIGHUP
+This lets
+.B syslogd
+perform a re-initialization. All open files are closed, the
+configuration file (default is
+.IR /etc/syslog.conf ")"
+will be reread and the
+.BR syslog (3)
+facility is started again.
+.TP
+.B SIGTERM
+The
+.B syslogd
+will die.
+.TP
+.BR SIGINT ", " SIGQUIT
+If debugging is enabled these are ignored, otherwise
+.B syslogd
+will die.
+.TP
+.B SIGUSR1
+Switch debugging on/off. This option can only be used if
+.B syslogd
+is started with the
+.B "\-d"
+debug option.
+.TP
+.B SIGCHLD
+Wait for childs if some were born, because of wall'ing messages.
+.LP
+.SH CONFIGURATION FILE SYNTAX DIFFERENCES
+.B Syslogd
+uses a slightly different syntax for its configuration file than
+the original BSD sources. Originally all messages of a specific priority
+and above were forwarded to the log file.
+.IP
+For example the following line caused ALL output from daemons using
+the daemon facilities (debug is the lowest priority, so every higher
+will also match) to go into
+.IR /usr/adm/daemons :
+.IP
+.nf
+ # Sample syslog.conf
+ daemon.debug /usr/adm/daemons
+.fi
+.PP
+Under the new scheme this behavior remains the same. The difference
+is the addition of four new specifiers, the asterisk (\fB*\fR)
+wildcard, the equation sign (\fB=\fR), the exclamation mark
+(\fB!\fR), and the minus sign (\fB-\fR).
+
+The \fB*\fR specifies that all messages for the
+specified facility are to be directed to the destination. Note that
+this behavior is degenerate with specifying a priority level of debug.
+Users have indicated that the asterisk notation is more intuitive.
+
+The \fB=\fR wildcard is used to restrict logging to the specified priority
+class. This allows, for example, routing only debug messages to a
+particular logging source.
+.IP
+For example the following line in
+.I syslog.conf
+would direct debug messages from all sources to the
+.I /usr/adm/debug
+file.
+.IP
+.nf
+ # Sample syslog.conf
+ *.=debug /usr/adm/debug
+.fi
+.PP
+.\" The \fB!\fR as the first character of a priority inverts the above
+.\" mentioned interpretation.
+The \fB!\fR is used to exclude logging of the specified
+priorities. This affects all (!) possibilities of specifying priorities.
+.IP
+For example the following lines would log all messages of the facility
+mail except those with the priority info to the
+.I /usr/adm/mail
+file. And all messages from news.info (including) to news.crit
+(excluding) would be logged to the
+.I /usr/adm/news
+file.
+.IP
+.nf
+ # Sample syslog.conf
+ mail.*;mail.!=info /usr/adm/mail
+ news.info;news.!crit /usr/adm/news
+.fi
+.PP
+You may use it intuitively as an exception specifier. The above
+mentioned interpretation is simply inverted. Doing that you may use
+
+.nf
+ mail.none
+.fi
+or
+.nf
+ mail.!*
+.fi
+or
+.nf
+ mail.!debug
+.fi
+
+to skip every message that comes with a mail facility. There is much
+room to play with it. :-)
+
+The \fB-\fR may only be used to prefix a filename if you want to omit
+sync'ing the file after every write to it.
+
+This may take some acclimatization for those individuals used to the
+pure BSD behavior but testers have indicated that this syntax is
+somewhat more flexible than the BSD behavior. Note that these changes
+should not affect standard
+.BR syslog.conf (5)
+files. You must specifically
+modify the configuration files to obtain the enhanced behavior.
+.LP
+.SH SUPPORT FOR REMOTE LOGGING
+These modifications provide network support to the syslogd facility.
+Network support means that messages can be forwarded from one node
+running syslogd to another node running syslogd where they will be
+actually logged to a disk file.
+
+To enable this you have to specify the
+.B "\-r"
+option on the command line. The default behavior is that
+.B syslogd
+won't listen to the network.
+
+The strategy is to have syslogd listen on a unix domain socket for
+locally generated log messages. This behavior will allow syslogd to
+inter-operate with the syslog found in the standard C library. At the
+same time syslogd listens on the standard syslog port for messages
+forwarded from other hosts. To have this work correctly the
+.BR services (5)
+files (typically found in
+.IR /etc )
+must have the following
+entry:
+.IP
+.nf
+ syslog 514/udp
+.fi
+.PP
+If this entry is missing
+.B syslogd
+neither can receive remote messages nor send them, because the UDP
+port cant be opened. Instead
+.B syslogd
+will die immediately, blowing out an error message.
+
+To cause messages to be forwarded to another host replace
+the normal file line in the
+.I syslog.conf
+file with the name of the host to which the messages is to be sent
+prepended with an @.
+.IP
+For example, to forward
+.B ALL
+messages to a remote host use the
+following
+.I syslog.conf
+entry:
+.IP
+.nf
+ # Sample syslogd configuration file to
+ # messages to a remote host forward all.
+ *.* @hostname
+.fi
+
+To forward all \fBkernel\fP messages to a remote host the
+configuration file would be as follows:
+.IP
+.nf
+ # Sample configuration file to forward all kernel
+ # messages to a remote host.
+ kern.* @hostname
+.fi
+.PP
+
+If the remote hostname cannot be resolved at startup, because the
+name-server might not be accessible (it may be started after syslogd)
+you don't have to worry.
+.B Syslogd
+will retry to resolve the name ten times and then complain. Another
+possibility to avoid this is to place the hostname in
+.IR /etc/hosts .
+
+With normal
+.BR syslogd s
+you would get syslog-loops if you send out messages that were received
+from a remote host to the same host (or more complicated to a third
+host that sends it back to the first one, and so on). In my domain
+(Infodrom Oldenburg) we accidently got one and our disks filled up
+with the same single message. :-(
+
+To avoid this in further times no messages that were received from a
+remote host are sent out to another (or the same) remote host
+anymore. If there are scenarios where this doesn't make sense, please
+drop me (Joey) a line.
+
+If the remote host is located in the same domain as the host,
+.B syslogd
+is running on, only the simple hostname will be logged instead of
+the whole fqdn.
+
+In a local network you may provide a central log server to have all
+the important information kept on one machine. If the network consists
+of different domains you don't have to complain about logging fully
+qualified names instead of simple hostnames. You may want to use the
+strip-domain feature
+.B \-s
+of this server. You can tell the
+.B syslogd
+to strip off several domains other than the one the server is located
+in and only log simple hostnames.
+
+Using the
+.B \-l
+option there's also a possibility to define single hosts as local
+machines. This, too, results in logging only their simple hostnames
+and not the fqdns.
+
+The UDP socket used to forward messages to remote hosts or to receive
+messages from them is only opened when it is needed. In releases
+prior to 1.3-23 it was opened every time but not opened for reading or
+forwarding respectively.
+
+.SH OUTPUT TO NAMED PIPES (FIFOs)
+This version of syslogd has support for logging output to named pipes
+(fifos). A fifo or named pipe can be used as a destination for log
+messages by prepending a pipy symbol (``|'') to the name of the
+file. This is handy for debugging. Note that the fifo must be created
+with the mkfifo command before syslogd is started.
+.IP
+The following configuration file routes debug messages from the
+kernel to a fifo:
+.IP
+.nf
+ # Sample configuration to route kernel debugging
+ # messages ONLY to /usr/adm/debug which is a
+ # named pipe.
+ kern.=debug |/usr/adm/debug
+.fi
+.LP
+.SH INSTALLATION CONCERNS
+There is probably one important consideration when installing this
+version of syslogd. This version of syslogd is dependent on proper
+formatting of messages by the syslog function. The functioning of the
+syslog function in the shared libraries changed somewhere in the
+region of libc.so.4.[2-4].n. The specific change was to
+null-terminate the message before transmitting it to the
+.I /dev/log
+socket. Proper functioning of this version of syslogd is dependent on
+null-termination of the message.
+
+This problem will typically manifest itself if old statically linked
+binaries are being used on the system. Binaries using old versions of
+the syslog function will cause empty lines to be logged followed by
+the message with the first character in the message removed.
+Relinking these binaries to newer versions of the shared libraries
+will correct this problem.
+
+Both the
+.BR syslogd "(8) and the " klogd (8)
+can either be run from
+.BR init (8)
+or started as part of the rc.*
+sequence. If it is started from init the option \fI\-n\fR must be set,
+otherwise you'll get tons of syslog daemons started. This is because
+.BR init (8)
+depends on the process ID.
+.LP
+.SH SECURITY THREATS
+There is the potential for the syslogd daemon to be
+used as a conduit for a denial of service attack. Thanks go to John
+Morrison (jmorriso@rflab.ee.ubc.ca) for alerting me to this potential.
+A rogue program(mer) could very easily flood the syslogd daemon with
+syslog messages resulting in the log files consuming all the remaining
+space on the filesystem. Activating logging over the inet domain
+sockets will of course expose a system to risks outside of programs or
+individuals on the local machine.
+
+There are a number of methods of protecting a machine:
+.IP 1.
+Implement kernel firewalling to limit which hosts or networks have
+access to the 514/UDP socket.
+.IP 2.
+Logging can be directed to an isolated or non-root filesystem which,
+if filled, will not impair the machine.
+.IP 3.
+The ext2 filesystem can be used which can be configured to limit a
+certain percentage of a filesystem to usage by root only. \fBNOTE\fP
+that this will require syslogd to be run as a non-root process.
+\fBALSO NOTE\fP that this will prevent usage of remote logging since
+syslogd will be unable to bind to the 514/UDP socket.
+.IP 4.
+Disabling inet domain sockets will limit risk to the local machine.
+.IP 5.
+Use step 4 and if the problem persists and is not secondary to a rogue
+program/daemon get a 3.5 ft (approx. 1 meter) length of sucker rod*
+and have a chat with the user in question.
+
+Sucker rod def. \(em 3/4, 7/8 or 1in. hardened steel rod, male
+threaded on each end. Primary use in the oil industry in Western
+North Dakota and other locations to pump 'suck' oil from oil wells.
+Secondary uses are for the construction of cattle feed lots and for
+dealing with the occasional recalcitrant or belligerent individual.
+.LP
+.SH DEBUGGING
+When debugging is turned on using
+.B "\-d"
+option then
+.B syslogd
+will be very verbose by writing much of what it does on stdout. Whenever
+the configuration file is reread and re-parsed you'll see a tabular,
+corresponding to the internal data structure. This tabular consists of
+four fields:
+.TP
+.I number
+This field contains a serial number starting by zero. This number
+represents the position in the internal data structure (i.e. the
+array). If one number is left out then there might be an error in the
+corresponding line in
+.IR /etc/syslog.conf .
+.TP
+.I pattern
+This field is tricky and represents the internal structure
+exactly. Every column stands for a facility (refer to
+.BR syslog (3)).
+As you can see, there are still some facilities left free for former
+use, only the left most are used. Every field in a column represents
+the priorities (refer to
+.BR syslog (3)).
+.TP
+.I action
+This field describes the particular action that takes place whenever a
+message is received that matches the pattern. Refer to the
+.BR syslog.conf (5)
+manpage for all possible actions.
+.TP
+.I arguments
+This field shows additional arguments to the actions in the last
+field. For file-logging this is the filename for the logfile; for
+user-logging this is a list of users; for remote logging this is the
+hostname of the machine to log to; for console-logging this is the
+used console; for tty-logging this is the specified tty; wall has no
+additional arguments.
+.SH FILES
+.PD 0
+.TP
+.I /etc/syslog.conf
+Configuration file for
+.BR syslogd .
+See
+.BR syslog.conf (5)
+for exact information.
+.TP
+.I /dev/log
+The Unix domain socket to from where local syslog messages are read.
+.TP
+.I /var/run/syslogd.pid
+The file containing the process id of
+.BR syslogd .
+.PD
+.SH BUGS
+If an error occurs in one line the whole rule is ignored.
+
+.B Syslogd
+doesn't change the filemode of opened logfiles at any stage of
+process. If a file is created it is world readable. If you want to
+avoid this, you have to create it and change permissions on your own.
+This could be done in combination with rotating logfiles using the
+.BR savelog (8)
+program that is shipped in the
+.B smail
+3.x distribution. Remember that it might be a security hole if
+everybody is able to read auth.* messages as these might contain
+passwords.
+.LP
+.SH SEE ALSO
+.BR syslog.conf (5),
+.BR klogd (8),
+.BR logger (1),
+.BR syslog (2),
+.BR syslog (3),
+.BR services (5),
+.BR savelog (8)
+.LP
+.SH COLLABORATORS
+.B Syslogd
+is taken from BSD sources, Greg Wettstein (greg@wind.enjellic.com)
+performed the port to Linux, Martin Schulze (joey@linux.de)
+fixed some bugs and added several new features.
+.B Klogd
+was originally written by Steve Lord (lord@cray.com), Greg Wettstein
+made major improvements.
+
+.PD 0
+.TP
+Dr. Greg Wettstein
+.TP
+Enjellic Systems Development
+.TP
+Oncology Research Division Computing Facility
+.TP
+Roger Maris Cancer Center
+.TP
+Fargo, ND
+.TP
+greg@wind.enjellic.com
+
+.TP
+Stephen Tweedie
+.TP
+Department of Computer Science
+.TP
+Edinburgh University, Scotland
+.TP
+sct@dcs.ed.ac.uk
+
+.TP
+Juha Virtanen
+.TP
+jiivee@hut.fi
+
+.TP
+Shane Alderton
+.TP
+shane@ion.apana.org.au
+
+.TP
+Martin Schulze
+.TP
+Infodrom Oldenburg
+.TP
+joey@linux.de
+.PD
+.zZ
diff --git a/syslog-tst.conf b/syslog-tst.conf
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/syslog-tst.conf
diff --git a/syslog.c b/syslog.c
new file mode 100644
index 00000000..0d63c81d
--- /dev/null
+++ b/syslog.c
@@ -0,0 +1,254 @@
+/*
+ * 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.
+ *
+ */
+
+#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;
+ 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 */
+ if (write(LogFile, tbuf, cnt + 1) >= 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);
+}
diff --git a/syslog.conf b/syslog.conf
new file mode 100644
index 00000000..801f35fb
--- /dev/null
+++ b/syslog.conf
@@ -0,0 +1,46 @@
+# /etc/syslog.conf - Configuration file for syslogd(8)
+#
+# For info about the format of this file, see "man syslog.conf".
+#
+*.=debug -/usr/adm/debug
+*.warning /usr/adm/syslog
+
+# Store critical stuff in critical
+#
+*.=crit;kern.none /var/adm/critical
+
+# Kernel messages are first, stored in the kernel file,
+# critical messages and higher ones also go to another
+# host and to the console
+#
+kern.* /var/adm/kernel
+kern.crit @finlandia
+kern.crit /dev/console
+kern.info;kern.!err /var/adm/kernel-info
+
+# The tcp wrapper loggs with mail.info, we display all
+# the connections on tty12
+#
+mail.=info /dev/tty12
+
+# Store all mail concearning stuff in a file
+#
+mail.*;mail.!=info -/var/adm/mail
+
+# Log all mail.info and news.info messages to info
+#
+mail,news.=info -/var/adm/info
+
+# Log info and notice mesages to messages file
+#
+*.=info;*.=notice;mail.none -/usr/adm/messages
+#*.=info;mail,news.none -/usr/adm/messages
+
+# Emergency messages will be displayed using wall
+#
+*.=emerg *
+
+# Messages of the priority alert will be directed
+# to the operator
+#
+*.alert root,joey
diff --git a/syslog.conf.5 b/syslog.conf.5
new file mode 100644
index 00000000..7f40c1cb
--- /dev/null
+++ b/syslog.conf.5
@@ -0,0 +1,397 @@
+.\" syslog.conf - syslogd(8) configuration file
+.\" 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.
+.\"
+.TH SYSLOG.CONF 5 "1 January 1998" "Version 1.3" "Linux System Administration"
+.SH NAME
+syslog.conf \- syslogd(8) configuration file
+.SH DESCRIPTION
+The
+.I syslog.conf
+file is the main configuration file for the
+.BR syslogd (8)
+which logs system messages on *nix systems. This file specifies rules
+for logging. For special features see the
+.BR sysklogd (8)
+manpage.
+
+Every rule consists of two fields, a
+.I selector
+field and an
+.I action
+field. These two fields are separated by one or more spaces or
+tabs. The selector field specifies a pattern of facilities and
+priorities belonging to the specified action.
+
+Lines starting with a hash mark (``#'') and empty lines are ignored.
+
+This release of
+.B syslogd
+is able to understand an extended syntax. One rule can be divided
+into several lines if the leading line is terminated with an backslash
+(``\\'').
+
+.SH SELECTORS
+The selector field itself again consists of two parts, a
+.I facility
+and a
+.IR priority ,
+separated by a period (``.'').
+Both parts are case insensitive and can also be specified as decimal
+numbers, but don't do that, you have been warned. Both facilities and
+priorities are described in
+.BR syslog (3).
+The names mentioned below correspond to the similar
+.BR LOG_ -values
+in
+.IR /usr/include/syslog.h .
+
+The
+.I facility
+is one of the following keywords:
+.BR auth ", " authpriv ", " cron ", " daemon ", " kern ", " lpr ", "
+.BR mail ", " mark ", " news ", " security " (same as " auth "), "
+.BR syslog ", " user ", " uucp " and " local0 " through " local7 .
+The keyword
+.B security
+should not be used anymore and
+.B mark
+is only for internal use and therefore should not be used in
+applications. Anyway, you may want to specify and redirect these
+messages here. The
+.I facility
+specifies the subsystem that produced the message, i.e. all mail
+programs log with the mail facility
+.BR "" ( LOG_MAIL )
+if they log using syslog.
+
+The
+.I priority
+is one of the following keywords, in ascending order:
+.BR debug ", " info ", " notice ", " warning ", " warn " (same as "
+.BR warning "), " err ", " error " (same as " err "), " crit ", "
+.BR alert ", " emerg ", " panic " (same as " emerg ).
+The keywords
+.BR error ", " warn " and " panic
+are deprecated and should not be used anymore. The
+.I priority
+defines the severity of the message
+
+The behavior of the original BSD syslogd is that all messages of the
+specified priority and higher are logged according to the given
+action. This
+.BR syslogd (8)
+behaves the same, but has some extensions.
+
+In addition to the above mentioned names the
+.BR syslogd (8)
+understands the following extensions: An asterisk (``*'') stands for
+all facilities or all priorities, depending on where it is used
+(before or after the period). The keyword
+.B none
+stands for no priority of the given facility.
+
+You can specify multiple facilities with the same priority pattern in
+one statement using the comma (``,'') operator. You may specify as
+much facilities as you want. Remember that only the facility part from
+such a statement is taken, a priority part would be skipped.
+
+Multiple selectors may be specified for a single
+.I action
+using the semicolon (``;'') separator. Remember that each selector in
+the
+.I selector
+field is capable to overwrite the preceding ones. Using this
+behavior you can exclude some priorities from the pattern.
+
+This
+.BR syslogd (8)
+has a syntax extension to the original BSD source, that makes its use
+more intuitively. You may precede every priority with an equation sign
+(``='') to specify only this single priority and not any of the
+above. You may also (both is valid, too) precede the priority with an
+exclamation mark (``!'') to ignore all that priorities, either exact
+this one or this and any higher priority. If you use both extensions
+than the exclamation mark must occur before the equation sign, just
+use it intuitively.
+
+.SH ACTIONS
+The action field of a rule describes the abstract term
+``logfile''. A ``logfile'' need not to be a real file, btw. The
+.BR syslogd (8)
+provides the following actions.
+
+.SS Regular File
+Typically messages are logged to real files. The file has to be
+specified with full pathname, beginning with a slash ``/''.
+
+You may prefix each entry with the minus ``-'' sign to omit syncing
+the file after every logging. Note that you might lose information if
+the system crashes right behind a write attempt. Nevertheless this
+might give you back some performance, especially if you run programs
+that use logging in a very verbose manner.
+
+.SS Named Pipes
+This version of
+.BR syslogd (8)
+has support for logging output to
+named pipes (fifos). A fifo or named pipe can be used as
+a destination for log messages by prepending a pipe symbol (``|'') to
+the name of the file. This is handy for debugging. Note that the fifo
+must be created with the
+.BR mkfifo (1)
+command before
+.BR syslogd (8)
+is started.
+
+.SS Terminal and Console
+If the file you specified is a tty, special tty-handling is done, same
+with
+.IR /dev/console .
+
+.SS Remote Machine
+This
+.BR syslogd (8)
+provides full remote logging, i.e. is able to send messages to a
+remote host running
+.BR syslogd (8)
+and to receive messages from remote hosts. The remote
+host won't forward the message again, it will just log them
+locally. To forward messages to another host, prepend the hostname
+with the at sign (``@'').
+
+Using this feature you're able to control all syslog messages on one
+host, if all other machines will log remotely to that. This tears down
+administration needs.
+
+.SS List of Users
+Usually critical messages are also directed to ``root'' on that
+machine. You can specify a list of users that shall get the message by
+simply writing the login. You may specify more than one user by
+separating them with commas (``,''). If they're logged in they
+get the message. Don't think a mail would be sent, that might be too
+late.
+
+.SS Everyone logged on
+Emergency messages often go to all users currently online to notify
+them that something strange is happening with the system. To specify
+this
+.IR wall (1)-feature
+use an asterisk (``*'').
+
+.SH EXAMPLES
+Here are some example, partially taken from a real existing site and
+configuration. Hopefully they rub out all questions to the
+configuration, if not, drop me (Joey) a line.
+.IP
+.nf
+# Store critical stuff in critical
+#
+*.=crit;kern.none /var/adm/critical
+.fi
+.LP
+This will store all messages with the priority
+.B crit
+in the file
+.IR /var/adm/critical ,
+except for any kernel message.
+
+.IP
+.nf
+# Kernel messages are first, stored in the kernel
+# file, critical messages and higher ones also go
+# to another host and to the console
+#
+kern.* /var/adm/kernel
+kern.crit @finlandia
+kern.crit /dev/console
+kern.info;kern.!err /var/adm/kernel-info
+.fi
+.LP
+The first rule direct any message that has the kernel facility to the
+file
+.IR /var/adm/kernel .
+
+The second statement directs all kernel messages of the priority
+.B crit
+and higher to the remote host finlandia. This is useful, because if
+the host crashes and the disks get irreparable errors you might not be
+able to read the stored messages. If they're on a remote host, too,
+you still can try to find out the reason for the crash.
+
+The third rule directs these messages to the actual console, so the
+person who works on the machine will get them, too.
+
+The fourth line tells the syslogd to save all kernel messages that
+come with priorities from
+.BR info " up to " warning
+in the file
+.IR /var/adm/kernel-info .
+Everything from
+.I err
+and higher is excluded.
+
+.IP
+.nf
+# The tcp wrapper loggs with mail.info, we display
+# all the connections on tty12
+#
+mail.=info /dev/tty12
+.fi
+.LP
+This directs all messages that uses
+.BR mail.info " (in source " LOG_MAIL " | " LOG_INFO )
+to
+.IR /dev/tty12 ,
+the 12th console. For example the tcpwrapper
+.BR tcpd (8)
+uses this as it's default.
+
+.IP
+.nf
+# Store all mail concerning stuff in a file
+#
+mail.*;mail.!=info /var/adm/mail
+.fi
+.LP
+This pattern matches all messages that come with the
+.B mail
+facility, except for the
+.B info
+priority. These will be stored in the file
+.IR /var/adm/mail .
+
+.IP
+.nf
+# Log all mail.info and news.info messages to info
+#
+mail,news.=info /var/adm/info
+.fi
+.LP
+This will extract all messages that come either with
+.BR mail.info " or with " news.info
+and store them in the file
+.IR /var/adm/info .
+
+.IP
+.nf
+# Log info and notice messages to messages file
+#
+*.=info;*.=notice;\\
+ mail.none /var/log/messages
+.fi
+.LP
+This lets the
+.B syslogd
+log all messages that come with either the
+.BR info " or the " notice
+facility into the file
+.IR /var/log/messages ,
+except for all messages that use the
+.B mail
+facility.
+
+.IP
+.nf
+# Log info messages to messages file
+#
+*.=info;\\
+ mail,news.none /var/log/messages
+.fi
+.LP
+This statement causes the
+.B syslogd
+to log all messages that come with the
+.B info
+priority to the file
+.IR /var/log/messages .
+But any message coming either with the
+.BR mail " or the " news
+facility will not be stored.
+
+.IP
+.nf
+# Emergency messages will be displayed using wall
+#
+*.=emerg *
+.fi
+.LP
+This rule tells the
+.B syslogd
+to write all emergency messages to all currently logged in users. This
+is the wall action.
+
+.IP
+.nf
+# Messages of the priority alert will be directed
+# to the operator
+#
+*.alert root,joey
+.fi
+.LP
+This rule directs all messages with a priority of
+.B alert
+or higher to the terminals of the operator, i.e. of the users ``root''
+and ``joey'' if they're logged in.
+
+.IP
+.nf
+*.* @finlandia
+.fi
+.LP
+This rule would redirect all messages to a remote host called
+finlandia. This is useful especially in a cluster of machines where
+all syslog messages will be stored on only one machine.
+
+.SH CONFIGURATION FILE SYNTAX DIFFERENCES
+.B Syslogd
+uses a slightly different syntax for its configuration file than
+the original BSD sources. Originally all messages of a specific priority
+and above were forwarded to the log file. The modifiers ``='', ``!''
+and ``-'' were added to make the
+.B syslogd
+more flexible and to use it in a more intuitive manner.
+
+The original BSD syslogd doesn't understand spaces as separators between
+the selector and the action field.
+.SH FILES
+.PD 0
+.TP
+.I /etc/syslog.conf
+Configuration file for
+.B syslogd
+
+.SH BUGS
+The effects of multiple selectors are sometimes not intuitive. For
+example ``mail.crit,*.err'' will select ``mail'' facility messages at
+the level of ``err'' or higher, not at the level of ``crit'' or
+higher.
+
+.SH SEE ALSO
+.BR sysklogd (8),
+.BR klogd (8),
+.BR logger (1),
+.BR syslog (2),
+.BR syslog (3)
+
+.SH AUTHORS
+The
+.B syslogd
+is taken from BSD sources, Greg Wettstein (greg@wind.enjellic.com)
+performed the port to Linux, Martin Schulze (joey@linux.de)
+made some bugfixes and added some new features.
diff --git a/syslog_tst.c b/syslog_tst.c
new file mode 100644
index 00000000..ca786018
--- /dev/null
+++ b/syslog_tst.c
@@ -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, bufr);
+ logged += strlen(bufr);
+ if ( logged > 1024 )
+ {
+ sleep(1);
+ logged = 0;
+ }
+
+ }
+ }
+ else
+ while (argc-- > 1)
+ syslog(LOG_INFO, 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);
+}
diff --git a/syslogd.8 b/syslogd.8
new file mode 100644
index 00000000..d5ef84b6
--- /dev/null
+++ b/syslogd.8
@@ -0,0 +1 @@
+.so man8/sysklogd.8
diff --git a/syslogd.c b/syslogd.c
new file mode 100644
index 00000000..4c2014f6
--- /dev/null
+++ b/syslogd.c
@@ -0,0 +1,2803 @@
+/*
+ * 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 the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if !defined(lint) && !defined(NO_SCCS)
+char copyright2[] =
+"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#if !defined(lint) && !defined(NO_SCCS)
+static char sccsid[] = "@(#)syslogd.c 5.27 (Berkeley) 10/10/88";
+#endif /* not lint */
+
+/*
+ * syslogd -- log system messages
+ *
+ * This program implements a system log. It takes a series of lines.
+ * Each line may have a priority, signified as "<n>" as
+ * the first characters of the line. If this is
+ * not present, a default priority is used.
+ *
+ * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
+ * cause it to reread its configuration file.
+ *
+ * Defined Constants:
+ *
+ * MAXLINE -- the maximum line length that can be handled.
+ * DEFUPRI -- the default priority for user messages
+ * DEFSPRI -- the default priority for kernel messages
+ *
+ * Author: Eric Allman
+ * extensive changes by Ralph Campbell
+ * more extensive changes by Eric Allman (again)
+ *
+ * Steve Lord: Fix UNIX domain socket code, added linux kernel logging
+ * change defines to
+ * SYSLOG_INET - listen on a UDP socket
+ * SYSLOG_UNIXAF - listen on unix domain socket
+ * SYSLOG_KERNEL - listen to linux kernel
+ *
+ * Mon Feb 22 09:55:42 CST 1993: Dr. Wettstein
+ * Additional modifications to the source. Changed priority scheme
+ * to increase the level of configurability. In its stock configuration
+ * syslogd no longer logs all messages of a certain priority and above
+ * to a log file. The * wildcard is supported to specify all priorities.
+ * Note that this is a departure from the BSD standard.
+ *
+ * Syslogd will now listen to both the inetd and the unixd socket. The
+ * strategy is to allow all local programs to direct their output to
+ * syslogd through the unixd socket while the program listens to the
+ * inetd socket to get messages forwarded from other hosts.
+ *
+ * Fri Mar 12 16:55:33 CST 1993: Dr. Wettstein
+ * Thanks to Stephen Tweedie (dcs.ed.ac.uk!sct) for helpful bug-fixes
+ * and an enlightened commentary on the prioritization problem.
+ *
+ * Changed the priority scheme so that the default behavior mimics the
+ * standard BSD. In this scenario all messages of a specified priority
+ * and above are logged.
+ *
+ * Add the ability to specify a wildcard (=) as the first character
+ * of the priority name. Doing this specifies that ONLY messages with
+ * this level of priority are to be logged. For example:
+ *
+ * *.=debug /usr/adm/debug
+ *
+ * Would log only messages with a priority of debug to the /usr/adm/debug
+ * file.
+ *
+ * Providing an * as the priority specifies that all messages are to be
+ * logged. Note that this case is degenerate with specifying a priority
+ * level of debug. The wildcard * was retained because I believe that
+ * this is more intuitive.
+ *
+ * Thu Jun 24 11:34:13 CDT 1993: Dr. Wettstein
+ * Modified sources to incorporate changes in libc4.4. Messages from
+ * syslog are now null-terminated, syslogd code now parses messages
+ * based on this termination scheme. Linux as of libc4.4 supports the
+ * fsync system call. Modified code to fsync after all writes to
+ * log files.
+ *
+ * Sat Dec 11 11:59:43 CST 1993: Dr. Wettstein
+ * Extensive changes to the source code to allow compilation with no
+ * complaints with -Wall.
+ *
+ * Reorganized the facility and priority name arrays so that they
+ * compatible with the syslog.h source found in /usr/include/syslog.h.
+ * NOTE that this should really be changed. The reason I do not
+ * allow the use of the values defined in syslog.h is on account of
+ * the extensions made to allow the wildcard character in the
+ * priority field. To fix this properly one should malloc an array,
+ * copy the contents of the array defined by syslog.h and then
+ * make whatever modifications that are desired. Next round.
+ *
+ * Thu Jan 6 12:07:36 CST 1994: Dr. Wettstein
+ * Added support for proper decomposition and re-assembly of
+ * fragment messages on UNIX domain sockets. Lack of this capability
+ * was causing 'partial' messages to be output. Since facility and
+ * priority information is encoded as a leader on the messages this
+ * was causing lines to be placed in erroneous files.
+ *
+ * Also added a patch from Shane Alderton (shane@ion.apana.org.au) to
+ * correct a problem with syslogd dumping core when an attempt was made
+ * to write log messages to a logged-on user. Thank you.
+ *
+ * Many thanks to Juha Virtanen (jiivee@hut.fi) for a series of
+ * interchanges which lead to the fixing of problems with messages set
+ * to priorities of none and emerg. Also thanks to Juha for a patch
+ * to exclude users with a class of LOGIN from receiving messages.
+ *
+ * Shane Alderton provided an additional patch to fix zombies which
+ * were conceived when messages were written to multiple users.
+ *
+ * Mon Feb 6 09:57:10 CST 1995: Dr. Wettstein
+ * Patch to properly reset the single priority message flag. Thanks
+ * to Christopher Gori for spotting this bug and forwarding a patch.
+ *
+ * Wed Feb 22 15:38:31 CST 1995: Dr. Wettstein
+ * Added version information to startup messages.
+ *
+ * Added defines so that paths to important files are taken from
+ * the definitions in paths.h. Hopefully this will insure that
+ * everything follows the FSSTND standards. Thanks to Chris Metcalf
+ * for a set of patches to provide this functionality. Also thanks
+ * Elias Levy for prompting me to get these into the sources.
+ *
+ * Wed Jul 26 18:57:23 MET DST 1995: Martin Schulze
+ * Linux' gethostname only returns the hostname and not the fqdn as
+ * expected in the code. But if you call hostname with an fqdn then
+ * gethostname will return an fqdn, so we have to mention that. This
+ * has been changed.
+ *
+ * The 'LocalDomain' and the hostname of a remote machine is
+ * converted to lower case, because the original caused some
+ * inconsistency, because the (at least my) nameserver did respond an
+ * fqdn containing of upper- _and_ lowercase letters while
+ * 'LocalDomain' consisted only of lowercase letters and that didn't
+ * match.
+ *
+ * Sat Aug 5 18:59:15 MET DST 1995: Martin Schulze
+ * Now no messages that were received from any remote host are sent
+ * out to another. At my domain this missing feature caused ugly
+ * syslog-loops, sometimes.
+ *
+ * Remember that no message is sent out. I can't figure out any
+ * scenario where it might be useful to change this behavior and to
+ * send out messages to other hosts than the one from which we
+ * received the message, but I might be shortsighted. :-/
+ *
+ * Thu Aug 10 19:01:08 MET DST 1995: Martin Schulze
+ * Added my pidfile.[ch] to it to perform a better handling with
+ * pidfiles. Now both, syslogd and klogd, can only be started
+ * once. They check the pidfile.
+ *
+ * Sun Aug 13 19:01:41 MET DST 1995: Martin Schulze
+ * Add an addition to syslog.conf's interpretation. If a priority
+ * begins with an exclamation mark ('!') the normal interpretation
+ * of the priority is inverted: ".!*" is the same as ".none", ".!=info"
+ * don't logs the info priority, ".!crit" won't log any message with
+ * the priority crit or higher. For example:
+ *
+ * mail.*;mail.!=info /usr/adm/mail
+ *
+ * Would log all messages of the facility mail except those with
+ * the priority info to /usr/adm/mail. This makes the syslogd
+ * much more flexible.
+ *
+ * Defined TABLE_ALLPRI=255 and changed some occurrences.
+ *
+ * Sat Aug 19 21:40:13 MET DST 1995: Martin Schulze
+ * Making the table of facilities and priorities while in debug
+ * mode more readable.
+ *
+ * If debugging is turned on, printing the whole table of
+ * facilities and priorities every hexadecimal or 'X' entry is
+ * now 2 characters wide.
+ *
+ * The number of the entry is prepended to each line of
+ * facilities and priorities, and F_UNUSED lines are not shown
+ * anymore.
+ *
+ * Corrected some #ifdef SYSV's.
+ *
+ * Mon Aug 21 22:10:35 MET DST 1995: Martin Schulze
+ * Corrected a strange behavior during parsing of configuration
+ * file. The original BSD syslogd doesn't understand spaces as
+ * separators between specifier and action. This syslogd now
+ * understands them. The old behavior caused some confusion over
+ * the Linux community.
+ *
+ * Thu Oct 19 00:02:07 MET 1995: Martin Schulze
+ * The default behavior has changed for security reasons. The
+ * syslogd will not receive any remote message unless you turn
+ * reception on with the "-r" option.
+ *
+ * Not defining SYSLOG_INET will result in not doing any network
+ * activity, i.e. not sending or receiving messages. I changed
+ * this because the old idea is implemented with the "-r" option
+ * and the old thing didn't work anyway.
+ *
+ * Thu Oct 26 13:14:06 MET 1995: Martin Schulze
+ * Added another logfile type F_FORW_UNKN. The problem I ran into
+ * was a name server that runs on my machine and a forwarder of
+ * kern.crit to another host. The hosts address can only be
+ * fetched using the nameserver. But named is started after
+ * syslogd, so syslogd complained.
+ *
+ * This logfile type will retry to get the address of the
+ * hostname ten times and then complain. This should be enough to
+ * get the named up and running during boot sequence.
+ *
+ * Fri Oct 27 14:08:15 1995: Dr. Wettstein
+ * Changed static array of logfiles to a dynamic array. This
+ * can grow during process.
+ *
+ * Fri Nov 10 23:08:18 1995: Martin Schulze
+ * Inserted a new tabular sys_h_errlist that contains plain text
+ * for error codes that are returned from the net subsystem and
+ * stored in h_errno. I have also changed some wrong lookups to
+ * sys_errlist.
+ *
+ * Wed Nov 22 22:32:55 1995: Martin Schulze
+ * Added the fabulous strip-domain feature that allows us to
+ * strip off (several) domain names from the fqdn and only log
+ * the simple hostname. This is useful if you're in a LAN that
+ * has a central log server and also different domains.
+ *
+ * I have also also added the -l switch do define hosts as
+ * local. These will get logged with their simple hostname, too.
+ *
+ * Thu Nov 23 19:02:56 MET DST 1995: Martin Schulze
+ * Added the possibility to omit fsyncing of logfiles after every
+ * write. This will give some performance back if you have
+ * programs that log in a very verbose manner (like innd or
+ * smartlist). Thanks to Stephen R. van den Berg <srb@cuci.nl>
+ * for the idea.
+ *
+ * Thu Jan 18 11:14:36 CST 1996: Dr. Wettstein
+ * Added patche from beta-testers to stop compile error. Also
+ * added removal of pid file as part of termination cleanup.
+ *
+ * Wed Feb 14 12:42:09 CST 1996: Dr. Wettstein
+ * Allowed forwarding of messages received from remote hosts to
+ * be controlled by a command-line switch. Specifying -h allows
+ * forwarding. The default behavior is to disable forwarding of
+ * messages which were received from a remote host.
+ *
+ * Parent process of syslogd does not exit until child process has
+ * finished initialization process. This allows rc.* startup to
+ * pause until syslogd facility is up and operating.
+ *
+ * Re-arranged the select code to move UNIX domain socket accepts
+ * to be processed later. This was a contributed change which
+ * has been proposed to correct the delays sometimes encountered
+ * when syslogd starts up.
+ *
+ * Minor code cleanups.
+ *
+ * Thu May 2 15:15:33 CDT 1996: Dr. Wettstein
+ * Fixed bug in init function which resulted in file descripters
+ * being orphaned when syslogd process was re-initialized with SIGHUP
+ * signal. Thanks to Edvard Tuinder
+ * (Edvard.Tuinder@praseodymium.cistron.nl) for putting me on the
+ * trail of this bug. I am amazed that we didn't catch this one
+ * before now.
+ *
+ * Tue May 14 00:03:35 MET DST 1996: Martin Schulze
+ * Corrected a mistake that causes the syslogd to stop logging at
+ * some virtual consoles under Linux. This was caused by checking
+ * the wrong error code. Thanks to Michael Nonweiler
+ * <mrn20@hermes.cam.ac.uk> for sending me a patch.
+ *
+ * Mon May 20 13:29:32 MET DST 1996: Miquel van Smoorenburg <miquels@cistron.nl>
+ * Added continuation line supported and fixed a bug in
+ * the init() code.
+ *
+ * Tue May 28 00:58:45 MET DST 1996: Martin Schulze
+ * Corrected behaviour of blocking pipes - i.e. the whole system
+ * hung. Michael Nonweiler <mrn20@hermes.cam.ac.uk> has sent us
+ * a patch to correct this. A new logfile type F_PIPE has been
+ * introduced.
+ *
+ * Mon Feb 3 10:12:15 MET DST 1997: Martin Schulze
+ * Corrected behaviour of logfiles if the file can't be opened.
+ * There was a bug that causes syslogd to try to log into non
+ * existing files which ate cpu power.
+ *
+ * Sun Feb 9 03:22:12 MET DST 1997: Martin Schulze
+ * Modified syslogd.c to not kill itself which confuses bash 2.0.
+ *
+ * Mon Feb 10 00:09:11 MET DST 1997: Martin Schulze
+ * Improved debug code to decode the numeric facility/priority
+ * pair into textual information.
+ *
+ * Tue Jun 10 12:35:10 MET DST 1997: Martin Schulze
+ * Corrected freeing of logfiles. Thanks to Jos Vos <jos@xos.nl>
+ * for reporting the bug and sending an idea to fix the problem.
+ *
+ * Tue Jun 10 12:51:41 MET DST 1997: Martin Schulze
+ * Removed sleep(10) from parent process. This has caused a slow
+ * startup in former times - and I don't see any reason for this.
+ *
+ * Sun Jun 15 16:23:29 MET DST 1997: Michael Alan Dorman
+ * Some more glibc patches made by <mdorman@debian.org>.
+ *
+ * Thu Jan 1 16:04:52 CET 1998: Martin Schulze <joey@infodrom.north.de
+ * Applied patch from Herbert Thielen <Herbert.Thielen@lpr.e-technik.tu-muenchen.de>.
+ * This included some balance parentheses for emacs and a bug in
+ * the exclamation mark handling.
+ *
+ * Fixed small bug which caused syslogd to write messages to the
+ * wrong logfile under some very rare conditions. Thanks to
+ * Herbert Xu <herbert@gondor.apana.org.au> for fiddling this out.
+ *
+ * Thu Jan 8 22:46:35 CET 1998: Martin Schulze <joey@infodrom.north.de>
+ * Reworked one line of the above patch as it prevented syslogd
+ * from binding the socket with the result that no messages were
+ * forwarded to other hosts.
+ *
+ * Sat Jan 10 01:33:06 CET 1998: Martin Schulze <joey@infodrom.north.de>
+ * Fixed small bugs in F_FORW_UNKN meachanism. Thanks to Torsten
+ * Neumann <torsten@londo.rhein-main.de> for pointing me to it.
+ *
+ * Mon Jan 12 19:50:58 CET 1998: Martin Schulze <joey@infodrom.north.de>
+ * Modified debug output concerning remote receiption.
+ *
+ * Mon Feb 23 23:32:35 CET 1998: Topi Miettinen <Topi.Miettinen@ml.tele.fi>
+ * Re-worked handling of Unix and UDP sockets to support closing /
+ * opening of them in order to have it open only if it is needed
+ * either for forwarding to a remote host or by receiption from
+ * the network.
+ *
+ * Wed Feb 25 10:54:09 CET 1998: Martin Schulze <joey@infodrom.north.de>
+ * Fixed little comparison mistake that prevented the MARK
+ * feature to work properly.
+ *
+ * Wed Feb 25 13:21:44 CET 1998: Martin Schulze <joey@infodrom.north.de>
+ * Corrected Topi's patch as it prevented forwarding during
+ * startup due to an unknown LogPort.
+ *
+ * Sat Oct 10 20:01:48 CEST 1998: Martin Schulze <joey@infodrom.north.de>
+ * Added support for TESTING define which will turn syslogd into
+ * stdio-mode used for debugging.
+ *
+ * Sun Oct 11 20:16:59 CEST 1998: Martin Schulze <joey@infodrom.north.de>
+ * Reworked the initialization/fork code. Now the parent
+ * process activates a signal handler which the daughter process
+ * will raise if it is initialized. Only after that one the
+ * parent process may exit. Otherwise klogd might try to flush
+ * its log cache while syslogd can't receive the messages yet.
+ *
+ * Mon Oct 12 13:30:35 CEST 1998: Martin Schulze <joey@infodrom.north.de>
+ * Redirected some error output with regard to argument parsing to
+ * stderr.
+ *
+ * Mon Oct 12 14:02:51 CEST 1998: Martin Schulze <joey@infodrom.north.de>
+ * Applied patch provided vom Topi Miettinen with regard to the
+ * people from OpenBSD. This provides the additional '-a'
+ * argument used for specifying additional UNIX domain sockets to
+ * listen to. This is been used with chroot()'ed named's for
+ * example. See for http://www.psionic.com/papers/dns.html
+ *
+ * Mon Oct 12 18:29:44 CEST 1998: Martin Schulze <joey@infodrom.north.de>
+ * Added `ftp' facility which was introduced in glibc version 2.
+ * It's #ifdef'ed so won't harm with older libraries.
+ *
+ * Mon Oct 12 19:59:21 MET DST 1998: Martin Schulze <joey@infodrom.north.de>
+ * Code cleanups with regard to bsd -> posix transition and
+ * stronger security (buffer length checking). Thanks to Topi
+ * Miettinen <tom@medialab.sonera.net>
+ * . index() --> strchr()
+ * . sprintf() --> snprintf()
+ * . bcopy() --> memcpy()
+ * . bzero() --> memset()
+ * . UNAMESZ --> UT_NAMESIZE
+ * . sys_errlist --> strerror()
+ *
+ * Mon Oct 12 20:22:59 CEST 1998: Martin Schulze <joey@infodrom.north.de>
+ * Added support for setutent()/getutent()/endutend() instead of
+ * binary reading the UTMP file. This is the the most portable
+ * way. This allows /var/run/utmp format to change, even to a
+ * real database or utmp daemon. Also if utmp file locking is
+ * implemented in libc, syslog will use it immediately. Thanks
+ * to Topi Miettinen <tom@medialab.sonera.net>.
+ *
+ * Mon Oct 12 20:49:18 MET DST 1998: Martin Schulze <joey@infodrom.north.de>
+ * Avoid logging of SIGCHLD when syslogd is in the process of
+ * exiting and closing its files. Again thanks to Topi.
+ *
+ * Mon Oct 12 22:18:34 CEST 1998: Martin Schulze <joey@infodrom.north.de>
+ * Modified printline() to support 8bit characters - such as
+ * russion letters. Thanks to Vladas Lapinskas <lapinskas@mail.iae.lt>.
+ *
+ * Sat Nov 14 02:29:37 CET 1998: Martin Schulze <joey@infodrom.north.de>
+ * ``-m 0'' now turns of MARK logging entirely.
+ *
+ * Tue Jan 19 01:04:18 MET 1999: Martin Schulze <joey@infodrom.north.de>
+ * Finally fixed an error with `-a' processing, thanks to Topi
+ * Miettinen <tom@medialab.sonera.net>.
+ *
+ * Sun May 23 10:08:53 CEST 1999: Martin Schulze <joey@infodrom.north.de>
+ * Removed superflous call to utmpname(). The path to the utmp
+ * file is defined in the used libc and should not be hardcoded
+ * into the syslogd binary referring the system it was compiled on.
+ *
+ * Sun Sep 17 20:45:33 CEST 2000: Martin Schulze <joey@infodrom.ffis.de>
+ * Fixed some bugs in printline() code that did not escape
+ * control characters '\177' through '\237' and contained a
+ * single-byte buffer overflow. Thanks to Solar Designer
+ * <solar@false.com>.
+ *
+ * Sun Sep 17 21:26:16 CEST 2000: Martin Schulze <joey@infodrom.ffis.de>
+ * Don't close open sockets upon reload. Thanks to Bill
+ * Nottingham.
+ *
+ * Mon Sep 18 09:10:47 CEST 2000: Martin Schulze <joey@infodrom.ffis.de>
+ * Fixed bug in printchopped() that caused syslogd to emit
+ * kern.emerg messages when splitting long lines. Thanks to
+ * Daniel Jacobowitz <dan@debian.org> for the fix.
+ *
+ * Mon Sep 18 15:33:26 CEST 2000: Martin Schulze <joey@infodrom.ffis.de>
+ * Removed unixm/unix domain sockets and switch to Datagram Unix
+ * Sockets. This should remove one possibility to play DoS with
+ * syslogd. Thanks to Olaf Kirch <okir@caldera.de> for the patch.
+ *
+ * Sun Mar 11 20:23:44 CET 2001: Martin Schulze <joey@infodrom.ffis.de>
+ * Don't return a closed fd if `-a' is called with a wrong path.
+ * Thanks to Bill Nottingham <notting@redhat.com> for providing
+ * a patch.
+ */
+
+
+#define MAXLINE 1024 /* maximum line length */
+#define MAXSVLINE 240 /* maximum saved line length */
+#define DEFUPRI (LOG_USER|LOG_NOTICE)
+#define DEFSPRI (LOG_KERN|LOG_CRIT)
+#define TIMERINTVL 30 /* interval for checking flush, mark */
+
+#define CONT_LINE 1 /* Allow continuation lines */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef SYSV
+#include <sys/types.h>
+#endif
+#include <utmp.h>
+#include <ctype.h>
+#include <string.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <time.h>
+
+#define SYSLOG_NAMES
+#include <sys/syslog.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#ifdef SYSV
+#include <fcntl.h>
+#else
+#include <sys/msgbuf.h>
+#endif
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <signal.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+#include <syscall.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#ifndef TESTING
+#include "pidfile.h"
+#endif
+#include "version.h"
+
+#if defined(__linux__)
+#include <paths.h>
+#endif
+
+#ifndef UTMP_FILE
+#ifdef UTMP_FILENAME
+#define UTMP_FILE UTMP_FILENAME
+#else
+#ifdef _PATH_UTMP
+#define UTMP_FILE _PATH_UTMP
+#else
+#define UTMP_FILE "/etc/utmp"
+#endif
+#endif
+#endif
+
+#ifndef _PATH_LOGCONF
+#define _PATH_LOGCONF "/etc/syslog.conf"
+#endif
+
+#if defined(SYSLOGD_PIDNAME)
+#undef _PATH_LOGPID
+#if defined(FSSTND)
+#define _PATH_LOGPID _PATH_VARRUN SYSLOGD_PIDNAME
+#else
+#define _PATH_LOGPID "/etc/" SYSLOGD_PIDNAME
+#endif
+#else
+#ifndef _PATH_LOGPID
+#if defined(FSSTND)
+#define _PATH_LOGPID _PATH_VARRUN "syslogd.pid"
+#else
+#define _PATH_LOGPID "/etc/syslogd.pid"
+#endif
+#endif
+#endif
+
+#ifndef _PATH_DEV
+#define _PATH_DEV "/dev/"
+#endif
+
+#ifndef _PATH_CONSOLE
+#define _PATH_CONSOLE "/dev/console"
+#endif
+
+#ifndef _PATH_TTY
+#define _PATH_TTY "/dev/tty"
+#endif
+
+#ifndef _PATH_LOG
+#define _PATH_LOG "/dev/log"
+#endif
+
+char *ConfFile = _PATH_LOGCONF;
+char *PidFile = _PATH_LOGPID;
+char ctty[] = _PATH_CONSOLE;
+
+char **parts;
+
+int inetm = 0;
+static int debugging_on = 0;
+static int nlogs = -1;
+static int restart = 0;
+
+#define MAXFUNIX 20
+
+int nfunix = 1;
+char *funixn[MAXFUNIX] = { _PATH_LOG };
+int funix[MAXFUNIX] = { -1, };
+
+#ifdef UT_NAMESIZE
+# define UNAMESZ UT_NAMESIZE /* length of a login name */
+#else
+# define UNAMESZ 8 /* length of a login name */
+#endif
+#define MAXUNAMES 20 /* maximum number of user names */
+#define MAXFNAME 200 /* max file pathname length */
+
+#define INTERNAL_NOPRI 0x10 /* the "no priority" priority */
+#define TABLE_NOPRI 0 /* Value to indicate no priority in f_pmask */
+#define TABLE_ALLPRI 0xFF /* Value to indicate all priorities in f_pmask */
+#define LOG_MARK LOG_MAKEPRI(LOG_NFACILITIES, 0) /* mark "facility" */
+
+/*
+ * Flags to logmsg().
+ */
+
+#define IGN_CONS 0x001 /* don't print on console */
+#define SYNC_FILE 0x002 /* do fsync on file after printing */
+#define ADDDATE 0x004 /* add a date to the message */
+#define MARK 0x008 /* this message is a mark */
+
+/*
+ * This table contains plain text for h_errno errors used by the
+ * net subsystem.
+ */
+const char *sys_h_errlist[] = {
+ "No problem", /* NETDB_SUCCESS */
+ "Authoritative answer: host not found", /* HOST_NOT_FOUND */
+ "Non-authoritative answer: host not found, or serverfail", /* TRY_AGAIN */
+ "Non recoverable errors", /* NO_RECOVERY */
+ "Valid name, no data record of requested type", /* NO_DATA */
+ "no address, look for MX record" /* NO_ADDRESS */
+ };
+
+/*
+ * This structure represents the files that will have log
+ * copies printed.
+ */
+
+struct filed {
+#ifndef SYSV
+ struct filed *f_next; /* next in linked list */
+#endif
+ short f_type; /* entry type, see below */
+ short f_file; /* file descriptor */
+ time_t f_time; /* time this was last written */
+ u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */
+ union {
+ char f_uname[MAXUNAMES][UNAMESZ+1];
+ struct {
+ char f_hname[MAXHOSTNAMELEN+1];
+ struct sockaddr_in f_addr;
+ } f_forw; /* forwarding address */
+ char f_fname[MAXFNAME];
+ } f_un;
+ char f_prevline[MAXSVLINE]; /* last message logged */
+ char f_lasttime[16]; /* time of last occurrence */
+ char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */
+ int f_prevpri; /* pri of f_prevline */
+ int f_prevlen; /* length of f_prevline */
+ int f_prevcount; /* repetition cnt of prevline */
+ int f_repeatcount; /* number of "repeated" msgs */
+ int f_flags; /* store some additional flags */
+};
+
+/*
+ * Intervals at which we flush out "message repeated" messages,
+ * in seconds after previous message is logged. After each flush,
+ * we move to the next interval until we reach the largest.
+ */
+int repeatinterval[] = { 30, 60 }; /* # of secs before flush */
+#define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
+#define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount])
+#define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \
+ (f)->f_repeatcount = MAXREPEAT; \
+ }
+#ifdef SYSLOG_INET
+#define INET_SUSPEND_TIME 180 /* equal to 3 minutes */
+#define INET_RETRY_MAX 10 /* maximum of retries for gethostbyname() */
+#endif
+
+#define LIST_DELIMITER ':' /* delimiter between two hosts */
+
+/* values for f_type */
+#define F_UNUSED 0 /* unused entry */
+#define F_FILE 1 /* regular file */
+#define F_TTY 2 /* terminal */
+#define F_CONSOLE 3 /* console terminal */
+#define F_FORW 4 /* remote machine */
+#define F_USERS 5 /* list of users */
+#define F_WALL 6 /* everyone logged on */
+#define F_FORW_SUSP 7 /* suspended host forwarding */
+#define F_FORW_UNKN 8 /* unknown host forwarding */
+#define F_PIPE 9 /* named pipe */
+char *TypeNames[] = {
+ "UNUSED", "FILE", "TTY", "CONSOLE",
+ "FORW", "USERS", "WALL", "FORW(SUSPENDED)",
+ "FORW(UNKNOWN)", "PIPE"
+};
+
+struct filed *Files = (struct filed *) 0;
+struct filed consfile;
+
+struct code {
+ char *c_name;
+ int c_val;
+};
+
+struct code PriNames[] = {
+ {"alert", LOG_ALERT},
+ {"crit", LOG_CRIT},
+ {"debug", LOG_DEBUG},
+ {"emerg", LOG_EMERG},
+ {"err", LOG_ERR},
+ {"error", LOG_ERR}, /* DEPRECATED */
+ {"info", LOG_INFO},
+ {"none", INTERNAL_NOPRI}, /* INTERNAL */
+ {"notice", LOG_NOTICE},
+ {"panic", LOG_EMERG}, /* DEPRECATED */
+ {"warn", LOG_WARNING}, /* DEPRECATED */
+ {"warning", LOG_WARNING},
+ {"*", TABLE_ALLPRI},
+ {NULL, -1}
+};
+
+struct code FacNames[] = {
+ {"auth", LOG_AUTH},
+ {"authpriv", LOG_AUTHPRIV},
+ {"cron", LOG_CRON},
+ {"daemon", LOG_DAEMON},
+ {"kern", LOG_KERN},
+ {"lpr", LOG_LPR},
+ {"mail", LOG_MAIL},
+ {"mark", LOG_MARK}, /* INTERNAL */
+ {"news", LOG_NEWS},
+ {"security", LOG_AUTH}, /* DEPRECATED */
+ {"syslog", LOG_SYSLOG},
+ {"user", LOG_USER},
+ {"uucp", LOG_UUCP},
+#if defined(LOG_FTP)
+ {"ftp", LOG_FTP},
+#endif
+ {"local0", LOG_LOCAL0},
+ {"local1", LOG_LOCAL1},
+ {"local2", LOG_LOCAL2},
+ {"local3", LOG_LOCAL3},
+ {"local4", LOG_LOCAL4},
+ {"local5", LOG_LOCAL5},
+ {"local6", LOG_LOCAL6},
+ {"local7", LOG_LOCAL7},
+ {NULL, -1},
+};
+
+int Debug; /* debug flag */
+char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */
+char *LocalDomain; /* our local domain name */
+int InetInuse = 0; /* non-zero if INET sockets are being used */
+int finet = -1; /* Internet datagram socket */
+int LogPort; /* port number for INET connections */
+int Initialized = 0; /* set when we have initialized ourselves */
+int MarkInterval = 20 * 60; /* interval between marks in seconds */
+int MarkSeq = 0; /* mark sequence number */
+int NoFork = 0; /* don't fork - don't run in daemon mode */
+int AcceptRemote = 0; /* receive messages that come via UDP */
+char **StripDomains = NULL; /* these domains may be stripped before writing logs */
+char **LocalHosts = NULL; /* these hosts are logged with their hostname */
+int NoHops = 1; /* Can we bounce syslog messages through an
+ intermediate host. */
+
+extern int errno;
+
+/* Function prototypes. */
+int main(int argc, char **argv);
+char **crunch_list(char *list);
+int usage(void);
+void untty(void);
+void printchopped(const char *hname, char *msg, int len, int fd);
+void printline(const char *hname, char *msg);
+void printsys(char *msg);
+void logmsg(int pri, char *msg, const char *from, int flags);
+void fprintlog(register struct filed *f, char *from, int flags, char *msg);
+void endtty();
+void wallmsg(register struct filed *f, struct iovec *iov);
+void reapchild();
+const char *cvthname(struct sockaddr_in *f);
+void domark();
+void debug_switch();
+void logerror(char *type);
+void die(int sig);
+#ifndef TESTING
+void doexit(int sig);
+#endif
+void init();
+void cfline(char *line, register struct filed *f);
+int decode(char *name, struct code *codetab);
+#if defined(__GLIBC__)
+#define dprintf mydprintf
+#endif /* __GLIBC__ */
+static void dprintf(char *, ...);
+static void allocate_log(void);
+void sighup_handler();
+
+#ifdef SYSLOG_UNIXAF
+static int create_unix_socket(const char *path);
+#endif
+#ifdef SYSLOG_INET
+static int create_inet_socket();
+#endif
+
+int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register int i;
+ register char *p;
+#if !defined(__GLIBC__)
+ int len, num_fds;
+#else /* __GLIBC__ */
+#ifndef TESTING
+ size_t len;
+#endif
+ int num_fds;
+#endif /* __GLIBC__ */
+ /*
+ * It took me quite some time to figure out how this is
+ * supposed to work so I guess I should better write it down.
+ * unixm is a list of file descriptors from which one can
+ * read(). This is in contrary to readfds which is a list of
+ * file descriptors where activity is monitored by select()
+ * and from which one cannot read(). -Joey
+ *
+ * Changed: unixm is gone, since we now use datagram unix sockets.
+ * Hence we recv() from unix sockets directly (rather than
+ * first accept()ing connections on them), so there's no need
+ * for separate book-keeping. --okir
+ */
+ fd_set readfds;
+
+#ifndef TESTING
+ int fd;
+#ifdef SYSLOG_INET
+ struct sockaddr_in frominet;
+ char *from;
+#endif
+ pid_t ppid = getpid();
+#endif
+ int ch;
+ struct hostent *hent;
+
+ char line[MAXLINE +1];
+ extern int optind;
+ extern char *optarg;
+ int maxfds;
+
+#ifndef TESTING
+ chdir ("/");
+#endif
+ for (i = 1; i < MAXFUNIX; i++) {
+ funixn[i] = "";
+ funix[i] = -1;
+ }
+
+ while ((ch = getopt(argc, argv, "a:dhf:l:m:np:rs:v")) != EOF)
+ switch((char)ch) {
+ case 'a':
+ if (nfunix < MAXFUNIX)
+ funixn[nfunix++] = optarg;
+ else
+ fprintf(stderr, "Out of descriptors, ignoring %s\n", optarg);
+ break;
+ case 'd': /* debug */
+ Debug = 1;
+ break;
+ case 'f': /* configuration file */
+ ConfFile = optarg;
+ break;
+ case 'h':
+ NoHops = 0;
+ break;
+ case 'l':
+ if (LocalHosts) {
+ fprintf (stderr, "Only one -l argument allowed," \
+ "the first one is taken.\n");
+ break;
+ }
+ LocalHosts = crunch_list(optarg);
+ break;
+ case 'm': /* mark interval */
+ MarkInterval = atoi(optarg) * 60;
+ break;
+ case 'n': /* don't fork */
+ NoFork = 1;
+ break;
+ case 'p': /* path to regular log socket */
+ funixn[0] = optarg;
+ break;
+ case 'r': /* accept remote messages */
+ AcceptRemote = 1;
+ break;
+ case 's':
+ if (StripDomains) {
+ fprintf (stderr, "Only one -s argument allowed," \
+ "the first one is taken.\n");
+ break;
+ }
+ StripDomains = crunch_list(optarg);
+ break;
+ case 'v':
+ printf("syslogd %s.%s\n", VERSION, PATCHLEVEL);
+ exit (0);
+ case '?':
+ default:
+ usage();
+ }
+ if ((argc -= optind))
+ usage();
+
+#ifndef TESTING
+ if ( !(Debug || NoFork) )
+ {
+ dprintf("Checking pidfile.\n");
+ if (!check_pid(PidFile))
+ {
+ if (fork()) {
+ /*
+ * Parent process
+ */
+ signal (SIGTERM, doexit);
+ sleep(300);
+ /*
+ * Not reached unless something major went wrong. 5
+ * minutes should be a fair amount of time to wait.
+ * Please note that this procedure is important since
+ * the father must not exit before syslogd isn't
+ * initialized or the klogd won't be able to flush its
+ * logs. -Joey
+ */
+ exit(1);
+ }
+ num_fds = getdtablesize();
+ for (i= 0; i < num_fds; i++)
+ (void) close(i);
+ untty();
+ }
+ else
+ {
+ fputs("syslogd: Already running.\n", stderr);
+ exit(1);
+ }
+ }
+ else
+#endif
+ debugging_on = 1;
+#ifndef SYSV
+ else
+ setlinebuf(stdout);
+#endif
+
+#ifndef TESTING
+ /* tuck my process id away */
+ if ( !Debug )
+ {
+ dprintf("Writing pidfile.\n");
+ if (!check_pid(PidFile))
+ {
+ if (!write_pid(PidFile))
+ {
+ dprintf("Can't write pid.\n");
+ exit(1);
+ }
+ }
+ else
+ {
+ dprintf("Pidfile (and pid) already exist.\n");
+ exit(1);
+ }
+ } /* if ( !Debug ) */
+#endif
+
+ consfile.f_type = F_CONSOLE;
+ (void) strcpy(consfile.f_un.f_fname, ctty);
+ (void) gethostname(LocalHostName, sizeof(LocalHostName));
+ if ( (p = strchr(LocalHostName, '.')) ) {
+ *p++ = '\0';
+ LocalDomain = p;
+ }
+ else
+ {
+ LocalDomain = "";
+
+ /*
+ * It's not clearly defined whether gethostname()
+ * should return the simple hostname or the fqdn. A
+ * good piece of software should be aware of both and
+ * we want to distribute good software. Joey
+ *
+ * Good software also always checks its return values...
+ * If syslogd starts up before DNS is up & /etc/hosts
+ * doesn't have LocalHostName listed, gethostbyname will
+ * return NULL.
+ */
+ hent = gethostbyname(LocalHostName);
+ if ( hent )
+ snprintf(LocalHostName, sizeof(LocalHostName), "%s", hent->h_name);
+
+ if ( (p = strchr(LocalHostName, '.')) )
+ {
+ *p++ = '\0';
+ LocalDomain = p;
+ }
+ }
+
+ /*
+ * Convert to lower case to recognize the correct domain laterly
+ */
+ for (p = (char *)LocalDomain; *p ; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+
+ (void) signal(SIGTERM, die);
+ (void) signal(SIGINT, Debug ? die : SIG_IGN);
+ (void) signal(SIGQUIT, Debug ? die : SIG_IGN);
+ (void) signal(SIGCHLD, reapchild);
+ (void) signal(SIGALRM, domark);
+ (void) signal(SIGUSR1, Debug ? debug_switch : SIG_IGN);
+ (void) alarm(TIMERINTVL);
+
+ /* Create a partial message table for all file descriptors. */
+ num_fds = getdtablesize();
+ dprintf("Allocated parts table for %d file descriptors.\n", num_fds);
+ if ( (parts = (char **) malloc(num_fds * sizeof(char *))) == \
+ (char **) 0 )
+ {
+ logerror("Cannot allocate memory for message parts table.");
+ die(0);
+ }
+ for(i= 0; i < num_fds; ++i)
+ parts[i] = (char *) 0;
+
+ dprintf("Starting.\n");
+ init();
+#ifndef TESTING
+ if ( Debug )
+ {
+ dprintf("Debugging disabled, SIGUSR1 to turn on debugging.\n");
+ debugging_on = 0;
+ }
+ /*
+ * Send a signal to the parent to it can terminate.
+ */
+ if (getpid() != ppid)
+ kill (ppid, SIGTERM);
+#endif
+
+ /* Main loop begins here. */
+ for (;;) {
+ int nfds;
+ errno = 0;
+ FD_ZERO(&readfds);
+ maxfds = 0;
+#ifdef SYSLOG_UNIXAF
+#ifndef TESTING
+ /*
+ * Add the Unix Domain Sockets to the list of read
+ * descriptors.
+ */
+ /* Copy master connections */
+ for (i = 0; i < nfunix; i++) {
+ if (funix[i] != -1) {
+ FD_SET(funix[i], &readfds);
+ if (funix[i]>maxfds) maxfds=funix[i];
+ }
+ }
+#endif
+#endif
+#ifdef SYSLOG_INET
+#ifndef TESTING
+ /*
+ * Add the Internet Domain Socket to the list of read
+ * descriptors.
+ */
+ if ( InetInuse && AcceptRemote ) {
+ FD_SET(inetm, &readfds);
+ if (inetm>maxfds) maxfds=inetm;
+ dprintf("Listening on syslog UDP port.\n");
+ }
+#endif
+#endif
+#ifdef TESTING
+ FD_SET(fileno(stdin), &readfds);
+ if (fileno(stdin) > maxfds) maxfds = fileno(stdin);
+
+ dprintf("Listening on stdin. Press Ctrl-C to interrupt.\n");
+#endif
+
+ if ( debugging_on )
+ {
+ dprintf("Calling select, active file descriptors (max %d): ", maxfds);
+ for (nfds= 0; nfds <= maxfds; ++nfds)
+ if ( FD_ISSET(nfds, &readfds) )
+ dprintf("%d ", nfds);
+ dprintf("\n");
+ }
+ nfds = select(maxfds+1, (fd_set *) &readfds, (fd_set *) NULL,
+ (fd_set *) NULL, (struct timeval *) NULL);
+ if ( restart )
+ {
+ dprintf("\nReceived SIGHUP, reloading syslogd.\n");
+ init();
+ restart = 0;
+ continue;
+ }
+ if (nfds == 0) {
+ dprintf("No select activity.\n");
+ continue;
+ }
+ if (nfds < 0) {
+ if (errno != EINTR)
+ logerror("select");
+ dprintf("Select interrupted.\n");
+ continue;
+ }
+
+ if ( debugging_on )
+ {
+ dprintf("\nSuccessful select, descriptor count = %d, " \
+ "Activity on: ", nfds);
+ for (nfds= 0; nfds <= maxfds; ++nfds)
+ if ( FD_ISSET(nfds, &readfds) )
+ dprintf("%d ", nfds);
+ dprintf(("\n"));
+ }
+
+#ifndef TESTING
+#ifdef SYSLOG_UNIXAF
+ for (i = 0; i < nfunix; i++) {
+ if ((fd = funix[i]) != -1 && FD_ISSET(fd, &readfds)) {
+ memset(line, '\0', sizeof(line));
+ i = recv(fd, line, MAXLINE - 2, 0);
+ dprintf("Message from UNIX socket: #%d\n", fd);
+ if (i > 0) {
+ line[i] = line[i+1] = '\0';
+ printchopped(LocalHostName, line, i + 2, fd);
+ } else if (i < 0 && errno != EINTR) {
+ dprintf("UNIX socket error: %d = %s.\n", \
+ errno, strerror(errno));
+ logerror("recvfrom UNIX");
+ }
+ }
+ }
+#endif
+
+#ifdef SYSLOG_INET
+ if (InetInuse && AcceptRemote && FD_ISSET(inetm, &readfds)) {
+ len = sizeof(frominet);
+ memset(line, '\0', sizeof(line));
+ i = recvfrom(finet, line, MAXLINE - 2, 0, \
+ (struct sockaddr *) &frominet, &len);
+ dprintf("Message from inetd socket: #%d, host: %s\n",
+ inetm, inet_ntoa(frominet.sin_addr));
+ if (i > 0) {
+ line[i] = line[i+1] = '\0';
+ from = (char *)cvthname(&frominet);
+ /*
+ * Here we could check if the host is permitted
+ * to send us syslog messages. We just have to
+ * catch the result of cvthname, look for a dot
+ * and if that doesn't exist, replace the first
+ * '\0' with '.' and we have the fqdn in lowercase
+ * letters so we could match them against whatever.
+ * -Joey
+ */
+ printchopped(from, line, \
+ i + 2, finet);
+ } else if (i < 0 && errno != EINTR) {
+ dprintf("INET socket error: %d = %s.\n", \
+ errno, strerror(errno));
+ logerror("recvfrom inet");
+ /* should be harmless now that we set
+ * BSDCOMPAT on the socket */
+ sleep(10);
+ }
+ }
+#endif
+#else
+ if ( FD_ISSET(fileno(stdin), &readfds) ) {
+ dprintf("Message from stdin.\n");
+ memset(line, '\0', sizeof(line));
+ line[0] = '.';
+ parts[fileno(stdin)] = (char *) 0;
+ i = read(fileno(stdin), line, MAXLINE);
+ if (i > 0) {
+ printchopped(LocalHostName, line, i+1, fileno(stdin));
+ } else if (i < 0) {
+ if (errno != EINTR) {
+ logerror("stdin");
+ }
+ }
+ FD_CLR(fileno(stdin), &readfds);
+ }
+
+#endif
+ }
+}
+
+int usage()
+{
+ fprintf(stderr, "usage: syslogd [-drvh] [-l hostlist] [-m markinterval] [-n] [-p path]\n" \
+ " [-s domainlist] [-f conffile]\n");
+ exit(1);
+}
+
+#ifdef SYSLOG_UNIXAF
+static int create_unix_socket(const char *path)
+{
+ struct sockaddr_un sunx;
+ int fd;
+ char line[MAXLINE +1];
+
+ if (path[0] == '\0')
+ return -1;
+
+ (void) unlink(path);
+
+ memset(&sunx, 0, sizeof(sunx));
+ sunx.sun_family = AF_UNIX;
+ (void) strncpy(sunx.sun_path, path, sizeof(sunx.sun_path));
+ fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (fd < 0 || bind(fd, (struct sockaddr *) &sunx,
+ sizeof(sunx.sun_family)+strlen(sunx.sun_path)) < 0 ||
+ chmod(path, 0666) < 0) {
+ (void) snprintf(line, sizeof(line), "cannot create %s", path);
+ logerror(line);
+ dprintf("cannot create %s (%d).\n", path, errno);
+ close(fd);
+#ifndef SYSV
+ die(0);
+#endif
+ return -1;
+ }
+ return fd;
+}
+#endif
+
+#ifdef SYSLOG_INET
+static int create_inet_socket()
+{
+ int fd, on = 1;
+ struct sockaddr_in sin;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ logerror("syslog: Unknown protocol, suspending inet service.");
+ return fd;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = LogPort;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, \
+ (char *) &on, sizeof(on)) < 0 ) {
+ logerror("setsockopt(REUSEADDR), suspending inet");
+ close(fd);
+ return -1;
+ }
+ /* We need to enable BSD compatibility. Otherwise an attacker
+ * could flood our log files by sending us tons of ICMP errors.
+ */
+ if (setsockopt(fd, SOL_SOCKET, SO_BSDCOMPAT, \
+ (char *) &on, sizeof(on)) < 0) {
+ logerror("setsockopt(BSDCOMPAT), suspending inet");
+ close(fd);
+ return -1;
+ }
+ if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+ logerror("bind, suspending inet");
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+#endif
+
+char **
+crunch_list(list)
+ char *list;
+{
+ int count, i;
+ char *p, *q;
+ char **result = NULL;
+
+ p = list;
+
+ /* strip off trailing delimiters */
+ while (p[strlen(p)-1] == LIST_DELIMITER) {
+ count--;
+ p[strlen(p)-1] = '\0';
+ }
+ /* cut off leading delimiters */
+ while (p[0] == LIST_DELIMITER) {
+ count--;
+ p++;
+ }
+
+ /* count delimiters to calculate elements */
+ for (count=i=0; p[i]; i++)
+ if (p[i] == LIST_DELIMITER) count++;
+
+ if ((result = (char **)malloc(sizeof(char *) * count+2)) == NULL) {
+ printf ("Sorry, can't get enough memory, exiting.\n");
+ exit(0);
+ }
+
+ /*
+ * We now can assume that the first and last
+ * characters are different from any delimiters,
+ * so we don't have to care about this.
+ */
+ count = 0;
+ while ((q=strchr(p, LIST_DELIMITER))) {
+ result[count] = (char *) malloc((q - p + 1) * sizeof(char));
+ if (result[count] == NULL) {
+ printf ("Sorry, can't get enough memory, exiting.\n");
+ exit(0);
+ }
+ strncpy(result[count], p, q - p);
+ result[count][q - p] = '\0';
+ p = q; p++;
+ count++;
+ }
+ if ((result[count] = \
+ (char *)malloc(sizeof(char) * strlen(p) + 1)) == NULL) {
+ printf ("Sorry, can't get enough memory, exiting.\n");
+ exit(0);
+ }
+ strcpy(result[count],p);
+ result[++count] = NULL;
+
+#if 0
+ count=0;
+ while (result[count])
+ dprintf ("#%d: %s\n", count, StripDomains[count++]);
+#endif
+ return result;
+}
+
+
+void untty()
+#ifdef SYSV
+{
+ if ( !Debug ) {
+ setsid();
+ }
+ return;
+}
+
+#else
+{
+ int i;
+
+ if ( !Debug ) {
+ i = open(_PATH_TTY, O_RDWR);
+ if (i >= 0) {
+ (void) ioctl(i, (int) TIOCNOTTY, (char *)0);
+ (void) close(i);
+ }
+ }
+}
+#endif
+
+
+/*
+ * Parse the line to make sure that the msg is not a composite of more
+ * than one message.
+ */
+
+void printchopped(hname, msg, len, fd)
+ const char *hname;
+ char *msg;
+ int len;
+ int fd;
+{
+ auto int ptlngth;
+
+ auto char *start = msg,
+ *p,
+ *end,
+ tmpline[MAXLINE + 1];
+
+ dprintf("Message length: %d, File descriptor: %d.\n", len, fd);
+ tmpline[0] = '\0';
+ if ( parts[fd] != (char *) 0 )
+ {
+ dprintf("Including part from messages.\n");
+ strcpy(tmpline, parts[fd]);
+ free(parts[fd]);
+ parts[fd] = (char *) 0;
+ if ( (strlen(msg) + strlen(tmpline)) > MAXLINE )
+ {
+ logerror("Cannot glue message parts together");
+ printline(hname, tmpline);
+ start = msg;
+ }
+ else
+ {
+ dprintf("Previous: %s\n", tmpline);
+ dprintf("Next: %s\n", msg);
+ strcat(tmpline, msg); /* length checked above */
+ printline(hname, tmpline);
+ if ( (strlen(msg) + 1) == len )
+ return;
+ else
+ start = strchr(msg, '\0') + 1;
+ }
+ }
+
+ if ( msg[len-1] != '\0' )
+ {
+ msg[len] = '\0';
+ for(p= msg+len-1; *p != '\0' && p > msg; )
+ --p;
+ if(*p == '\0') p++;
+ ptlngth = strlen(p);
+ if ( (parts[fd] = malloc(ptlngth + 1)) == (char *) 0 )
+ logerror("Cannot allocate memory for message part.");
+ else
+ {
+ strcpy(parts[fd], p);
+ dprintf("Saving partial msg: %s\n", parts[fd]);
+ memset(p, '\0', ptlngth);
+ }
+ }
+
+ do {
+ end = strchr(start + 1, '\0');
+ printline(hname, start);
+ start = end + 1;
+ } while ( *start != '\0' );
+
+ return;
+}
+
+
+
+/*
+ * Take a raw input line, decode the message, and print the message
+ * on the appropriate log files.
+ */
+
+void printline(hname, msg)
+ const char *hname;
+ char *msg;
+{
+ register char *p, *q;
+ register unsigned char c;
+ char line[MAXLINE + 1];
+ int pri;
+
+ /* test for special codes */
+ pri = DEFUPRI;
+ p = msg;
+
+ if (*p == '<') {
+ pri = 0;
+ while (isdigit(*++p))
+ {
+ pri = 10 * pri + (*p - '0');
+ }
+ if (*p == '>')
+ ++p;
+ }
+ if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
+ pri = DEFUPRI;
+
+ memset (line, 0, sizeof(line));
+ q = line;
+ while ((c = *p++) && q < &line[sizeof(line) - 4]) {
+ if (c == '\n')
+ *q++ = ' ';
+ else if (c < 040) {
+ *q++ = '^';
+ *q++ = c ^ 0100;
+ } else if (c == 0177 || (c & 0177) < 040) {
+ *q++ = '\\';
+ *q++ = '0' + ((c & 0300) >> 6);
+ *q++ = '0' + ((c & 0070) >> 3);
+ *q++ = '0' + (c & 0007);
+ } else
+ *q++ = c;
+ }
+ *q = '\0';
+
+ logmsg(pri, line, hname, SYNC_FILE);
+ return;
+}
+
+
+
+/*
+ * Take a raw input line from /dev/klog, split and format similar to syslog().
+ */
+
+void printsys(msg)
+ char *msg;
+{
+ register char *p, *q;
+ register int c;
+ char line[MAXLINE + 1];
+ int pri, flags;
+ char *lp;
+
+ (void) snprintf(line, sizeof(line), "vmunix: ");
+ lp = line + strlen(line);
+ for (p = msg; *p != '\0'; ) {
+ flags = ADDDATE;
+ pri = DEFSPRI;
+ if (*p == '<') {
+ pri = 0;
+ while (isdigit(*++p))
+ pri = 10 * pri + (*p - '0');
+ if (*p == '>')
+ ++p;
+ } else {
+ /* kernel printf's come out on console */
+ flags |= IGN_CONS;
+ }
+ if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
+ pri = DEFSPRI;
+ q = lp;
+ while (*p != '\0' && (c = *p++) != '\n' &&
+ q < &line[MAXLINE])
+ *q++ = c;
+ *q = '\0';
+ logmsg(pri, line, LocalHostName, flags);
+ }
+ return;
+}
+
+/*
+ * Decode a priority into textual information like auth.emerg.
+ */
+char *textpri(pri)
+ int pri;
+{
+ static char res[20];
+ CODE *c_pri, *c_fac;
+
+ for (c_fac = facilitynames; c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri)<<3); c_fac++);
+ for (c_pri = prioritynames; c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
+
+ snprintf (res, sizeof(res), "%s.%s<%d>", c_fac->c_name, c_pri->c_name, pri);
+
+ return res;
+}
+
+time_t now;
+
+/*
+ * Log a message to the appropriate log files, users, etc. based on
+ * the priority.
+ */
+
+void logmsg(pri, msg, from, flags)
+ int pri;
+ char *msg;
+ const char *from;
+ int flags;
+{
+ register struct filed *f;
+ int fac, prilev, lognum;
+ int msglen;
+ char *timestamp;
+
+ dprintf("logmsg: %s, flags %x, from %s, msg %s\n", textpri(pri), flags, from, msg);
+
+#ifndef SYSV
+ omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
+#endif
+
+ /*
+ * Check to see if msg looks non-standard.
+ */
+ msglen = strlen(msg);
+ if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
+ msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
+ flags |= ADDDATE;
+
+ (void) time(&now);
+ if (flags & ADDDATE)
+ timestamp = ctime(&now) + 4;
+ else {
+ timestamp = msg;
+ msg += 16;
+ msglen -= 16;
+ }
+
+ /* extract facility and priority level */
+ if (flags & MARK)
+ fac = LOG_NFACILITIES;
+ else
+ fac = LOG_FAC(pri);
+ prilev = LOG_PRI(pri);
+
+ /* log the message to the particular outputs */
+ if (!Initialized) {
+ f = &consfile;
+ f->f_file = open(ctty, O_WRONLY|O_NOCTTY);
+
+ if (f->f_file >= 0) {
+ untty();
+ fprintlog(f, (char *)from, flags, msg);
+ (void) close(f->f_file);
+ f->f_file = -1;
+ }
+#ifndef SYSV
+ (void) sigsetmask(omask);
+#endif
+ return;
+ }
+#ifdef SYSV
+ for (lognum = 0; lognum <= nlogs; lognum++) {
+ f = &Files[lognum];
+#else
+ for (f = Files; f; f = f->f_next) {
+#endif
+
+ /* skip messages that are incorrect priority */
+ if ( (f->f_pmask[fac] == TABLE_NOPRI) || \
+ ((f->f_pmask[fac] & (1<<prilev)) == 0) )
+ continue;
+
+ if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
+ continue;
+
+ /* don't output marks to recently written files */
+ if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
+ continue;
+
+ /*
+ * suppress duplicate lines to this file
+ */
+ if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
+ !strcmp(msg, f->f_prevline) &&
+ !strcmp(from, f->f_prevhost)) {
+ (void) strncpy(f->f_lasttime, timestamp, 15);
+ f->f_prevcount++;
+ dprintf("msg repeated %d times, %ld sec of %d.\n",
+ f->f_prevcount, now - f->f_time,
+ repeatinterval[f->f_repeatcount]);
+ /*
+ * If domark would have logged this by now,
+ * flush it now (so we don't hold isolated messages),
+ * but back off so we'll flush less often
+ * in the future.
+ */
+ if (now > REPEATTIME(f)) {
+ fprintlog(f, (char *)from, flags, (char *)NULL);
+ BACKOFF(f);
+ }
+ } else {
+ /* new line, save it */
+ if (f->f_prevcount)
+ fprintlog(f, (char *)from, 0, (char *)NULL);
+ f->f_prevpri = pri;
+ f->f_repeatcount = 0;
+ (void) strncpy(f->f_lasttime, timestamp, 15);
+ (void) strncpy(f->f_prevhost, from,
+ sizeof(f->f_prevhost));
+ if (msglen < MAXSVLINE) {
+ f->f_prevlen = msglen;
+ (void) strcpy(f->f_prevline, msg);
+ fprintlog(f, (char *)from, flags, (char *)NULL);
+ } else {
+ f->f_prevline[0] = 0;
+ f->f_prevlen = 0;
+ fprintlog(f, (char *)from, flags, msg);
+ }
+ }
+ }
+#ifndef SYSV
+ (void) sigsetmask(omask);
+#endif
+}
+#if FALSE
+} /* balance parentheses for emacs */
+#endif
+
+void fprintlog(f, from, flags, msg)
+ register struct filed *f;
+ char *from;
+ int flags;
+ char *msg;
+{
+ struct iovec iov[6];
+ register struct iovec *v = iov;
+ char repbuf[80];
+#ifdef SYSLOG_INET
+ register int l;
+ char line[MAXLINE + 1];
+ time_t fwd_suspend;
+ struct hostent *hp;
+#endif
+
+ dprintf("Called fprintlog, ");
+
+ v->iov_base = f->f_lasttime;
+ v->iov_len = 15;
+ v++;
+ v->iov_base = " ";
+ v->iov_len = 1;
+ v++;
+ v->iov_base = f->f_prevhost;
+ v->iov_len = strlen(v->iov_base);
+ v++;
+ v->iov_base = " ";
+ v->iov_len = 1;
+ v++;
+ if (msg) {
+ v->iov_base = msg;
+ v->iov_len = strlen(msg);
+ } else if (f->f_prevcount > 1) {
+ (void) snprintf(repbuf, sizeof(repbuf), "last message repeated %d times",
+ f->f_prevcount);
+ v->iov_base = repbuf;
+ v->iov_len = strlen(repbuf);
+ } else {
+ v->iov_base = f->f_prevline;
+ v->iov_len = f->f_prevlen;
+ }
+ v++;
+
+ dprintf("logging to %s", TypeNames[f->f_type]);
+
+ switch (f->f_type) {
+ case F_UNUSED:
+ f->f_time = now;
+ dprintf("\n");
+ break;
+
+#ifdef SYSLOG_INET
+ case F_FORW_SUSP:
+ fwd_suspend = time((time_t *) 0) - f->f_time;
+ if ( fwd_suspend >= INET_SUSPEND_TIME ) {
+ dprintf("\nForwarding suspension over, " \
+ "retrying FORW ");
+ f->f_type = F_FORW;
+ goto f_forw;
+ }
+ else {
+ dprintf(" %s\n", f->f_un.f_forw.f_hname);
+ dprintf("Forwarding suspension not over, time " \
+ "left: %d.\n", INET_SUSPEND_TIME - \
+ fwd_suspend);
+ }
+ break;
+
+ /*
+ * The trick is to wait some time, then retry to get the
+ * address. If that fails retry x times and then give up.
+ *
+ * You'll run into this problem mostly if the name server you
+ * need for resolving the address is on the same machine, but
+ * is started after syslogd.
+ */
+ case F_FORW_UNKN:
+ dprintf(" %s\n", f->f_un.f_forw.f_hname);
+ fwd_suspend = time((time_t *) 0) - f->f_time;
+ if ( fwd_suspend >= INET_SUSPEND_TIME ) {
+ dprintf("Forwarding suspension to unknown over, retrying\n");
+ if ( (hp = gethostbyname(f->f_un.f_forw.f_hname)) == NULL ) {
+ dprintf("Failure: %s\n", sys_h_errlist[h_errno]);
+ dprintf("Retries: %d\n", f->f_prevcount);
+ if ( --f->f_prevcount < 0 ) {
+ dprintf("Giving up.\n");
+ f->f_type = F_UNUSED;
+ }
+ else
+ dprintf("Left retries: %d\n", f->f_prevcount);
+ }
+ else {
+ dprintf("%s found, resuming.\n", f->f_un.f_forw.f_hname);
+ memcpy((char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length);
+ f->f_prevcount = 0;
+ f->f_type = F_FORW;
+ goto f_forw;
+ }
+ }
+ else
+ dprintf("Forwarding suspension not over, time " \
+ "left: %d\n", INET_SUSPEND_TIME - fwd_suspend);
+ break;
+
+ case F_FORW:
+ /*
+ * Don't send any message to a remote host if it
+ * already comes from one. (we don't care 'bout who
+ * sent the message, we don't send it anyway) -Joey
+ */
+ f_forw:
+ dprintf(" %s\n", f->f_un.f_forw.f_hname);
+ if ( strcmp(from, LocalHostName) && NoHops )
+ dprintf("Not sending message to remote.\n");
+ else {
+ f->f_time = now;
+ (void) snprintf(line, sizeof(line), "<%d>%s\n", f->f_prevpri, \
+ (char *) iov[4].iov_base);
+ l = strlen(line);
+ if (l > MAXLINE)
+ l = MAXLINE;
+ if (sendto(finet, line, l, 0, \
+ (struct sockaddr *) &f->f_un.f_forw.f_addr,
+ sizeof(f->f_un.f_forw.f_addr)) != l) {
+ int e = errno;
+ dprintf("INET sendto error: %d = %s.\n",
+ e, strerror(e));
+ f->f_type = F_FORW_SUSP;
+ errno = e;
+ logerror("sendto");
+ }
+ }
+ break;
+#endif
+
+ case F_CONSOLE:
+ f->f_time = now;
+#ifdef UNIXPC
+ if (1) {
+#else
+ if (flags & IGN_CONS) {
+#endif
+ dprintf(" (ignored).\n");
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case F_TTY:
+ case F_FILE:
+ case F_PIPE:
+ f->f_time = now;
+ dprintf(" %s\n", f->f_un.f_fname);
+ if (f->f_type == F_TTY || f->f_type == F_CONSOLE) {
+ v->iov_base = "\r\n";
+ v->iov_len = 2;
+ } else {
+ v->iov_base = "\n";
+ v->iov_len = 1;
+ }
+ again:
+ /* f->f_file == -1 is an indicator that the we couldn't
+ open the file at startup. */
+ if (f->f_file == -1)
+ break;
+
+ if (writev(f->f_file, iov, 6) < 0) {
+ int e = errno;
+
+ /* If a named pipe is full, just ignore it for now
+ - mrn 24 May 96 */
+ if (f->f_type == F_PIPE && e == EAGAIN)
+ break;
+
+ (void) close(f->f_file);
+ /*
+ * Check for EBADF on TTY's due to vhangup() XXX
+ * Linux uses EIO instead (mrn 12 May 96)
+ */
+ if ((f->f_type == F_TTY || f->f_type == F_CONSOLE)
+#ifdef linux
+ && e == EIO) {
+#else
+ && e == EBADF) {
+#endif
+ f->f_file = open(f->f_un.f_fname, O_WRONLY|O_APPEND|O_NOCTTY);
+ if (f->f_file < 0) {
+ f->f_type = F_UNUSED;
+ logerror(f->f_un.f_fname);
+ } else {
+ untty();
+ goto again;
+ }
+ } else {
+ f->f_type = F_UNUSED;
+ errno = e;
+ logerror(f->f_un.f_fname);
+ }
+ } else if (f->f_flags & SYNC_FILE)
+ (void) fsync(f->f_file);
+ break;
+
+ case F_USERS:
+ case F_WALL:
+ f->f_time = now;
+ dprintf("\n");
+ v->iov_base = "\r\n";
+ v->iov_len = 2;
+ wallmsg(f, iov);
+ break;
+ } /* switch */
+ if (f->f_type != F_FORW_UNKN)
+ f->f_prevcount = 0;
+ return;
+}
+#if FALSE
+}} /* balance parentheses for emacs */
+#endif
+
+jmp_buf ttybuf;
+
+void endtty()
+{
+ longjmp(ttybuf, 1);
+}
+
+/*
+ * WALLMSG -- Write a message to the world at large
+ *
+ * Write the specified message to either the entire
+ * world, or a list of approved users.
+ */
+
+void wallmsg(f, iov)
+ register struct filed *f;
+ struct iovec *iov;
+{
+ char p[6 + UNAMESZ];
+ register int i;
+ int ttyf, len;
+ static int reenter = 0;
+ struct utmp ut;
+ struct utmp *uptr;
+ char greetings[200];
+
+ if (reenter++)
+ return;
+
+ /* open the user login file */
+ setutent();
+
+
+ /*
+ * Might as well fork instead of using nonblocking I/O
+ * and doing notty().
+ */
+ if (fork() == 0) {
+ (void) signal(SIGTERM, SIG_DFL);
+ (void) alarm(0);
+ (void) signal(SIGALRM, endtty);
+#ifndef SYSV
+ (void) signal(SIGTTOU, SIG_IGN);
+ (void) sigsetmask(0);
+#endif
+ (void) snprintf(greetings, sizeof(greetings),
+ "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
+ (char *) iov[2].iov_base, ctime(&now));
+ len = strlen(greetings);
+
+ /* scan the user login file */
+ while ((uptr = getutent())) {
+ memcpy(&ut, uptr, sizeof(ut));
+ /* is this slot used? */
+ if (ut.ut_name[0] == '\0')
+ continue;
+ if (ut.ut_type == LOGIN_PROCESS)
+ continue;
+ if (!(strcmp (ut.ut_name,"LOGIN"))) /* paranoia */
+ continue;
+
+ /* should we send the message to this user? */
+ if (f->f_type == F_USERS) {
+ for (i = 0; i < MAXUNAMES; i++) {
+ if (!f->f_un.f_uname[i][0]) {
+ i = MAXUNAMES;
+ break;
+ }
+ if (strncmp(f->f_un.f_uname[i],
+ ut.ut_name, UNAMESZ) == 0)
+ break;
+ }
+ if (i >= MAXUNAMES)
+ continue;
+ }
+
+ /* compute the device name */
+ strcpy(p, _PATH_DEV);
+ strncat(p, ut.ut_line, UNAMESZ);
+
+ if (f->f_type == F_WALL) {
+ iov[0].iov_base = greetings;
+ iov[0].iov_len = len;
+ iov[1].iov_len = 0;
+ }
+ if (setjmp(ttybuf) == 0) {
+ (void) alarm(15);
+ /* open the terminal */
+ ttyf = open(p, O_WRONLY|O_NOCTTY);
+ if (ttyf >= 0) {
+ struct stat statb;
+
+ if (fstat(ttyf, &statb) == 0 &&
+ (statb.st_mode & S_IWRITE))
+ (void) writev(ttyf, iov, 6);
+ close(ttyf);
+ ttyf = -1;
+ }
+ }
+ (void) alarm(0);
+ }
+ exit(0);
+ }
+ /* close the user login file */
+ endutent();
+ reenter = 0;
+}
+
+void reapchild()
+{
+ int saved_errno = errno;
+#if defined(SYSV) && !defined(linux)
+ (void) signal(SIGCHLD, reapchild); /* reset signal handler -ASP */
+ wait ((int *)0);
+#else
+ union wait status;
+
+ while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
+ ;
+#endif
+#ifdef linux
+ (void) signal(SIGCHLD, reapchild); /* reset signal handler -ASP */
+#endif
+ errno = saved_errno;
+}
+
+/*
+ * Return a printable representation of a host address.
+ */
+const char *cvthname(f)
+ struct sockaddr_in *f;
+{
+ struct hostent *hp;
+ register char *p;
+ int count;
+
+ if (f->sin_family != AF_INET) {
+ dprintf("Malformed from address.\n");
+ return ("???");
+ }
+ hp = gethostbyaddr((char *) &f->sin_addr, sizeof(struct in_addr), \
+ f->sin_family);
+ if (hp == 0) {
+ dprintf("Host name for your address (%s) unknown.\n",
+ inet_ntoa(f->sin_addr));
+ return (inet_ntoa(f->sin_addr));
+ }
+ /*
+ * Convert to lower case, just like LocalDomain above
+ */
+ for (p = (char *)hp->h_name; *p ; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+
+ /*
+ * Notice that the string still contains the fqdn, but your
+ * hostname and domain are separated by a '\0'.
+ */
+ if ((p = strchr(hp->h_name, '.'))) {
+ if (strcmp(p + 1, LocalDomain) == 0) {
+ *p = '\0';
+ return (hp->h_name);
+ } else {
+ if (StripDomains) {
+ count=0;
+ while (StripDomains[count]) {
+ if (strcmp(p + 1, StripDomains[count]) == 0) {
+ *p = '\0';
+ return (hp->h_name);
+ }
+ count++;
+ }
+ }
+ if (LocalHosts) {
+ count=0;
+ while (LocalHosts[count]) {
+ if (!strcmp(hp->h_name, LocalHosts[count])) {
+ *p = '\0';
+ return (hp->h_name);
+ }
+ count++;
+ }
+ }
+ }
+ }
+
+ return (hp->h_name);
+}
+
+void domark()
+{
+ register struct filed *f;
+#ifdef SYSV
+ int lognum;
+#endif
+
+ if (MarkInterval > 0) {
+ now = time(0);
+ MarkSeq += TIMERINTVL;
+ if (MarkSeq >= MarkInterval) {
+ logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
+ MarkSeq = 0;
+ }
+
+#ifdef SYSV
+ for (lognum = 0; lognum <= nlogs; lognum++) {
+ f = &Files[lognum];
+#else
+ for (f = Files; f; f = f->f_next) {
+#endif
+ if (f->f_prevcount && now >= REPEATTIME(f)) {
+ dprintf("flush %s: repeated %d times, %d sec.\n",
+ TypeNames[f->f_type], f->f_prevcount,
+ repeatinterval[f->f_repeatcount]);
+ fprintlog(f, LocalHostName, 0, (char *)NULL);
+ BACKOFF(f);
+ }
+ }
+ }
+ (void) signal(SIGALRM, domark);
+ (void) alarm(TIMERINTVL);
+}
+
+void debug_switch()
+
+{
+ dprintf("Switching debugging_on to %s\n", (debugging_on == 0) ? "true" : "false");
+ debugging_on = (debugging_on == 0) ? 1 : 0;
+ signal(SIGUSR1, debug_switch);
+}
+
+
+/*
+ * Print syslogd errors some place.
+ */
+void logerror(type)
+ char *type;
+{
+ char buf[100];
+
+ dprintf("Called logerr, msg: %s\n", type);
+
+ if (errno == 0)
+ (void) snprintf(buf, sizeof(buf), "syslogd: %s", type);
+ else
+ (void) snprintf(buf, sizeof(buf), "syslogd: %s: %s", type, strerror(errno));
+ errno = 0;
+ logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
+ return;
+}
+
+void die(sig)
+
+ int sig;
+
+{
+ register struct filed *f;
+ char buf[100];
+ int lognum;
+ int i;
+ int was_initialized = Initialized;
+
+ Initialized = 0; /* Don't log SIGCHLDs in case we
+ receive one during exiting */
+
+ for (lognum = 0; lognum <= nlogs; lognum++) {
+ f = &Files[lognum];
+ /* flush any pending output */
+ if (f->f_prevcount)
+ fprintlog(f, LocalHostName, 0, (char *)NULL);
+ }
+
+ Initialized = was_initialized;
+ if (sig) {
+ dprintf("syslogd: exiting on signal %d\n", sig);
+ (void) snprintf(buf, sizeof(buf), "exiting on signal %d", sig);
+ errno = 0;
+ logmsg(LOG_SYSLOG|LOG_INFO, buf, LocalHostName, ADDDATE);
+ }
+
+ /* Close the UNIX sockets. */
+ for (i = 0; i < nfunix; i++)
+ if (funix[i] != -1)
+ close(funix[i]);
+ /* Close the inet socket. */
+ if (InetInuse) close(inetm);
+
+ /* Clean-up files. */
+ for (i = 0; i < nfunix; i++)
+ if (funixn[i] && funix[i] != -1)
+ (void)unlink(funixn[i]);
+#ifndef TESTING
+ (void) remove_pid(PidFile);
+#endif
+ exit(0);
+}
+
+/*
+ * Signal handler to terminate the parent process.
+ */
+#ifndef TESTING
+void doexit(sig)
+ int sig;
+{
+ exit (0);
+}
+#endif
+
+/*
+ * INIT -- Initialize syslogd from configuration table
+ */
+
+void init()
+{
+ register int i, lognum;
+ register FILE *cf;
+ register struct filed *f;
+#ifndef TESTING
+#ifndef SYSV
+ register struct filed **nextp = (struct filed **) 0;
+#endif
+#endif
+ register char *p;
+ register unsigned int Forwarding = 0;
+#ifdef CONT_LINE
+ char cbuf[BUFSIZ];
+ char *cline;
+#else
+ char cline[BUFSIZ];
+#endif
+ struct servent *sp;
+
+ sp = getservbyname("syslog", "udp");
+ if (sp == NULL) {
+ errno = 0;
+ logerror("network logging disabled (syslog/udp service unknown).");
+ logerror("see syslogd(8) for details of whether and how to enable it.");
+ return;
+ }
+ LogPort = sp->s_port;
+
+ /*
+ * Close all open log files and free log descriptor array.
+ */
+ dprintf("Called init.\n");
+ Initialized = 0;
+ if ( nlogs > -1 )
+ {
+ dprintf("Initializing log structures.\n");
+
+ for (lognum = 0; lognum <= nlogs; lognum++ ) {
+ f = &Files[lognum];
+
+ /* flush any pending output */
+ if (f->f_prevcount)
+ fprintlog(f, LocalHostName, 0, (char *)NULL);
+
+ switch (f->f_type) {
+ case F_FILE:
+ case F_PIPE:
+ case F_TTY:
+ case F_CONSOLE:
+ (void) close(f->f_file);
+ break;
+ }
+ }
+
+ /*
+ * This is needed especially when HUPing syslogd as the
+ * structure would grow infinitively. -Joey
+ */
+ nlogs = -1;
+ free((void *) Files);
+ Files = (struct filed *) 0;
+ }
+
+
+#ifdef SYSV
+ lognum = 0;
+#else
+ f = NULL;
+#endif
+
+ /* open the configuration file */
+ if ((cf = fopen(ConfFile, "r")) == NULL) {
+ dprintf("cannot open %s.\n", ConfFile);
+#ifdef SYSV
+ allocate_log();
+ f = &Files[lognum++];
+#ifndef TESTING
+ cfline("*.err\t" _PATH_CONSOLE, f);
+#else
+ snprintf(cbuf,sizeof(cbuf), "*.*\t%s", ttyname(0));
+ cfline(cbuf, f);
+#endif
+#else
+ *nextp = (struct filed *)calloc(1, sizeof(*f));
+ cfline("*.ERR\t" _PATH_CONSOLE, *nextp);
+ (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)) /* ASP */
+ cfline("*.PANIC\t*", (*nextp)->f_next);
+#endif
+ Initialized = 1;
+ return;
+ }
+
+ /*
+ * Foreach line in the conf table, open that file.
+ */
+#if CONT_LINE
+ cline = cbuf;
+ while (fgets(cline, sizeof(cbuf) - (cline - cbuf), cf) != NULL) {
+#else
+ while (fgets(cline, sizeof(cline), cf) != NULL) {
+#endif
+ /*
+ * check for end-of-section, comments, strip off trailing
+ * spaces and newline character.
+ */
+ for (p = cline; isspace(*p); ++p);
+ if (*p == '\0' || *p == '#')
+ continue;
+#if CONT_LINE
+ strcpy(cline, p);
+#endif
+ for (p = strchr(cline, '\0'); isspace(*--p););
+#if CONT_LINE
+ if (*p == '\\') {
+ if ((p - cbuf) > BUFSIZ - 30) {
+ /* Oops the buffer is full - what now? */
+ cline = cbuf;
+ } else {
+ *p = 0;
+ cline = p;
+ continue;
+ }
+ } else
+ cline = cbuf;
+#endif
+ *++p = '\0';
+#ifndef SYSV
+ f = (struct filed *)calloc(1, sizeof(*f));
+ *nextp = f;
+ nextp = &f->f_next;
+#endif
+ allocate_log();
+ f = &Files[lognum++];
+#if CONT_LINE
+ cfline(cbuf, f);
+#else
+ cfline(cline, f);
+#endif
+ if (f->f_type == F_FORW || f->f_type == F_FORW_SUSP || f->f_type == F_FORW_UNKN) {
+ Forwarding++;
+ }
+ }
+
+ /* close the configuration file */
+ (void) fclose(cf);
+
+#ifdef SYSLOG_UNIXAF
+ for (i = 0; i < nfunix; i++) {
+ if (funix[i] != -1)
+ /* Don't close the socket, preserve it instead
+ close(funix[i]);
+ */
+ continue;
+ if ((funix[i] = create_unix_socket(funixn[i])) != -1)
+ dprintf("Opened UNIX socket `%s'.\n", funixn[i]);
+ }
+#endif
+
+#ifdef SYSLOG_INET
+ if (Forwarding || AcceptRemote) {
+ if (finet < 0) {
+ finet = create_inet_socket();
+ if (finet >= 0) {
+ InetInuse = 1;
+ dprintf("Opened syslog UDP port.\n");
+ }
+ }
+ }
+ else {
+ if (finet >= 0)
+ close(finet);
+ finet = -1;
+ InetInuse = 0;
+ }
+ inetm = finet;
+#endif
+
+ Initialized = 1;
+
+ if ( Debug ) {
+#ifdef SYSV
+ for (lognum = 0; lognum <= nlogs; lognum++) {
+ f = &Files[lognum];
+ if (f->f_type != F_UNUSED) {
+ printf ("%2d: ", lognum);
+#else
+ for (f = Files; f; f = f->f_next) {
+ if (f->f_type != F_UNUSED) {
+#endif
+ for (i = 0; i <= LOG_NFACILITIES; i++)
+ if (f->f_pmask[i] == TABLE_NOPRI)
+ printf(" X ");
+ else
+ printf("%2X ", f->f_pmask[i]);
+ printf("%s: ", TypeNames[f->f_type]);
+ switch (f->f_type) {
+ case F_FILE:
+ case F_PIPE:
+ case F_TTY:
+ case F_CONSOLE:
+ printf("%s", f->f_un.f_fname);
+ if (f->f_file == -1)
+ printf(" (unused)");
+ break;
+
+ case F_FORW:
+ case F_FORW_SUSP:
+ case F_FORW_UNKN:
+ printf("%s", f->f_un.f_forw.f_hname);
+ break;
+
+ case F_USERS:
+ for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
+ printf("%s, ", f->f_un.f_uname[i]);
+ break;
+ }
+ printf("\n");
+ }
+ }
+ }
+
+ if ( AcceptRemote )
+#ifdef DEBRELEASE
+ logmsg(LOG_SYSLOG|LOG_INFO, "syslogd " VERSION "." PATCHLEVEL "#" DEBRELEASE \
+ ": restart (remote reception)." , LocalHostName, \
+ ADDDATE);
+#else
+ logmsg(LOG_SYSLOG|LOG_INFO, "syslogd " VERSION "." PATCHLEVEL \
+ ": restart (remote reception)." , LocalHostName, \
+ ADDDATE);
+#endif
+ else
+#ifdef DEBRELEASE
+ logmsg(LOG_SYSLOG|LOG_INFO, "syslogd " VERSION "." PATCHLEVEL "#" DEBRELEASE \
+ ": restart." , LocalHostName, ADDDATE);
+#else
+ logmsg(LOG_SYSLOG|LOG_INFO, "syslogd " VERSION "." PATCHLEVEL \
+ ": restart." , LocalHostName, ADDDATE);
+#endif
+ (void) signal(SIGHUP, sighup_handler);
+ dprintf("syslogd: restarted.\n");
+}
+#if FALSE
+ }}} /* balance parentheses for emacs */
+#endif
+
+/*
+ * Crack a configuration file line
+ */
+
+void cfline(line, f)
+ char *line;
+ register struct filed *f;
+{
+ register char *p;
+ register char *q;
+ register int i, i2;
+ char *bp;
+ int pri;
+ int singlpri = 0;
+ int ignorepri = 0;
+ int syncfile;
+#ifdef SYSLOG_INET
+ struct hostent *hp;
+#endif
+ char buf[MAXLINE];
+ char xbuf[200];
+
+ dprintf("cfline(%s)\n", line);
+
+ errno = 0; /* keep strerror() stuff out of logerror messages */
+
+ /* clear out file entry */
+#ifndef SYSV
+ memset((char *) f, 0, sizeof(*f));
+#endif
+ for (i = 0; i <= LOG_NFACILITIES; i++) {
+ f->f_pmask[i] = TABLE_NOPRI;
+ f->f_flags = 0;
+ }
+
+ /* scan through the list of selectors */
+ for (p = line; *p && *p != '\t' && *p != ' ';) {
+
+ /* find the end of this facility name list */
+ for (q = p; *q && *q != '\t' && *q++ != '.'; )
+ continue;
+
+ /* collect priority name */
+ for (bp = buf; *q && !strchr("\t ,;", *q); )
+ *bp++ = *q++;
+ *bp = '\0';
+
+ /* skip cruft */
+ while (strchr(",;", *q))
+ q++;
+
+ /* decode priority name */
+ if ( *buf == '!' ) {
+ ignorepri = 1;
+ for (bp=buf; *(bp+1); bp++)
+ *bp=*(bp+1);
+ *bp='\0';
+ }
+ else {
+ ignorepri = 0;
+ }
+ if ( *buf == '=' )
+ {
+ singlpri = 1;
+ pri = decode(&buf[1], PriNames);
+ }
+ else {
+ singlpri = 0;
+ pri = decode(buf, PriNames);
+ }
+
+ if (pri < 0) {
+ (void) snprintf(xbuf, sizeof(xbuf), "unknown priority name \"%s\"", buf);
+ logerror(xbuf);
+ return;
+ }
+
+ /* scan facilities */
+ while (*p && !strchr("\t .;", *p)) {
+ for (bp = buf; *p && !strchr("\t ,;.", *p); )
+ *bp++ = *p++;
+ *bp = '\0';
+ if (*buf == '*') {
+ for (i = 0; i <= LOG_NFACILITIES; i++) {
+ if ( pri == INTERNAL_NOPRI ) {
+ if ( ignorepri )
+ f->f_pmask[i] = TABLE_ALLPRI;
+ else
+ f->f_pmask[i] = TABLE_NOPRI;
+ }
+ else if ( singlpri ) {
+ if ( ignorepri )
+ f->f_pmask[i] &= ~(1<<pri);
+ else
+ f->f_pmask[i] |= (1<<pri);
+ }
+ else
+ {
+ if ( pri == TABLE_ALLPRI ) {
+ if ( ignorepri )
+ f->f_pmask[i] = TABLE_NOPRI;
+ else
+ f->f_pmask[i] = TABLE_ALLPRI;
+ }
+ else
+ {
+ if ( ignorepri )
+ for (i2= 0; i2 <= pri; ++i2)
+ f->f_pmask[i] &= ~(1<<i2);
+ else
+ for (i2= 0; i2 <= pri; ++i2)
+ f->f_pmask[i] |= (1<<i2);
+ }
+ }
+ }
+ } else {
+ i = decode(buf, FacNames);
+ if (i < 0) {
+
+ (void) snprintf(xbuf, sizeof(xbuf), "unknown facility name \"%s\"", buf);
+ logerror(xbuf);
+ return;
+ }
+
+ if ( pri == INTERNAL_NOPRI ) {
+ if ( ignorepri )
+ f->f_pmask[i >> 3] = TABLE_ALLPRI;
+ else
+ f->f_pmask[i >> 3] = TABLE_NOPRI;
+ } else if ( singlpri ) {
+ if ( ignorepri )
+ f->f_pmask[i >> 3] &= ~(1<<pri);
+ else
+ f->f_pmask[i >> 3] |= (1<<pri);
+ } else {
+ if ( pri == TABLE_ALLPRI ) {
+ if ( ignorepri )
+ f->f_pmask[i >> 3] = TABLE_NOPRI;
+ else
+ f->f_pmask[i >> 3] = TABLE_ALLPRI;
+ } else {
+ if ( ignorepri )
+ for (i2= 0; i2 <= pri; ++i2)
+ f->f_pmask[i >> 3] &= ~(1<<i2);
+ else
+ for (i2= 0; i2 <= pri; ++i2)
+ f->f_pmask[i >> 3] |= (1<<i2);
+ }
+ }
+ }
+ while (*p == ',' || *p == ' ')
+ p++;
+ }
+
+ p = q;
+ }
+
+ /* skip to action part */
+ while (*p == '\t' || *p == ' ')
+ p++;
+
+ if (*p == '-')
+ {
+ syncfile = 0;
+ p++;
+ } else
+ syncfile = 1;
+
+ dprintf("leading char in action: %c\n", *p);
+ switch (*p)
+ {
+ case '@':
+#ifdef SYSLOG_INET
+ (void) strcpy(f->f_un.f_forw.f_hname, ++p);
+ dprintf("forwarding host: %s\n", p); /*ASP*/
+ if ( (hp = gethostbyname(p)) == NULL ) {
+ f->f_type = F_FORW_UNKN;
+ f->f_prevcount = INET_RETRY_MAX;
+ f->f_time = time ( (time_t *)0 );
+ } else {
+ f->f_type = F_FORW;
+ }
+
+ memset((char *) &f->f_un.f_forw.f_addr, 0,
+ sizeof(f->f_un.f_forw.f_addr));
+ f->f_un.f_forw.f_addr.sin_family = AF_INET;
+ f->f_un.f_forw.f_addr.sin_port = LogPort;
+ if ( f->f_type == F_FORW )
+ memcpy((char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length);
+ /*
+ * Otherwise the host might be unknown due to an
+ * inaccessible nameserver (perhaps on the same
+ * host). We try to get the ip number later, like
+ * FORW_SUSP.
+ */
+#endif
+ break;
+
+ case '|':
+ case '/':
+ (void) strcpy(f->f_un.f_fname, p);
+ dprintf ("filename: %s\n", p); /*ASP*/
+ if (syncfile)
+ f->f_flags |= SYNC_FILE;
+ if ( *p == '|' ) {
+ f->f_file = open(++p, O_RDWR|O_NONBLOCK);
+ f->f_type = F_PIPE;
+ } else {
+ f->f_file = open(p, O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY,
+ 0644);
+ f->f_type = F_FILE;
+ }
+
+ if ( f->f_file < 0 ){
+ f->f_file = -1;
+ dprintf("Error opening log file: %s\n", p);
+ logerror(p);
+ break;
+ }
+ if (isatty(f->f_file)) {
+ f->f_type = F_TTY;
+ untty();
+ }
+ if (strcmp(p, ctty) == 0)
+ f->f_type = F_CONSOLE;
+ break;
+
+ case '*':
+ dprintf ("write-all\n");
+ f->f_type = F_WALL;
+ break;
+
+ default:
+ dprintf ("users: %s\n", p); /* ASP */
+ for (i = 0; i < MAXUNAMES && *p; i++) {
+ for (q = p; *q && *q != ','; )
+ q++;
+ (void) strncpy(f->f_un.f_uname[i], p, UNAMESZ);
+ if ((q - p) > UNAMESZ)
+ f->f_un.f_uname[i][UNAMESZ] = '\0';
+ else
+ f->f_un.f_uname[i][q - p] = '\0';
+ while (*q == ',' || *q == ' ')
+ q++;
+ p = q;
+ }
+ f->f_type = F_USERS;
+ break;
+ }
+ return;
+}
+
+
+/*
+ * Decode a symbolic name to a numeric value
+ */
+
+int decode(name, codetab)
+ char *name;
+ struct code *codetab;
+{
+ register struct code *c;
+ register char *p;
+ char buf[80];
+
+ dprintf ("symbolic name: %s", name);
+ if (isdigit(*name))
+ {
+ dprintf ("\n");
+ return (atoi(name));
+ }
+ (void) strncpy(buf, name, 79);
+ for (p = buf; *p; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+ for (c = codetab; c->c_name; c++)
+ if (!strcmp(buf, c->c_name))
+ {
+ dprintf (" ==> %d\n", c->c_val);
+ return (c->c_val);
+ }
+ return (-1);
+}
+
+static void dprintf(char *fmt, ...)
+
+{
+ va_list ap;
+
+ if ( !(Debug && debugging_on) )
+ return;
+
+ va_start(ap, fmt);
+ vfprintf(stdout, fmt, ap);
+ va_end(ap);
+
+ fflush(stdout);
+ return;
+}
+
+
+/*
+ * The following function is responsible for allocating/reallocating the
+ * array which holds the structures which define the logging outputs.
+ */
+static void allocate_log()
+
+{
+ dprintf("Called allocate_log, nlogs = %d.\n", nlogs);
+
+ /*
+ * Decide whether the array needs to be initialized or needs to
+ * grow.
+ */
+ if ( nlogs == -1 )
+ {
+ Files = (struct filed *) malloc(sizeof(struct filed));
+ if ( Files == (void *) 0 )
+ {
+ dprintf("Cannot initialize log structure.");
+ logerror("Cannot initialize log structure.");
+ return;
+ }
+ }
+ else
+ {
+ /* Re-allocate the array. */
+ Files = (struct filed *) realloc(Files, (nlogs+2) * \
+ sizeof(struct filed));
+ if ( Files == (struct filed *) 0 )
+ {
+ dprintf("Cannot grow log structure.");
+ logerror("Cannot grow log structure.");
+ return;
+ }
+ }
+
+ /*
+ * Initialize the array element, bump the number of elements in the
+ * the array and return.
+ */
+ ++nlogs;
+ memset(&Files[nlogs], '\0', sizeof(struct filed));
+ return;
+}
+
+
+/*
+ * The following function is resposible for handling a SIGHUP signal. Since
+ * we are now doing mallocs/free as part of init we had better not being
+ * doing this during a signal handler. Instead this function simply sets
+ * a flag variable which will tell the main loop to go through a restart.
+ */
+void sighup_handler()
+
+{
+ restart = 1;
+ signal(SIGHUP, sighup_handler);
+ return;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
+
diff --git a/version.h b/version.h
new file mode 100644
index 00000000..3188fc38
--- /dev/null
+++ b/version.h
@@ -0,0 +1,2 @@
+#define VERSION "1.4"
+#define PATCHLEVEL "1"