|
|
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
6: * provided that the above copyright notice and this paragraph are
7: * duplicated in all such forms and that any documentation,
8: * advertising materials, and other materials related to such
9: * distribution and use acknowledge that the software was developed
10: * by the University of California, Berkeley. The name of the
11: * University may not be used to endorse or promote products derived
12: * from this software without specific prior written permission.
13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16: */
17:
18: #ifndef lint
19: char copyright[] =
20: "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
21: All rights reserved.\n";
22: #endif /* not lint */
23:
24: #ifndef lint
25: static char sccsid[] = "@(#)syslogd.c 5.24 (Berkeley) 6/18/88";
26: #endif /* not lint */
27:
28: /*
29: * syslogd -- log system messages
30: *
31: * This program implements a system log. It takes a series of lines.
32: * Each line may have a priority, signified as "<n>" as
33: * the first characters of the line. If this is
34: * not present, a default priority is used.
35: *
36: * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will
37: * cause it to reread its configuration file.
38: *
39: * Defined Constants:
40: *
41: * MAXLINE -- the maximimum line length that can be handled.
42: * DEFUPRI -- the default priority for user messages
43: * DEFSPRI -- the default priority for kernel messages
44: *
45: * Author: Eric Allman
46: * extensive changes by Ralph Campbell
47: * more extensive changes by Eric Allman (again)
48: */
49:
50: #define MAXLINE 1024 /* maximum line length */
51: #define MAXSVLINE 120 /* maximum saved line length */
52: #define DEFUPRI (LOG_USER|LOG_NOTICE)
53: #define DEFSPRI (LOG_KERN|LOG_CRIT)
54: #define TIMERINTVL 30 /* interval for checking flush, mark */
55:
56: #include <stdio.h>
57: #include <utmp.h>
58: #include <ctype.h>
59: #include <strings.h>
60: #include <setjmp.h>
61:
62: #include <sys/syslog.h>
63: #include <sys/param.h>
64: #include <sys/errno.h>
65: #include <sys/ioctl.h>
66: #include <sys/stat.h>
67: #include <sys/wait.h>
68: #include <sys/socket.h>
69: #include <sys/file.h>
70: #include <sys/msgbuf.h>
71: #include <sys/uio.h>
72: #include <sys/un.h>
73: #include <sys/time.h>
74: #include <sys/resource.h>
75: #include <sys/signal.h>
76:
77: #include <netinet/in.h>
78: #include <netdb.h>
79:
80: #define CTTY "/dev/console"
81: char *LogName = "/dev/log";
82: char *ConfFile = "/etc/syslog.conf";
83: char *PidFile = "/etc/syslog.pid";
84: char ctty[] = CTTY;
85:
86: #define FDMASK(fd) (1 << (fd))
87:
88: #define dprintf if (Debug) printf
89:
90: #define UNAMESZ 8 /* length of a login name */
91: #define MAXUNAMES 20 /* maximum number of user names */
92: #define MAXFNAME 200 /* max file pathname length */
93:
94: #define NOPRI 0x10 /* the "no priority" priority */
95: #define LOG_MARK LOG_MAKEPRI(LOG_NFACILITIES, 0) /* mark "facility" */
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][UNAMESZ+1];
119: struct {
120: char f_hname[MAXHOSTNAMELEN+1];
121: struct sockaddr_in f_addr;
122: } f_forw; /* forwarding address */
123: char f_fname[MAXFNAME];
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, sys_nerr;
174: extern char *sys_errlist[];
175: extern char *ctime(), *index(), *calloc();
176:
177: main(argc, argv)
178: int argc;
179: char **argv;
180: {
181: register int i;
182: register char *p;
183: int funix, inetm, fklog, klogm, len;
184: struct sockaddr_un sunx, fromunix;
185: struct sockaddr_in sin, frominet;
186: FILE *fp;
187: char line[MSG_BSIZE + 1];
188: extern int die(), domark(), reapchild();
189:
190: while (--argc > 0) {
191: p = *++argv;
192: if (p[0] != '-')
193: usage();
194: switch (p[1]) {
195: case 'f': /* configuration file */
196: if (p[2] != '\0')
197: ConfFile = &p[2];
198: break;
199:
200: case 'd': /* debug */
201: Debug++;
202: break;
203:
204: case 'p': /* path */
205: if (p[2] != '\0')
206: LogName = &p[2];
207: break;
208:
209: case 'm': /* mark interval */
210: if (p[2] != '\0')
211: MarkInterval = atoi(&p[2]) * 60;
212: break;
213:
214: default:
215: usage();
216: }
217: }
218:
219: if (!Debug) {
220: if (fork())
221: exit(0);
222: for (i = 0; i < 10; i++)
223: (void) close(i);
224: (void) open("/", 0);
225: (void) dup2(0, 1);
226: (void) dup2(0, 2);
227: untty();
228: } else
229: setlinebuf(stdout);
230:
231: consfile.f_type = F_CONSOLE;
232: (void) strcpy(consfile.f_un.f_fname, ctty);
233: (void) gethostname(LocalHostName, sizeof LocalHostName);
234: if (p = index(LocalHostName, '.')) {
235: *p++ = '\0';
236: LocalDomain = p;
237: }
238: else
239: LocalDomain = "";
240: (void) signal(SIGTERM, die);
241: (void) signal(SIGINT, Debug ? die : SIG_IGN);
242: (void) signal(SIGQUIT, Debug ? die : SIG_IGN);
243: (void) signal(SIGCHLD, reapchild);
244: (void) signal(SIGALRM, domark);
245: (void) alarm(TIMERINTVL);
246: (void) unlink(LogName);
247:
248: sunx.sun_family = AF_UNIX;
249: (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path);
250: funix = socket(AF_UNIX, SOCK_DGRAM, 0);
251: if (funix < 0 || bind(funix, (struct sockaddr *) &sunx,
252: sizeof(sunx.sun_family)+strlen(sunx.sun_path)) < 0 ||
253: chmod(LogName, 0666) < 0) {
254: (void) sprintf(line, "cannot create %s", LogName);
255: logerror(line);
256: dprintf("cannot create %s (%d)\n", LogName, errno);
257: die(0);
258: }
259: finet = socket(AF_INET, SOCK_DGRAM, 0);
260: if (finet >= 0) {
261: struct servent *sp;
262:
263: sp = getservbyname("syslog", "udp");
264: if (sp == NULL) {
265: errno = 0;
266: logerror("syslog/udp: unknown service");
267: die(0);
268: }
269: sin.sin_family = AF_INET;
270: sin.sin_port = LogPort = sp->s_port;
271: if (bind(finet, &sin, sizeof(sin)) < 0) {
272: logerror("bind");
273: if (!Debug)
274: die(0);
275: } else {
276: inetm = FDMASK(finet);
277: InetInuse = 1;
278: }
279: }
280: if ((fklog = open("/dev/klog", O_RDONLY)) >= 0)
281: klogm = FDMASK(fklog);
282: else {
283: dprintf("can't open /dev/klog (%d)\n", errno);
284: klogm = 0;
285: }
286:
287: /* tuck my process id away */
288: fp = fopen(PidFile, "w");
289: if (fp != NULL) {
290: fprintf(fp, "%d\n", getpid());
291: (void) fclose(fp);
292: }
293:
294: dprintf("off & running....\n");
295:
296: init();
297: (void) signal(SIGHUP, init);
298:
299: for (;;) {
300: int nfds, readfds = FDMASK(funix) | inetm | klogm;
301:
302: errno = 0;
303: dprintf("readfds = %#x\n", readfds);
304: nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL,
305: (fd_set *) NULL, (struct timeval *) NULL);
306: if (nfds == 0)
307: continue;
308: if (nfds < 0) {
309: if (errno != EINTR)
310: logerror("select");
311: continue;
312: }
313: dprintf("got a message (%d, %#x)\n", nfds, readfds);
314: if (readfds & klogm) {
315: i = read(fklog, line, sizeof(line) - 1);
316: if (i > 0) {
317: line[i] = '\0';
318: printsys(line);
319: } else if (i < 0 && errno != EINTR) {
320: logerror("klog");
321: fklog = -1;
322: klogm = 0;
323: }
324: }
325: if (readfds & FDMASK(funix)) {
326: len = sizeof fromunix;
327: i = recvfrom(funix, line, MAXLINE, 0,
328: (struct sockaddr *) &fromunix, &len);
329: if (i > 0) {
330: line[i] = '\0';
331: printline(LocalHostName, line);
332: } else if (i < 0 && errno != EINTR)
333: logerror("recvfrom unix");
334: }
335: if (readfds & inetm) {
336: len = sizeof frominet;
337: i = recvfrom(finet, line, MAXLINE, 0, &frominet, &len);
338: if (i > 0) {
339: extern char *cvthname();
340:
341: line[i] = '\0';
342: printline(cvthname(&frominet), line);
343: } else if (i < 0 && errno != EINTR)
344: logerror("recvfrom inet");
345: }
346: }
347: }
348:
349: usage()
350: {
351: fprintf(stderr, "usage: syslogd [-d] [-mmarkinterval] [-ppath] [-fconffile]\n");
352: exit(1);
353: }
354:
355: untty()
356: {
357: int i;
358:
359: if (!Debug) {
360: i = open("/dev/tty", O_RDWR);
361: if (i >= 0) {
362: (void) ioctl(i, (int) TIOCNOTTY, (char *)0);
363: (void) close(i);
364: }
365: }
366: }
367:
368: /*
369: * Take a raw input line, decode the message, and print the message
370: * on the appropriate log files.
371: */
372:
373: printline(hname, msg)
374: char *hname;
375: char *msg;
376: {
377: register char *p, *q;
378: register int c;
379: char line[MAXLINE + 1];
380: int pri;
381:
382: /* test for special codes */
383: pri = DEFUPRI;
384: p = msg;
385: if (*p == '<') {
386: pri = 0;
387: while (isdigit(*++p))
388: pri = 10 * pri + (*p - '0');
389: if (*p == '>')
390: ++p;
391: }
392: if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
393: pri = DEFUPRI;
394:
395: /* don't allow users to log kernel messages */
396: if (LOG_FAC(pri) == LOG_KERN)
397: pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
398:
399: q = line;
400:
401: while ((c = *p++ & 0177) != '\0' && c != '\n' &&
402: q < &line[sizeof(line) - 1]) {
403: if (iscntrl(c)) {
404: *q++ = '^';
405: *q++ = c ^ 0100;
406: } else
407: *q++ = c;
408: }
409: *q = '\0';
410:
411: logmsg(pri, line, hname, 0);
412: }
413:
414: /*
415: * Take a raw input line from /dev/klog, split and format similar to syslog().
416: */
417:
418: printsys(msg)
419: char *msg;
420: {
421: register char *p, *q;
422: register int c;
423: char line[MAXLINE + 1];
424: int pri, flags;
425: char *lp;
426:
427: (void) sprintf(line, "vmunix: ");
428: lp = line + strlen(line);
429: for (p = msg; *p != '\0'; ) {
430: flags = SYNC_FILE | ADDDATE; /* fsync file after write */
431: pri = DEFSPRI;
432: if (*p == '<') {
433: pri = 0;
434: while (isdigit(*++p))
435: pri = 10 * pri + (*p - '0');
436: if (*p == '>')
437: ++p;
438: } else {
439: /* kernel printf's come out on console */
440: flags |= IGN_CONS;
441: }
442: if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
443: pri = DEFSPRI;
444: q = lp;
445: while (*p != '\0' && (c = *p++) != '\n' &&
446: q < &line[MAXLINE])
447: *q++ = c;
448: *q = '\0';
449: logmsg(pri, line, LocalHostName, flags);
450: }
451: }
452:
453: time_t now;
454:
455: /*
456: * Log a message to the appropriate log files, users, etc. based on
457: * the priority.
458: */
459:
460: logmsg(pri, msg, from, flags)
461: int pri;
462: char *msg, *from;
463: int flags;
464: {
465: register struct filed *f;
466: int fac, prilev;
467: int omask, msglen;
468: char *timestamp;
469:
470: dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", pri, flags, from, msg);
471:
472: omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
473:
474: /*
475: * Check to see if msg looks non-standard.
476: */
477: msglen = strlen(msg);
478: if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
479: msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
480: flags |= ADDDATE;
481:
482: (void) time(&now);
483: if (flags & ADDDATE)
484: timestamp = ctime(&now) + 4;
485: else {
486: timestamp = msg;
487: msg += 16;
488: msglen -= 16;
489: }
490:
491: /* extract facility and priority level */
492: if (flags & MARK)
493: fac = LOG_NFACILITIES;
494: else
495: fac = LOG_FAC(pri);
496: prilev = LOG_PRI(pri);
497:
498: /* log the message to the particular outputs */
499: if (!Initialized) {
500: f = &consfile;
501: f->f_file = open(ctty, O_WRONLY);
502:
503: if (f->f_file >= 0) {
504: untty();
505: fprintlog(f, flags, (char *)NULL);
506: (void) close(f->f_file);
507: }
508: (void) sigsetmask(omask);
509: return;
510: }
511: for (f = Files; f; f = f->f_next) {
512: /* skip messages that are incorrect priority */
513: if (f->f_pmask[fac] < prilev || f->f_pmask[fac] == NOPRI)
514: continue;
515:
516: if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
517: continue;
518:
519: /* don't output marks to recently written files */
520: if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
521: continue;
522:
523: /*
524: * suppress duplicate lines to this file
525: */
526: if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
527: !strcmp(msg, f->f_prevline) &&
528: !strcmp(from, f->f_prevhost)) {
529: (void) strncpy(f->f_lasttime, timestamp, 15);
530: f->f_prevcount++;
531: dprintf("msg repeated %d times, %d sec of %d\n",
532: f->f_prevcount, now - f->f_time,
533: repeatinterval[f->f_repeatcount]);
534: /*
535: * If domark would have logged this by now,
536: * flush it now (so we don't hold isolated messages),
537: * but back off so we'll flush less often
538: * in the future.
539: */
540: if (now > REPEATTIME(f)) {
541: fprintlog(f, flags, (char *)NULL);
542: BACKOFF(f);
543: }
544: } else {
545: /* new line, save it */
546: if (f->f_prevcount)
547: fprintlog(f, 0, (char *)NULL);
548: f->f_repeatcount = 0;
549: (void) strncpy(f->f_lasttime, timestamp, 15);
550: (void) strncpy(f->f_prevhost, from,
551: sizeof(f->f_prevhost));
552: if (msglen < MAXSVLINE) {
553: f->f_prevlen = msglen;
554: f->f_prevpri = pri;
555: (void) strcpy(f->f_prevline, msg);
556: fprintlog(f, flags, (char *)NULL);
557: } else {
558: f->f_prevline[0] = 0;
559: f->f_prevlen = 0;
560: fprintlog(f, flags, msg);
561: }
562: }
563: }
564: (void) sigsetmask(omask);
565: }
566:
567: fprintlog(f, flags, msg)
568: register struct filed *f;
569: int flags;
570: char *msg;
571: {
572: struct iovec iov[6];
573: register struct iovec *v = iov;
574: register int l;
575: char line[MAXLINE + 1];
576: char repbuf[80];
577:
578: v->iov_base = f->f_lasttime;
579: v->iov_len = 15;
580: v++;
581: v->iov_base = " ";
582: v->iov_len = 1;
583: v++;
584: v->iov_base = f->f_prevhost;
585: v->iov_len = strlen(v->iov_base);
586: v++;
587: v->iov_base = " ";
588: v->iov_len = 1;
589: v++;
590: if (msg) {
591: v->iov_base = msg;
592: v->iov_len = strlen(msg);
593: } else if (f->f_prevcount > 1) {
594: (void) sprintf(repbuf, "last message repeated %d times",
595: f->f_prevcount);
596: v->iov_base = repbuf;
597: v->iov_len = strlen(repbuf);
598: } else {
599: v->iov_base = f->f_prevline;
600: v->iov_len = f->f_prevlen;
601: }
602: v++;
603:
604: dprintf("Logging to %s", TypeNames[f->f_type]);
605: f->f_time = now;
606:
607: switch (f->f_type) {
608: case F_UNUSED:
609: dprintf("\n");
610: break;
611:
612: case F_FORW:
613: dprintf(" %s\n", f->f_un.f_forw.f_hname);
614: (void) sprintf(line, "<%d>%.15s %s", f->f_prevpri,
615: iov[0].iov_base, iov[4].iov_base);
616: l = strlen(line);
617: if (l > MAXLINE)
618: l = MAXLINE;
619: if (sendto(finet, line, l, 0, &f->f_un.f_forw.f_addr,
620: sizeof f->f_un.f_forw.f_addr) != l) {
621: int e = errno;
622: (void) close(f->f_file);
623: f->f_type = F_UNUSED;
624: errno = e;
625: logerror("sendto");
626: }
627: break;
628:
629: case F_CONSOLE:
630: if (flags & IGN_CONS) {
631: dprintf(" (ignored)\n");
632: break;
633: }
634: /* FALLTHROUGH */
635:
636: case F_TTY:
637: case F_FILE:
638: dprintf(" %s\n", f->f_un.f_fname);
639: if (f->f_type != F_FILE) {
640: v->iov_base = "\r\n";
641: v->iov_len = 2;
642: } else {
643: v->iov_base = "\n";
644: v->iov_len = 1;
645: }
646: again:
647: if (writev(f->f_file, iov, 6) < 0) {
648: int e = errno;
649: (void) close(f->f_file);
650: /*
651: * Check for EBADF on TTY's due to vhangup() XXX
652: */
653: if (e == EBADF && f->f_type != F_FILE) {
654: f->f_file = open(f->f_un.f_fname, O_WRONLY|O_APPEND);
655: if (f->f_file < 0) {
656: f->f_type = F_UNUSED;
657: logerror(f->f_un.f_fname);
658: } else {
659: untty();
660: goto again;
661: }
662: } else {
663: f->f_type = F_UNUSED;
664: errno = e;
665: logerror(f->f_un.f_fname);
666: }
667: } else if (flags & SYNC_FILE)
668: (void) fsync(f->f_file);
669: break;
670:
671: case F_USERS:
672: case F_WALL:
673: dprintf("\n");
674: v->iov_base = "\r\n";
675: v->iov_len = 2;
676: wallmsg(f, iov);
677: break;
678: }
679: f->f_prevcount = 0;
680: }
681:
682: jmp_buf ttybuf;
683:
684: endtty()
685: {
686: longjmp(ttybuf, 1);
687: }
688:
689: /*
690: * WALLMSG -- Write a message to the world at large
691: *
692: * Write the specified message to either the entire
693: * world, or a list of approved users.
694: */
695:
696: wallmsg(f, iov)
697: register struct filed *f;
698: struct iovec *iov;
699: {
700: register char *p;
701: register int i;
702: int ttyf, len;
703: FILE *uf;
704: static int reenter = 0;
705: struct utmp ut;
706: char greetings[200];
707:
708: if (reenter++)
709: return;
710:
711: /* open the user login file */
712: if ((uf = fopen("/etc/utmp", "r")) == NULL) {
713: logerror("/etc/utmp");
714: reenter = 0;
715: return;
716: }
717:
718: /*
719: * Might as well fork instead of using nonblocking I/O
720: * and doing notty().
721: */
722: if (fork() == 0) {
723: (void) signal(SIGTERM, SIG_DFL);
724: (void) alarm(0);
725: (void) signal(SIGALRM, endtty);
726: (void) signal(SIGTTOU, SIG_IGN);
727: (void) sigsetmask(0);
728: (void) sprintf(greetings,
729: "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
730: iov[2].iov_base, ctime(&now));
731: len = strlen(greetings);
732:
733: /* scan the user login file */
734: while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
735: /* is this slot used? */
736: if (ut.ut_name[0] == '\0')
737: continue;
738:
739: /* should we send the message to this user? */
740: if (f->f_type == F_USERS) {
741: for (i = 0; i < MAXUNAMES; i++) {
742: if (!f->f_un.f_uname[i][0]) {
743: i = MAXUNAMES;
744: break;
745: }
746: if (strncmp(f->f_un.f_uname[i],
747: ut.ut_name, UNAMESZ) == 0)
748: break;
749: }
750: if (i >= MAXUNAMES)
751: continue;
752: }
753:
754: /* compute the device name */
755: p = "/dev/12345678";
756: strncpy(&p[5], ut.ut_line, UNAMESZ);
757:
758: if (f->f_type == F_WALL) {
759: iov[0].iov_base = greetings;
760: iov[0].iov_len = len;
761: iov[1].iov_len = 0;
762: }
763: if (setjmp(ttybuf) == 0) {
764: (void) alarm(15);
765: /* open the terminal */
766: ttyf = open(p, O_WRONLY);
767: if (ttyf >= 0) {
768: struct stat statb;
769:
770: if (fstat(ttyf, &statb) == 0 &&
771: (statb.st_mode & S_IWRITE))
772: (void) writev(ttyf, iov, 6);
773: close(ttyf);
774: ttyf = -1;
775: }
776: }
777: (void) alarm(0);
778: }
779: exit(0);
780: }
781: /* close the user login file */
782: (void) fclose(uf);
783: reenter = 0;
784: }
785:
786: reapchild()
787: {
788: union wait status;
789:
790: while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
791: ;
792: }
793:
794: /*
795: * Return a printable representation of a host address.
796: */
797: char *
798: cvthname(f)
799: struct sockaddr_in *f;
800: {
801: struct hostent *hp;
802: register char *p;
803: extern char *inet_ntoa();
804:
805: dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
806:
807: if (f->sin_family != AF_INET) {
808: dprintf("Malformed from address\n");
809: return ("???");
810: }
811: hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family);
812: if (hp == 0) {
813: dprintf("Host name for your address (%s) unknown\n",
814: inet_ntoa(f->sin_addr));
815: return (inet_ntoa(f->sin_addr));
816: }
817: if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
818: *p = '\0';
819: return (hp->h_name);
820: }
821:
822: domark()
823: {
824: register struct filed *f;
825:
826: now = time(0);
827: MarkSeq += TIMERINTVL;
828: if (MarkSeq >= MarkInterval) {
829: logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
830: MarkSeq = 0;
831: }
832:
833: for (f = Files; f; f = f->f_next) {
834: if (f->f_prevcount && now >= REPEATTIME(f)) {
835: dprintf("flush %s: repeated %d times, %d sec.\n",
836: TypeNames[f->f_type], f->f_prevcount,
837: repeatinterval[f->f_repeatcount]);
838: fprintlog(f, 0, (char *)NULL);
839: BACKOFF(f);
840: }
841: }
842: (void) alarm(TIMERINTVL);
843: }
844:
845: /*
846: * Print syslogd errors some place.
847: */
848: logerror(type)
849: char *type;
850: {
851: char buf[100];
852:
853: if (errno == 0)
854: (void) sprintf(buf, "syslogd: %s", type);
855: else if ((unsigned) errno > sys_nerr)
856: (void) sprintf(buf, "syslogd: %s: error %d", type, errno);
857: else
858: (void) sprintf(buf, "syslogd: %s: %s", type, sys_errlist[errno]);
859: errno = 0;
860: dprintf("%s\n", buf);
861: logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
862: }
863:
864: die(sig)
865: {
866: register struct filed *f;
867: char buf[100];
868:
869: for (f = Files; f != NULL; f = f->f_next) {
870: /* flush any pending output */
871: if (f->f_prevcount)
872: fprintlog(f, 0, (char *)NULL);
873: }
874: if (sig) {
875: dprintf("syslogd: exiting on signal %d\n", sig);
876: (void) sprintf(buf, "exiting on signal %d", sig);
877: errno = 0;
878: logerror(buf);
879: }
880: (void) unlink(LogName);
881: exit(0);
882: }
883:
884: /*
885: * INIT -- Initialize syslogd from configuration table
886: */
887:
888: init()
889: {
890: register int i;
891: register FILE *cf;
892: register struct filed *f, *next, **nextp;
893: register char *p;
894: char cline[BUFSIZ];
895:
896: dprintf("init\n");
897:
898: /*
899: * Close all open log files.
900: */
901: Initialized = 0;
902: for (f = Files; f != NULL; f = next) {
903: /* flush any pending output */
904: if (f->f_prevcount)
905: fprintlog(f, 0, (char *)NULL);
906:
907: switch (f->f_type) {
908: case F_FILE:
909: case F_TTY:
910: case F_CONSOLE:
911: (void) close(f->f_file);
912: break;
913: }
914: next = f->f_next;
915: free((char *) f);
916: }
917: Files = NULL;
918: nextp = &Files;
919:
920: /* open the configuration file */
921: if ((cf = fopen(ConfFile, "r")) == NULL) {
922: dprintf("cannot open %s\n", ConfFile);
923: *nextp = (struct filed *)calloc(1, sizeof(*f));
924: cfline("*.ERR\t/dev/console", *nextp);
925: (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
926: cfline("*.PANIC\t*", (*nextp)->f_next);
927: Initialized = 1;
928: return;
929: }
930:
931: /*
932: * Foreach line in the conf table, open that file.
933: */
934: f = NULL;
935: while (fgets(cline, sizeof cline, cf) != NULL) {
936: /*
937: * check for end-of-section, comments, strip off trailing
938: * spaces and newline character.
939: */
940: for (p = cline; isspace(*p); ++p);
941: if (*p == NULL || *p == '#')
942: continue;
943: for (p = index(cline, '\0'); isspace(*--p););
944: *++p = '\0';
945: f = (struct filed *)calloc(1, sizeof(*f));
946: *nextp = f;
947: nextp = &f->f_next;
948: cfline(cline, f);
949: }
950:
951: /* close the configuration file */
952: (void) fclose(cf);
953:
954: Initialized = 1;
955:
956: if (Debug) {
957: for (f = Files; f; f = f->f_next) {
958: for (i = 0; i <= LOG_NFACILITIES; i++)
959: if (f->f_pmask[i] == NOPRI)
960: printf("X ");
961: else
962: printf("%d ", f->f_pmask[i]);
963: printf("%s: ", TypeNames[f->f_type]);
964: switch (f->f_type) {
965: case F_FILE:
966: case F_TTY:
967: case F_CONSOLE:
968: printf("%s", f->f_un.f_fname);
969: break;
970:
971: case F_FORW:
972: printf("%s", f->f_un.f_forw.f_hname);
973: break;
974:
975: case F_USERS:
976: for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
977: printf("%s, ", f->f_un.f_uname[i]);
978: break;
979: }
980: printf("\n");
981: }
982: }
983:
984: logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
985: dprintf("syslogd: restarted\n");
986: }
987:
988: /*
989: * Crack a configuration file line
990: */
991:
992: struct code {
993: char *c_name;
994: int c_val;
995: };
996:
997: struct code PriNames[] = {
998: "panic", LOG_EMERG,
999: "emerg", LOG_EMERG,
1000: "alert", LOG_ALERT,
1001: "crit", LOG_CRIT,
1002: "err", LOG_ERR,
1003: "error", LOG_ERR,
1004: "warn", LOG_WARNING,
1005: "warning", LOG_WARNING,
1006: "notice", LOG_NOTICE,
1007: "info", LOG_INFO,
1008: "debug", LOG_DEBUG,
1009: "none", NOPRI,
1010: NULL, -1
1011: };
1012:
1013: struct code FacNames[] = {
1014: "kern", LOG_KERN,
1015: "user", LOG_USER,
1016: "mail", LOG_MAIL,
1017: "daemon", LOG_DAEMON,
1018: "auth", LOG_AUTH,
1019: "security", LOG_AUTH,
1020: "mark", LOG_MARK,
1021: "syslog", LOG_SYSLOG,
1022: "lpr", LOG_LPR,
1023: "news", LOG_NEWS,
1024: "uucp", LOG_UUCP,
1025: "local0", LOG_LOCAL0,
1026: "local1", LOG_LOCAL1,
1027: "local2", LOG_LOCAL2,
1028: "local3", LOG_LOCAL3,
1029: "local4", LOG_LOCAL4,
1030: "local5", LOG_LOCAL5,
1031: "local6", LOG_LOCAL6,
1032: "local7", LOG_LOCAL7,
1033: NULL, -1
1034: };
1035:
1036: cfline(line, f)
1037: char *line;
1038: register struct filed *f;
1039: {
1040: register char *p;
1041: register char *q;
1042: register int i;
1043: char *bp;
1044: int pri;
1045: struct hostent *hp;
1046: char buf[MAXLINE];
1047:
1048: dprintf("cfline(%s)\n", line);
1049:
1050: errno = 0; /* keep sys_errlist stuff out of logerror messages */
1051:
1052: /* clear out file entry */
1053: bzero((char *) f, sizeof *f);
1054: for (i = 0; i <= LOG_NFACILITIES; i++)
1055: f->f_pmask[i] = NOPRI;
1056:
1057: /* scan through the list of selectors */
1058: for (p = line; *p && *p != '\t';) {
1059:
1060: /* find the end of this facility name list */
1061: for (q = p; *q && *q != '\t' && *q++ != '.'; )
1062: continue;
1063:
1064: /* collect priority name */
1065: for (bp = buf; *q && !index("\t,;", *q); )
1066: *bp++ = *q++;
1067: *bp = '\0';
1068:
1069: /* skip cruft */
1070: while (index(", ;", *q))
1071: q++;
1072:
1073: /* decode priority name */
1074: pri = decode(buf, PriNames);
1075: if (pri < 0) {
1076: char xbuf[200];
1077:
1078: (void) sprintf(xbuf, "unknown priority name \"%s\"", buf);
1079: logerror(xbuf);
1080: return;
1081: }
1082:
1083: /* scan facilities */
1084: while (*p && !index("\t.;", *p)) {
1085: int i;
1086:
1087: for (bp = buf; *p && !index("\t,;.", *p); )
1088: *bp++ = *p++;
1089: *bp = '\0';
1090: if (*buf == '*')
1091: for (i = 0; i < LOG_NFACILITIES; i++)
1092: f->f_pmask[i] = pri;
1093: else {
1094: i = decode(buf, FacNames);
1095: if (i < 0) {
1096: char xbuf[200];
1097:
1098: (void) sprintf(xbuf, "unknown facility name \"%s\"", buf);
1099: logerror(xbuf);
1100: return;
1101: }
1102: f->f_pmask[i >> 3] = pri;
1103: }
1104: while (*p == ',' || *p == ' ')
1105: p++;
1106: }
1107:
1108: p = q;
1109: }
1110:
1111: /* skip to action part */
1112: while (*p == '\t')
1113: p++;
1114:
1115: switch (*p)
1116: {
1117: case '@':
1118: if (!InetInuse)
1119: break;
1120: (void) strcpy(f->f_un.f_forw.f_hname, ++p);
1121: hp = gethostbyname(p);
1122: if (hp == NULL) {
1123: char buf[100];
1124:
1125: (void) sprintf(buf, "unknown host %s", p);
1126: errno = 0;
1127: logerror(buf);
1128: break;
1129: }
1130: bzero((char *) &f->f_un.f_forw.f_addr,
1131: sizeof f->f_un.f_forw.f_addr);
1132: f->f_un.f_forw.f_addr.sin_family = AF_INET;
1133: f->f_un.f_forw.f_addr.sin_port = LogPort;
1134: bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
1135: f->f_type = F_FORW;
1136: break;
1137:
1138: case '/':
1139: (void) strcpy(f->f_un.f_fname, p);
1140: if ((f->f_file = open(p, O_WRONLY|O_APPEND)) < 0) {
1141: f->f_file = F_UNUSED;
1142: logerror(p);
1143: break;
1144: }
1145: if (isatty(f->f_file)) {
1146: f->f_type = F_TTY;
1147: untty();
1148: }
1149: else
1150: f->f_type = F_FILE;
1151: if (strcmp(p, ctty) == 0)
1152: f->f_type = F_CONSOLE;
1153: break;
1154:
1155: case '*':
1156: f->f_type = F_WALL;
1157: break;
1158:
1159: default:
1160: for (i = 0; i < MAXUNAMES && *p; i++) {
1161: for (q = p; *q && *q != ','; )
1162: q++;
1163: (void) strncpy(f->f_un.f_uname[i], p, UNAMESZ);
1164: if ((q - p) > UNAMESZ)
1165: f->f_un.f_uname[i][UNAMESZ] = '\0';
1166: else
1167: f->f_un.f_uname[i][q - p] = '\0';
1168: while (*q == ',' || *q == ' ')
1169: q++;
1170: p = q;
1171: }
1172: f->f_type = F_USERS;
1173: break;
1174: }
1175: }
1176:
1177:
1178: /*
1179: * Decode a symbolic name to a numeric value
1180: */
1181:
1182: decode(name, codetab)
1183: char *name;
1184: struct code *codetab;
1185: {
1186: register struct code *c;
1187: register char *p;
1188: char buf[40];
1189:
1190: if (isdigit(*name))
1191: return (atoi(name));
1192:
1193: (void) strcpy(buf, name);
1194: for (p = buf; *p; p++)
1195: if (isupper(*p))
1196: *p = tolower(*p);
1197: for (c = codetab; c->c_name; c++)
1198: if (!strcmp(buf, c->c_name))
1199: return (c->c_val);
1200:
1201: return (-1);
1202: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.