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