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