dklann@heurikon.UUCP (David Klann) (04/21/89)
I have been collecting, and using the sources contributed to the Net for quite a while now. It's my turn to contribute (in a small way :-). After reading John Milton's article of a few weeks ago concerning the error logger portion of smgr, I decided that it would be a good idea to track error coming from UNIX (I don't run UA/smgr/wmgr). Here's the source to an Error Logger daemon. Enjoy- David Klann Heurikon Corporation {backbone}!uwvax!heurikon!dklann ---------------------- cut -------------------------------------------------- #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 1 (of 1)." # Contents: MANIFEST Makefile er.1 er.c # Wrapped by dklann@grunch on Wed Apr 19 22:57:31 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'MANIFEST' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'MANIFEST'\" else echo shar: Extracting \"'MANIFEST'\" \(220 characters\) sed "s/^X//" >'MANIFEST' <<'END_OF_FILE' X File Name Archive # Description X----------------------------------------------------------- X MANIFEST 1 X Makefile 1 X er.1 1 X er.c 1 END_OF_FILE if test 220 -ne `wc -c <'MANIFEST'`; then echo shar: \"'MANIFEST'\" unpacked with wrong size! fi # end of 'MANIFEST' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(436 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# X# Makefile for error daemon, er(1). X# XCC = shcc XCFLAGS = -O XINSDIR = /etc/daemons X Xer: er.c X $(CC) $(CFLAGS) -o er er.c X Xclean: X rm -f *.o er X Xinstall: er X strip er X cp er $(INSDIR) X if [ -d usr/man/man1 ]; \ X then \ X cp er.1 /usr/man/man1; \ X fi X Xer.c: \ X /usr/include/stdio.h \ X /usr/include/sys/types.h \ X /usr/include/sys/err.h \ X /usr/include/sys/signal.h \ X /usr/include/fcntl.h \ X /usr/include/time.h \ X /usr/include/status.h END_OF_FILE if test 436 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'er.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'er.1'\" else echo shar: Extracting \"'er.1'\" \(815 characters\) sed "s/^X//" >'er.1' <<'END_OF_FILE' X.\" This program is in the public domain. X.TH er 1 "UNIX PC Local" X.SH NAME X.I Xer X\- error daemon X.SH SYNOPSIS X.I Xer X.B [ X-t X.B ] X.SH OPTIONS XThe single option X.B Xt Xinstructs X.I Xer Xto truncate log files before Xwriting them. X.SH DESCRIPTION X.I XEr Xreplaces part of the functionality of the Xsmgr(1) program. X.I XEr's Xgoal in life is to read the file X/dev/error, and write messages to one of Xtwo files. XMessages originating in the kernel (PID X\=\= 0) are written to the file X/usr/adm/unix.log. XMessages originating in user space (PID X\> 0) are written to the file X/usr/adm/err.log. X.I XEr Xforks itself, and changes its process Xgroup. XThis means that the program can be run Xas a daemon at boot time by placing it in X/etc/daemons. X.SH "FILES" X/usr/adm/unix.log, X/usr/adm/err.log. X.SH "SEE ALSO" Xerror(7), stdio(3), /etc/rc END_OF_FILE if test 815 -ne `wc -c <'er.1'`; then echo shar: \"'er.1'\" unpacked with wrong size! fi # end of 'er.1' fi if test -f 'er.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'er.c'\" else echo shar: Extracting \"'er.c'\" \(3505 characters\) sed "s/^X//" >'er.c' <<'END_OF_FILE' X/* X * Kernel error logger daemon. X * This program is in the public domain. X */ X X#include <stdio.h> X#include <sys/types.h> X#include <sys/err.h> X#include <sys/signal.h> X#include <fcntl.h> X#include <time.h> X#include <status.h> X Xint fd; Xvoid eprintf(); X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X register short truncate = 0; X register struct err *err; X register FILE *fp; X register c; X int getopt(); X time_t now; X void die(); X void quit(); X extern int optind; X extern char *optarg; X X /* X * Allow truncation of the log files. X */ X while ((c = getopt(argc, argv, "t")) != EOF) { X switch (c) { X case 't': X truncate++; X break; X default: X fprintf(stderr, "%s: usage: %s [ -t ]\n", X argv[0], argv[0]); X exit(1); X } X } X X if (fork() != 0) { X exit(0); X } else { X /* X * Get the error logger device. X */ X if ((fd = open("/dev/error", O_RDONLY)) == NULL) { X perror("open /dev/error"); X quit(); X } X X /* X * Close these, so setpgrp() will work. X */ X (void)fclose(stdin); X (void)fclose(stdout); X (void)fclose(stderr); X X /* X * Change the process group to disassociate us with windows. X */ X (void)setpgrp(); X X /* X * Set up signal handlers. X */ X signal(SIGINT, SIG_IGN); X signal(SIGHUP, SIG_IGN); X signal(SIGQUIT, SIG_IGN); X signal(SIGTERM, SIG_IGN); X signal(SIGUSR1, die); X X /* X * Write the initial message to the log file X */ X time(&now); X if ((fp = fopen("/usr/adm/unix.log", X (truncate ? "w" : "a+"))) == NULL) { X eprintf(ST_LOG, ST_LOGFILE, "root", X "err.log : cannot fopen /usr/adm/unix.log"); X quit(); X } X (void)fprintf(fp, "Error Logger started: (%d) %s", X getpid(), asctime(localtime(&now))); X (void)fclose(fp); X X /* X * Do the same for the non-kernel message file X */ X if ((fp = fopen("/usr/adm/err.log", X (truncate ? "w" : "a+"))) == NULL) { X eprintf(ST_LOG, ST_LOGFILE, "root", X "err.log : cannot fopen /usr/adm/err.log"); X quit(); X } X (void)fprintf(fp, "Error Logger started: (%d) %s", X getpid(), asctime(localtime(&now))); X (void)fclose(fp); X X /* X * Get some space for the error messages X */ X err = (struct err *)malloc(sizeof(struct err)); X if (err == NULL) { X eprintf(ST_LOG, ST_LOGFILE, "root", X "err.log : cannot malloc struct err"); X quit(); X } X X /* X * Loop forever X */ X while (1) { X if (read(fd,(char *)err,sizeof(struct err)) != sizeof(struct err)) { X eprintf(ST_LOG, ST_LOGFILE, "root", X "err.log : cannot read /dev/error"); X quit(); X } X time(&now); X if (err->e_pid == 0) { X if ((fp = fopen("/usr/adm/unix.log", "a+")) == NULL) { X eprintf(ST_LOG, ST_LOGFILE, "root", X "err.log : cannot fopen /usr/adm/unix.log"); X quit(); X } X (void)fprintf(fp, "%s: %s", X err->e_text, asctime(localtime(&now))); X (void)fflush(fp); X (void)fclose(fp); X } else { X if ((fp = fopen("/usr/adm/err.log", "a+")) == NULL) { X eprintf(ST_LOG, ST_LOGFILE, "root", X "err.log : cannot fopen /usr/adm/err.log"); X quit(); X } X (void)fprintf(fp, "%s (%d): %s", X err->e_text, err->e_pid, asctime(localtime(&now))); X (void)fflush(fp); X (void)fclose(fp); X } X } X } X} X Xvoid Xdie() X{ X register FILE *fp; X time_t now; X void quit(); X X if ((fp = fopen("/usr/adm/unix.log", "a+")) == NULL) { X eprintf(ST_LOG, ST_LOGFILE, "root", X "err.log : cannot fopen /usr/adm/unix.log"); X quit(); X } X time(&now); X (void)fprintf(fp, "er: exiting SIGUSR1: %s", asctime(localtime(&now))); X close(fd); X exit(2); X} X Xvoid Xquit() X{ X close(fd); X exit(1); X} END_OF_FILE if test 3505 -ne `wc -c <'er.c'`; then echo shar: \"'er.c'\" unpacked with wrong size! fi # end of 'er.c' fi echo shar: End of archive 1 \(of 1\). cp /dev/null ark1isdone MISSING="" for I in 1 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have the archive. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0