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