add network news subsystem facility
[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
bb112360 14static char sccsid[] = "@(#)syslogd.c 5.14 (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 44
e677da31
RC
45#include <errno.h>
46#include <stdio.h>
47#include <utmp.h>
48#include <ctype.h>
a24c481a
RC
49#include <signal.h>
50#include <sysexits.h>
51#include <strings.h>
52
c16a39e2 53#include <sys/syslog.h>
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 */
c16a39e2 84#define LOG_MARK (LOG_NFACILITIES << 3) /* 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 */
92#define NOCOPY 0x004 /* don't suppress duplicate messages */
93#define ADDDATE 0x008 /* add a date to the message */
ad58e75e 94#define MARK 0x010 /* this message is a mark */
8a7154b1 95
e677da31
RC
96/*
97 * This structure represents the files that will have log
98 * copies printed.
99 */
100
101struct filed {
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;
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;
c16a39e2
MK
500 if (flags & MARK)
501 fac = LOG_NFACILITIES;
64b300b4
EA
502 prilev = pri & LOG_PRIMASK;
503
e677da31 504 /* log the message to the particular outputs */
64b300b4
EA
505 if (!Initialized) {
506 int cfd = open(ctty, O_WRONLY);
507
508 if (cfd >= 0) {
509 v->iov_base = "\r\n";
510 v->iov_len = 2;
511 (void) writev(cfd, iov, 6);
512 (void) close(cfd);
513 }
67f1f408 514 untty();
7eefe9c1 515 (void) sigsetmask(omask);
64b300b4
EA
516 return;
517 }
e677da31 518 for (f = Files; f < &Files[NLOGS]; f++) {
64b300b4
EA
519 /* skip messages that are incorrect priority */
520 if (f->f_pmask[fac] < prilev || f->f_pmask[fac] == NOPRI)
a49a6aba 521 continue;
64b300b4 522
ad58e75e
EA
523 /* don't output marks to recently written files */
524 if ((flags & MARK) && (now - f->f_time) < (MarkInterval * 60 / 2))
525 continue;
526
64b300b4 527 dprintf("Logging to %s", TypeNames[f->f_type]);
ad58e75e 528 f->f_time = now;
64b300b4
EA
529 switch (f->f_type) {
530 case F_UNUSED:
531 dprintf("\n");
532 break;
533
534 case F_FORW:
535 dprintf(" %s\n", f->f_un.f_forw.f_hname);
9b6fb12c
KM
536 (void) sprintf(line, "<%d>%.15s %s", pri,
537 iov[0].iov_base, iov[4].iov_base);
e677da31
RC
538 l = strlen(line);
539 if (l > MAXLINE)
540 l = MAXLINE;
541 if (sendto(f->f_file, line, l, 0,
64b300b4
EA
542 &f->f_un.f_forw.f_addr,
543 sizeof f->f_un.f_forw.f_addr) != l) {
8a7154b1
RC
544 int e = errno;
545 (void) close(f->f_file);
64b300b4 546 f->f_type = F_UNUSED;
8a7154b1 547 errno = e;
e677da31 548 logerror("sendto");
8a7154b1 549 }
e677da31
RC
550 break;
551
64b300b4
EA
552 case F_CONSOLE:
553 if (flags & IGN_CONS) {
554 dprintf(" (ignored)\n");
555 break;
ada83039 556 }
64b300b4
EA
557
558 case F_TTY:
559 case F_FILE:
560 dprintf(" %s\n", f->f_un.f_fname);
561 if (f->f_type != F_FILE) {
562 v->iov_base = "\r\n";
563 v->iov_len = 2;
564 } else {
565 v->iov_base = "\n";
566 v->iov_len = 1;
e677da31 567 }
64b300b4
EA
568 if (writev(f->f_file, iov, 6) < 0) {
569 int e = errno;
570 (void) close(f->f_file);
571 /*
572 * Check for EBADF on TTY's due to vhangup() XXX
573 */
574 if (e == EBADF && f->f_type != F_FILE) {
575 f->f_file = open(f->f_un.f_fname, O_WRONLY|O_APPEND);
576 if (f->f_file < 0) {
577 f->f_type = F_UNUSED;
578 logerror(f->f_un.f_fname);
579 }
580 } else {
581 f->f_type = F_UNUSED;
582 errno = e;
583 logerror(f->f_un.f_fname);
584 }
585 } else if (flags & SYNC_FILE)
586 (void) fsync(f->f_file);
587 break;
e677da31 588
64b300b4
EA
589 case F_USERS:
590 case F_WALL:
591 dprintf("\n");
592 v->iov_base = "\r\n";
593 v->iov_len = 2;
594 wallmsg(f, iov);
595 break;
596 }
e677da31
RC
597 }
598
64b300b4 599 (void) sigsetmask(omask);
e677da31
RC
600}
601
64b300b4 602
e677da31
RC
603/*
604 * WALLMSG -- Write a message to the world at large
605 *
606 * Write the specified message to either the entire
607 * world, or a list of approved users.
608 */
609
64b300b4
EA
610wallmsg(f, iov)
611 register struct filed *f;
612 struct iovec *iov;
e677da31
RC
613{
614 register char *p;
615 register int i;
64b300b4 616 int ttyf, len;
ada83039 617 FILE *uf;
64b300b4 618 static int reenter = 0;
e677da31 619 struct utmp ut;
64b300b4
EA
620 time_t now;
621 char greetings[200];
622
623 if (reenter++)
624 return;
e677da31
RC
625
626 /* open the user login file */
ada83039
RC
627 if ((uf = fopen("/etc/utmp", "r")) == NULL) {
628 logerror("/etc/utmp");
64b300b4 629 reenter = 0;
e677da31 630 return;
ada83039 631 }
e677da31 632
64b300b4
EA
633 (void) time(&now);
634 (void) sprintf(greetings,
635 "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
636 iov[2].iov_base, ctime(&now));
637 len = strlen(greetings);
e677da31
RC
638
639 /* scan the user login file */
64b300b4 640 while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
e677da31
RC
641 /* is this slot used? */
642 if (ut.ut_name[0] == '\0')
643 continue;
644
645 /* should we send the message to this user? */
64b300b4
EA
646 if (f->f_type == F_USERS) {
647 for (i = 0; i < MAXUNAMES; i++) {
648 if (!f->f_un.f_uname[i][0]) {
649 i = MAXUNAMES;
650 break;
651 }
652 if (strncmp(f->f_un.f_uname[i], ut.ut_name,
84555b38 653 UNAMESZ) == 0)
64b300b4 654 break;
e677da31 655 }
64b300b4
EA
656 if (i >= MAXUNAMES)
657 continue;
e677da31 658 }
e677da31
RC
659
660 /* compute the device name */
661 p = "/dev/12345678";
662 strcpyn(&p[5], ut.ut_line, UNAMESZ);
663
84555b38
RC
664 /*
665 * Might as well fork instead of using nonblocking I/O
666 * and doing notty().
667 */
e677da31 668 if (fork() == 0) {
64b300b4
EA
669 if (f->f_type == F_WALL) {
670 iov[0].iov_base = greetings;
671 iov[0].iov_len = len;
ad58e75e 672 iov[1].iov_len = 0;
64b300b4
EA
673 }
674 (void) signal(SIGALRM, SIG_DFL);
675 (void) alarm(30);
84555b38 676 /* open the terminal */
64b300b4
EA
677 ttyf = open(p, O_WRONLY);
678 if (ttyf >= 0)
679 (void) writev(ttyf, iov, 6);
e677da31
RC
680 exit(0);
681 }
e677da31 682 }
e677da31 683 /* close the user login file */
84555b38 684 (void) fclose(uf);
64b300b4 685 reenter = 0;
84555b38
RC
686}
687
688reapchild()
689{
690 union wait status;
691
64b300b4 692 while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
84555b38 693 ;
e677da31
RC
694}
695
696/*
64b300b4 697 * Return a printable representation of a host address.
e677da31 698 */
64b300b4
EA
699char *
700cvthname(f)
e677da31
RC
701 struct sockaddr_in *f;
702{
703 struct hostent *hp;
ad58e75e 704 register char *p;
e677da31
RC
705 extern char *inet_ntoa();
706
64b300b4 707 dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
e677da31
RC
708
709 if (f->sin_family != AF_INET) {
710 dprintf("Malformed from address\n");
64b300b4 711 return ("???");
e677da31
RC
712 }
713 hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family);
714 if (hp == 0) {
715 dprintf("Host name for your address (%s) unknown\n",
716 inet_ntoa(f->sin_addr));
64b300b4 717 return (inet_ntoa(f->sin_addr));
e677da31 718 }
ad58e75e
EA
719 if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
720 *p = '\0';
64b300b4 721 return (hp->h_name);
e677da31
RC
722}
723
ad58e75e
EA
724domark()
725{
726 int pri;
727
728 if ((++MarkSeq % MARKCOUNT) == 0)
c16a39e2 729 logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
ad58e75e
EA
730 else
731 flushmsg();
732 alarm(MarkInterval * 60 / MARKCOUNT);
733}
734
a49a6aba
RC
735flushmsg()
736{
64b300b4 737 if (PrevCount == 0)
a49a6aba 738 return;
64b300b4
EA
739 if (PrevCount > 1)
740 (void) sprintf(PrevLine+16, "last message repeated %d times", PrevCount);
741 PrevCount = 0;
742 logmsg(PrevPri, PrevLine, PrevHost, PrevFlags|NOCOPY);
743 PrevLine[0] = '\0';
a49a6aba
RC
744}
745
e677da31
RC
746/*
747 * Print syslogd errors some place.
748 */
749logerror(type)
750 char *type;
751{
752 char buf[100];
753
754 if (errno == 0)
64b300b4 755 (void) sprintf(buf, "syslogd: %s", type);
e677da31 756 else if ((unsigned) errno > sys_nerr)
64b300b4 757 (void) sprintf(buf, "syslogd: %s: error %d", type, errno);
e677da31 758 else
64b300b4 759 (void) sprintf(buf, "syslogd: %s: %s", type, sys_errlist[errno]);
e677da31 760 errno = 0;
ada83039 761 dprintf("%s\n", buf);
ad58e75e 762 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
e677da31
RC
763}
764
64b300b4 765die(sig)
e677da31 766{
64b300b4 767 char buf[100];
ada83039 768
a075f884
MK
769 if (sig) {
770 dprintf("syslogd: going down on signal %d\n", sig);
771 flushmsg();
772 (void) sprintf(buf, "going down on signal %d", sig);
773 logerror(buf);
774 }
64b300b4 775 (void) unlink(LogName);
e677da31
RC
776 exit(0);
777}
a49a6aba
RC
778
779/*
64b300b4 780 * INIT -- Initialize syslogd from configuration table
a49a6aba 781 */
64b300b4
EA
782
783init()
a49a6aba 784{
a49a6aba 785 register int i;
64b300b4
EA
786 register FILE *cf;
787 register struct filed *f;
788 register char *p;
789 char cline[BUFSIZ];
a49a6aba 790
64b300b4
EA
791 dprintf("init\n");
792
793 /* flush any pending output */
794 flushmsg();
795
796 /*
797 * Close all open log files.
798 */
799 for (f = Files; f < &Files[NLOGS]; f++) {
bb112360
EA
800 switch (f->f_type) {
801 case F_FILE:
802 case F_TTY:
803 case F_FORW:
804 case F_CONSOLE:
64b300b4 805 (void) close(f->f_file);
bb112360
EA
806 f->f_type = F_UNUSED;
807 break;
808 }
64b300b4
EA
809 }
810
811 /* open the configuration file */
812 if ((cf = fopen(ConfFile, "r")) == NULL) {
813 dprintf("cannot open %s\n", ConfFile);
814 cfline("*.ERR\t/dev/console", &Files[0]);
815 cfline("*.PANIC\t*", &Files[1]);
816 return;
817 }
818
819 /*
820 * Foreach line in the conf table, open that file.
821 */
822 f = Files;
823 while (fgets(cline, sizeof cline, cf) != NULL && f < &Files[NLOGS]) {
824 /* check for end-of-section */
825 if (cline[0] == '\n' || cline[0] == '#')
a49a6aba
RC
826 continue;
827
64b300b4
EA
828 /* strip off newline character */
829 p = index(cline, '\n');
830 if (p)
831 *p = '\0';
832
833 cfline(cline, f++);
834 }
835
836 /* close the configuration file */
837 (void) fclose(cf);
838
839 Initialized = 1;
840
841 if (Debug) {
842 for (f = Files; f < &Files[NLOGS]; f++) {
c16a39e2 843 for (i = 0; i <= LOG_NFACILITIES; i++)
64b300b4
EA
844 if (f->f_pmask[i] == NOPRI)
845 printf("X ");
846 else
847 printf("%d ", f->f_pmask[i]);
848 printf("%s: ", TypeNames[f->f_type]);
849 switch (f->f_type) {
850 case F_FILE:
851 case F_TTY:
852 case F_CONSOLE:
853 printf("%s", f->f_un.f_fname);
854 break;
855
856 case F_FORW:
857 printf("%s", f->f_un.f_forw.f_hname);
858 break;
859
860 case F_USERS:
861 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
862 printf("%s, ", f->f_un.f_uname[i]);
863 break;
864 }
865 printf("\n");
866 }
867 }
868
ad58e75e 869 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
64b300b4
EA
870 dprintf("syslogd: restarted\n");
871}
872
873/*
874 * Crack a configuration file line
875 */
876
877struct code {
878 char *c_name;
879 int c_val;
880};
881
882struct code PriNames[] = {
883 "panic", LOG_EMERG,
884 "emerg", LOG_EMERG,
885 "alert", LOG_ALERT,
886 "crit", LOG_CRIT,
887 "err", LOG_ERR,
888 "error", LOG_ERR,
889 "warn", LOG_WARNING,
890 "warning", LOG_WARNING,
891 "notice", LOG_NOTICE,
892 "info", LOG_INFO,
893 "debug", LOG_DEBUG,
ad58e75e 894 "none", NOPRI,
64b300b4
EA
895 NULL, -1
896};
897
898struct code FacNames[] = {
899 "kern", LOG_KERN,
900 "user", LOG_USER,
901 "mail", LOG_MAIL,
623d5539 902 "daemon", LOG_DAEMON,
64b300b4
EA
903 "auth", LOG_AUTH,
904 "security", LOG_AUTH,
c16a39e2 905 "mark", LOG_MARK,
ad58e75e 906 "syslog", LOG_SYSLOG,
891383bf 907 "lpr", LOG_LPR,
64b300b4
EA
908 "local0", LOG_LOCAL0,
909 "local1", LOG_LOCAL1,
910 "local2", LOG_LOCAL2,
911 "local3", LOG_LOCAL3,
912 "local4", LOG_LOCAL4,
913 "local5", LOG_LOCAL5,
914 "local6", LOG_LOCAL6,
915 "local7", LOG_LOCAL7,
916 NULL, -1
917};
918
919cfline(line, f)
920 char *line;
921 register struct filed *f;
922{
923 register char *p;
924 register char *q;
925 register int i;
926 char *bp;
927 int pri;
928 struct hostent *hp;
929 char buf[MAXLINE];
930
931 dprintf("cfline(%s)\n", line);
932
933 /* clear out file entry */
934 bzero((char *) f, sizeof *f);
c16a39e2 935 for (i = 0; i <= LOG_NFACILITIES; i++)
64b300b4
EA
936 f->f_pmask[i] = NOPRI;
937
938 /* scan through the list of selectors */
939 for (p = line; *p && *p != '\t';) {
940
941 /* find the end of this facility name list */
942 for (q = p; *q && *q != '\t' && *q++ != '.'; )
a49a6aba 943 continue;
64b300b4
EA
944
945 /* collect priority name */
946 for (bp = buf; *q && !index("\t,;", *q); )
947 *bp++ = *q++;
948 *bp = '\0';
949
950 /* skip cruft */
951 while (index(", ;", *q))
952 q++;
953
954 /* decode priority name */
955 pri = decode(buf, PriNames);
956 if (pri < 0) {
957 char xbuf[200];
958
959 (void) sprintf(xbuf, "unknown priority name \"%s\"", buf);
960 logerror(xbuf);
961 return;
962 }
963
964 /* scan facilities */
965 while (*p && !index("\t.;", *p)) {
966 int i;
967
968 for (bp = buf; *p && !index("\t,;.", *p); )
969 *bp++ = *p++;
970 *bp = '\0';
971 if (*buf == '*')
972 for (i = 0; i < LOG_NFACILITIES; i++)
973 f->f_pmask[i] = pri;
974 else {
975 i = decode(buf, FacNames);
976 if (i < 0) {
977 char xbuf[200];
978
979 (void) sprintf(xbuf, "unknown facility name \"%s\"", buf);
980 logerror(xbuf);
981 return;
982 }
983 f->f_pmask[i >> 3] = pri;
984 }
985 while (*p == ',' || *p == ' ')
986 p++;
987 }
988
989 p = q;
990 }
991
992 /* skip to action part */
993 while (*p == '\t')
994 p++;
995
996 switch (*p)
997 {
998 case '@':
999 if (!InetInuse)
1000 break;
1001 (void) strcpy(f->f_un.f_forw.f_hname, ++p);
1002 hp = gethostbyname(p);
1003 if (hp == NULL) {
1004 char buf[100];
1005
1006 (void) sprintf(buf, "unknown host %s", p);
1007 errno = 0;
1008 logerror(buf);
1009 break;
1010 }
1011 bzero((char *) &f->f_un.f_forw.f_addr,
1012 sizeof f->f_un.f_forw.f_addr);
1013 f->f_un.f_forw.f_addr.sin_family = AF_INET;
1014 f->f_un.f_forw.f_addr.sin_port = LogPort;
1015 bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
1016 f->f_file = socket(AF_INET, SOCK_DGRAM, 0);
1017 if (f->f_file < 0) {
1018 logerror("socket");
1019 break;
1020 }
1021 f->f_type = F_FORW;
1022 break;
1023
1024 case '/':
1025 (void) strcpy(f->f_un.f_fname, p);
1026 if ((f->f_file = open(p, O_WRONLY|O_APPEND)) < 0) {
1027 logerror(p);
1028 break;
1029 }
1030 if (isatty(f->f_file)) {
1031 f->f_type = F_TTY;
1032 untty();
a49a6aba 1033 }
64b300b4
EA
1034 else
1035 f->f_type = F_FILE;
1036 if (strcmp(p, ctty) == 0)
1037 f->f_type = F_CONSOLE;
1038 break;
1039
1040 case '*':
1041 f->f_type = F_WALL;
1042 break;
1043
1044 default:
1045 for (i = 0; i < MAXUNAMES && *p; i++) {
1046 for (q = p; *q && *q != ','; )
1047 q++;
1048 (void) strncpy(f->f_un.f_uname[i], p, UNAMESZ);
1049 if ((q - p) > UNAMESZ)
1050 f->f_un.f_uname[i][UNAMESZ] = '\0';
1051 else
1052 f->f_un.f_uname[i][q - p] = '\0';
1053 while (*q == ',' || *q == ' ')
1054 q++;
1055 p = q;
1056 }
1057 f->f_type = F_USERS;
1058 break;
a49a6aba 1059 }
64b300b4
EA
1060}
1061
1062
1063/*
1064 * Decode a symbolic name to a numeric value
1065 */
1066
1067decode(name, codetab)
1068 char *name;
1069 struct code *codetab;
1070{
1071 register struct code *c;
1072 register char *p;
1073 char buf[40];
1074
1075 if (isdigit(*name))
1076 return (atoi(name));
1077
1078 (void) strcpy(buf, name);
1079 for (p = buf; *p; p++)
1080 if (isupper(*p))
1081 *p = tolower(*p);
1082 for (c = codetab; c->c_name; c++)
1083 if (!strcmp(buf, c->c_name))
1084 return (c->c_val);
a49a6aba 1085
64b300b4 1086 return (-1);
a49a6aba 1087}