diff --git a/usr.sbin/syslogd/Makefile b/usr.sbin/syslogd/Makefile index 5112bd4..0a59664 100644 --- a/usr.sbin/syslogd/Makefile +++ b/usr.sbin/syslogd/Makefile @@ -1,9 +1,14 @@ -# @(#)Makefile 8.1 (Berkeley) 6/6/93 +# +# $Id: Makefile,v 1.2 1998/10/31 19:02:47 gdr-ftp Exp $ +# -PROG= syslogd -SRCS= syslogd.c ttymsg.c -.PATH: ${.CURDIR}/../../usr.bin/wall -MAN5= syslog.conf.5 -MAN8= syslogd.8 +PROG = syslogd +MAIN = syslogd2 +SRCS = syslogd2.c -.include +CFLAGS += -D__STACK_CHECK__ +STACK = 4096 +BINDIR = /usr/sbin +CHAPTER = 8 + +.INCLUDE: /src/gno/prog.mk diff --git a/usr.sbin/syslogd/syslogd.desc b/usr.sbin/syslogd/syslogd.desc new file mode 100644 index 0000000..ecbb938 --- /dev/null +++ b/usr.sbin/syslogd/syslogd.desc @@ -0,0 +1,11 @@ +Name: syslogd +Version: 2.0 (Alpha-1: 31 Oct 98) +Shell: GNO +Author: Devin Reade +Contact: gdr@trenco.gno.org +Where: /usr/sbin +FTP: ftp.gno.org + +System logging daemon. Syslogd responds to logging requests from various +programs and writes them to a file or files based on the facility and priority +level. diff --git a/usr.sbin/syslogd/syslogd.rez b/usr.sbin/syslogd/syslogd.rez new file mode 100644 index 0000000..fb22aab --- /dev/null +++ b/usr.sbin/syslogd/syslogd.rez @@ -0,0 +1,19 @@ +/* + * $Id: syslogd.rez,v 1.1 1998/10/31 19:02:47 gdr-ftp Exp $ + */ + +#include "Types.Rez" +#include "/src/gno/build.tools/builddate.rez" + +resource rVersion (0x1, purgeable3, nocrossbank) { + + { 2, 0, 0, /* version */ + alpha, /* development|alpha|beta|final|release */ + 1 /* non-final release number */ + }, + verUS, + "syslogd", + "System Logger Daemon\n" + "Written by Devin Reade for GNO v2.0.6\n" + BUILD_DATE +}; diff --git a/usr.sbin/syslogd/syslogd2.c b/usr.sbin/syslogd/syslogd2.c new file mode 100644 index 0000000..8c9eab5 --- /dev/null +++ b/usr.sbin/syslogd/syslogd2.c @@ -0,0 +1,462 @@ +/* + * This implementation of syslogd was written by Devin Reade for GNO v2.0.6. + * It was written because Phil Vandry's original version of syslogd didn't + * have sufficient bits for the facility/priority values, and at the time + * his sources weren't available for modification. + * + * $Id: syslogd2.c,v 1.1 1998/10/31 19:02:47 gdr-ftp Exp $ + */ + +/* + * To Do: + * - get all our configuration from the syslog.conf file, and use that + * information in logMessage() + * - background ourselves + * - eliminate the command line args, except for "-f conf_file" + * - internal error messages should go through a logInternal + * routine so that they can potentially go to a file as well + * as (instead of?) the console + * - the main loop should be rewritten so that it immediately copies + * the data and releases the caller rather than waiting until it + * has parsed the buffer. + * - eliminate various pieces of dead code, clean up comments + * - ensure all routines are properly documented + * - should writeConsole be exported to libc? + * - in order to do 'mark' entries, we could set up a signal handler + * for SIGALRM. We'll either need a semaphore or a signal mask + * set up so that we can't get interrupted by SIGHUP or SIGTERM + * while we're in the SIGALRM handler. + * - should logInternal be using the internal "none" priority? + */ + +/* + * How many processes can send to us before they block? We don't need many + * since syslog(3), vsyslog(3), syslogmt(3), and vsyslogmt(3) won't return + * until we handle the request, anyway. + * + * Since sendPort() in the syslog(3) implementation is currently doing a + * busy wait while waiting for syslogd to release it's buffer, we set NPORTS + * to 1 so that any additional senders get blocked by the kernel instead of + * using up clock cycles. + */ +#define NPORTS 1 + +/* + * Define DEBUG to get syslogd to exit after a NLOOPS loops. Why do we + * need this? Because there is a bug in the v2.0.6 kernel which kills our + * shell if we send a SIGTERM to a child process. Blech. Limiting the + * number of loops lets us proceed with debugging without always having to + * log in again. See PR#53 in the GNO bug report system. + * +#if 0 +#define DEBUG +#define NLOOPS 5 +#endif + +/* We need this for internal structs in */ +#define __SYSLOG_INTERNALS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __STACK_CHECK__ +#include +#endif +#include + +#ifndef EOF +#define EOF (-1) +#endif + +#define MIN(a,b) ((a) < (b) ? (a) :(b)) + +#if 0 +static void die (const char *message); +#endif +static int logMessage (long facpri, char *msg, int len); +static void logInternal (const char *message, ...); +static int writeConsole (const char *buf, size_t size); +#if 0 +static void handle_HUP (int sig, int code); +#endif +static void handle_TERM (int sig, int code); + + +int Port = -1; +char MessageBuffer[_SYSLOG_BUFFERLEN]; +int MessageBufferLen = 0; /* number of used chars in MessageBuffer */ +int bytesToCopy; + +long FacPri; /* facility/priorty */ +time_t Now; + +char * LogFile = NULL; /* temporary kludge */ +int LogConsole = 0; /* temporary kludge */ + +int +main(int argc, char **argv) { + int fd, ch; + SyslogDataBuffer_t *dataptr; + char *p, *q; +#ifdef DEBUG + int loopcount = 0; +#endif + +#ifdef __STACK_CHECK__ + /* + * Don't use the __REPORT_STACK() macro here; we don't want + * to have to call atexit() since we may be in a signal handler + * when we have to die. + */ + _beginStackCheck(); +#endif + + while ((ch = getopt(argc, argv, "cF:")) != EOF) { + switch(ch) { + case 'c': + LogConsole = 1; + break; + case 'F': + LogFile = optarg; + break; + default: + logInternal("usage: syslogd [-c] [-F logfile]"); + exit(1); + } + } + +#if 0 + { + char *myname; + myname = __prognameGS(); + writeConsole(argv[0], strlen(argv[0])); + writeConsole(myname, strlen(myname)); + } +#endif + +#if 0 + signal(SIGHUP, handle_HUP); +#endif + signal(SIGTERM, handle_TERM); + + /* detach from controlling terminal */ + if ((fd = open(_PATH_TTY, O_RDWR)) < 0) { + logInternal("couldn't open controlling terminal: %s", + strerror(errno)); + exit(1); + } + +#if 0 + if (tcnewpgrp(fd) < 0) { + logInternal("tcnewpgrp failed: %s", strerror(errno)); + exit(1); + } +#endif + + if (ioctl(fd, TIOCNOTTY, 0) < 0) { + logInternal("ioctl failed: %s", strerror(errno)); + exit(1); + } + close(fd); + + /* create and bind a port on which programs can contact us */ + if ((Port = pcreate(NPORTS)) == -1) { + /* + * Does this actually ever happen? The ports(2) man page + * does not document an error condition for pcreate(2). + */ + logInternal("couldn't create port: %s", strerror(errno)); + exit(1); + } + if (pbind (Port, __SYSLOG_PORT_NAME) == -1) { + logInternal("couldn't bind port: %s", strerror(errno)); + exit(1); + } + + /* now loop forever waiting for messages */ + for (;;) { +#ifdef DEBUG + loopcount++; + if (loopcount > NLOOPS) { +# ifdef __STACK_CHECK__ + logInternal("%d bytes used", _endStackCheck()); +# endif + logInternal("Done debugging loops. Exiting."); + exit(0); + } +#endif + + /* block until a message comes in */ + dataptr = (SyslogDataBuffer_t *) preceive(Port); + + /* verify that this isn't a garbage pointer */ + if (dataptr->sdb_magic != _SYSLOG_MAGIC) { + logInternal("Bad magic number 0x%X; message " + "discarded. Caller may hang.", + dataptr->sdb_magic); + continue; + } + + /* + * Do the library and daemon agree on the format of the + * SyslogDataBuffer_t structure? + */ + if (dataptr->sdb_version != _SYSLOG_STRUCT_VERSION) { + logInternal("Message version mismatch. Expected %d " + "got %d. Message discarded. Caller may hang.", + _SYSLOG_STRUCT_VERSION, + dataptr->sdb_version); + continue; + } + + /* + * Do we have a facility/priority prefix? It's of the + * form "rest_of_message", where the angle brackets + * are literals. Set FacPri to this value if present, + * otherwise set it to the default value, user.notice. + * + * This should be changed so that we immediately copy the + * buffer and any other required info, then release the caller. + */ + p = dataptr->sdb_buffer; + bytesToCopy = dataptr->sdb_msglen; + if (*p == '<') { + p++; + FacPri = strtol(p, &q, 10); + if (p == q) { + FacPri = LOG_MAKEPRI(LOG_USER, LOG_NOTICE); + --p; + } else if (*q == '>') { + p = q + 1; + } else { + p = q; + } + bytesToCopy -= (p - dataptr->sdb_buffer); + } else { + FacPri = LOG_MAKEPRI(LOG_USER, LOG_NOTICE); + } + /* + * At this point, p points the point in the caller's buffer + * where we should start copying bytes. bytesToCopy + * contains the number of bytes in the callers buffer that + * we should copy. + * + * If the 'needtime' flag is set, we now copy a time stamp + * into our own buffer (the user's buffer is untouched). + */ + if (dataptr->sdb_needtime) { + time(&Now); + q = ctime(&Now) + 4; + q[16] = '\0'; + strcpy(MessageBuffer, q); + q = MessageBuffer + 16; + MessageBufferLen = 16; + } else { + q = MessageBuffer; + *q = '\0'; + MessageBufferLen = 0; + } + /* + * Now we can also say that q points to the point in + * MessageBuffer to where we should start copying characters. + * MessageBufferLen is the number of characters we've used + * in MessageBuffer. + * + * Copy the message to our buffer, minus any prefix, and + * append a newline. Make sure MessageBuffer is NULL- + * terminated. + */ + if (bytesToCopy > _SYSLOG_BUFFERLEN-2) { + bytesToCopy = _SYSLOG_BUFFERLEN-2; + } + MessageBufferLen += bytesToCopy; + if (bytesToCopy == 0) { + q[0] = '\r'; + q[1] = '\0'; + MessageBufferLen++; + } else { + memcpy(q, p, bytesToCopy); + if (q[bytesToCopy-1] != '\r') { + q[bytesToCopy++] = '\r'; + MessageBufferLen++; + } + q[bytesToCopy] = '\0'; + } + + /* + * We have our own version of the message now, so we can + * release the caller's data buffer and then proceed to print + * our own copy. + * + * See the comments in the syslog(3) code as to why we do + * it with a busy-wait. + */ + dataptr->sdb_busywait = 0; + + /* print the message */ + logMessage(FacPri, MessageBuffer, MessageBufferLen); + } + + /*NOTREACHED*/ + return 0; +} + +/* + * Print the message of length to the relevent files based on + * the facility/priority value . + * + * This routine is still a kludge. We need information parsed from the + * /etc/syslog.conf file to be referenced here. + * + * The following globals must already be set: + * LogConsole (temporary kludge) + * LogFile (temporary kludge) + */ +static int +logMessage (long facpri, const char *msg, int len) { + int result = 0; + + if (LogConsole) { + if (writeConsole(msg, len) != 0) { + result = 1; + } + } + if (LogFile != NULL) { + int logfd; + + if ((logfd = open(LogFile, O_RDWR | O_APPEND)) > -1) { + /* + * Don't throw an error if it fails; the file may + * not exist. + * + * Always having to open/write/close the file is + * a pain in the ass, but on the GS we need to do + * this to ensure that the file remains readable + * to other processes. + */ + if (write(logfd, msg, len) < 0) { + result = 1; + } + close(logfd); + } + } + return result; +} + +/* + * Choke and puke. + * If is not the empty string, print it out to console, first, + * prefixed by "syslogd: ". + * + * Careful what you call here; we may be inside a signal handler. + */ +#if 0 +static void +die (const char *message) +{ +#define BUFFER_LEN 80 +#define HEADER "syslogd: " + static char buffer[BUFFER_LEN]; + + if ((message != NULL) && (*message != '\0')) { + sprintmt(buffer, BUFFER_LEN, "syslogd: %s\r", message); + writeConsole(buffer, strlen(buffer)); + } + kill(getpid(), SIGKILL); +} +#endif + +#pragma databank 1 +#define MSG_QUIT "received a quit signal\r" + +#if 0 +static void +handle_HUP (int sig, int code) { +#define MSG_HUP "received a SIGHUP\r" + /* we should re-read the config file here */ + writeConsole(MSG_HUP, sizeof(MSG_HUP)-1); +} +#endif + +static void +handle_TERM (int sig, int code) { +#if 1 + if (Port != -1) { + pdelete(Port, NULL); + } + kill(getpid(), SIGKILL); +#else + if (pdelete(Port, NULL) != 0) { + die("failed to delete port on exit"); + } + die(""); /* don't print a message */ +#endif +} + +#pragma databank 0 + +static int +writeConsole (const char *buf, size_t size) { +#if 1 + int fd; + + if ((fd = open(_PATH_CONSOLE, O_WRONLY)) < 0) { + return -1; + } + /* we should probably loop to ensure that the write completes */ + write(fd, buf, size); + close(fd); + return 0; +#else +#endif +} + + +#pragma optimize 78 +#pragma debug 0 + +static void +logInternal (const char *message, ...) { +#define BUFFER_SIZE 256 + static char buffer[BUFFER_SIZE]; + time_t now; + va_list ap; + char *p; + + va_start(ap, message); + + /* + * Put our prefix at the front of the message. + */ + time(&now); + p = ctime(&now) + 4; + p[16] = '\0'; + p = sprintmt(buffer, BUFFER_SIZE, "%s syslogd[%d]: ", p, getpid()); + p = vsprintmt(p, p - buffer, message, ap); + + logMessage(LOG_MAKEPRI(LOG_DAEMON, LOG_CRIT), buffer, p - buffer); + +#if 0 + if ((p - buffer) < BUFFER_SIZE) { + *p++ = '\r'; + *p = '\0'; + } else { + *(p-1) = '\r'; + } + writeConsole(buffer, p-buffer); +#endif + va_end(ap); +} +