convert to understand dynamic file systems
[unix-history] / usr / src / usr.sbin / syslogd / syslogd.c
CommitLineData
8c5eec2f 1/*
92e73e63 2 * Copyright (c) 1983,1988 Regents of the University of California.
8c5eec2f
DF
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
92e73e63 9"@(#) Copyright (c) 1983,1988 Regents of the University of California.\n\
8c5eec2f
DF
10 All rights reserved.\n";
11#endif not lint
12
e677da31 13#ifndef lint
b8cbb72e 14static char sccsid[] = "@(#)syslogd.c 5.21 (Berkeley) %G%";
8c5eec2f 15#endif not lint
e677da31
RC
16
17/*
18 * syslogd -- log system messages
19 *
20 * This program implements a system log. It takes a series of lines.
21 * Each line may have a priority, signified as "<n>" as
a49a6aba
RC
22 * the first characters of the line. If this is
23 * not present, a default priority is used.
e677da31
RC
24 *
25 * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
26 * cause it to reread its configuration file.
27 *
28 * Defined Constants:
29 *
e677da31 30 * MAXLINE -- the maximimum line length that can be handled.
a49a6aba
RC
31 * DEFUPRI -- the default priority for user messages
32 * DEFSPRI -- the default priority for kernel messages
ada83039
RC
33 *
34 * Author: Eric Allman
a49a6aba 35 * extensive changes by Ralph Campbell
61a57de9 36 * more extensive changes by Eric Allman (again)
e677da31
RC
37 */
38
a49a6aba 39#define MAXLINE 1024 /* maximum line length */
35c3f83c 40#define MAXSVLINE 120 /* maximum saved line length */
64b300b4
EA
41#define DEFUPRI (LOG_USER|LOG_NOTICE)
42#define DEFSPRI (LOG_KERN|LOG_CRIT)
92e73e63 43#define TIMERINTVL 30 /* interval for checking flush, mark */
e677da31 44
e677da31
RC
45#include <stdio.h>
46#include <utmp.h>
47#include <ctype.h>
a24c481a 48#include <strings.h>
92e73e63 49#include <setjmp.h>
a24c481a 50
c16a39e2 51#include <sys/syslog.h>
2f6a4049 52#include <sys/param.h>
92e73e63 53#include <sys/errno.h>
e677da31
RC
54#include <sys/ioctl.h>
55#include <sys/stat.h>
84555b38 56#include <sys/wait.h>
e677da31
RC
57#include <sys/socket.h>
58#include <sys/file.h>
63cb489e 59#include <sys/msgbuf.h>
ada83039 60#include <sys/uio.h>
e677da31 61#include <sys/un.h>
64b300b4
EA
62#include <sys/time.h>
63#include <sys/resource.h>
92e73e63 64#include <sys/signal.h>
a24c481a 65
e677da31
RC
66#include <netinet/in.h>
67#include <netdb.h>
68
92e73e63 69#define CTTY "/dev/console"
64b300b4
EA
70char *LogName = "/dev/log";
71char *ConfFile = "/etc/syslog.conf";
72char *PidFile = "/etc/syslog.pid";
92e73e63 73char ctty[] = CTTY;
e677da31 74
64b300b4
EA
75#define FDMASK(fd) (1 << (fd))
76
e677da31
RC
77#define dprintf if (Debug) printf
78
64b300b4
EA
79#define UNAMESZ 8 /* length of a login name */
80#define MAXUNAMES 20 /* maximum number of user names */
81#define MAXFNAME 200 /* max file pathname length */
e677da31 82
64b300b4 83#define NOPRI 0x10 /* the "no priority" priority */
35c3f83c 84#define LOG_MARK LOG_MAKEPRI(LOG_NFACILITIES, 0) /* mark "facility" */
a49a6aba 85
8a7154b1
RC
86/*
87 * Flags to logmsg().
88 */
64b300b4
EA
89
90#define IGN_CONS 0x001 /* don't print on console */
91#define SYNC_FILE 0x002 /* do fsync on file after printing */
92e73e63
MK
92#define ADDDATE 0x004 /* add a date to the message */
93#define MARK 0x008 /* this message is a mark */
8a7154b1 94
e677da31
RC
95/*
96 * This structure represents the files that will have log
97 * copies printed.
98 */
99
100struct filed {
92e73e63 101 struct filed *f_next; /* next in linked list */
64b300b4
EA
102 short f_type; /* entry type, see below */
103 short f_file; /* file descriptor */
ad58e75e 104 time_t f_time; /* time this was last written */
c16a39e2 105 u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */
64b300b4 106 union {
486e5830 107 char f_uname[MAXUNAMES][UNAMESZ+1];
c16a39e2 108 struct {
74440133 109 char f_hname[MAXHOSTNAMELEN+1];
64b300b4 110 struct sockaddr_in f_addr;
c16a39e2 111 } f_forw; /* forwarding address */
64b300b4 112 char f_fname[MAXFNAME];
c16a39e2 113 } f_un;
92e73e63
MK
114 char f_prevline[MAXSVLINE]; /* last message logged */
115 char f_lasttime[16]; /* time of last occurrence */
116 char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */
117 int f_prevpri; /* pri of f_prevline */
118 int f_prevlen; /* length of f_prevline */
119 int f_prevcount; /* repetition cnt of prevline */
120 int f_repeatcount; /* number of "repeated" msgs */
e677da31
RC
121};
122
92e73e63
MK
123/*
124 * Intervals at which we flush out "message repeated" messages,
125 * in seconds after previous message is logged. After each flush,
126 * we move to the next interval until we reach the largest.
127 */
128int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */
129#define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
130#define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount])
131#define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \
132 (f)->f_repeatcount = MAXREPEAT; \
133 }
134
64b300b4
EA
135/* values for f_type */
136#define F_UNUSED 0 /* unused entry */
137#define F_FILE 1 /* regular file */
138#define F_TTY 2 /* terminal */
139#define F_CONSOLE 3 /* console terminal */
140#define F_FORW 4 /* remote machine */
141#define F_USERS 5 /* list of users */
142#define F_WALL 6 /* everyone logged on */
143
144char *TypeNames[7] = {
145 "UNUSED", "FILE", "TTY", "CONSOLE",
146 "FORW", "USERS", "WALL"
e677da31
RC
147};
148
92e73e63
MK
149struct filed *Files;
150struct filed consfile;
e677da31
RC
151
152int Debug; /* debug flag */
74440133 153char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */
ad58e75e 154char *LocalDomain; /* our local domain name */
64b300b4 155int InetInuse = 0; /* non-zero if INET sockets are being used */
92e73e63 156int finet; /* Internet datagram socket */
64b300b4 157int LogPort; /* port number for INET connections */
64b300b4 158int Initialized = 0; /* set when we have initialized ourselves */
92e73e63 159int MarkInterval = 20 * 60; /* interval between marks in seconds */
ad58e75e 160int MarkSeq = 0; /* mark sequence number */
e677da31
RC
161
162extern int errno, sys_nerr;
163extern char *sys_errlist[];
92e73e63 164extern char *ctime(), *index(), *calloc();
e677da31
RC
165
166main(argc, argv)
167 int argc;
168 char **argv;
169{
170 register int i;
171 register char *p;
92e73e63 172 int funix, inetm, fklog, klogm, len;
0d20624e 173 struct sockaddr_un sunx, fromunix;
e677da31
RC
174 struct sockaddr_in sin, frominet;
175 FILE *fp;
63cb489e 176 char line[MSG_BSIZE + 1];
84555b38 177 extern int die(), domark(), reapchild();
e677da31 178
e677da31
RC
179 while (--argc > 0) {
180 p = *++argv;
a49a6aba
RC
181 if (p[0] != '-')
182 usage();
183 switch (p[1]) {
a49a6aba
RC
184 case 'f': /* configuration file */
185 if (p[2] != '\0')
186 ConfFile = &p[2];
187 break;
188
189 case 'd': /* debug */
190 Debug++;
191 break;
192
193 case 'p': /* path */
194 if (p[2] != '\0')
64b300b4 195 LogName = &p[2];
a49a6aba
RC
196 break;
197
ad58e75e
EA
198 case 'm': /* mark interval */
199 if (p[2] != '\0')
92e73e63 200 MarkInterval = atoi(&p[2]) * 60;
ad58e75e
EA
201 break;
202
a49a6aba
RC
203 default:
204 usage();
e677da31
RC
205 }
206 }
207
208 if (!Debug) {
209 if (fork())
210 exit(0);
211 for (i = 0; i < 10; i++)
212 (void) close(i);
213 (void) open("/", 0);
214 (void) dup2(0, 1);
215 (void) dup2(0, 2);
a49a6aba 216 untty();
84555b38
RC
217 } else
218 setlinebuf(stdout);
219
92e73e63
MK
220 consfile.f_type = F_CONSOLE;
221 (void) strcpy(consfile.f_un.f_fname, ctty);
ad58e75e
EA
222 (void) gethostname(LocalHostName, sizeof LocalHostName);
223 if (p = index(LocalHostName, '.')) {
224 *p++ = '\0';
225 LocalDomain = p;
226 }
227 else
228 LocalDomain = "";
64b300b4 229 (void) signal(SIGTERM, die);
67f1f408
EA
230 (void) signal(SIGINT, Debug ? die : SIG_IGN);
231 (void) signal(SIGQUIT, Debug ? die : SIG_IGN);
64b300b4 232 (void) signal(SIGCHLD, reapchild);
ad58e75e 233 (void) signal(SIGALRM, domark);
92e73e63 234 (void) alarm(TIMERINTVL);
64b300b4
EA
235 (void) unlink(LogName);
236
0d20624e
KM
237 sunx.sun_family = AF_UNIX;
238 (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path);
e677da31 239 funix = socket(AF_UNIX, SOCK_DGRAM, 0);
0d20624e
KM
240 if (funix < 0 || bind(funix, (struct sockaddr *) &sunx,
241 sizeof(sunx.sun_family)+strlen(sunx.sun_path)) < 0 ||
64b300b4
EA
242 chmod(LogName, 0666) < 0) {
243 (void) sprintf(line, "cannot create %s", LogName);
244 logerror(line);
245 dprintf("cannot create %s (%d)\n", LogName, errno);
246 die(0);
e677da31 247 }
e677da31
RC
248 finet = socket(AF_INET, SOCK_DGRAM, 0);
249 if (finet >= 0) {
250 struct servent *sp;
251
252 sp = getservbyname("syslog", "udp");
253 if (sp == NULL) {
254 errno = 0;
255 logerror("syslog/udp: unknown service");
64b300b4 256 die(0);
e677da31
RC
257 }
258 sin.sin_family = AF_INET;
64b300b4
EA
259 sin.sin_port = LogPort = sp->s_port;
260 if (bind(finet, &sin, sizeof(sin)) < 0) {
e677da31 261 logerror("bind");
64b300b4
EA
262 if (!Debug)
263 die(0);
264 } else {
265 inetm = FDMASK(finet);
266 InetInuse = 1;
e677da31 267 }
e677da31 268 }
84555b38 269 if ((fklog = open("/dev/klog", O_RDONLY)) >= 0)
64b300b4 270 klogm = FDMASK(fklog);
84555b38 271 else {
63cb489e 272 dprintf("can't open /dev/klog (%d)\n", errno);
a49a6aba
RC
273 klogm = 0;
274 }
e677da31
RC
275
276 /* tuck my process id away */
64b300b4 277 fp = fopen(PidFile, "w");
e677da31
RC
278 if (fp != NULL) {
279 fprintf(fp, "%d\n", getpid());
64b300b4 280 (void) fclose(fp);
e677da31
RC
281 }
282
283 dprintf("off & running....\n");
284
e677da31 285 init();
64b300b4 286 (void) signal(SIGHUP, init);
454c883a 287
e677da31 288 for (;;) {
64b300b4 289 int nfds, readfds = FDMASK(funix) | inetm | klogm;
e677da31 290
64b300b4 291 errno = 0;
ff8002b1 292 dprintf("readfds = %#x\n", readfds);
64b300b4
EA
293 nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL,
294 (fd_set *) NULL, (struct timeval *) NULL);
e677da31
RC
295 if (nfds == 0)
296 continue;
297 if (nfds < 0) {
64b300b4
EA
298 if (errno != EINTR)
299 logerror("select");
e677da31
RC
300 continue;
301 }
92e73e63 302 dprintf("got a message (%d, %#x)\n", nfds, readfds);
a49a6aba 303 if (readfds & klogm) {
84555b38 304 i = read(fklog, line, sizeof(line) - 1);
8a7154b1
RC
305 if (i > 0) {
306 line[i] = '\0';
307 printsys(line);
a49a6aba 308 } else if (i < 0 && errno != EINTR) {
84555b38
RC
309 logerror("klog");
310 fklog = -1;
a49a6aba
RC
311 klogm = 0;
312 }
8a7154b1 313 }
64b300b4 314 if (readfds & FDMASK(funix)) {
e677da31 315 len = sizeof fromunix;
64b300b4
EA
316 i = recvfrom(funix, line, MAXLINE, 0,
317 (struct sockaddr *) &fromunix, &len);
a24c481a
RC
318 if (i > 0) {
319 line[i] = '\0';
64b300b4 320 printline(LocalHostName, line);
a24c481a 321 } else if (i < 0 && errno != EINTR)
64b300b4 322 logerror("recvfrom unix");
a24c481a 323 }
84555b38 324 if (readfds & inetm) {
e677da31
RC
325 len = sizeof frominet;
326 i = recvfrom(finet, line, MAXLINE, 0, &frominet, &len);
64b300b4
EA
327 if (i > 0) {
328 extern char *cvthname();
329
a24c481a 330 line[i] = '\0';
64b300b4 331 printline(cvthname(&frominet), line);
a24c481a 332 } else if (i < 0 && errno != EINTR)
64b300b4 333 logerror("recvfrom inet");
a24c481a 334 }
e677da31
RC
335 }
336}
337
a49a6aba
RC
338usage()
339{
ad58e75e 340 fprintf(stderr, "usage: syslogd [-d] [-mmarkinterval] [-ppath] [-fconffile]\n");
a49a6aba
RC
341 exit(1);
342}
343
344untty()
345{
346 int i;
347
348 if (!Debug) {
349 i = open("/dev/tty", O_RDWR);
350 if (i >= 0) {
64b300b4 351 (void) ioctl(i, (int) TIOCNOTTY, (char *)0);
a49a6aba
RC
352 (void) close(i);
353 }
354 }
355}
356
e677da31
RC
357/*
358 * Take a raw input line, decode the message, and print the message
359 * on the appropriate log files.
360 */
361
64b300b4
EA
362printline(hname, msg)
363 char *hname;
e677da31
RC
364 char *msg;
365{
366 register char *p, *q;
367 register int c;
63cb489e 368 char line[MAXLINE + 1];
e677da31
RC
369 int pri;
370
371 /* test for special codes */
a49a6aba 372 pri = DEFUPRI;
e677da31 373 p = msg;
a49a6aba
RC
374 if (*p == '<') {
375 pri = 0;
376 while (isdigit(*++p))
377 pri = 10 * pri + (*p - '0');
378 if (*p == '>')
379 ++p;
e677da31 380 }
35c3f83c
MK
381 if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
382 pri = DEFUPRI;
e677da31 383
64b300b4 384 /* don't allow users to log kernel messages */
35c3f83c
MK
385 if (LOG_FAC(pri) == LOG_KERN)
386 pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
64b300b4 387
e677da31 388 q = line;
64b300b4 389
e677da31 390 while ((c = *p++ & 0177) != '\0' && c != '\n' &&
63cb489e 391 q < &line[sizeof(line) - 1]) {
e677da31
RC
392 if (iscntrl(c)) {
393 *q++ = '^';
394 *q++ = c ^ 0100;
395 } else
396 *q++ = c;
397 }
e677da31
RC
398 *q = '\0';
399
64b300b4 400 logmsg(pri, line, hname, 0);
e677da31
RC
401}
402
63cb489e
RC
403/*
404 * Take a raw input line from /dev/klog, split and format similar to syslog().
405 */
406
407printsys(msg)
408 char *msg;
409{
410 register char *p, *q;
411 register int c;
412 char line[MAXLINE + 1];
8a7154b1 413 int pri, flags;
a49a6aba 414 char *lp;
63cb489e 415
92e73e63 416 (void) sprintf(line, "vmunix: ");
a49a6aba 417 lp = line + strlen(line);
63cb489e 418 for (p = msg; *p != '\0'; ) {
92e73e63 419 flags = SYNC_FILE | ADDDATE; /* fsync file after write */
a49a6aba
RC
420 pri = DEFSPRI;
421 if (*p == '<') {
422 pri = 0;
423 while (isdigit(*++p))
424 pri = 10 * pri + (*p - '0');
425 if (*p == '>')
426 ++p;
8a7154b1
RC
427 } else {
428 /* kernel printf's come out on console */
429 flags |= IGN_CONS;
430 }
35c3f83c
MK
431 if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
432 pri = DEFSPRI;
a49a6aba
RC
433 q = lp;
434 while (*p != '\0' && (c = *p++) != '\n' &&
435 q < &line[MAXLINE])
63cb489e
RC
436 *q++ = c;
437 *q = '\0';
64b300b4 438 logmsg(pri, line, LocalHostName, flags);
63cb489e
RC
439 }
440}
441
92e73e63
MK
442time_t now;
443
e677da31
RC
444/*
445 * Log a message to the appropriate log files, users, etc. based on
446 * the priority.
447 */
448
8a7154b1 449logmsg(pri, msg, from, flags)
64b300b4
EA
450 int pri;
451 char *msg, *from;
452 int flags;
e677da31 453{
e677da31 454 register struct filed *f;
64b300b4 455 int fac, prilev;
92e73e63
MK
456 int omask, msglen;
457 char *timestamp;
84555b38 458
64b300b4
EA
459 dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", pri, flags, from, msg);
460
ad58e75e 461 omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
ada83039 462
64b300b4
EA
463 /*
464 * Check to see if msg looks non-standard.
465 */
92e73e63
MK
466 msglen = strlen(msg);
467 if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
ad58e75e 468 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
64b300b4 469 flags |= ADDDATE;
a49a6aba 470
ad58e75e
EA
471 (void) time(&now);
472 if (flags & ADDDATE)
92e73e63
MK
473 timestamp = ctime(&now) + 4;
474 else {
475 timestamp = msg;
476 msg += 16;
477 msglen -= 16;
478 }
64b300b4
EA
479
480 /* extract facility and priority level */
c16a39e2
MK
481 if (flags & MARK)
482 fac = LOG_NFACILITIES;
35c3f83c
MK
483 else
484 fac = LOG_FAC(pri);
485 prilev = LOG_PRI(pri);
64b300b4 486
e677da31 487 /* log the message to the particular outputs */
64b300b4 488 if (!Initialized) {
92e73e63
MK
489 f = &consfile;
490 f->f_file = open(ctty, O_WRONLY);
64b300b4 491
92e73e63
MK
492 if (f->f_file >= 0) {
493 untty();
35c3f83c 494 fprintlog(f, flags, (char *)NULL);
92e73e63 495 (void) close(f->f_file);
64b300b4 496 }
7eefe9c1 497 (void) sigsetmask(omask);
64b300b4
EA
498 return;
499 }
92e73e63 500 for (f = Files; f; f = f->f_next) {
64b300b4
EA
501 /* skip messages that are incorrect priority */
502 if (f->f_pmask[fac] < prilev || f->f_pmask[fac] == NOPRI)
a49a6aba 503 continue;
64b300b4 504
35c3f83c
MK
505 if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
506 continue;
507
ad58e75e 508 /* don't output marks to recently written files */
92e73e63 509 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
ad58e75e
EA
510 continue;
511
92e73e63
MK
512 /*
513 * suppress duplicate lines to this file
514 */
515 if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
516 !strcmp(msg, f->f_prevline) &&
517 !strcmp(from, f->f_prevhost)) {
518 (void) strncpy(f->f_lasttime, timestamp, 15);
519 f->f_prevcount++;
520 dprintf("msg repeated %d times, %d sec of %d\n",
521 f->f_prevcount, now - f->f_time,
522 repeatinterval[f->f_repeatcount]);
523 /*
524 * If domark would have logged this by now,
525 * flush it now (so we don't hold isolated messages),
526 * but back off so we'll flush less often
527 * in the future.
528 */
529 if (now > REPEATTIME(f)) {
35c3f83c 530 fprintlog(f, flags, (char *)NULL);
92e73e63 531 BACKOFF(f);
8a7154b1 532 }
92e73e63
MK
533 } else {
534 /* new line, save it */
35c3f83c
MK
535 if (f->f_prevcount)
536 fprintlog(f, 0, (char *)NULL);
537 f->f_repeatcount = 0;
92e73e63 538 (void) strncpy(f->f_lasttime, timestamp, 15);
35c3f83c
MK
539 (void) strncpy(f->f_prevhost, from,
540 sizeof(f->f_prevhost));
541 if (msglen < MAXSVLINE) {
92e73e63
MK
542 f->f_prevlen = msglen;
543 f->f_prevpri = pri;
544 (void) strcpy(f->f_prevline, msg);
35c3f83c
MK
545 fprintlog(f, flags, (char *)NULL);
546 } else {
92e73e63 547 f->f_prevline[0] = 0;
35c3f83c
MK
548 f->f_prevlen = 0;
549 fprintlog(f, flags, msg);
550 }
92e73e63
MK
551 }
552 }
553 (void) sigsetmask(omask);
554}
64b300b4 555
35c3f83c 556fprintlog(f, flags, msg)
92e73e63
MK
557 register struct filed *f;
558 int flags;
35c3f83c 559 char *msg;
92e73e63
MK
560{
561 struct iovec iov[6];
562 register struct iovec *v = iov;
563 register int l;
564 char line[MAXLINE + 1];
565 char repbuf[80];
566
567 v->iov_base = f->f_lasttime;
568 v->iov_len = 15;
569 v++;
570 v->iov_base = " ";
571 v->iov_len = 1;
572 v++;
573 v->iov_base = f->f_prevhost;
574 v->iov_len = strlen(v->iov_base);
575 v++;
576 v->iov_base = " ";
577 v->iov_len = 1;
578 v++;
35c3f83c
MK
579 if (msg) {
580 v->iov_base = msg;
581 v->iov_len = strlen(msg);
582 } else if (f->f_prevcount > 1) {
92e73e63
MK
583 (void) sprintf(repbuf, "last message repeated %d times",
584 f->f_prevcount);
585 v->iov_base = repbuf;
586 v->iov_len = strlen(repbuf);
587 } else {
588 v->iov_base = f->f_prevline;
589 v->iov_len = f->f_prevlen;
590 }
591 v++;
592
593 dprintf("Logging to %s", TypeNames[f->f_type]);
594 f->f_time = now;
595
596 switch (f->f_type) {
597 case F_UNUSED:
598 dprintf("\n");
599 break;
600
601 case F_FORW:
602 dprintf(" %s\n", f->f_un.f_forw.f_hname);
603 (void) sprintf(line, "<%d>%.15s %s", f->f_prevpri,
604 iov[0].iov_base, iov[4].iov_base);
605 l = strlen(line);
606 if (l > MAXLINE)
607 l = MAXLINE;
608 if (sendto(finet, line, l, 0, &f->f_un.f_forw.f_addr,
609 sizeof f->f_un.f_forw.f_addr) != l) {
610 int e = errno;
611 (void) close(f->f_file);
612 f->f_type = F_UNUSED;
613 errno = e;
614 logerror("sendto");
615 }
616 break;
617
618 case F_CONSOLE:
619 if (flags & IGN_CONS) {
620 dprintf(" (ignored)\n");
64b300b4 621 break;
92e73e63
MK
622 }
623 /* FALLTHROUGH */
e677da31 624
92e73e63
MK
625 case F_TTY:
626 case F_FILE:
627 dprintf(" %s\n", f->f_un.f_fname);
628 if (f->f_type != F_FILE) {
64b300b4
EA
629 v->iov_base = "\r\n";
630 v->iov_len = 2;
92e73e63
MK
631 } else {
632 v->iov_base = "\n";
633 v->iov_len = 1;
64b300b4 634 }
92e73e63
MK
635 again:
636 if (writev(f->f_file, iov, 6) < 0) {
637 int e = errno;
638 (void) close(f->f_file);
639 /*
640 * Check for EBADF on TTY's due to vhangup() XXX
641 */
642 if (e == EBADF && f->f_type != F_FILE) {
643 f->f_file = open(f->f_un.f_fname, O_WRONLY|O_APPEND);
644 if (f->f_file < 0) {
645 f->f_type = F_UNUSED;
646 logerror(f->f_un.f_fname);
647 } else {
648 untty();
649 goto again;
650 }
651 } else {
652 f->f_type = F_UNUSED;
653 errno = e;
654 logerror(f->f_un.f_fname);
655 }
656 } else if (flags & SYNC_FILE)
657 (void) fsync(f->f_file);
658 break;
e677da31 659
92e73e63
MK
660 case F_USERS:
661 case F_WALL:
662 dprintf("\n");
663 v->iov_base = "\r\n";
664 v->iov_len = 2;
665 wallmsg(f, iov);
666 break;
667 }
668 f->f_prevcount = 0;
e677da31
RC
669}
670
92e73e63
MK
671jmp_buf ttybuf;
672
673endtty()
674{
675 longjmp(ttybuf, 1);
676}
64b300b4 677
e677da31
RC
678/*
679 * WALLMSG -- Write a message to the world at large
680 *
681 * Write the specified message to either the entire
682 * world, or a list of approved users.
683 */
684
64b300b4
EA
685wallmsg(f, iov)
686 register struct filed *f;
687 struct iovec *iov;
e677da31
RC
688{
689 register char *p;
690 register int i;
64b300b4 691 int ttyf, len;
ada83039 692 FILE *uf;
64b300b4 693 static int reenter = 0;
e677da31 694 struct utmp ut;
64b300b4
EA
695 char greetings[200];
696
697 if (reenter++)
698 return;
e677da31
RC
699
700 /* open the user login file */
ada83039
RC
701 if ((uf = fopen("/etc/utmp", "r")) == NULL) {
702 logerror("/etc/utmp");
64b300b4 703 reenter = 0;
e677da31 704 return;
ada83039 705 }
e677da31 706
92e73e63
MK
707 /*
708 * Might as well fork instead of using nonblocking I/O
709 * and doing notty().
710 */
711 if (fork() == 0) {
712 (void) signal(SIGTERM, SIG_DFL);
713 (void) alarm(0);
714 (void) signal(SIGALRM, endtty);
715 (void) signal(SIGTTOU, SIG_IGN);
716 (void) sigsetmask(0);
717 (void) sprintf(greetings,
718 "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
719 iov[2].iov_base, ctime(&now));
720 len = strlen(greetings);
721
722 /* scan the user login file */
723 while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
724 /* is this slot used? */
725 if (ut.ut_name[0] == '\0')
726 continue;
e677da31 727
92e73e63
MK
728 /* should we send the message to this user? */
729 if (f->f_type == F_USERS) {
730 for (i = 0; i < MAXUNAMES; i++) {
731 if (!f->f_un.f_uname[i][0]) {
732 i = MAXUNAMES;
733 break;
734 }
735 if (strncmp(f->f_un.f_uname[i],
736 ut.ut_name, UNAMESZ) == 0)
737 break;
64b300b4 738 }
92e73e63
MK
739 if (i >= MAXUNAMES)
740 continue;
e677da31 741 }
e677da31 742
92e73e63
MK
743 /* compute the device name */
744 p = "/dev/12345678";
745 strncpy(&p[5], ut.ut_line, UNAMESZ);
e677da31 746
64b300b4
EA
747 if (f->f_type == F_WALL) {
748 iov[0].iov_base = greetings;
749 iov[0].iov_len = len;
ad58e75e 750 iov[1].iov_len = 0;
64b300b4 751 }
92e73e63
MK
752 if (setjmp(ttybuf) == 0) {
753 (void) alarm(15);
754 /* open the terminal */
755 ttyf = open(p, O_WRONLY);
756 if (ttyf >= 0) {
757 struct stat statb;
758
759 if (fstat(ttyf, &statb) == 0 &&
760 (statb.st_mode & S_IWRITE))
761 (void) writev(ttyf, iov, 6);
762 close(ttyf);
763 ttyf = -1;
764 }
fcd484c8 765 }
92e73e63 766 (void) alarm(0);
e677da31 767 }
92e73e63 768 exit(0);
e677da31 769 }
e677da31 770 /* close the user login file */
84555b38 771 (void) fclose(uf);
64b300b4 772 reenter = 0;
84555b38
RC
773}
774
775reapchild()
776{
777 union wait status;
778
64b300b4 779 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
84555b38 780 ;
e677da31
RC
781}
782
783/*
64b300b4 784 * Return a printable representation of a host address.
e677da31 785 */
64b300b4
EA
786char *
787cvthname(f)
e677da31
RC
788 struct sockaddr_in *f;
789{
790 struct hostent *hp;
ad58e75e 791 register char *p;
e677da31
RC
792 extern char *inet_ntoa();
793
64b300b4 794 dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
e677da31
RC
795
796 if (f->sin_family != AF_INET) {
797 dprintf("Malformed from address\n");
64b300b4 798 return ("???");
e677da31
RC
799 }
800 hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family);
801 if (hp == 0) {
802 dprintf("Host name for your address (%s) unknown\n",
803 inet_ntoa(f->sin_addr));
64b300b4 804 return (inet_ntoa(f->sin_addr));
e677da31 805 }
ad58e75e
EA
806 if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
807 *p = '\0';
64b300b4 808 return (hp->h_name);
e677da31
RC
809}
810
ad58e75e
EA
811domark()
812{
92e73e63 813 register struct filed *f;
ad58e75e 814
92e73e63
MK
815 now = time(0);
816 MarkSeq += TIMERINTVL;
817 if (MarkSeq >= MarkInterval) {
c16a39e2 818 logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
92e73e63
MK
819 MarkSeq = 0;
820 }
ad58e75e 821
92e73e63
MK
822 for (f = Files; f; f = f->f_next) {
823 if (f->f_prevcount && now >= REPEATTIME(f)) {
824 dprintf("flush %s: repeated %d times, %d sec.\n",
825 TypeNames[f->f_type], f->f_prevcount,
826 repeatinterval[f->f_repeatcount]);
35c3f83c 827 fprintlog(f, 0, (char *)NULL);
92e73e63
MK
828 BACKOFF(f);
829 }
830 }
831 (void) alarm(TIMERINTVL);
a49a6aba
RC
832}
833
e677da31
RC
834/*
835 * Print syslogd errors some place.
836 */
837logerror(type)
838 char *type;
839{
840 char buf[100];
841
842 if (errno == 0)
64b300b4 843 (void) sprintf(buf, "syslogd: %s", type);
e677da31 844 else if ((unsigned) errno > sys_nerr)
64b300b4 845 (void) sprintf(buf, "syslogd: %s: error %d", type, errno);
e677da31 846 else
64b300b4 847 (void) sprintf(buf, "syslogd: %s: %s", type, sys_errlist[errno]);
e677da31 848 errno = 0;
ada83039 849 dprintf("%s\n", buf);
ad58e75e 850 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
e677da31
RC
851}
852
64b300b4 853die(sig)
e677da31 854{
92e73e63 855 register struct filed *f;
64b300b4 856 char buf[100];
ada83039 857
92e73e63
MK
858 for (f = Files; f != NULL; f = f->f_next) {
859 /* flush any pending output */
860 if (f->f_prevcount)
35c3f83c 861 fprintlog(f, 0, (char *)NULL);
92e73e63 862 }
a075f884 863 if (sig) {
92e73e63
MK
864 dprintf("syslogd: exiting on signal %d\n", sig);
865 (void) sprintf(buf, "exiting on signal %d", sig);
d34bf11a 866 errno = 0;
a075f884
MK
867 logerror(buf);
868 }
64b300b4 869 (void) unlink(LogName);
e677da31
RC
870 exit(0);
871}
a49a6aba
RC
872
873/*
64b300b4 874 * INIT -- Initialize syslogd from configuration table
a49a6aba 875 */
64b300b4
EA
876
877init()
a49a6aba 878{
a49a6aba 879 register int i;
64b300b4 880 register FILE *cf;
92e73e63 881 register struct filed *f, *next, **nextp;
64b300b4
EA
882 register char *p;
883 char cline[BUFSIZ];
a49a6aba 884
64b300b4
EA
885 dprintf("init\n");
886
64b300b4
EA
887 /*
888 * Close all open log files.
889 */
d34bf11a 890 Initialized = 0;
92e73e63
MK
891 for (f = Files; f != NULL; f = next) {
892 /* flush any pending output */
893 if (f->f_prevcount)
35c3f83c 894 fprintlog(f, 0, (char *)NULL);
92e73e63 895
bb112360
EA
896 switch (f->f_type) {
897 case F_FILE:
898 case F_TTY:
bb112360 899 case F_CONSOLE:
64b300b4 900 (void) close(f->f_file);
bb112360
EA
901 break;
902 }
92e73e63
MK
903 next = f->f_next;
904 free((char *) f);
64b300b4 905 }
92e73e63
MK
906 Files = NULL;
907 nextp = &Files;
64b300b4
EA
908
909 /* open the configuration file */
910 if ((cf = fopen(ConfFile, "r")) == NULL) {
911 dprintf("cannot open %s\n", ConfFile);
92e73e63
MK
912 *nextp = (struct filed *)calloc(1, sizeof(*f));
913 cfline("*.ERR\t/dev/console", *nextp);
914 (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
915 cfline("*.PANIC\t*", (*nextp)->f_next);
916 Initialized = 1;
64b300b4
EA
917 return;
918 }
919
920 /*
921 * Foreach line in the conf table, open that file.
922 */
92e73e63
MK
923 f = NULL;
924 while (fgets(cline, sizeof cline, cf) != NULL) {
64b300b4
EA
925 /* check for end-of-section */
926 if (cline[0] == '\n' || cline[0] == '#')
a49a6aba
RC
927 continue;
928
92e73e63
MK
929 f = (struct filed *)calloc(1, sizeof(*f));
930 *nextp = f;
931 nextp = &f->f_next;
64b300b4
EA
932 /* strip off newline character */
933 p = index(cline, '\n');
934 if (p)
935 *p = '\0';
936
92e73e63 937 cfline(cline, f);
64b300b4
EA
938 }
939
940 /* close the configuration file */
941 (void) fclose(cf);
942
943 Initialized = 1;
944
945 if (Debug) {
92e73e63 946 for (f = Files; f; f = f->f_next) {
c16a39e2 947 for (i = 0; i <= LOG_NFACILITIES; i++)
64b300b4
EA
948 if (f->f_pmask[i] == NOPRI)
949 printf("X ");
950 else
951 printf("%d ", f->f_pmask[i]);
952 printf("%s: ", TypeNames[f->f_type]);
953 switch (f->f_type) {
954 case F_FILE:
955 case F_TTY:
956 case F_CONSOLE:
957 printf("%s", f->f_un.f_fname);
958 break;
959
960 case F_FORW:
961 printf("%s", f->f_un.f_forw.f_hname);
962 break;
963
964 case F_USERS:
965 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
966 printf("%s, ", f->f_un.f_uname[i]);
967 break;
968 }
969 printf("\n");
970 }
971 }
972
ad58e75e 973 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
64b300b4
EA
974 dprintf("syslogd: restarted\n");
975}
976
977/*
978 * Crack a configuration file line
979 */
980
981struct code {
982 char *c_name;
983 int c_val;
984};
985
986struct code PriNames[] = {
987 "panic", LOG_EMERG,
988 "emerg", LOG_EMERG,
989 "alert", LOG_ALERT,
990 "crit", LOG_CRIT,
991 "err", LOG_ERR,
992 "error", LOG_ERR,
993 "warn", LOG_WARNING,
994 "warning", LOG_WARNING,
995 "notice", LOG_NOTICE,
996 "info", LOG_INFO,
997 "debug", LOG_DEBUG,
ad58e75e 998 "none", NOPRI,
64b300b4
EA
999 NULL, -1
1000};
1001
1002struct code FacNames[] = {
1003 "kern", LOG_KERN,
1004 "user", LOG_USER,
1005 "mail", LOG_MAIL,
623d5539 1006 "daemon", LOG_DAEMON,
64b300b4
EA
1007 "auth", LOG_AUTH,
1008 "security", LOG_AUTH,
c16a39e2 1009 "mark", LOG_MARK,
ad58e75e 1010 "syslog", LOG_SYSLOG,
891383bf 1011 "lpr", LOG_LPR,
61a57de9 1012 "news", LOG_NEWS,
64b300b4
EA
1013 "local0", LOG_LOCAL0,
1014 "local1", LOG_LOCAL1,
1015 "local2", LOG_LOCAL2,
1016 "local3", LOG_LOCAL3,
1017 "local4", LOG_LOCAL4,
1018 "local5", LOG_LOCAL5,
1019 "local6", LOG_LOCAL6,
1020 "local7", LOG_LOCAL7,
1021 NULL, -1
1022};
1023
1024cfline(line, f)
1025 char *line;
1026 register struct filed *f;
1027{
1028 register char *p;
1029 register char *q;
1030 register int i;
1031 char *bp;
1032 int pri;
1033 struct hostent *hp;
1034 char buf[MAXLINE];
1035
1036 dprintf("cfline(%s)\n", line);
1037
d34bf11a
KM
1038 errno = 0; /* keep sys_errlist stuff out of logerror messages */
1039
64b300b4
EA
1040 /* clear out file entry */
1041 bzero((char *) f, sizeof *f);
c16a39e2 1042 for (i = 0; i <= LOG_NFACILITIES; i++)
64b300b4
EA
1043 f->f_pmask[i] = NOPRI;
1044
1045 /* scan through the list of selectors */
1046 for (p = line; *p && *p != '\t';) {
1047
1048 /* find the end of this facility name list */
1049 for (q = p; *q && *q != '\t' && *q++ != '.'; )
a49a6aba 1050 continue;
64b300b4
EA
1051
1052 /* collect priority name */
1053 for (bp = buf; *q && !index("\t,;", *q); )
1054 *bp++ = *q++;
1055 *bp = '\0';
1056
1057 /* skip cruft */
1058 while (index(", ;", *q))
1059 q++;
1060
1061 /* decode priority name */
1062 pri = decode(buf, PriNames);
1063 if (pri < 0) {
1064 char xbuf[200];
1065
1066 (void) sprintf(xbuf, "unknown priority name \"%s\"", buf);
1067 logerror(xbuf);
1068 return;
1069 }
1070
1071 /* scan facilities */
1072 while (*p && !index("\t.;", *p)) {
1073 int i;
1074
1075 for (bp = buf; *p && !index("\t,;.", *p); )
1076 *bp++ = *p++;
1077 *bp = '\0';
1078 if (*buf == '*')
1079 for (i = 0; i < LOG_NFACILITIES; i++)
1080 f->f_pmask[i] = pri;
1081 else {
1082 i = decode(buf, FacNames);
1083 if (i < 0) {
1084 char xbuf[200];
1085
1086 (void) sprintf(xbuf, "unknown facility name \"%s\"", buf);
1087 logerror(xbuf);
1088 return;
1089 }
1090 f->f_pmask[i >> 3] = pri;
1091 }
1092 while (*p == ',' || *p == ' ')
1093 p++;
1094 }
1095
1096 p = q;
1097 }
1098
1099 /* skip to action part */
1100 while (*p == '\t')
1101 p++;
1102
1103 switch (*p)
1104 {
1105 case '@':
1106 if (!InetInuse)
1107 break;
1108 (void) strcpy(f->f_un.f_forw.f_hname, ++p);
1109 hp = gethostbyname(p);
1110 if (hp == NULL) {
1111 char buf[100];
1112
1113 (void) sprintf(buf, "unknown host %s", p);
1114 errno = 0;
1115 logerror(buf);
1116 break;
1117 }
1118 bzero((char *) &f->f_un.f_forw.f_addr,
1119 sizeof f->f_un.f_forw.f_addr);
1120 f->f_un.f_forw.f_addr.sin_family = AF_INET;
1121 f->f_un.f_forw.f_addr.sin_port = LogPort;
1122 bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
64b300b4
EA
1123 f->f_type = F_FORW;
1124 break;
1125
1126 case '/':
1127 (void) strcpy(f->f_un.f_fname, p);
1128 if ((f->f_file = open(p, O_WRONLY|O_APPEND)) < 0) {
1129 logerror(p);
1130 break;
1131 }
1132 if (isatty(f->f_file)) {
1133 f->f_type = F_TTY;
1134 untty();
a49a6aba 1135 }
64b300b4
EA
1136 else
1137 f->f_type = F_FILE;
1138 if (strcmp(p, ctty) == 0)
1139 f->f_type = F_CONSOLE;
1140 break;
1141
1142 case '*':
1143 f->f_type = F_WALL;
1144 break;
1145
1146 default:
1147 for (i = 0; i < MAXUNAMES && *p; i++) {
1148 for (q = p; *q && *q != ','; )
1149 q++;
1150 (void) strncpy(f->f_un.f_uname[i], p, UNAMESZ);
1151 if ((q - p) > UNAMESZ)
1152 f->f_un.f_uname[i][UNAMESZ] = '\0';
1153 else
1154 f->f_un.f_uname[i][q - p] = '\0';
1155 while (*q == ',' || *q == ' ')
1156 q++;
1157 p = q;
1158 }
1159 f->f_type = F_USERS;
1160 break;
a49a6aba 1161 }
64b300b4
EA
1162}
1163
1164
1165/*
1166 * Decode a symbolic name to a numeric value
1167 */
1168
1169decode(name, codetab)
1170 char *name;
1171 struct code *codetab;
1172{
1173 register struct code *c;
1174 register char *p;
1175 char buf[40];
1176
1177 if (isdigit(*name))
1178 return (atoi(name));
1179
1180 (void) strcpy(buf, name);
1181 for (p = buf; *p; p++)
1182 if (isupper(*p))
1183 *p = tolower(*p);
1184 for (c = codetab; c->c_name; c++)
1185 if (!strcmp(buf, c->c_name))
1186 return (c->c_val);
a49a6aba 1187
64b300b4 1188 return (-1);
a49a6aba 1189}