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