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