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