xref: /openbsd-src/usr.sbin/syslogd/syslogd.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: syslogd.c,v 1.65 2003/07/31 18:20:07 avsm Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1988, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #ifndef lint
33 static const char copyright[] =
34 "@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
35 	The Regents of the University of California.  All rights reserved.\n";
36 #endif /* not lint */
37 
38 #ifndef lint
39 #if 0
40 static const char sccsid[] = "@(#)syslogd.c	8.3 (Berkeley) 4/4/94";
41 #else
42 static const char rcsid[] = "$OpenBSD: syslogd.c,v 1.65 2003/07/31 18:20:07 avsm Exp $";
43 #endif
44 #endif /* not lint */
45 
46 /*
47  *  syslogd -- log system messages
48  *
49  * This program implements a system log. It takes a series of lines.
50  * Each line may have a priority, signified as "<n>" as
51  * the first characters of the line.  If this is
52  * not present, a default priority is used.
53  *
54  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
55  * cause it to reread its configuration file.
56  *
57  * Defined Constants:
58  *
59  * MAXLINE -- the maximum line length that can be handled.
60  * DEFUPRI -- the default priority for user messages
61  * DEFSPRI -- the default priority for kernel messages
62  *
63  * Author: Eric Allman
64  * extensive changes by Ralph Campbell
65  * more extensive changes by Eric Allman (again)
66  */
67 
68 #define	MAXLINE		1024		/* maximum line length */
69 #define	MAXSVLINE	120		/* maximum saved line length */
70 #define DEFUPRI		(LOG_USER|LOG_NOTICE)
71 #define DEFSPRI		(LOG_KERN|LOG_CRIT)
72 #define TIMERINTVL	30		/* interval for checking flush, mark */
73 #define TTYMSGTIME	1		/* timeout passed to ttymsg */
74 
75 #include <sys/param.h>
76 #include <sys/ioctl.h>
77 #include <sys/stat.h>
78 #include <sys/wait.h>
79 #include <sys/socket.h>
80 #include <sys/msgbuf.h>
81 #include <sys/uio.h>
82 #include <sys/sysctl.h>
83 #include <sys/un.h>
84 #include <sys/time.h>
85 #include <sys/resource.h>
86 
87 #include <netinet/in.h>
88 #include <netdb.h>
89 #include <arpa/inet.h>
90 
91 #include <ctype.h>
92 #include <errno.h>
93 #include <err.h>
94 #include <fcntl.h>
95 #include <paths.h>
96 #include <signal.h>
97 #include <stdio.h>
98 #include <stdlib.h>
99 #include <string.h>
100 #include <unistd.h>
101 #include <utmp.h>
102 #include <vis.h>
103 
104 #define SYSLOG_NAMES
105 #include <sys/syslog.h>
106 
107 #include "syslogd.h"
108 
109 char *ConfFile = _PATH_LOGCONF;
110 const char ctty[] = _PATH_CONSOLE;
111 
112 #define MAXUNAMES	20	/* maximum number of user names */
113 
114 
115 /*
116  * Flags to logmsg().
117  */
118 
119 #define IGN_CONS	0x001	/* don't print on console */
120 #define SYNC_FILE	0x002	/* do fsync on file after printing */
121 #define ADDDATE		0x004	/* add a date to the message */
122 #define MARK		0x008	/* this message is a mark */
123 
124 /*
125  * This structure represents the files that will have log
126  * copies printed.
127  */
128 
129 struct filed {
130 	struct	filed *f_next;		/* next in linked list */
131 	short	f_type;			/* entry type, see below */
132 	short	f_file;			/* file descriptor */
133 	time_t	f_time;			/* time this was last written */
134 	u_char	f_pmask[LOG_NFACILITIES+1];	/* priority mask */
135 	char	*f_program;		/* program this applies to */
136 	union {
137 		char	f_uname[MAXUNAMES][UT_NAMESIZE+1];
138 		struct {
139 			char	f_hname[MAXHOSTNAMELEN];
140 			struct sockaddr_in	f_addr;
141 		} f_forw;		/* forwarding address */
142 		char	f_fname[MAXPATHLEN];
143 	} f_un;
144 	char	f_prevline[MAXSVLINE];		/* last message logged */
145 	char	f_lasttime[16];			/* time of last occurrence */
146 	char	f_prevhost[MAXHOSTNAMELEN];	/* host from which recd. */
147 	int	f_prevpri;			/* pri of f_prevline */
148 	int	f_prevlen;			/* length of f_prevline */
149 	int	f_prevcount;			/* repetition cnt of prevline */
150 	int	f_repeatcount;			/* number of "repeated" msgs */
151 };
152 
153 /*
154  * Intervals at which we flush out "message repeated" messages,
155  * in seconds after previous message is logged.  After each flush,
156  * we move to the next interval until we reach the largest.
157  */
158 int	repeatinterval[] = { 30, 120, 600 };	/* # of secs before flush */
159 #define	MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
160 #define	REPEATTIME(f)	((f)->f_time + repeatinterval[(f)->f_repeatcount])
161 #define	BACKOFF(f)	{ if (++(f)->f_repeatcount > MAXREPEAT) \
162 				(f)->f_repeatcount = MAXREPEAT; \
163 			}
164 
165 /* values for f_type */
166 #define F_UNUSED	0		/* unused entry */
167 #define F_FILE		1		/* regular file */
168 #define F_TTY		2		/* terminal */
169 #define F_CONSOLE	3		/* console terminal */
170 #define F_FORW		4		/* remote machine */
171 #define F_USERS		5		/* list of users */
172 #define F_WALL		6		/* everyone logged on */
173 
174 char	*TypeNames[7] = {
175 	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
176 	"FORW",		"USERS",	"WALL"
177 };
178 
179 struct	filed *Files;
180 struct	filed consfile;
181 
182 int	Debug;			/* debug flag */
183 int	Startup = 1;		/* startup flag */
184 char	LocalHostName[MAXHOSTNAMELEN];	/* our hostname */
185 char	*LocalDomain;		/* our local domain name */
186 int	InetInuse = 0;		/* non-zero if INET sockets are being used */
187 int	finet = -1;		/* Internet datagram socket */
188 int	fklog = -1;		/* Kernel log device socket */
189 int	LogPort;		/* port number for INET connections */
190 int	Initialized = 0;	/* set when we have initialized ourselves */
191 
192 int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
193 int	MarkSeq = 0;		/* mark sequence number */
194 int	SecureMode = 1;		/* when true, speak only unix domain socks */
195 int	NoDNS = 0;		/* when true, will refrain from doing DNS lookups */
196 
197 volatile sig_atomic_t MarkSet;
198 volatile sig_atomic_t WantDie;
199 volatile sig_atomic_t DoInit;
200 
201 void	cfline(char *, struct filed *, char *);
202 void    cvthname(struct sockaddr_in *, char *, size_t);
203 int	decode(const char *, const CODE *);
204 void	dodie(int);
205 void	doinit(int);
206 void	die(int);
207 void	domark(int);
208 void	markit(void);
209 void	fprintlog(struct filed *, int, char *);
210 void	init(void);
211 void	logerror(char *);
212 void	logmsg(int, char *, char *, int);
213 void	printline(char *, char *);
214 void	printsys(char *);
215 void	reapchild(int);
216 char   *ttymsg(struct iovec *, int, char *, int);
217 void	usage(void);
218 void	wallmsg(struct filed *, struct iovec *);
219 int	getmsgbufsize(void);
220 
221 #define MAXFUNIX	21
222 
223 int nfunix = 1;
224 char *funixn[MAXFUNIX] = { _PATH_LOG };
225 int funix[MAXFUNIX];
226 
227 int
228 main(int argc, char *argv[])
229 {
230 	int ch, i, linesize, fdsrmax = 0;
231 	struct sockaddr_un sunx, fromunix;
232 	struct sockaddr_in sin, frominet;
233 	socklen_t slen, len;
234 	fd_set *fdsr = NULL;
235 	char *p, *line;
236 	char resolve[MAXHOSTNAMELEN];
237 	int lockpipe[2], nullfd = -1;
238 	FILE *fp;
239 
240 	while ((ch = getopt(argc, argv, "dnuf:m:p:a:")) != -1)
241 		switch (ch) {
242 		case 'd':		/* debug */
243 			Debug++;
244 			break;
245 		case 'f':		/* configuration file */
246 			ConfFile = optarg;
247 			break;
248 		case 'm':		/* mark interval */
249 			MarkInterval = atoi(optarg) * 60;
250 			break;
251 		case 'n':		/* don't do DNS lookups */
252 			NoDNS = 1;
253 			break;
254 		case 'p':		/* path */
255 			if (strlen(optarg) >= sizeof(sunx.sun_path)) {
256 				fprintf(stderr,
257 				    "syslogd: socket path too long, exiting\n");
258 				exit(1);
259 			} else
260 				funixn[0] = optarg;
261 			break;
262 		case 'u':		/* allow udp input port */
263 			SecureMode = 0;
264 			break;
265 		case 'a':
266 			if (nfunix >= MAXFUNIX)
267 				fprintf(stderr,
268 				    "syslogd: out of descriptors, ignoring %s\n",
269 				    optarg);
270 			else if (strlen(optarg) >= sizeof(sunx.sun_path))
271 				fprintf(stderr,
272 				    "syslogd: path too long, ignoring %s\n",
273 				    optarg);
274 			else
275 				funixn[nfunix++] = optarg;
276 			break;
277 		case '?':
278 		default:
279 			usage();
280 		}
281 	if ((argc -= optind) != 0)
282 		usage();
283 
284 	if (Debug)
285 		setlinebuf(stdout);
286 
287 	consfile.f_type = F_CONSOLE;
288 	(void)strlcpy(consfile.f_un.f_fname, ctty,
289 	    sizeof(consfile.f_un.f_fname));
290 	(void)gethostname(LocalHostName, sizeof(LocalHostName));
291 	if ((p = strchr(LocalHostName, '.')) != NULL) {
292 		*p++ = '\0';
293 		LocalDomain = p;
294 	} else
295 		LocalDomain = "";
296 
297 	linesize = getmsgbufsize();
298 	if (linesize < MAXLINE)
299 		linesize = MAXLINE;
300 	linesize++;
301 	line = malloc(linesize);
302 
303 #ifndef SUN_LEN
304 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
305 #endif
306 	for (i = 0; i < nfunix; i++) {
307 		(void)unlink(funixn[i]);
308 
309 		memset(&sunx, 0, sizeof(sunx));
310 		sunx.sun_family = AF_UNIX;
311 		(void)strlcpy(sunx.sun_path, funixn[i], sizeof(sunx.sun_path));
312 		funix[i] = socket(AF_UNIX, SOCK_DGRAM, 0);
313 		if (funix[i] < 0 ||
314 		    bind(funix[i], (struct sockaddr *)&sunx,
315 		    SUN_LEN(&sunx)) < 0 ||
316 		    chmod(funixn[i], 0666) < 0) {
317 			(void)snprintf(line, linesize, "cannot create %s",
318 			    funixn[i]);
319 			logerror(line);
320 			dprintf("cannot create %s (%d)\n", funixn[i], errno);
321 			if (i == 0)
322 				die(0);
323 		}
324 		/* double socket receive buffer size */
325 		if (getsockopt(funix[i], SOL_SOCKET, SO_RCVBUF, &len,
326 		    &slen) == 0) {
327 			len *= 2;
328 			(void)setsockopt(funix[i], SOL_SOCKET, SO_RCVBUF, &len,
329 			    slen);
330 		}
331 	}
332 	finet = socket(AF_INET, SOCK_DGRAM, 0);
333 	if (finet >= 0) {
334 		struct servent *sp;
335 
336 		sp = getservbyname("syslog", "udp");
337 		if (sp == NULL) {
338 			errno = 0;
339 			logerror("syslog/udp: unknown service");
340 			die(0);
341 		}
342 		memset(&sin, 0, sizeof(sin));
343 		sin.sin_len = sizeof(sin);
344 		sin.sin_family = AF_INET;
345 		sin.sin_port = LogPort = sp->s_port;
346 		if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
347 			logerror("bind");
348 			if (!Debug)
349 				die(0);
350 		} else {
351 			InetInuse = 1;
352 			/* double socket receive buffer size */
353 			if (getsockopt(finet, SOL_SOCKET, SO_RCVBUF, &len,
354 			    &slen) == 0) {
355 				len *= 2;
356 				(void)setsockopt(finet, SOL_SOCKET,
357 				    SO_RCVBUF, &len, slen);
358 			}
359 		}
360 	}
361 	if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0)
362 		dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
363 
364 	dprintf("off & running....\n");
365 
366 	chdir("/");
367 
368 	if (!Debug) {
369 		char c;
370 
371 		pipe(lockpipe);
372 
373 		switch(fork()) {
374 		case -1:
375 			exit(1);
376 		case 0:
377 			setsid();
378 			nullfd = open(_PATH_DEVNULL, O_RDWR);
379 			close(lockpipe[0]);
380 			break;
381 		default:
382 			close(lockpipe[1]);
383 			read(lockpipe[0], &c, 1);
384 			_exit(0);
385 		}
386 	}
387 
388 	/* tuck my process id away */
389 	if (!Debug) {
390 		fp = fopen(_PATH_LOGPID, "w");
391 		if (fp != NULL) {
392 			fprintf(fp, "%ld\n", (long)getpid());
393 			(void) fclose(fp);
394 		}
395 	}
396 
397 	/* Privilege separation begins here */
398 	if (priv_init(ConfFile, NoDNS, lockpipe[1], nullfd, argv) < 0)
399 		errx(1, "unable to privsep");
400 
401 	/* Process is now unprivileged and inside a chroot */
402 	init();
403 
404 	Startup = 0;
405 
406 	if (!Debug) {
407 		dup2(nullfd, STDIN_FILENO);
408 		dup2(nullfd, STDOUT_FILENO);
409 		dup2(nullfd, STDERR_FILENO);
410 		if (nullfd > 2)
411 			close(nullfd);
412 		close(lockpipe[1]);
413 	}
414 
415 	/*
416 	 * Signal to the priv process that the initial config parsing is done
417 	 * so that it will reject any future attempts to open more files
418 	 */
419 	priv_config_parse_done();
420 
421 	(void)signal(SIGHUP, doinit);
422 	(void)signal(SIGTERM, dodie);
423 	(void)signal(SIGINT, Debug ? dodie : SIG_IGN);
424 	(void)signal(SIGQUIT, Debug ? dodie : SIG_IGN);
425 	(void)signal(SIGCHLD, reapchild);
426 	(void)signal(SIGALRM, domark);
427 	(void)alarm(TIMERINTVL);
428 
429 	if (fklog != -1 && fklog > fdsrmax)
430 		fdsrmax = fklog;
431 	if (finet != -1 && finet > fdsrmax)
432 		fdsrmax = finet;
433 	for (i = 0; i < nfunix; i++) {
434 		if (funix[i] != -1 && funix[i] > fdsrmax)
435 			fdsrmax = funix[i];
436 	}
437 
438 	fdsr = (fd_set *)calloc(howmany(fdsrmax+1, NFDBITS),
439 	    sizeof(fd_mask));
440 	if (fdsr == NULL)
441 		errx(1, "calloc fd_set");
442 
443 	for (;;) {
444 		if (MarkSet)
445 			markit();
446 		if (WantDie)
447 			die(WantDie);
448 
449 		if (DoInit) {
450 			init();
451 			DoInit = 0;
452 		}
453 
454 		bzero(fdsr, howmany(fdsrmax+1, NFDBITS) *
455 		    sizeof(fd_mask));
456 
457 		if (fklog != -1)
458 			FD_SET(fklog, fdsr);
459 		if (finet != -1)
460 			FD_SET(finet, fdsr);
461 		for (i = 0; i < nfunix; i++) {
462 			if (funix[i] != -1)
463 				FD_SET(funix[i], fdsr);
464 		}
465 
466 		switch (select(fdsrmax+1, fdsr, NULL, NULL, NULL)) {
467 		case 0:
468 			continue;
469 		case -1:
470 			if (errno != EINTR)
471 				logerror("select");
472 			continue;
473 		}
474 
475 		if (fklog != -1 && FD_ISSET(fklog, fdsr)) {
476 			i = read(fklog, line, linesize - 1);
477 			if (i > 0) {
478 				line[i] = '\0';
479 				printsys(line);
480 			} else if (i < 0 && errno != EINTR) {
481 				logerror("klog");
482 				fklog = -1;
483 			}
484 		}
485 		if (finet != -1 && FD_ISSET(finet, fdsr)) {
486 			len = sizeof(frominet);
487 			i = recvfrom(finet, line, MAXLINE, 0,
488 			    (struct sockaddr *)&frominet, &len);
489 			if (SecureMode) {
490 				/* silently drop it */
491 			} else {
492 				if (i > 0) {
493 					line[i] = '\0';
494 					cvthname(&frominet, resolve, sizeof resolve);
495 					dprintf("cvthname res: %s\n", resolve);
496 					printline(resolve, line);
497 				} else if (i < 0 && errno != EINTR)
498 					logerror("recvfrom inet");
499 			}
500 		}
501 
502 		for (i = 0; i < nfunix; i++) {
503 			if (funix[i] != -1 && FD_ISSET(funix[i], fdsr)) {
504 				len = sizeof(fromunix);
505 				len = recvfrom(funix[i], line, MAXLINE, 0,
506 				    (struct sockaddr *)&fromunix, &len);
507 				if (len > 0) {
508 					line[len] = '\0';
509 					printline(LocalHostName, line);
510 				} else if (len < 0 && errno != EINTR)
511 					logerror("recvfrom unix");
512 			}
513 		}
514 	}
515 	if (fdsr)
516 		free(fdsr);
517 }
518 
519 void
520 usage(void)
521 {
522 
523 	(void)fprintf(stderr,
524 	    "usage: syslogd [-dnu] [-f config_file] [-m mark_interval] "
525 	    "[-a path] [-p log_socket]\n");
526 	exit(1);
527 }
528 
529 /*
530  * Take a raw input line, decode the message, and print the message
531  * on the appropriate log files.
532  */
533 void
534 printline(char *hname, char *msg)
535 {
536 	int pri;
537 	char *p, *q, line[MAXLINE + 1];
538 
539 	/* test for special codes */
540 	pri = DEFUPRI;
541 	p = msg;
542 	if (*p == '<') {
543 		pri = 0;
544 		while (isdigit(*++p))
545 			pri = 10 * pri + (*p - '0');
546 		if (*p == '>')
547 			++p;
548 	}
549 	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
550 		pri = DEFUPRI;
551 
552 	/*
553 	 * Don't allow users to log kernel messages.
554 	 * NOTE: since LOG_KERN == 0 this will also match
555 	 * messages with no facility specified.
556 	 */
557 	if (LOG_FAC(pri) == LOG_KERN)
558 		pri = LOG_USER | LOG_PRI(pri);
559 
560 	for (q = line; *p && q < &line[sizeof(line) - 4]; p++) {
561 		if (*p == '\n')
562 			*q++ = ' ';
563 		else
564 			q = vis(q, *p, 0, 0);
565 	}
566 	*q = '\0';
567 
568 	logmsg(pri, line, hname, 0);
569 }
570 
571 /*
572  * Take a raw input line from /dev/klog, split and format similar to syslog().
573  */
574 void
575 printsys(char *msg)
576 {
577 	int c, pri, flags;
578 	char *lp, *p, *q, line[MAXLINE + 1];
579 
580 	(void)snprintf(line, sizeof line, "%s: ", _PATH_UNIX);
581 	lp = line + strlen(line);
582 	for (p = msg; *p != '\0'; ) {
583 		flags = SYNC_FILE | ADDDATE;	/* fsync file after write */
584 		pri = DEFSPRI;
585 		if (*p == '<') {
586 			pri = 0;
587 			while (isdigit(*++p))
588 				pri = 10 * pri + (*p - '0');
589 			if (*p == '>')
590 				++p;
591 		} else {
592 			/* kernel printf's come out on console */
593 			flags |= IGN_CONS;
594 		}
595 		if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
596 			pri = DEFSPRI;
597 
598 		q = lp;
599 		while (*p && (c = *p++) != '\n' && q < &line[sizeof(line) - 4])
600 			q = vis(q, c, 0, 0);
601 
602 		logmsg(pri, line, LocalHostName, flags);
603 	}
604 }
605 
606 time_t	now;
607 
608 /*
609  * Log a message to the appropriate log files, users, etc. based on
610  * the priority.
611  */
612 void
613 logmsg(int pri, char *msg, char *from, int flags)
614 {
615 	struct filed *f;
616 	int fac, msglen, prilev, i;
617 	sigset_t mask, omask;
618 	char *timestamp;
619 	char prog[NAME_MAX+1];
620 
621 	dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n",
622 	    pri, flags, from, msg);
623 
624 	sigemptyset(&mask);
625 	sigaddset(&mask, SIGALRM);
626 	sigaddset(&mask, SIGHUP);
627 	sigprocmask(SIG_BLOCK, &mask, &omask);
628 
629 	/*
630 	 * Check to see if msg looks non-standard.
631 	 */
632 	msglen = strlen(msg);
633 	if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
634 	    msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
635 		flags |= ADDDATE;
636 
637 	(void)time(&now);
638 	if (flags & ADDDATE)
639 		timestamp = ctime(&now) + 4;
640 	else {
641 		timestamp = msg;
642 		msg += 16;
643 		msglen -= 16;
644 	}
645 
646 	/* extract facility and priority level */
647 	if (flags & MARK)
648 		fac = LOG_NFACILITIES;
649 	else
650 		fac = LOG_FAC(pri);
651 	prilev = LOG_PRI(pri);
652 
653 	/* extract program name */
654 	for(i = 0; i < NAME_MAX; i++) {
655 		if (!isalnum(msg[i]))
656 			break;
657 		prog[i] = msg[i];
658 	}
659 	prog[i] = 0;
660 
661 	/* log the message to the particular outputs */
662 	if (!Initialized) {
663 		f = &consfile;
664 		f->f_file = priv_open_tty(ctty);
665 
666 		if (f->f_file >= 0) {
667 			fprintlog(f, flags, msg);
668 			(void)close(f->f_file);
669 			f->f_file = -1;
670 		}
671 		(void)sigprocmask(SIG_SETMASK, &omask, NULL);
672 		return;
673 	}
674 	for (f = Files; f; f = f->f_next) {
675 		/* skip messages that are incorrect priority */
676 		if (f->f_pmask[fac] < prilev ||
677 		    f->f_pmask[fac] == INTERNAL_NOPRI)
678 			continue;
679 
680 		/* skip messages with the incorrect program name */
681 		if (f->f_program)
682 			if (strcmp(prog, f->f_program) != 0)
683 				continue;
684 
685 		if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
686 			continue;
687 
688 		/* don't output marks to recently written files */
689 		if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
690 			continue;
691 
692 		/*
693 		 * suppress duplicate lines to this file
694 		 */
695 		if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
696 		    !strcmp(msg, f->f_prevline) &&
697 		    !strcmp(from, f->f_prevhost)) {
698 			strlcpy(f->f_lasttime, timestamp, 16);
699 			f->f_prevcount++;
700 			dprintf("msg repeated %d times, %ld sec of %d\n",
701 			    f->f_prevcount, (long)(now - f->f_time),
702 			    repeatinterval[f->f_repeatcount]);
703 			/*
704 			 * If domark would have logged this by now,
705 			 * flush it now (so we don't hold isolated messages),
706 			 * but back off so we'll flush less often
707 			 * in the future.
708 			 */
709 			if (now > REPEATTIME(f)) {
710 				fprintlog(f, flags, (char *)NULL);
711 				BACKOFF(f);
712 			}
713 		} else {
714 			/* new line, save it */
715 			if (f->f_prevcount)
716 				fprintlog(f, 0, (char *)NULL);
717 			f->f_repeatcount = 0;
718 			f->f_prevpri = pri;
719 			strlcpy(f->f_lasttime, timestamp, 16);
720 			strlcpy(f->f_prevhost, from,
721 			    sizeof(f->f_prevhost));
722 			if (msglen < MAXSVLINE) {
723 				f->f_prevlen = msglen;
724 				strlcpy(f->f_prevline, msg, sizeof(f->f_prevline));
725 				fprintlog(f, flags, (char *)NULL);
726 			} else {
727 				f->f_prevline[0] = 0;
728 				f->f_prevlen = 0;
729 				fprintlog(f, flags, msg);
730 			}
731 		}
732 	}
733 	(void)sigprocmask(SIG_SETMASK, &omask, NULL);
734 }
735 
736 void
737 fprintlog(struct filed *f, int flags, char *msg)
738 {
739 	struct iovec iov[6];
740 	struct iovec *v;
741 	int l;
742 	char line[MAXLINE + 1], repbuf[80], greetings[500];
743 
744 	v = iov;
745 	if (f->f_type == F_WALL) {
746 		if ((l = snprintf(greetings, sizeof(greetings),
747 		    "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
748 		    f->f_prevhost, ctime(&now))) >= sizeof(greetings) ||
749 		    l == -1)
750 			l = strlen(greetings);
751 		v->iov_base = greetings;
752 		v->iov_len = l;
753 		v++;
754 		v->iov_base = "";
755 		v->iov_len = 0;
756 		v++;
757 	} else {
758 		v->iov_base = f->f_lasttime;
759 		v->iov_len = 15;
760 		v++;
761 		v->iov_base = " ";
762 		v->iov_len = 1;
763 		v++;
764 	}
765 	v->iov_base = f->f_prevhost;
766 	v->iov_len = strlen(v->iov_base);
767 	v++;
768 	v->iov_base = " ";
769 	v->iov_len = 1;
770 	v++;
771 
772 	if (msg) {
773 		v->iov_base = msg;
774 		v->iov_len = strlen(msg);
775 	} else if (f->f_prevcount > 1) {
776 		if ((l = snprintf(repbuf, sizeof(repbuf),
777 		    "last message repeated %d times", f->f_prevcount)) >=
778 		    sizeof(repbuf) || l == -1)
779 			l = strlen(repbuf);
780 		v->iov_base = repbuf;
781 		v->iov_len = l;
782 	} else {
783 		v->iov_base = f->f_prevline;
784 		v->iov_len = f->f_prevlen;
785 	}
786 	v++;
787 
788 	dprintf("Logging to %s", TypeNames[f->f_type]);
789 	f->f_time = now;
790 
791 	switch (f->f_type) {
792 	case F_UNUSED:
793 		dprintf("\n");
794 		break;
795 
796 	case F_FORW:
797 		dprintf(" %s\n", f->f_un.f_forw.f_hname);
798 		if ((l = snprintf(line, sizeof(line), "<%d>%.15s %s",
799 		    f->f_prevpri, (char *)iov[0].iov_base,
800 		    (char *)iov[4].iov_base)) >= sizeof(line) || l == -1)
801 			l = strlen(line);
802 		if (sendto(finet, line, l, 0,
803 		    (struct sockaddr *)&f->f_un.f_forw.f_addr,
804 		    sizeof(f->f_un.f_forw.f_addr)) != l) {
805 			f->f_type = F_UNUSED;
806 			logerror("sendto");
807 		}
808 		break;
809 
810 	case F_CONSOLE:
811 		if (flags & IGN_CONS) {
812 			dprintf(" (ignored)\n");
813 			break;
814 		}
815 		/* FALLTHROUGH */
816 
817 	case F_TTY:
818 	case F_FILE:
819 		dprintf(" %s\n", f->f_un.f_fname);
820 		if (f->f_type != F_FILE) {
821 			v->iov_base = "\r\n";
822 			v->iov_len = 2;
823 		} else {
824 			v->iov_base = "\n";
825 			v->iov_len = 1;
826 		}
827 	again:
828 		if (writev(f->f_file, iov, 6) < 0) {
829 			int e = errno;
830 			(void)close(f->f_file);
831 			/*
832 			 * Check for errors on TTY's due to loss of tty
833 			 */
834 			if (e == EAGAIN) {
835 				/*
836 				 * Silently drop messages on blocked write.
837 				 * This can happen when logging to a locked tty.
838 				 */
839 				break;
840 			} else if ((e == EIO || e == EBADF) &&
841 			    f->f_type != F_FILE) {
842 				f->f_file = priv_open_tty(f->f_un.f_fname);
843 				if (f->f_file < 0) {
844 					f->f_type = F_UNUSED;
845 					logerror(f->f_un.f_fname);
846 				} else
847 					goto again;
848 			} else {
849 				f->f_type = F_UNUSED;
850 				f->f_file = -1;
851 				errno = e;
852 				logerror(f->f_un.f_fname);
853 			}
854 		} else if (flags & SYNC_FILE)
855 			(void)fsync(f->f_file);
856 		break;
857 
858 	case F_USERS:
859 	case F_WALL:
860 		dprintf("\n");
861 		v->iov_base = "\r\n";
862 		v->iov_len = 2;
863 		wallmsg(f, iov);
864 		break;
865 	}
866 	f->f_prevcount = 0;
867 }
868 
869 /*
870  *  WALLMSG -- Write a message to the world at large
871  *
872  *	Write the specified message to either the entire
873  *	world, or a list of approved users.
874  */
875 void
876 wallmsg(struct filed *f, struct iovec *iov)
877 {
878 	struct utmp ut;
879 	char line[sizeof(ut.ut_line) + 1], *p;
880 	static int reenter;			/* avoid calling ourselves */
881 	FILE *uf;
882 	int i;
883 
884 	if (reenter++)
885 		return;
886 	if ((uf = priv_open_utmp()) == NULL) {
887 		logerror(_PATH_UTMP);
888 		reenter = 0;
889 		return;
890 	}
891 	/* NOSTRICT */
892 	while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
893 		if (ut.ut_name[0] == '\0')
894 			continue;
895 		/* must use strncpy since ut_* may not be NUL terminated */
896 		strncpy(line, ut.ut_line, sizeof(line) - 1);
897 		line[sizeof(line) - 1] = '\0';
898 		if (f->f_type == F_WALL) {
899 			if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) != NULL) {
900 				errno = 0;	/* already in msg */
901 				logerror(p);
902 			}
903 			continue;
904 		}
905 		/* should we send the message to this user? */
906 		for (i = 0; i < MAXUNAMES; i++) {
907 			if (!f->f_un.f_uname[i][0])
908 				break;
909 			if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
910 			    UT_NAMESIZE)) {
911 				if ((p = ttymsg(iov, 6, line, TTYMSGTIME))
912 								!= NULL) {
913 					errno = 0;	/* already in msg */
914 					logerror(p);
915 				}
916 				break;
917 			}
918 		}
919 	}
920 	(void)fclose(uf);
921 	reenter = 0;
922 }
923 
924 void
925 reapchild(int signo)
926 {
927 	int save_errno = errno;
928 	int status;
929 
930 	while (waitpid(-1, &status, WNOHANG) > 0)
931 		;
932 	errno = save_errno;
933 }
934 
935 /*
936  * Return a printable representation of a host address.
937  */
938 void
939 cvthname(struct sockaddr_in *f, char *result, size_t res_len)
940 {
941 	sigset_t omask, nmask;
942 	char *p, *ip;
943 	int ret_len;
944 
945 	if (f->sin_family != AF_INET) {
946 		dprintf("Malformed from address\n");
947 		strlcpy(result, "???", res_len);
948 		return;
949 	}
950 
951 	ip = inet_ntoa(f->sin_addr);
952 	dprintf("cvthname(%s)\n", ip);
953 	if (NoDNS) {
954 		strlcpy(result, ip, res_len);
955 		return;
956 	}
957 
958 	sigemptyset(&nmask);
959 	sigaddset(&nmask, SIGHUP);
960 	sigprocmask(SIG_BLOCK, &nmask, &omask);
961 
962 	ret_len = priv_gethostbyaddr((char *)&f->sin_addr,
963 		sizeof(struct in_addr), f->sin_family, result, res_len);
964 
965 	sigprocmask(SIG_SETMASK, &omask, NULL);
966 	if (ret_len == 0) {
967 		dprintf("Host name for your address (%s) unknown\n", ip);
968 		strlcpy(result, ip, res_len);
969 	} else if ((p = strchr(result, '.')) && strcmp(p + 1, LocalDomain) == 0)
970 		*p = '\0';
971 }
972 
973 void
974 dodie(int signo)
975 {
976 	WantDie = signo;
977 }
978 
979 void
980 domark(int signo)
981 {
982 	MarkSet = 1;
983 }
984 
985 void
986 doinit(int signo)
987 {
988 	DoInit = 1;
989 }
990 
991 /*
992  * Print syslogd errors some place.
993  */
994 void
995 logerror(char *type)
996 {
997 	char buf[100];
998 
999 	if (errno)
1000 		(void)snprintf(buf, sizeof(buf), "syslogd: %s: %s",
1001 		    type, strerror(errno));
1002 	else
1003 		(void)snprintf(buf, sizeof(buf), "syslogd: %s", type);
1004 	errno = 0;
1005 	dprintf("%s\n", buf);
1006 	if (Startup)
1007 		fprintf(stderr, "%s\n", buf);
1008 	else
1009 		logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
1010 }
1011 
1012 void
1013 die(int signo)
1014 {
1015 	struct filed *f;
1016 	int was_initialized = Initialized;
1017 	char buf[100];
1018 
1019 	Initialized = 0;		/* Don't log SIGCHLDs */
1020 	alarm(0);
1021 	for (f = Files; f != NULL; f = f->f_next) {
1022 		/* flush any pending output */
1023 		if (f->f_prevcount)
1024 			fprintlog(f, 0, (char *)NULL);
1025 	}
1026 	Initialized = was_initialized;
1027 	if (signo) {
1028 		dprintf("syslogd: exiting on signal %d\n", signo);
1029 		(void)snprintf(buf, sizeof buf, "exiting on signal %d", signo);
1030 		errno = 0;
1031 		logerror(buf);
1032 	}
1033 	dprintf("[unpriv] syslogd child about to exit\n");
1034 	exit(0);
1035 }
1036 
1037 /*
1038  *  INIT -- Initialize syslogd from configuration table
1039  */
1040 void
1041 init(void)
1042 {
1043 	char cline[LINE_MAX], prog[NAME_MAX+1], *p;
1044 	struct filed *f, *next, **nextp;
1045 	FILE *cf;
1046 	int i;
1047 
1048 	dprintf("init\n");
1049 
1050 	/* If config file has been modified, then just die to restart */
1051 	if (priv_config_modified()) {
1052 		dprintf("config file changed: dying\n");
1053 		die(0);
1054 	}
1055 
1056 	/*
1057 	 *  Close all open log files.
1058 	 */
1059 	Initialized = 0;
1060 	for (f = Files; f != NULL; f = next) {
1061 		/* flush any pending output */
1062 		if (f->f_prevcount)
1063 			fprintlog(f, 0, (char *)NULL);
1064 
1065 		switch (f->f_type) {
1066 		case F_FILE:
1067 		case F_TTY:
1068 		case F_CONSOLE:
1069 			(void)close(f->f_file);
1070 			break;
1071 		case F_FORW:
1072 			break;
1073 		}
1074 		next = f->f_next;
1075 		if (f->f_program)
1076 			free(f->f_program);
1077 		free((char *)f);
1078 	}
1079 	Files = NULL;
1080 	nextp = &Files;
1081 
1082 	/* open the configuration file */
1083 	if ((cf = priv_open_config()) == NULL) {
1084 		dprintf("cannot open %s\n", ConfFile);
1085 		*nextp = (struct filed *)calloc(1, sizeof(*f));
1086 		cfline("*.ERR\t/dev/console", *nextp, "*");
1087 		(*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f));
1088 		cfline("*.PANIC\t*", (*nextp)->f_next, "*");
1089 		Initialized = 1;
1090 		return;
1091 	}
1092 
1093 	/*
1094 	 *  Foreach line in the conf table, open that file.
1095 	 */
1096 	f = NULL;
1097 	strlcpy(prog, "*", sizeof(prog));
1098 	while (fgets(cline, sizeof(cline), cf) != NULL) {
1099 		/*
1100 		 * check for end-of-section, comments, strip off trailing
1101 		 * spaces and newline character. !prog is treated
1102 		 * specially: the following lines apply only to that program.
1103 		 */
1104 		for (p = cline; isspace(*p); ++p)
1105 			continue;
1106 		if (*p == '\0' || *p == '#')
1107 			continue;
1108 		if (*p == '!') {
1109 			p++;
1110 			while (isspace(*p))
1111 				p++;
1112 			if (!*p) {
1113 				strlcpy(prog, "*", sizeof(prog));
1114 				continue;
1115 			}
1116 			for (i = 0; i < NAME_MAX; i++) {
1117 				if (!isalnum(p[i]))
1118 					break;
1119 				prog[i] = p[i];
1120 			}
1121 			prog[i] = 0;
1122 			continue;
1123 		}
1124 		p = cline + strlen(cline);
1125 		while (p > cline)
1126 			if (!isspace(*--p)) {
1127 				p++;
1128 				break;
1129 			}
1130 		*p = '\0';
1131 		f = (struct filed *)calloc(1, sizeof(*f));
1132 		*nextp = f;
1133 		nextp = &f->f_next;
1134 		cfline(cline, f, prog);
1135 	}
1136 
1137 	/* close the configuration file */
1138 	(void)fclose(cf);
1139 
1140 	Initialized = 1;
1141 
1142 	if (Debug) {
1143 		for (f = Files; f; f = f->f_next) {
1144 			for (i = 0; i <= LOG_NFACILITIES; i++)
1145 				if (f->f_pmask[i] == INTERNAL_NOPRI)
1146 					printf("X ");
1147 				else
1148 					printf("%d ", f->f_pmask[i]);
1149 			printf("%s: ", TypeNames[f->f_type]);
1150 			switch (f->f_type) {
1151 			case F_FILE:
1152 			case F_TTY:
1153 			case F_CONSOLE:
1154 				printf("%s", f->f_un.f_fname);
1155 				break;
1156 
1157 			case F_FORW:
1158 				printf("%s", f->f_un.f_forw.f_hname);
1159 				break;
1160 
1161 			case F_USERS:
1162 				for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
1163 					printf("%s, ", f->f_un.f_uname[i]);
1164 				break;
1165 			}
1166 			if (f->f_program)
1167 				printf(" (%s)", f->f_program);
1168 			printf("\n");
1169 		}
1170 	}
1171 
1172 	logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName,
1173 	    ADDDATE);
1174 	dprintf("syslogd: restarted\n");
1175 }
1176 
1177 /*
1178  * Crack a configuration file line
1179  */
1180 void
1181 cfline(char *line, struct filed *f, char *prog)
1182 {
1183 	int i, pri, addr_len;
1184 	char *bp, *p, *q;
1185 	char buf[MAXLINE], ebuf[100];
1186 	char addr[MAXHOSTNAMELEN];
1187 
1188 	dprintf("cfline(\"%s\", f, \"%s\")\n", line, prog);
1189 
1190 	errno = 0;	/* keep strerror() stuff out of logerror messages */
1191 
1192 	/* clear out file entry */
1193 	memset(f, 0, sizeof(*f));
1194 	for (i = 0; i <= LOG_NFACILITIES; i++)
1195 		f->f_pmask[i] = INTERNAL_NOPRI;
1196 
1197 	/* save program name if any */
1198 	if (!strcmp(prog, "*"))
1199 		prog = NULL;
1200 	else {
1201 		f->f_program = calloc(1, strlen(prog)+1);
1202 		if (f->f_program)
1203 			strlcpy(f->f_program, prog, strlen(prog)+1);
1204 	}
1205 
1206 	/* scan through the list of selectors */
1207 	for (p = line; *p && *p != '\t';) {
1208 
1209 		/* find the end of this facility name list */
1210 		for (q = p; *q && *q != '\t' && *q++ != '.'; )
1211 			continue;
1212 
1213 		/* collect priority name */
1214 		for (bp = buf; *q && !strchr("\t,;", *q); )
1215 			*bp++ = *q++;
1216 		*bp = '\0';
1217 
1218 		/* skip cruft */
1219 		while (strchr(", ;", *q))
1220 			q++;
1221 
1222 		/* decode priority name */
1223 		if (*buf == '*')
1224 			pri = LOG_PRIMASK + 1;
1225 		else {
1226 			/* ignore trailing spaces */
1227 			int i;
1228 			for (i=strlen(buf)-1; i >= 0 && buf[i] == ' '; i--) {
1229 				buf[i]='\0';
1230 			}
1231 
1232 			pri = decode(buf, prioritynames);
1233 			if (pri < 0) {
1234 				(void)snprintf(ebuf, sizeof ebuf,
1235 				    "unknown priority name \"%s\"", buf);
1236 				logerror(ebuf);
1237 				return;
1238 			}
1239 		}
1240 
1241 		/* scan facilities */
1242 		while (*p && !strchr("\t.;", *p)) {
1243 			for (bp = buf; *p && !strchr("\t,;.", *p); )
1244 				*bp++ = *p++;
1245 			*bp = '\0';
1246 			if (*buf == '*')
1247 				for (i = 0; i < LOG_NFACILITIES; i++)
1248 					f->f_pmask[i] = pri;
1249 			else {
1250 				i = decode(buf, facilitynames);
1251 				if (i < 0) {
1252 					(void)snprintf(ebuf, sizeof(ebuf),
1253 					    "unknown facility name \"%s\"",
1254 					    buf);
1255 					logerror(ebuf);
1256 					return;
1257 				}
1258 				f->f_pmask[i >> 3] = pri;
1259 			}
1260 			while (*p == ',' || *p == ' ')
1261 				p++;
1262 		}
1263 
1264 		p = q;
1265 	}
1266 
1267 	/* skip to action part */
1268 	while (*p == '\t')
1269 		p++;
1270 
1271 	switch (*p) {
1272 	case '@':
1273 		if (!InetInuse)
1274 			break;
1275 		(void)strlcpy(f->f_un.f_forw.f_hname, ++p,
1276 		    sizeof(f->f_un.f_forw.f_hname));
1277 		addr_len = priv_gethostbyname(f->f_un.f_forw.f_hname,
1278 		    addr, sizeof addr);
1279 		if (addr_len < 1) {
1280 			logerror((char *)hstrerror(h_errno));
1281 			break;
1282 		}
1283 		memset(&f->f_un.f_forw.f_addr, 0,
1284 		    sizeof(f->f_un.f_forw.f_addr));
1285 		f->f_un.f_forw.f_addr.sin_len = sizeof(f->f_un.f_forw.f_addr);
1286 		f->f_un.f_forw.f_addr.sin_family = AF_INET;
1287 		f->f_un.f_forw.f_addr.sin_port = LogPort;
1288 		memmove(&f->f_un.f_forw.f_addr.sin_addr, addr, addr_len);
1289 		f->f_type = F_FORW;
1290 		break;
1291 
1292 	case '/':
1293 		(void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname));
1294 		if (strcmp(p, ctty) == 0)
1295 			f->f_file = priv_open_tty(p);
1296 		else
1297 			f->f_file = priv_open_log(p);
1298 		if (f->f_file < 0) {
1299 			f->f_type = F_UNUSED;
1300 			logerror(p);
1301 			break;
1302 		}
1303 		if (isatty(f->f_file)) {
1304 			if (strcmp(p, ctty) == 0)
1305 				f->f_type = F_CONSOLE;
1306 			else
1307 				f->f_type = F_TTY;
1308 		} else {
1309 			f->f_type = F_FILE;
1310 			/* Clear O_NONBLOCK flag on f->f_file */
1311 			if ((i = fcntl(f->f_file, F_GETFL, 0)) != -1) {
1312 				i &= ~O_NONBLOCK;
1313 				fcntl(f->f_file, F_SETFL, i);
1314 			}
1315 		}
1316 		break;
1317 
1318 	case '*':
1319 		f->f_type = F_WALL;
1320 		break;
1321 
1322 	default:
1323 		for (i = 0; i < MAXUNAMES && *p; i++) {
1324 			for (q = p; *q && *q != ','; )
1325 				q++;
1326 			(void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
1327 			if ((q - p) > UT_NAMESIZE)
1328 				f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
1329 			else
1330 				f->f_un.f_uname[i][q - p] = '\0';
1331 			while (*q == ',' || *q == ' ')
1332 				q++;
1333 			p = q;
1334 		}
1335 		f->f_type = F_USERS;
1336 		break;
1337 	}
1338 }
1339 
1340 
1341 /*
1342  * Retrieve the size of the kernel message buffer, via sysctl.
1343  */
1344 int
1345 getmsgbufsize(void)
1346 {
1347 	int msgbufsize, mib[2];
1348 	size_t size;
1349 
1350 	mib[0] = CTL_KERN;
1351 	mib[1] = KERN_MSGBUFSIZE;
1352 	size = sizeof msgbufsize;
1353 	if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) {
1354 		dprintf("couldn't get kern.msgbufsize\n");
1355 		return (0);
1356 	}
1357 	return (msgbufsize);
1358 }
1359 
1360 /*
1361  *  Decode a symbolic name to a numeric value
1362  */
1363 int
1364 decode(const char *name, const CODE *codetab)
1365 {
1366 	const CODE *c;
1367 	char *p, buf[40];
1368 
1369 	if (isdigit(*name))
1370 		return (atoi(name));
1371 
1372 	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
1373 		if (isupper(*name))
1374 			*p = tolower(*name);
1375 		else
1376 			*p = *name;
1377 	}
1378 	*p = '\0';
1379 	for (c = codetab; c->c_name; c++)
1380 		if (!strcmp(buf, c->c_name))
1381 			return (c->c_val);
1382 
1383 	return (-1);
1384 }
1385 
1386 void
1387 markit(void)
1388 {
1389 	struct filed *f;
1390 
1391 	now = time((time_t *)NULL);
1392 	MarkSeq += TIMERINTVL;
1393 	if (MarkSeq >= MarkInterval) {
1394 		logmsg(LOG_INFO, "-- MARK --",
1395 		    LocalHostName, ADDDATE|MARK);
1396 		MarkSeq = 0;
1397 	}
1398 
1399 	for (f = Files; f; f = f->f_next) {
1400 		if (f->f_prevcount && now >= REPEATTIME(f)) {
1401 			dprintf("flush %s: repeated %d times, %d sec.\n",
1402 			    TypeNames[f->f_type], f->f_prevcount,
1403 			    repeatinterval[f->f_repeatcount]);
1404 			fprintlog(f, 0, (char *)NULL);
1405 			BACKOFF(f);
1406 		}
1407 	}
1408 	MarkSet = 0;
1409 	(void)alarm(TIMERINTVL);
1410 }
1411