xref: /csrg-svn/usr.sbin/syslogd/syslogd.c (revision 66699)
121181Sdist /*
2*66699Spendry  * Copyright (c) 1983, 1988, 1993, 1994
361883Sbostic  *	The Regents of the University of California.  All rights reserved.
434627Sbostic  *
542825Sbostic  * %sccs.include.redist.c%
621181Sdist  */
721181Sdist 
816411Sralph #ifndef lint
961883Sbostic static char copyright[] =
10*66699Spendry "@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
1161883Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1234627Sbostic #endif /* not lint */
1316411Sralph 
1421181Sdist #ifndef lint
15*66699Spendry static char sccsid[] = "@(#)syslogd.c	8.3 (Berkeley) 04/04/94";
1634627Sbostic #endif /* not lint */
1721181Sdist 
1816411Sralph /*
1916411Sralph  *  syslogd -- log system messages
2016411Sralph  *
2116411Sralph  * This program implements a system log. It takes a series of lines.
2216411Sralph  * Each line may have a priority, signified as "<n>" as
2317535Sralph  * the first characters of the line.  If this is
2417535Sralph  * not present, a default priority is used.
2516411Sralph  *
2616411Sralph  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
2716411Sralph  * cause it to reread its configuration file.
2816411Sralph  *
2916411Sralph  * Defined Constants:
3016411Sralph  *
3116411Sralph  * MAXLINE -- the maximimum line length that can be handled.
3217535Sralph  * DEFUPRI -- the default priority for user messages
3317535Sralph  * DEFSPRI -- the default priority for kernel messages
3416651Sralph  *
3516651Sralph  * Author: Eric Allman
3617535Sralph  * extensive changes by Ralph Campbell
3729917Seric  * more extensive changes by Eric Allman (again)
3816411Sralph  */
3916411Sralph 
4017535Sralph #define	MAXLINE		1024		/* maximum line length */
4134513Skarels #define	MAXSVLINE	120		/* maximum saved line length */
4224837Seric #define DEFUPRI		(LOG_USER|LOG_NOTICE)
4324837Seric #define DEFSPRI		(LOG_KERN|LOG_CRIT)
4434443Skarels #define TIMERINTVL	30		/* interval for checking flush, mark */
4516411Sralph 
4637301Sbostic #include <sys/param.h>
4716411Sralph #include <sys/ioctl.h>
4816411Sralph #include <sys/stat.h>
4917888Sralph #include <sys/wait.h>
5016411Sralph #include <sys/socket.h>
5116748Sralph #include <sys/msgbuf.h>
5216651Sralph #include <sys/uio.h>
5316411Sralph #include <sys/un.h>
5424837Seric #include <sys/time.h>
5524837Seric #include <sys/resource.h>
5617179Sralph 
5716411Sralph #include <netinet/in.h>
5816411Sralph #include <netdb.h>
5957924Sbostic #include <arpa/inet.h>
6016411Sralph 
6157924Sbostic #include <ctype.h>
6257924Sbostic #include <errno.h>
6357924Sbostic #include <fcntl.h>
6437301Sbostic #include <setjmp.h>
6557924Sbostic #include <signal.h>
6637301Sbostic #include <stdio.h>
6757924Sbostic #include <stdlib.h>
6842066Sbostic #include <string.h>
6939425Sbostic #include <unistd.h>
7057924Sbostic #include <utmp.h>
7137301Sbostic #include "pathnames.h"
7216411Sralph 
7339526Sbostic #define SYSLOG_NAMES
7439526Sbostic #include <sys/syslog.h>
7539526Sbostic 
7637301Sbostic char	*LogName = _PATH_LOG;
7737301Sbostic char	*ConfFile = _PATH_LOGCONF;
7837301Sbostic char	*PidFile = _PATH_LOGPID;
7937301Sbostic char	ctty[] = _PATH_CONSOLE;
8037301Sbostic 
8124837Seric #define FDMASK(fd)	(1 << (fd))
8224837Seric 
8316411Sralph #define	dprintf		if (Debug) printf
8416411Sralph 
8524837Seric #define MAXUNAMES	20	/* maximum number of user names */
8616411Sralph 
8716411Sralph /*
8817266Sralph  * Flags to logmsg().
8917266Sralph  */
9017266Sralph 
9124837Seric #define IGN_CONS	0x001	/* don't print on console */
9224837Seric #define SYNC_FILE	0x002	/* do fsync on file after printing */
9334443Skarels #define ADDDATE		0x004	/* add a date to the message */
9434443Skarels #define MARK		0x008	/* this message is a mark */
9524837Seric 
9617266Sralph /*
9716411Sralph  * This structure represents the files that will have log
9816411Sralph  * copies printed.
9916411Sralph  */
10016411Sralph 
10116411Sralph struct filed {
10234443Skarels 	struct	filed *f_next;		/* next in linked list */
10324837Seric 	short	f_type;			/* entry type, see below */
10424837Seric 	short	f_file;			/* file descriptor */
10525181Seric 	time_t	f_time;			/* time this was last written */
10628799Skarels 	u_char	f_pmask[LOG_NFACILITIES+1];	/* priority mask */
10724837Seric 	union {
10839417Sbostic 		char	f_uname[MAXUNAMES][UT_NAMESIZE+1];
10928799Skarels 		struct {
11024932Seric 			char	f_hname[MAXHOSTNAMELEN+1];
11124837Seric 			struct sockaddr_in	f_addr;
11228799Skarels 		} f_forw;		/* forwarding address */
11339417Sbostic 		char	f_fname[MAXPATHLEN];
11428799Skarels 	} f_un;
11534443Skarels 	char	f_prevline[MAXSVLINE];		/* last message logged */
11634443Skarels 	char	f_lasttime[16];			/* time of last occurrence */
11734443Skarels 	char	f_prevhost[MAXHOSTNAMELEN+1];	/* host from which recd. */
11834443Skarels 	int	f_prevpri;			/* pri of f_prevline */
11934443Skarels 	int	f_prevlen;			/* length of f_prevline */
12034443Skarels 	int	f_prevcount;			/* repetition cnt of prevline */
12134443Skarels 	int	f_repeatcount;			/* number of "repeated" msgs */
12216411Sralph };
12316411Sralph 
12434443Skarels /*
12534443Skarels  * Intervals at which we flush out "message repeated" messages,
12634443Skarels  * in seconds after previous message is logged.  After each flush,
12734443Skarels  * we move to the next interval until we reach the largest.
12834443Skarels  */
12934443Skarels int	repeatinterval[] = { 30, 120, 600 };	/* # of secs before flush */
13034443Skarels #define	MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
13134443Skarels #define	REPEATTIME(f)	((f)->f_time + repeatinterval[(f)->f_repeatcount])
13234443Skarels #define	BACKOFF(f)	{ if (++(f)->f_repeatcount > MAXREPEAT) \
13334443Skarels 				 (f)->f_repeatcount = MAXREPEAT; \
13434443Skarels 			}
13534443Skarels 
13624837Seric /* values for f_type */
13724837Seric #define F_UNUSED	0		/* unused entry */
13824837Seric #define F_FILE		1		/* regular file */
13924837Seric #define F_TTY		2		/* terminal */
14024837Seric #define F_CONSOLE	3		/* console terminal */
14124837Seric #define F_FORW		4		/* remote machine */
14224837Seric #define F_USERS		5		/* list of users */
14324837Seric #define F_WALL		6		/* everyone logged on */
14416411Sralph 
14524837Seric char	*TypeNames[7] = {
14624837Seric 	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
14724837Seric 	"FORW",		"USERS",	"WALL"
14816411Sralph };
14916411Sralph 
15034443Skarels struct	filed *Files;
15134443Skarels struct	filed consfile;
15216411Sralph 
15316411Sralph int	Debug;			/* debug flag */
15424932Seric char	LocalHostName[MAXHOSTNAMELEN+1];	/* our hostname */
15525181Seric char	*LocalDomain;		/* our local domain name */
15624837Seric int	InetInuse = 0;		/* non-zero if INET sockets are being used */
15734443Skarels int	finet;			/* Internet datagram socket */
15824837Seric int	LogPort;		/* port number for INET connections */
15924837Seric int	Initialized = 0;	/* set when we have initialized ourselves */
16034443Skarels int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
16125181Seric int	MarkSeq = 0;		/* mark sequence number */
16216411Sralph 
163*66699Spendry void	cfline __P((char *, struct filed *));
164*66699Spendry char   *cvthname __P((struct sockaddr_in *));
165*66699Spendry int	decode __P((const char *, CODE *));
166*66699Spendry void	die __P((int));
167*66699Spendry void	domark __P((int));
168*66699Spendry void	fprintlog __P((struct filed *, int, char *));
169*66699Spendry void	init __P((int));
170*66699Spendry void	logerror __P((char *));
171*66699Spendry void	logmsg __P((int, char *, char *, int));
172*66699Spendry void	printline __P((char *, char *));
173*66699Spendry void	printsys __P((char *));
174*66699Spendry void	reapchild __P((int));
175*66699Spendry char   *ttymsg __P((struct iovec *, int, char *, int));
176*66699Spendry void	usage __P((void));
177*66699Spendry void	wallmsg __P((struct filed *, struct iovec *));
17816411Sralph 
17957924Sbostic int
main(argc,argv)18016411Sralph main(argc, argv)
18116411Sralph 	int argc;
18257924Sbostic 	char *argv[];
18316411Sralph {
184*66699Spendry 	int ch, funix, i, inetm, fklog, klogm, len;
18530434Smckusick 	struct sockaddr_un sunx, fromunix;
18616411Sralph 	struct sockaddr_in sin, frominet;
18716411Sralph 	FILE *fp;
188*66699Spendry 	char *p, line[MSG_BSIZE + 1];
18916411Sralph 
19035526Sbostic 	while ((ch = getopt(argc, argv, "df:m:p:")) != EOF)
191*66699Spendry 		switch(ch) {
19217535Sralph 		case 'd':		/* debug */
19317535Sralph 			Debug++;
19417535Sralph 			break;
19535526Sbostic 		case 'f':		/* configuration file */
19635526Sbostic 			ConfFile = optarg;
19717535Sralph 			break;
19825181Seric 		case 'm':		/* mark interval */
19935526Sbostic 			MarkInterval = atoi(optarg) * 60;
20025181Seric 			break;
20135526Sbostic 		case 'p':		/* path */
20235526Sbostic 			LogName = optarg;
20335526Sbostic 			break;
20435526Sbostic 		case '?':
20517535Sralph 		default:
20617535Sralph 			usage();
20716411Sralph 		}
20864882Sbostic 	if ((argc -= optind) != 0)
20935526Sbostic 		usage();
21016411Sralph 
21144695Skarels 	if (!Debug)
21259444Sbostic 		(void)daemon(0, 0);
21344695Skarels 	else
21417888Sralph 		setlinebuf(stdout);
21517888Sralph 
21634443Skarels 	consfile.f_type = F_CONSOLE;
21758238Storek 	(void)strcpy(consfile.f_un.f_fname, ctty);
218*66699Spendry 	(void)gethostname(LocalHostName, sizeof(LocalHostName));
219*66699Spendry 	if ((p = strchr(LocalHostName, '.')) != NULL) {
22025181Seric 		*p++ = '\0';
22125181Seric 		LocalDomain = p;
22258238Storek 	} else
22325181Seric 		LocalDomain = "";
22458238Storek 	(void)signal(SIGTERM, die);
22558238Storek 	(void)signal(SIGINT, Debug ? die : SIG_IGN);
22658238Storek 	(void)signal(SIGQUIT, Debug ? die : SIG_IGN);
22758238Storek 	(void)signal(SIGCHLD, reapchild);
22858238Storek 	(void)signal(SIGALRM, domark);
22958238Storek 	(void)alarm(TIMERINTVL);
23058238Storek 	(void)unlink(LogName);
23124837Seric 
23258238Storek #ifndef SUN_LEN
23358238Storek #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
23458238Storek #endif
235*66699Spendry 	memset(&sunx, 0, sizeof(sunx));
23630434Smckusick 	sunx.sun_family = AF_UNIX;
237*66699Spendry 	(void)strncpy(sunx.sun_path, LogName, sizeof(sunx.sun_path));
23816411Sralph 	funix = socket(AF_UNIX, SOCK_DGRAM, 0);
23958238Storek 	if (funix < 0 ||
24058238Storek 	    bind(funix, (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 ||
24124837Seric 	    chmod(LogName, 0666) < 0) {
24224837Seric 		(void) sprintf(line, "cannot create %s", LogName);
24324837Seric 		logerror(line);
24424837Seric 		dprintf("cannot create %s (%d)\n", LogName, errno);
24524837Seric 		die(0);
24616411Sralph 	}
24716411Sralph 	finet = socket(AF_INET, SOCK_DGRAM, 0);
24857924Sbostic 	inetm = 0;
24916411Sralph 	if (finet >= 0) {
25016411Sralph 		struct servent *sp;
25116411Sralph 
25216411Sralph 		sp = getservbyname("syslog", "udp");
25316411Sralph 		if (sp == NULL) {
25416411Sralph 			errno = 0;
25516411Sralph 			logerror("syslog/udp: unknown service");
25624837Seric 			die(0);
25716411Sralph 		}
258*66699Spendry 		memset(&sin, 0, sizeof(sin));
25916411Sralph 		sin.sin_family = AF_INET;
26024837Seric 		sin.sin_port = LogPort = sp->s_port;
26139425Sbostic 		if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
26216411Sralph 			logerror("bind");
26324837Seric 			if (!Debug)
26424837Seric 				die(0);
26524837Seric 		} else {
26624837Seric 			inetm = FDMASK(finet);
26724837Seric 			InetInuse = 1;
26816411Sralph 		}
26916411Sralph 	}
27037301Sbostic 	if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
27124837Seric 		klogm = FDMASK(fklog);
27217888Sralph 	else {
27337301Sbostic 		dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
27417535Sralph 		klogm = 0;
27517535Sralph 	}
27616411Sralph 
27716411Sralph 	/* tuck my process id away */
27824837Seric 	fp = fopen(PidFile, "w");
27916411Sralph 	if (fp != NULL) {
28016411Sralph 		fprintf(fp, "%d\n", getpid());
28124837Seric 		(void) fclose(fp);
28216411Sralph 	}
28316411Sralph 
28416411Sralph 	dprintf("off & running....\n");
28516411Sralph 
28657924Sbostic 	init(0);
28758238Storek 	(void)signal(SIGHUP, init);
28816457Sralph 
28916411Sralph 	for (;;) {
29024837Seric 		int nfds, readfds = FDMASK(funix) | inetm | klogm;
29116411Sralph 
29230791Sbostic 		dprintf("readfds = %#x\n", readfds);
29358238Storek 		nfds = select(20, (fd_set *)&readfds, (fd_set *)NULL,
29458238Storek 		    (fd_set *)NULL, (struct timeval *)NULL);
29516411Sralph 		if (nfds == 0)
29616411Sralph 			continue;
29716411Sralph 		if (nfds < 0) {
29824837Seric 			if (errno != EINTR)
29924837Seric 				logerror("select");
30016411Sralph 			continue;
30116411Sralph 		}
30234443Skarels 		dprintf("got a message (%d, %#x)\n", nfds, readfds);
30317535Sralph 		if (readfds & klogm) {
30417888Sralph 			i = read(fklog, line, sizeof(line) - 1);
30517266Sralph 			if (i > 0) {
30617266Sralph 				line[i] = '\0';
30717266Sralph 				printsys(line);
30817535Sralph 			} else if (i < 0 && errno != EINTR) {
30917888Sralph 				logerror("klog");
31017888Sralph 				fklog = -1;
31117535Sralph 				klogm = 0;
31217535Sralph 			}
31317266Sralph 		}
31424837Seric 		if (readfds & FDMASK(funix)) {
315*66699Spendry 			len = sizeof(fromunix);
31624837Seric 			i = recvfrom(funix, line, MAXLINE, 0,
31758238Storek 			    (struct sockaddr *)&fromunix, &len);
31817179Sralph 			if (i > 0) {
31917179Sralph 				line[i] = '\0';
32024837Seric 				printline(LocalHostName, line);
32117179Sralph 			} else if (i < 0 && errno != EINTR)
32224837Seric 				logerror("recvfrom unix");
32317179Sralph 		}
32417888Sralph 		if (readfds & inetm) {
325*66699Spendry 			len = sizeof(frominet);
32639425Sbostic 			i = recvfrom(finet, line, MAXLINE, 0,
32758238Storek 			    (struct sockaddr *)&frominet, &len);
32824837Seric 			if (i > 0) {
32917179Sralph 				line[i] = '\0';
33024837Seric 				printline(cvthname(&frominet), line);
33117179Sralph 			} else if (i < 0 && errno != EINTR)
33224837Seric 				logerror("recvfrom inet");
33317179Sralph 		}
33416411Sralph 	}
33516411Sralph }
33616411Sralph 
33757924Sbostic void
usage()33817535Sralph usage()
33917535Sralph {
340*66699Spendry 
34158238Storek 	(void)fprintf(stderr,
34245273Sbostic 	    "usage: syslogd [-f conffile] [-m markinterval] [-p logpath]\n");
34317535Sralph 	exit(1);
34417535Sralph }
34517535Sralph 
34616411Sralph /*
34716411Sralph  * Take a raw input line, decode the message, and print the message
34816411Sralph  * on the appropriate log files.
34916411Sralph  */
35057924Sbostic void
printline(hname,msg)35124837Seric printline(hname, msg)
35224837Seric 	char *hname;
35316411Sralph 	char *msg;
35416411Sralph {
355*66699Spendry 	int c, pri;
356*66699Spendry 	char *p, *q, line[MAXLINE + 1];
35716411Sralph 
35816411Sralph 	/* test for special codes */
35917535Sralph 	pri = DEFUPRI;
36016411Sralph 	p = msg;
36117535Sralph 	if (*p == '<') {
36217535Sralph 		pri = 0;
36317535Sralph 		while (isdigit(*++p))
36417535Sralph 			pri = 10 * pri + (*p - '0');
36517535Sralph 		if (*p == '>')
36617535Sralph 			++p;
36716411Sralph 	}
36834513Skarels 	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
36934513Skarels 		pri = DEFUPRI;
37016411Sralph 
37124837Seric 	/* don't allow users to log kernel messages */
37234513Skarels 	if (LOG_FAC(pri) == LOG_KERN)
37334513Skarels 		pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
37424837Seric 
37516411Sralph 	q = line;
37624837Seric 
37735526Sbostic 	while ((c = *p++ & 0177) != '\0' &&
37835526Sbostic 	    q < &line[sizeof(line) - 1])
37936936Sbostic 		if (iscntrl(c))
38036936Sbostic 			if (c == '\n')
38136936Sbostic 				*q++ = ' ';
38236936Sbostic 			else if (c == '\t')
38336936Sbostic 				*q++ = '\t';
38436936Sbostic 			else {
38536936Sbostic 				*q++ = '^';
38636936Sbostic 				*q++ = c ^ 0100;
38736936Sbostic 			}
38836936Sbostic 		else
38916411Sralph 			*q++ = c;
39016411Sralph 	*q = '\0';
39116411Sralph 
39224837Seric 	logmsg(pri, line, hname, 0);
39316411Sralph }
39416411Sralph 
39516411Sralph /*
39616748Sralph  * Take a raw input line from /dev/klog, split and format similar to syslog().
39716748Sralph  */
39857924Sbostic void
printsys(msg)39916748Sralph printsys(msg)
40016748Sralph 	char *msg;
40116748Sralph {
402*66699Spendry 	int c, pri, flags;
403*66699Spendry 	char *lp, *p, *q, line[MAXLINE + 1];
40416748Sralph 
40558238Storek 	(void)strcpy(line, "vmunix: ");
40617535Sralph 	lp = line + strlen(line);
40716748Sralph 	for (p = msg; *p != '\0'; ) {
40834443Skarels 		flags = SYNC_FILE | ADDDATE;	/* fsync file after write */
40917535Sralph 		pri = DEFSPRI;
41017535Sralph 		if (*p == '<') {
41117535Sralph 			pri = 0;
41217535Sralph 			while (isdigit(*++p))
41317535Sralph 				pri = 10 * pri + (*p - '0');
41417535Sralph 			if (*p == '>')
41517535Sralph 				++p;
41617266Sralph 		} else {
41717266Sralph 			/* kernel printf's come out on console */
41817266Sralph 			flags |= IGN_CONS;
41917266Sralph 		}
42034513Skarels 		if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
42134513Skarels 			pri = DEFSPRI;
42217535Sralph 		q = lp;
42317535Sralph 		while (*p != '\0' && (c = *p++) != '\n' &&
42417535Sralph 		    q < &line[MAXLINE])
42516748Sralph 			*q++ = c;
42616748Sralph 		*q = '\0';
42724837Seric 		logmsg(pri, line, LocalHostName, flags);
42816748Sralph 	}
42916748Sralph }
43016748Sralph 
43134443Skarels time_t	now;
43234443Skarels 
43316748Sralph /*
43416411Sralph  * Log a message to the appropriate log files, users, etc. based on
43516411Sralph  * the priority.
43616411Sralph  */
43757924Sbostic void
logmsg(pri,msg,from,flags)43817266Sralph logmsg(pri, msg, from, flags)
43924837Seric 	int pri;
44024837Seric 	char *msg, *from;
44124837Seric 	int flags;
44216411Sralph {
443*66699Spendry 	struct filed *f;
444*66699Spendry 	int fac, msglen, omask, prilev;
44534443Skarels 	char *timestamp;
44616411Sralph 
44739417Sbostic 	dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
44839417Sbostic 	    pri, flags, from, msg);
44924837Seric 
45025181Seric 	omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
45117888Sralph 
45224837Seric 	/*
45324837Seric 	 * Check to see if msg looks non-standard.
45424837Seric 	 */
45534443Skarels 	msglen = strlen(msg);
45634443Skarels 	if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
45725181Seric 	    msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
45824837Seric 		flags |= ADDDATE;
45924837Seric 
46058238Storek 	(void)time(&now);
46125181Seric 	if (flags & ADDDATE)
46234443Skarels 		timestamp = ctime(&now) + 4;
46334443Skarels 	else {
46434443Skarels 		timestamp = msg;
46534443Skarels 		msg += 16;
46634443Skarels 		msglen -= 16;
46734443Skarels 	}
46824837Seric 
46924837Seric 	/* extract facility and priority level */
47028799Skarels 	if (flags & MARK)
47128799Skarels 		fac = LOG_NFACILITIES;
47234513Skarels 	else
47334513Skarels 		fac = LOG_FAC(pri);
47434513Skarels 	prilev = LOG_PRI(pri);
47524837Seric 
47616411Sralph 	/* log the message to the particular outputs */
47724837Seric 	if (!Initialized) {
47834443Skarels 		f = &consfile;
47939425Sbostic 		f->f_file = open(ctty, O_WRONLY, 0);
48024837Seric 
48134443Skarels 		if (f->f_file >= 0) {
48235344Sbostic 			fprintlog(f, flags, msg);
48358238Storek 			(void)close(f->f_file);
48424837Seric 		}
48558238Storek 		(void)sigsetmask(omask);
48624837Seric 		return;
48724837Seric 	}
48834443Skarels 	for (f = Files; f; f = f->f_next) {
48924837Seric 		/* skip messages that are incorrect priority */
49039526Sbostic 		if (f->f_pmask[fac] < prilev ||
49139526Sbostic 		    f->f_pmask[fac] == INTERNAL_NOPRI)
49216411Sralph 			continue;
49317888Sralph 
49434513Skarels 		if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
49534513Skarels 			continue;
49634513Skarels 
49725181Seric 		/* don't output marks to recently written files */
49834443Skarels 		if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
49925181Seric 			continue;
50025181Seric 
50134443Skarels 		/*
50234443Skarels 		 * suppress duplicate lines to this file
50334443Skarels 		 */
50434443Skarels 		if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
50534443Skarels 		    !strcmp(msg, f->f_prevline) &&
50634443Skarels 		    !strcmp(from, f->f_prevhost)) {
50758238Storek 			(void)strncpy(f->f_lasttime, timestamp, 15);
50834443Skarels 			f->f_prevcount++;
50935526Sbostic 			dprintf("msg repeated %d times, %ld sec of %d\n",
51034443Skarels 			    f->f_prevcount, now - f->f_time,
51134443Skarels 			    repeatinterval[f->f_repeatcount]);
51234443Skarels 			/*
51334443Skarels 			 * If domark would have logged this by now,
51434443Skarels 			 * flush it now (so we don't hold isolated messages),
51534443Skarels 			 * but back off so we'll flush less often
51634443Skarels 			 * in the future.
51734443Skarels 			 */
51834443Skarels 			if (now > REPEATTIME(f)) {
51934513Skarels 				fprintlog(f, flags, (char *)NULL);
52034443Skarels 				BACKOFF(f);
52117266Sralph 			}
52234443Skarels 		} else {
52334443Skarels 			/* new line, save it */
52434513Skarels 			if (f->f_prevcount)
52534513Skarels 				fprintlog(f, 0, (char *)NULL);
52634513Skarels 			f->f_repeatcount = 0;
52758238Storek 			(void)strncpy(f->f_lasttime, timestamp, 15);
52858238Storek 			(void)strncpy(f->f_prevhost, from,
52934513Skarels 					sizeof(f->f_prevhost));
53034513Skarels 			if (msglen < MAXSVLINE) {
53134443Skarels 				f->f_prevlen = msglen;
53234443Skarels 				f->f_prevpri = pri;
53358238Storek 				(void)strcpy(f->f_prevline, msg);
53434513Skarels 				fprintlog(f, flags, (char *)NULL);
53534513Skarels 			} else {
53634443Skarels 				f->f_prevline[0] = 0;
53734513Skarels 				f->f_prevlen = 0;
53834513Skarels 				fprintlog(f, flags, msg);
53934513Skarels 			}
54034443Skarels 		}
54134443Skarels 	}
54258238Storek 	(void)sigsetmask(omask);
54334443Skarels }
54424837Seric 
54557924Sbostic void
fprintlog(f,flags,msg)54634513Skarels fprintlog(f, flags, msg)
547*66699Spendry 	struct filed *f;
54834443Skarels 	int flags;
54934513Skarels 	char *msg;
55034443Skarels {
55134443Skarels 	struct iovec iov[6];
552*66699Spendry 	struct iovec *v;
553*66699Spendry 	int l;
55439425Sbostic 	char line[MAXLINE + 1], repbuf[80], greetings[200];
55534443Skarels 
55639425Sbostic 	v = iov;
55739425Sbostic 	if (f->f_type == F_WALL) {
55839425Sbostic 		v->iov_base = greetings;
55939425Sbostic 		v->iov_len = sprintf(greetings,
56039425Sbostic 		    "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
56139425Sbostic 		    f->f_prevhost, ctime(&now));
56239425Sbostic 		v++;
56339425Sbostic 		v->iov_base = "";
56439425Sbostic 		v->iov_len = 0;
56539425Sbostic 		v++;
56639425Sbostic 	} else {
56739425Sbostic 		v->iov_base = f->f_lasttime;
56839425Sbostic 		v->iov_len = 15;
56939425Sbostic 		v++;
57039425Sbostic 		v->iov_base = " ";
57139425Sbostic 		v->iov_len = 1;
57239425Sbostic 		v++;
57339425Sbostic 	}
57434443Skarels 	v->iov_base = f->f_prevhost;
57534443Skarels 	v->iov_len = strlen(v->iov_base);
57634443Skarels 	v++;
57734443Skarels 	v->iov_base = " ";
57834443Skarels 	v->iov_len = 1;
57934443Skarels 	v++;
58039425Sbostic 
58134513Skarels 	if (msg) {
58234513Skarels 		v->iov_base = msg;
58334513Skarels 		v->iov_len = strlen(msg);
58434513Skarels 	} else if (f->f_prevcount > 1) {
58539425Sbostic 		v->iov_base = repbuf;
58639425Sbostic 		v->iov_len = sprintf(repbuf, "last message repeated %d times",
58734443Skarels 		    f->f_prevcount);
58834443Skarels 	} else {
58934443Skarels 		v->iov_base = f->f_prevline;
59034443Skarels 		v->iov_len = f->f_prevlen;
59134443Skarels 	}
59234443Skarels 	v++;
59334443Skarels 
59434443Skarels 	dprintf("Logging to %s", TypeNames[f->f_type]);
59534443Skarels 	f->f_time = now;
59634443Skarels 
59734443Skarels 	switch (f->f_type) {
59834443Skarels 	case F_UNUSED:
59934443Skarels 		dprintf("\n");
60034443Skarels 		break;
60134443Skarels 
60234443Skarels 	case F_FORW:
60334443Skarels 		dprintf(" %s\n", f->f_un.f_forw.f_hname);
60439425Sbostic 		l = sprintf(line, "<%d>%.15s %s", f->f_prevpri,
60539425Sbostic 		    iov[0].iov_base, iov[4].iov_base);
60634443Skarels 		if (l > MAXLINE)
60734443Skarels 			l = MAXLINE;
60846930Sbostic 		if (sendto(finet, line, l, 0,
60946930Sbostic 		    (struct sockaddr *)&f->f_un.f_forw.f_addr,
610*66699Spendry 		    sizeof(f->f_un.f_forw.f_addr)) != l) {
61134443Skarels 			int e = errno;
61258238Storek 			(void)close(f->f_file);
61334443Skarels 			f->f_type = F_UNUSED;
61434443Skarels 			errno = e;
61534443Skarels 			logerror("sendto");
61634443Skarels 		}
61734443Skarels 		break;
61834443Skarels 
61934443Skarels 	case F_CONSOLE:
62034443Skarels 		if (flags & IGN_CONS) {
62134443Skarels 			dprintf(" (ignored)\n");
62224837Seric 			break;
62334443Skarels 		}
62434443Skarels 		/* FALLTHROUGH */
62524837Seric 
62634443Skarels 	case F_TTY:
62734443Skarels 	case F_FILE:
62834443Skarels 		dprintf(" %s\n", f->f_un.f_fname);
62934443Skarels 		if (f->f_type != F_FILE) {
63016651Sralph 			v->iov_base = "\r\n";
63116651Sralph 			v->iov_len = 2;
63234443Skarels 		} else {
63334443Skarels 			v->iov_base = "\n";
63434443Skarels 			v->iov_len = 1;
63516411Sralph 		}
63634443Skarels 	again:
63734443Skarels 		if (writev(f->f_file, iov, 6) < 0) {
63834443Skarels 			int e = errno;
63958238Storek 			(void)close(f->f_file);
64034443Skarels 			/*
64139583Smckusick 			 * Check for errors on TTY's due to loss of tty
64234443Skarels 			 */
64339583Smckusick 			if ((e == EIO || e == EBADF) && f->f_type != F_FILE) {
64439425Sbostic 				f->f_file = open(f->f_un.f_fname,
64539425Sbostic 				    O_WRONLY|O_APPEND, 0);
64634443Skarels 				if (f->f_file < 0) {
64734443Skarels 					f->f_type = F_UNUSED;
64834443Skarels 					logerror(f->f_un.f_fname);
64944695Skarels 				} else
65034443Skarels 					goto again;
65134443Skarels 			} else {
65234443Skarels 				f->f_type = F_UNUSED;
65334443Skarels 				errno = e;
65434443Skarels 				logerror(f->f_un.f_fname);
65534443Skarels 			}
65634443Skarels 		} else if (flags & SYNC_FILE)
65758238Storek 			(void)fsync(f->f_file);
65834443Skarels 		break;
65934443Skarels 
66034443Skarels 	case F_USERS:
66134443Skarels 	case F_WALL:
66234443Skarels 		dprintf("\n");
66334443Skarels 		v->iov_base = "\r\n";
66434443Skarels 		v->iov_len = 2;
66534443Skarels 		wallmsg(f, iov);
66634443Skarels 		break;
66716411Sralph 	}
66834443Skarels 	f->f_prevcount = 0;
66934443Skarels }
67016411Sralph 
67116411Sralph /*
67216411Sralph  *  WALLMSG -- Write a message to the world at large
67316411Sralph  *
67416411Sralph  *	Write the specified message to either the entire
67516411Sralph  *	world, or a list of approved users.
67616411Sralph  */
67757924Sbostic void
wallmsg(f,iov)67824837Seric wallmsg(f, iov)
679*66699Spendry 	struct filed *f;
68024837Seric 	struct iovec *iov;
68116411Sralph {
68239425Sbostic 	static int reenter;			/* avoid calling ourselves */
683*66699Spendry 	FILE *uf;
68416411Sralph 	struct utmp ut;
685*66699Spendry 	int i;
68657924Sbostic 	char *p;
68764882Sbostic 	char line[sizeof(ut.ut_line) + 1];
68816411Sralph 
68924837Seric 	if (reenter++)
69024837Seric 		return;
69137301Sbostic 	if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
69240750Sbostic 		logerror(_PATH_UTMP);
69324837Seric 		reenter = 0;
69416411Sralph 		return;
69516651Sralph 	}
69639425Sbostic 	/* NOSTRICT */
697*66699Spendry 	while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
69839425Sbostic 		if (ut.ut_name[0] == '\0')
69939425Sbostic 			continue;
70064882Sbostic 		strncpy(line, ut.ut_line, sizeof(ut.ut_line));
70164882Sbostic 		line[sizeof(ut.ut_line)] = '\0';
70239425Sbostic 		if (f->f_type == F_WALL) {
70364882Sbostic 			if ((p = ttymsg(iov, 6, line, 60*5)) != NULL) {
70439526Sbostic 				errno = 0;	/* already in msg */
70539425Sbostic 				logerror(p);
70639526Sbostic 			}
70739425Sbostic 			continue;
70839425Sbostic 		}
70939425Sbostic 		/* should we send the message to this user? */
71039425Sbostic 		for (i = 0; i < MAXUNAMES; i++) {
71139425Sbostic 			if (!f->f_un.f_uname[i][0])
71239425Sbostic 				break;
71339425Sbostic 			if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
71439425Sbostic 			    UT_NAMESIZE)) {
71564882Sbostic 				if ((p = ttymsg(iov, 6, line, 60*5)) != NULL) {
71639526Sbostic 					errno = 0;	/* already in msg */
71739425Sbostic 					logerror(p);
71839526Sbostic 				}
71939425Sbostic 				break;
72016411Sralph 			}
72116411Sralph 		}
72216411Sralph 	}
72358238Storek 	(void)fclose(uf);
72424837Seric 	reenter = 0;
72516411Sralph }
72616411Sralph 
72739256Sbostic void
reapchild(signo)72857924Sbostic reapchild(signo)
72957924Sbostic 	int signo;
73017888Sralph {
73117888Sralph 	union wait status;
73217888Sralph 
73358238Storek 	while (wait3((int *)&status, WNOHANG, (struct rusage *)NULL) > 0)
73417888Sralph 		;
73517888Sralph }
73617888Sralph 
73716411Sralph /*
73824837Seric  * Return a printable representation of a host address.
73916411Sralph  */
74024837Seric char *
cvthname(f)74124837Seric cvthname(f)
74216411Sralph 	struct sockaddr_in *f;
74316411Sralph {
74416411Sralph 	struct hostent *hp;
745*66699Spendry 	char *p;
74616411Sralph 
74724837Seric 	dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
74816411Sralph 
74916411Sralph 	if (f->sin_family != AF_INET) {
75016411Sralph 		dprintf("Malformed from address\n");
75124837Seric 		return ("???");
75216411Sralph 	}
75346930Sbostic 	hp = gethostbyaddr((char *)&f->sin_addr,
75446930Sbostic 	    sizeof(struct in_addr), f->sin_family);
75516411Sralph 	if (hp == 0) {
75616411Sralph 		dprintf("Host name for your address (%s) unknown\n",
75716411Sralph 			inet_ntoa(f->sin_addr));
75824837Seric 		return (inet_ntoa(f->sin_addr));
75916411Sralph 	}
760*66699Spendry 	if ((p = strchr(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
76125181Seric 		*p = '\0';
76224837Seric 	return (hp->h_name);
76316411Sralph }
76416411Sralph 
76539256Sbostic void
domark(signo)76657924Sbostic domark(signo)
76757924Sbostic 	int signo;
76825181Seric {
769*66699Spendry 	struct filed *f;
77025181Seric 
77139425Sbostic 	now = time((time_t *)NULL);
77234443Skarels 	MarkSeq += TIMERINTVL;
77334443Skarels 	if (MarkSeq >= MarkInterval) {
77428799Skarels 		logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
77534443Skarels 		MarkSeq = 0;
77634443Skarels 	}
77725181Seric 
77834443Skarels 	for (f = Files; f; f = f->f_next) {
77934443Skarels 		if (f->f_prevcount && now >= REPEATTIME(f)) {
78034443Skarels 			dprintf("flush %s: repeated %d times, %d sec.\n",
78134443Skarels 			    TypeNames[f->f_type], f->f_prevcount,
78234443Skarels 			    repeatinterval[f->f_repeatcount]);
78334513Skarels 			fprintlog(f, 0, (char *)NULL);
78434443Skarels 			BACKOFF(f);
78534443Skarels 		}
78634443Skarels 	}
78758238Storek 	(void)alarm(TIMERINTVL);
78817535Sralph }
78917535Sralph 
79017535Sralph /*
79116411Sralph  * Print syslogd errors some place.
79216411Sralph  */
79357924Sbostic void
logerror(type)79416411Sralph logerror(type)
79516411Sralph 	char *type;
79616411Sralph {
79757924Sbostic 	char buf[100];
79816411Sralph 
79939417Sbostic 	if (errno)
80058238Storek 		(void)snprintf(buf,
80157924Sbostic 		    sizeof(buf), "syslogd: %s: %s", type, strerror(errno));
80239417Sbostic 	else
80358238Storek 		(void)snprintf(buf, sizeof(buf), "syslogd: %s", type);
80416411Sralph 	errno = 0;
80516651Sralph 	dprintf("%s\n", buf);
80625181Seric 	logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
80716411Sralph }
80816411Sralph 
80939256Sbostic void
die(signo)81057924Sbostic die(signo)
81157924Sbostic 	int signo;
81216411Sralph {
813*66699Spendry 	struct filed *f;
81424837Seric 	char buf[100];
81516651Sralph 
81634443Skarels 	for (f = Files; f != NULL; f = f->f_next) {
81734443Skarels 		/* flush any pending output */
81834443Skarels 		if (f->f_prevcount)
81934513Skarels 			fprintlog(f, 0, (char *)NULL);
82034443Skarels 	}
82157924Sbostic 	if (signo) {
82257924Sbostic 		dprintf("syslogd: exiting on signal %d\n", signo);
82358238Storek 		(void)sprintf(buf, "exiting on signal %d", signo);
82430561Smckusick 		errno = 0;
82526142Skarels 		logerror(buf);
82626142Skarels 	}
82758238Storek 	(void)unlink(LogName);
82816411Sralph 	exit(0);
82916411Sralph }
83017535Sralph 
83117535Sralph /*
83224837Seric  *  INIT -- Initialize syslogd from configuration table
83317535Sralph  */
83439425Sbostic void
init(signo)83557924Sbostic init(signo)
83657924Sbostic 	int signo;
83717535Sralph {
838*66699Spendry 	int i;
839*66699Spendry 	FILE *cf;
840*66699Spendry 	struct filed *f, *next, **nextp;
841*66699Spendry 	char *p;
842*66699Spendry 	char cline[LINE_MAX];
84317535Sralph 
84424837Seric 	dprintf("init\n");
84524837Seric 
84624837Seric 	/*
84724837Seric 	 *  Close all open log files.
84824837Seric 	 */
84930561Smckusick 	Initialized = 0;
85034443Skarels 	for (f = Files; f != NULL; f = next) {
85134443Skarels 		/* flush any pending output */
85234443Skarels 		if (f->f_prevcount)
85334513Skarels 			fprintlog(f, 0, (char *)NULL);
85434443Skarels 
85529904Seric 		switch (f->f_type) {
85658238Storek 		case F_FILE:
85758238Storek 		case F_TTY:
85858238Storek 		case F_CONSOLE:
85958238Storek 		case F_FORW:
86058238Storek 			(void)close(f->f_file);
86129904Seric 			break;
86229904Seric 		}
86334443Skarels 		next = f->f_next;
86458238Storek 		free((char *)f);
86524837Seric 	}
86634443Skarels 	Files = NULL;
86734443Skarels 	nextp = &Files;
86824837Seric 
86924837Seric 	/* open the configuration file */
87024837Seric 	if ((cf = fopen(ConfFile, "r")) == NULL) {
87124837Seric 		dprintf("cannot open %s\n", ConfFile);
87234443Skarels 		*nextp = (struct filed *)calloc(1, sizeof(*f));
87334443Skarels 		cfline("*.ERR\t/dev/console", *nextp);
87434443Skarels 		(*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
87534443Skarels 		cfline("*.PANIC\t*", (*nextp)->f_next);
87634443Skarels 		Initialized = 1;
87724837Seric 		return;
87824837Seric 	}
87924837Seric 
88024837Seric 	/*
88124837Seric 	 *  Foreach line in the conf table, open that file.
88224837Seric 	 */
88334443Skarels 	f = NULL;
884*66699Spendry 	while (fgets(cline, sizeof(cline), cf) != NULL) {
88534627Sbostic 		/*
88634627Sbostic 		 * check for end-of-section, comments, strip off trailing
88734627Sbostic 		 * spaces and newline character.
88834627Sbostic 		 */
889*66699Spendry 		for (p = cline; isspace(*p); ++p)
890*66699Spendry 			continue;
89134627Sbostic 		if (*p == NULL || *p == '#')
89217535Sralph 			continue;
893*66699Spendry 		for (p = strchr(cline, '\0'); isspace(*--p);)
894*66699Spendry 			continue;
89534627Sbostic 		*++p = '\0';
89634443Skarels 		f = (struct filed *)calloc(1, sizeof(*f));
89734443Skarels 		*nextp = f;
89834443Skarels 		nextp = &f->f_next;
89934443Skarels 		cfline(cline, f);
90024837Seric 	}
90124837Seric 
90224837Seric 	/* close the configuration file */
90358238Storek 	(void)fclose(cf);
90424837Seric 
90524837Seric 	Initialized = 1;
90624837Seric 
90724837Seric 	if (Debug) {
90834443Skarels 		for (f = Files; f; f = f->f_next) {
90928799Skarels 			for (i = 0; i <= LOG_NFACILITIES; i++)
91039526Sbostic 				if (f->f_pmask[i] == INTERNAL_NOPRI)
91124837Seric 					printf("X ");
91224837Seric 				else
91324837Seric 					printf("%d ", f->f_pmask[i]);
91424837Seric 			printf("%s: ", TypeNames[f->f_type]);
91524837Seric 			switch (f->f_type) {
91624837Seric 			case F_FILE:
91724837Seric 			case F_TTY:
91824837Seric 			case F_CONSOLE:
91924837Seric 				printf("%s", f->f_un.f_fname);
92024837Seric 				break;
92124837Seric 
92224837Seric 			case F_FORW:
92324837Seric 				printf("%s", f->f_un.f_forw.f_hname);
92424837Seric 				break;
92524837Seric 
92624837Seric 			case F_USERS:
92724837Seric 				for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
92824837Seric 					printf("%s, ", f->f_un.f_uname[i]);
92924837Seric 				break;
93024837Seric 			}
93124837Seric 			printf("\n");
93224837Seric 		}
93324837Seric 	}
93424837Seric 
93525181Seric 	logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
93624837Seric 	dprintf("syslogd: restarted\n");
93724837Seric }
93824837Seric 
93924837Seric /*
94024837Seric  * Crack a configuration file line
94124837Seric  */
94257924Sbostic void
cfline(line,f)94324837Seric cfline(line, f)
94424837Seric 	char *line;
945*66699Spendry 	struct filed *f;
94624837Seric {
94724837Seric 	struct hostent *hp;
948*66699Spendry 	int i, pri;
949*66699Spendry 	char *bp, *p, *q;
95045266Sbostic 	char buf[MAXLINE], ebuf[100];
95124837Seric 
95224837Seric 	dprintf("cfline(%s)\n", line);
95324837Seric 
95439417Sbostic 	errno = 0;	/* keep strerror() stuff out of logerror messages */
95530561Smckusick 
95624837Seric 	/* clear out file entry */
957*66699Spendry 	memset(f, 0, sizeof(*f));
95828799Skarels 	for (i = 0; i <= LOG_NFACILITIES; i++)
95939526Sbostic 		f->f_pmask[i] = INTERNAL_NOPRI;
96024837Seric 
96124837Seric 	/* scan through the list of selectors */
96224837Seric 	for (p = line; *p && *p != '\t';) {
96324837Seric 
96424837Seric 		/* find the end of this facility name list */
96524837Seric 		for (q = p; *q && *q != '\t' && *q++ != '.'; )
96617535Sralph 			continue;
96724837Seric 
96824837Seric 		/* collect priority name */
969*66699Spendry 		for (bp = buf; *q && !strchr("\t,;", *q); )
97024837Seric 			*bp++ = *q++;
97124837Seric 		*bp = '\0';
97224837Seric 
97324837Seric 		/* skip cruft */
974*66699Spendry 		while (strchr(", ;", *q))
97524837Seric 			q++;
97624837Seric 
97724837Seric 		/* decode priority name */
97845266Sbostic 		if (*buf == '*')
97945266Sbostic 			pri = LOG_PRIMASK + 1;
98045266Sbostic 		else {
98145266Sbostic 			pri = decode(buf, prioritynames);
98245266Sbostic 			if (pri < 0) {
98358238Storek 				(void)sprintf(ebuf,
98445266Sbostic 				    "unknown priority name \"%s\"", buf);
98545266Sbostic 				logerror(ebuf);
98645266Sbostic 				return;
98745266Sbostic 			}
98817535Sralph 		}
98924837Seric 
99024837Seric 		/* scan facilities */
991*66699Spendry 		while (*p && !strchr("\t.;", *p)) {
992*66699Spendry 			for (bp = buf; *p && !strchr("\t,;.", *p); )
99324837Seric 				*bp++ = *p++;
99424837Seric 			*bp = '\0';
99524837Seric 			if (*buf == '*')
99624837Seric 				for (i = 0; i < LOG_NFACILITIES; i++)
99724837Seric 					f->f_pmask[i] = pri;
99824837Seric 			else {
99939526Sbostic 				i = decode(buf, facilitynames);
100024837Seric 				if (i < 0) {
100158238Storek 					(void)sprintf(ebuf,
100239425Sbostic 					    "unknown facility name \"%s\"",
100339425Sbostic 					    buf);
100445266Sbostic 					logerror(ebuf);
100524837Seric 					return;
100624837Seric 				}
100724837Seric 				f->f_pmask[i >> 3] = pri;
100824837Seric 			}
100924837Seric 			while (*p == ',' || *p == ' ')
101024837Seric 				p++;
101124837Seric 		}
101224837Seric 
101324837Seric 		p = q;
101417535Sralph 	}
101517535Sralph 
101624837Seric 	/* skip to action part */
101724837Seric 	while (*p == '\t')
101824837Seric 		p++;
101924837Seric 
102024837Seric 	switch (*p)
102124837Seric 	{
102224837Seric 	case '@':
102324837Seric 		if (!InetInuse)
102424837Seric 			break;
102558238Storek 		(void)strcpy(f->f_un.f_forw.f_hname, ++p);
102624837Seric 		hp = gethostbyname(p);
102724837Seric 		if (hp == NULL) {
1028*66699Spendry 			extern int h_errno;
102924837Seric 
1030*66699Spendry 			logerror(hstrerror(h_errno));
103124837Seric 			break;
103224837Seric 		}
1033*66699Spendry 		memset(&f->f_un.f_forw.f_addr, 0,
1034*66699Spendry 			 sizeof(f->f_un.f_forw.f_addr));
103524837Seric 		f->f_un.f_forw.f_addr.sin_family = AF_INET;
103624837Seric 		f->f_un.f_forw.f_addr.sin_port = LogPort;
1037*66699Spendry 		memmove(&f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length);
103824837Seric 		f->f_type = F_FORW;
103924837Seric 		break;
104024837Seric 
104124837Seric 	case '/':
104258238Storek 		(void)strcpy(f->f_un.f_fname, p);
104339425Sbostic 		if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
104434627Sbostic 			f->f_file = F_UNUSED;
104524837Seric 			logerror(p);
104624837Seric 			break;
104724837Seric 		}
104844695Skarels 		if (isatty(f->f_file))
104924837Seric 			f->f_type = F_TTY;
105024837Seric 		else
105124837Seric 			f->f_type = F_FILE;
105224837Seric 		if (strcmp(p, ctty) == 0)
105324837Seric 			f->f_type = F_CONSOLE;
105424837Seric 		break;
105524837Seric 
105624837Seric 	case '*':
105724837Seric 		f->f_type = F_WALL;
105824837Seric 		break;
105924837Seric 
106024837Seric 	default:
106124837Seric 		for (i = 0; i < MAXUNAMES && *p; i++) {
106224837Seric 			for (q = p; *q && *q != ','; )
106324837Seric 				q++;
106458238Storek 			(void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
106539417Sbostic 			if ((q - p) > UT_NAMESIZE)
106639417Sbostic 				f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
106724837Seric 			else
106824837Seric 				f->f_un.f_uname[i][q - p] = '\0';
106924837Seric 			while (*q == ',' || *q == ' ')
107024837Seric 				q++;
107124837Seric 			p = q;
107224837Seric 		}
107324837Seric 		f->f_type = F_USERS;
107424837Seric 		break;
107524837Seric 	}
107617535Sralph }
107724837Seric 
107824837Seric 
107924837Seric /*
108024837Seric  *  Decode a symbolic name to a numeric value
108124837Seric  */
108257924Sbostic int
decode(name,codetab)108324837Seric decode(name, codetab)
108458583Sralph 	const char *name;
108539526Sbostic 	CODE *codetab;
108624837Seric {
1087*66699Spendry 	CODE *c;
1088*66699Spendry 	char *p, buf[40];
108924837Seric 
109024837Seric 	if (isdigit(*name))
109124837Seric 		return (atoi(name));
109224837Seric 
109358583Sralph 	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
109458583Sralph 		if (isupper(*name))
109558583Sralph 			*p = tolower(*name);
109658583Sralph 		else
109758583Sralph 			*p = *name;
109858583Sralph 	}
109958583Sralph 	*p = '\0';
110024837Seric 	for (c = codetab; c->c_name; c++)
110124837Seric 		if (!strcmp(buf, c->c_name))
110224837Seric 			return (c->c_val);
110324837Seric 
110424837Seric 	return (-1);
110524837Seric }
1106