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