rs@uunet.UUCP (09/17/87)
Submitted-by: Johan Vromans <mcvax!mh.nl!jv> Posting-number: Volume 11, Issue 50 Archive-name: syslog.sysv [ I understand my "younger brother" Brandon is working on a complete 4.3BSD-compatible version that uses named pipes. Keep up the great work, folks: maybe we can get this as part of the Posvidix or something. --r$ ] This is a more realistic syslog development version. It is designed for System V with IPC (it uses message queues). I linked it to my sendmail for debugging purposes. It is not full-blown (it does not take a configuration file) but has proven to be very usefull. One special remark: because the logfile is default written on the /tmp filesystem, and our /tmp filesystems are cleaned up daily, an alarm timer is used to write a timestamp record 24 hours after the last activity to prevent the logfile from being removed due to lack of access. -- Johan Vromans | jv@mh.nl via European backbone Multihouse N.V., Gouda, the Netherlands | uucp: ..{?????!}mcvax!mh.nl!jv "It is better to light a candle than to curse the darkness" -------------------------------- cut here -------------------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # makefile # syslog.c # sendlog.c # This archive created: Thu Sep 3 09:35:37 1987 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'makefile'" '(419 characters)' if test -f 'makefile' then echo shar: "will not over-write existing file 'makefile'" else cat << \SHAR_EOF > 'makefile' CFLAGS = -O syslog: syslog.c $(CC) $(CFLAGS) -o syslog syslog.c libsyslog.a: syslog.c $(CC) $(CFLAGS) -DLIB_SYSLOG -c syslog.c ar r libsyslog.a syslog.o sendlog: sendlog.c libsyslog.a $(CC) $(CFLAGS) -o sendlog sendlog.c libsyslog.a install: syslog libsyslog.a cp syslog /etc/syslog chmod 0555 /etc/syslog cp libsyslog.a /usr/lib/libsyslog.a chmod 0444 /usr/lib/libsyslog.a all: syslog sendlog libsyslog.a SHAR_EOF if test 419 -ne "`wc -c < 'makefile'`" then echo shar: "error transmitting 'makefile'" '(should have been 419 characters)' fi fi echo shar: "extracting 'syslog.c'" '(7709 characters)' if test -f 'syslog.c' then echo shar: "will not over-write existing file 'syslog.c'" else cat << \SHAR_EOF > 'syslog.c' #ifdef LIB_SYSLOG static char SCCS_ID[] = "@(#)@ syslog 1.8 system logger"; #else static char SCCS_ID[] = "@(#)@ syslog 1.8 syslog.o"; #endif static char CPYRGHT[] = "@(#)@ (c) Multihouse Group Support"; /* * usage: /etc/syslog [ logfilename ] * * default logfilename: /tmp/syslog.log * * use "kill -1 pid" to release and re-open the logfile * "kill -15 pid" to exit the program and remove the message queue * * Reasons to terminate: * * 0: normal (catched a SIGTERM) * 1: could not reopen logfile after SIGHUP * 2: error during message recveive * 3: catched another signal * * define LIB_SYSLOG to obtain a library of access routines */ #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <unistd.h> #include <signal.h> #include <errno.h> #define TRUE 1 #define FALSE 0 #define EOS '\0' #define SIG_ERR ((int (*)())-1) static int msgkey = -1; static int msgid = -1; static char *msgnam = "/etc/syslog"; /* used for ftok! */ #define SYSLOG_MAGIC 0xfeff #define MSG_SIZE 512 static struct { long type; /* must be SYSLOG_MAGIC */ long tm; /* timestamp */ unsigned char class; /* message class */ unsigned char length; /* length of msg.text */ short pid; /* pid of sending process */ short uid; /* uid of sending process */ char text[MSG_SIZE]; /* text of the message */ } msg; #ifndef LIB_SYSLOG static struct { long type; /* must be not SYSLOG_MAGIC */ char text[MSG_SIZE]; } oldmsg; static char *lognam = "/tmp/syslog.log"; static FILE *logfile = NULL; #define MAXERRCNT 10 /* max number of conseq. recv errors */ static char *msgclass[] = { "ALERT", "SALERT", "EMERG", "ERROR", "CRIT", "WARNING", "NOTICE", "INFO", "DEBUG" }; /* signal catchers */ static int hup = FALSE; static int term = FALSE; static int timedout = FALSE; static int delay = 24 * 60 * 60; int timeout () { timedout = TRUE; (void) signal (SIGALRM, timeout); } int sighup () { hup = TRUE; (void) signal (SIGHUP, sighup); } int sigterm () { term = TRUE; (void) signal (SIGTERM, sigterm); } int sigcatch () { terminate (3); } terminate (why) int why; { (void) msgctl (msgid, IPC_RMID, ((struct msqid_ds *) NULL)); if (logfile != NULL) { if (why == 0 && term) sprintf (msg.text, "normal termination (caught SIGTERM)"); else sprintf (msg.text, "terminated reason=%d", why); putlog (TRUE); } fclose (logfile); exit (why); } catchit (sig) int sig; { int (*sg)(); sg = signal (sig, sigcatch); if (sg != SIG_DFL && sg != SIG_ERR) signal (sig, sg); } main (argc, argv) int argc; char *argv[]; { char *cp; int errcnt = 0; msgkey = ftok (msgnam, 0); if (msgkey < 0) { perror ("ftok"); exit (2); } msgid = msgget (msgkey, IPC_CREAT | IPC_EXCL | 0722); while (msgid < 0) { if (errno = EEXIST) { fprintf (stderr, "syslog: warning - queue already exists\n"); msgid = msgget (msgkey, IPC_CREAT | 0722); } else { perror ("msgget"); exit (2); } } if (argc > 1) lognam = *++argv; /* open logfile with correct protection */ umask (022); logfile = fopen (lognam, "a"); if (logfile == NULL) { perror ("open logfile"); exit (2); } /* make sure no other logger is active */ if (lockf (fileno (logfile), F_TEST, 0l) < 0) { perror ("syslog: cannot lock logfile"); exit (2); } #ifndef DEBUG /* detach */ if (fork ()) exit (0); setpgrp (); /* forget where we came from */ /* re-claim the logfile (we lost the lock because we are a fork) */ if (lockf (fileno (logfile), F_TLOCK, 0l) < 0) { perror ("syslog: logfile lock failed"); exit (2); } #endif /* catch SIGHUP and SIGTERM */ (void) signal (SIGTERM, sigterm); (void) signal (SIGHUP, sighup); /* ignore SIGINT and SIGQUIT */ (void) signal (SIGINT, SIG_IGN); (void) signal (SIGQUIT, SIG_IGN); /* set alarm */ (void) signal (SIGALRM, timeout); strcpy (msg.text, "started"); putlog (TRUE); for (;;) { int res = msgrcv (msgid, &msg, MSG_SIZE, 0, 0 & MSG_NOERROR); if (res >= 0) { if (msg.type != SYSLOG_MAGIC) { memcpy (&oldmsg, &msg, sizeof (oldmsg)); (void) time (&msg.tm); msg.class = oldmsg.type; msg.length = strlen (oldmsg.text); msg.type = SYSLOG_MAGIC; msg.pid = msg.uid = -1; strcpy (msg.text, oldmsg.text); } putlog (FALSE); errcnt = 0; } else { /* message receive error */ if (errno == EINTR) { /* receive was interrupted */ if (hup) { /* catched SIGHUP => release logfile */ strcpy (msg.text, "logfile released (caught SIGHUP)"); putlog (TRUE); fclose (logfile); logfile = fopen (lognam, "a"); if (logfile == NULL) { perror ("reopen logfile"); terminate (1); } strcpy (msg.text, "logfile reopened after SIGHUP"); putlog (TRUE); hup = FALSE; } if (term) { /* catched SIGTERM => exit receive loop */ break; } if (timedout) { strcpy (msg.text, "timestamp"); putlog (TRUE); timedout = FALSE; } /* otherwise, retry */ errcnt = 0; continue; } else { /* other message receive error */ sprintf (msg.text, "msgrcv error %d", errno); putlog (TRUE); if (errcnt++ > MAXERRCNT) terminate (2); } } } /* come here to exit the program */ terminate (0); } putlog (internal) int internal; { long time(); char *ctime(); long now = (internal) ? time (&now) : msg.tm; register char *date = ctime (&now); if (internal) { msg.pid = getpid (); msg.uid = getuid (); msg.length = strlen (msg.text); } fprintf (logfile, "%.2s-%.3s-%.2s %.8s", date+8, date+4, date+22, date+11); if (msg.pid >= 0) fprintf (logfile, "%6d ", msg.pid); else fprintf (logfile, " "); if (msg.uid >= 0) fprintf (logfile, "%6d ", msg.uid); else fprintf (logfile, " "); if (internal) fprintf (logfile, "SYSLOG "); else if (msg.class > 0 && msg.class < 10) fprintf (logfile, "%-7s ", msgclass[msg.class-1]); else fprintf (logfile, "?%-7d", msg.class); fprintf (logfile, "%.*s", msg.length, msg.text); /* append newline if needed */ if (msg.text[msg.length-1] != '\n') fprintf (logfile, "\n"); fflush (logfile); /* set new time out */ alarm (delay); } #endif !LIB_SYSLOG #ifdef LIB_SYSLOG #define MAX_LOGNAME 32 #define MAX_BUF 256 static char logname[MAX_LOGNAME] = ""; /* chkque - checks message queue existence */ static int chkque () { if (msgid == -1) msgid = msgget (ftok (msgnam, 0), 0, 0); return (msgid != -1); } /* openlog - sets up logname; checks message queue existence */ int openlog (tag) char *tag; { strncpy (logname, tag, MAX_LOGNAME); logname[MAX_LOGNAME-1] = EOS; return (chkque () ? 0 : -1); } /* syslog - writes message to system logger */ int syslog (class, fmt, p1, p2, p3, p4, p5, p6, p7, p8, p9) int class; char *fmt; { if (logname[0]) sprintf (msg.text, "%s: ", logname); sprintf (msg.text+strlen(msg.text), fmt, p1, p2, p3, p4, p5, p6, p7, p8, p9); if (!chkque ()) return (-1); msg.type = SYSLOG_MAGIC; (void) time (&msg.tm); msg.class = class; msg.pid = getpid (); msg.uid = getuid (); msg.length = strlen (msg.text); return (msgsnd (msgid, &msg, sizeof (msg) - MSG_SIZE + msg.length + 1, 0)); } /* closelog - close message queue, resets logname */ void closelog () { msgid = -1; logname[0] = EOS; } #ifdef TEST main () { openlog ("test"); syslog (55, "test message %d", 4); } #endif TEST #endif LIB_SYSLOG SHAR_EOF if test 7709 -ne "`wc -c < 'syslog.c'`" then echo shar: "error transmitting 'syslog.c'" '(should have been 7709 characters)' fi fi echo shar: "extracting 'sendlog.c'" '(370 characters)' if test -f 'sendlog.c' then echo shar: "will not over-write existing file 'sendlog.c'" else cat << \SHAR_EOF > 'sendlog.c' static char SCCS_id[] = "@(#)@ sendlog 1.2 - syslog interface"; #include <stdio.h> #include <sys/syslog.h> main (argc, argv) int argc; char *argv[]; { char buf [512]; char *cp = buf; while (argc-- > 1) { char *cq = *++argv; while (*cp++ = *cq++); cp[-1] = ' '; } cp[-1] = '\n'; cp[0] = '\0'; openlog ("sendlog"); syslog (LOG_INFO, buf); closelog (); } SHAR_EOF if test 370 -ne "`wc -c < 'sendlog.c'`" then echo shar: "error transmitting 'sendlog.c'" '(should have been 370 characters)' fi fi exit 0 # End of shell archive