xref: /openbsd/usr.sbin/syslogd/syslogd.c (revision cca36db2)
1 /*	$OpenBSD: syslogd.c,v 1.104 2011/07/12 11:28:31 sthen 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 /*
33  *  syslogd -- log system messages
34  *
35  * This program implements a system log. It takes a series of lines.
36  * Each line may have a priority, signified as "<n>" as
37  * the first characters of the line.  If this is
38  * not present, a default priority is used.
39  *
40  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
41  * cause it to reread its configuration file.
42  *
43  * Defined Constants:
44  *
45  * MAXLINE -- the maximum line length that can be handled.
46  * DEFUPRI -- the default priority for user messages
47  * DEFSPRI -- the default priority for kernel messages
48  *
49  * Author: Eric Allman
50  * extensive changes by Ralph Campbell
51  * more extensive changes by Eric Allman (again)
52  * memory buffer logging by Damien Miller
53  */
54 
55 #define	MAXLINE		1024		/* maximum line length */
56 #define MIN_MEMBUF	(MAXLINE * 4)	/* Minimum memory buffer size */
57 #define MAX_MEMBUF	(256 * 1024)	/* Maximum memory buffer size */
58 #define MAX_MEMBUF_NAME	64		/* Max length of membuf log name */
59 #define	MAXSVLINE	120		/* maximum saved line length */
60 #define DEFUPRI		(LOG_USER|LOG_NOTICE)
61 #define DEFSPRI		(LOG_KERN|LOG_CRIT)
62 #define TIMERINTVL	30		/* interval for checking flush, mark */
63 #define TTYMSGTIME	1		/* timeout passed to ttymsg */
64 
65 #include <sys/param.h>
66 #include <sys/ioctl.h>
67 #include <sys/stat.h>
68 #include <sys/wait.h>
69 #include <sys/socket.h>
70 #include <sys/msgbuf.h>
71 #include <sys/uio.h>
72 #include <sys/sysctl.h>
73 #include <sys/un.h>
74 #include <sys/time.h>
75 #include <sys/resource.h>
76 
77 #include <netinet/in.h>
78 #include <netdb.h>
79 #include <arpa/inet.h>
80 
81 #include <ctype.h>
82 #include <errno.h>
83 #include <err.h>
84 #include <fcntl.h>
85 #include <paths.h>
86 #include <poll.h>
87 #include <signal.h>
88 #include <stdio.h>
89 #include <stdlib.h>
90 #include <string.h>
91 #include <unistd.h>
92 #include <utmp.h>
93 #include <vis.h>
94 
95 #define SYSLOG_NAMES
96 #include <sys/syslog.h>
97 
98 #include "syslogd.h"
99 
100 char *ConfFile = _PATH_LOGCONF;
101 const char ctty[] = _PATH_CONSOLE;
102 
103 #define MAXUNAMES	20	/* maximum number of user names */
104 
105 
106 /*
107  * Flags to logmsg().
108  */
109 
110 #define IGN_CONS	0x001	/* don't print on console */
111 #define SYNC_FILE	0x002	/* do fsync on file after printing */
112 #define ADDDATE		0x004	/* add a date to the message */
113 #define MARK		0x008	/* this message is a mark */
114 
115 /*
116  * This structure represents the files that will have log
117  * copies printed.
118  */
119 
120 struct filed {
121 	struct	filed *f_next;		/* next in linked list */
122 	short	f_type;			/* entry type, see below */
123 	short	f_file;			/* file descriptor */
124 	time_t	f_time;			/* time this was last written */
125 	u_char	f_pmask[LOG_NFACILITIES+1];	/* priority mask */
126 	char	*f_program;		/* program this applies to */
127 	union {
128 		char	f_uname[MAXUNAMES][UT_NAMESIZE+1];
129 		struct {
130 			char	f_hname[MAXHOSTNAMELEN];
131 			struct sockaddr_storage	f_addr;
132 		} f_forw;		/* forwarding address */
133 		char	f_fname[MAXPATHLEN];
134 		struct {
135 			char	f_mname[MAX_MEMBUF_NAME];
136 			struct ringbuf *f_rb;
137 			int	f_overflow;
138 			int	f_attached;
139 			size_t	f_len;
140 		} f_mb;		/* Memory buffer */
141 	} f_un;
142 	char	f_prevline[MAXSVLINE];		/* last message logged */
143 	char	f_lasttime[16];			/* time of last occurrence */
144 	char	f_prevhost[MAXHOSTNAMELEN];	/* host from which recd. */
145 	int	f_prevpri;			/* pri of f_prevline */
146 	int	f_prevlen;			/* length of f_prevline */
147 	int	f_prevcount;			/* repetition cnt of prevline */
148 	unsigned int f_repeatcount;		/* number of "repeated" msgs */
149 	int	f_quick;			/* abort when matched */
150 	time_t	f_lasterrtime;			/* last error was reported */
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 #define F_MEMBUF	7		/* memory buffer */
174 #define F_PIPE		8		/* pipe to external program */
175 
176 char	*TypeNames[9] = {
177 	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
178 	"FORW",		"USERS",	"WALL",		"MEMBUF",
179 	"PIPE"
180 };
181 
182 struct	filed *Files;
183 struct	filed consfile;
184 
185 int	nfunix = 1;		/* Number of Unix domain sockets requested */
186 char	*funixn[MAXFUNIX] = { _PATH_LOG }; /* Paths to Unix domain sockets */
187 int	Debug;			/* debug flag */
188 int	Startup = 1;		/* startup flag */
189 char	LocalHostName[MAXHOSTNAMELEN];	/* our hostname */
190 char	*LocalDomain;		/* our local domain name */
191 int	InetInuse = 0;		/* non-zero if INET sockets are being used */
192 int	Initialized = 0;	/* set when we have initialized ourselves */
193 
194 int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
195 int	MarkSeq = 0;		/* mark sequence number */
196 int	SecureMode = 1;		/* when true, speak only unix domain socks */
197 int	NoDNS = 0;		/* when true, will refrain from doing DNS lookups */
198 
199 char	*ctlsock_path = NULL;	/* Path to control socket */
200 
201 #define CTL_READING_CMD		1
202 #define CTL_WRITING_REPLY	2
203 #define CTL_WRITING_CONT_REPLY	3
204 int	ctl_state = 0;		/* What the control socket is up to */
205 int	membuf_drop = 0;	/* logs were dropped in continuous membuf read */
206 
207 /*
208  * Client protocol NB. all numeric fields in network byte order
209  */
210 #define CTL_VERSION		2
211 
212 /* Request */
213 struct	{
214 	u_int32_t	version;
215 #define CMD_READ	1	/* Read out log */
216 #define CMD_READ_CLEAR	2	/* Read and clear log */
217 #define CMD_CLEAR	3	/* Clear log */
218 #define CMD_LIST	4	/* List available logs */
219 #define CMD_FLAGS	5	/* Query flags only */
220 #define CMD_READ_CONT	6	/* Read out log continuously */
221 	u_int32_t	cmd;
222 	u_int32_t	lines;
223 	char		logname[MAX_MEMBUF_NAME];
224 }	ctl_cmd;
225 
226 size_t	ctl_cmd_bytes = 0;	/* number of bytes of ctl_cmd read */
227 
228 /* Reply */
229 struct ctl_reply_hdr {
230 	u_int32_t	version;
231 #define CTL_HDR_FLAG_OVERFLOW	0x01
232 	u_int32_t	flags;
233 	/* Reply text follows, up to MAX_MEMBUF long */
234 };
235 
236 #define CTL_HDR_LEN		(sizeof(struct ctl_reply_hdr))
237 #define CTL_REPLY_MAXSIZE	(CTL_HDR_LEN + MAX_MEMBUF)
238 #define CTL_REPLY_SIZE		(strlen(reply_text) + CTL_HDR_LEN)
239 
240 char	*ctl_reply = NULL;	/* Buffer for control connection reply */
241 char	*reply_text;		/* Start of reply text in buffer */
242 size_t	ctl_reply_size = 0;	/* Number of bytes used in reply */
243 size_t	ctl_reply_offset = 0;	/* Number of bytes of reply written so far */
244 
245 struct pollfd pfd[N_PFD];
246 
247 volatile sig_atomic_t MarkSet;
248 volatile sig_atomic_t WantDie;
249 volatile sig_atomic_t DoInit;
250 
251 struct filed *cfline(char *, char *);
252 void    cvthname(struct sockaddr_in *, char *, size_t);
253 int	decode(const char *, const CODE *);
254 void	dodie(int);
255 void	doinit(int);
256 void	die(int);
257 void	domark(int);
258 void	markit(void);
259 void	fprintlog(struct filed *, int, char *);
260 void	init(void);
261 void	logerror(const char *);
262 void	logmsg(int, char *, char *, int);
263 struct filed *find_dup(struct filed *);
264 void	printline(char *, char *);
265 void	printsys(char *);
266 void	reapchild(int);
267 char   *ttymsg(struct iovec *, int, char *, int);
268 void	usage(void);
269 void	wallmsg(struct filed *, struct iovec *);
270 int	getmsgbufsize(void);
271 int	unix_socket(char *, int, mode_t);
272 void	double_rbuf(int);
273 void	ctlsock_accept_handler(void);
274 void	ctlconn_read_handler(void);
275 void	ctlconn_write_handler(void);
276 void	tailify_replytext(char *, int);
277 void	logto_ctlconn(char *);
278 
279 int
280 main(int argc, char *argv[])
281 {
282 	int ch, i, linesize, fd;
283 	struct sockaddr_un fromunix;
284 	struct sockaddr_in frominet;
285 	socklen_t len;
286 	char *p, *line;
287 	char resolve[MAXHOSTNAMELEN];
288 	int lockpipe[2] = { -1, -1}, nullfd;
289 	struct addrinfo hints, *res, *res0;
290 	FILE *fp;
291 
292 	while ((ch = getopt(argc, argv, "dnuf:m:p:a:s:")) != -1)
293 		switch (ch) {
294 		case 'd':		/* debug */
295 			Debug++;
296 			break;
297 		case 'f':		/* configuration file */
298 			ConfFile = optarg;
299 			break;
300 		case 'm':		/* mark interval */
301 			MarkInterval = atoi(optarg) * 60;
302 			break;
303 		case 'n':		/* don't do DNS lookups */
304 			NoDNS = 1;
305 			break;
306 		case 'p':		/* path */
307 			funixn[0] = optarg;
308 			break;
309 		case 'u':		/* allow udp input port */
310 			SecureMode = 0;
311 			break;
312 		case 'a':
313 			if (nfunix >= MAXFUNIX)
314 				fprintf(stderr, "syslogd: "
315 				    "out of descriptors, ignoring %s\n",
316 				    optarg);
317 			else
318 				funixn[nfunix++] = optarg;
319 			break;
320 		case 's':
321 			ctlsock_path = optarg;
322 			break;
323 		default:
324 			usage();
325 		}
326 	if ((argc -= optind) != 0)
327 		usage();
328 
329 	if (Debug)
330 		setlinebuf(stdout);
331 
332 	if ((fd = nullfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
333 		logerror("Couldn't open /dev/null");
334 		die(0);
335 	}
336 	while (fd++ <= 2) {
337 		if (fcntl(fd, F_GETFL, 0) == -1)
338 			if (dup2(nullfd, fd) == -1)
339 				logerror("dup2");
340 	}
341 
342 	consfile.f_type = F_CONSOLE;
343 	(void)strlcpy(consfile.f_un.f_fname, ctty,
344 	    sizeof(consfile.f_un.f_fname));
345 	(void)gethostname(LocalHostName, sizeof(LocalHostName));
346 	if ((p = strchr(LocalHostName, '.')) != NULL) {
347 		*p++ = '\0';
348 		LocalDomain = p;
349 	} else
350 		LocalDomain = "";
351 
352 	linesize = getmsgbufsize();
353 	if (linesize < MAXLINE)
354 		linesize = MAXLINE;
355 	linesize++;
356 	if ((line = malloc(linesize)) == NULL) {
357 		logerror("Couldn't allocate line buffer");
358 		die(0);
359 	}
360 
361 	/* Clear poll array, set all fds to ignore */
362 	for (i = 0; i < N_PFD; i++) {
363 		pfd[i].fd = -1;
364 		pfd[i].events = 0;
365 	}
366 
367 	memset(&hints, 0, sizeof(hints));
368 	hints.ai_family = AF_INET;
369 	hints.ai_socktype = SOCK_DGRAM;
370 	hints.ai_protocol = IPPROTO_UDP;
371 	hints.ai_flags = AI_PASSIVE;
372 
373 	i = getaddrinfo(NULL, "syslog", &hints, &res0);
374 	if (i) {
375 		errno = 0;
376 		logerror("syslog/udp: unknown service");
377 		die(0);
378 	}
379 
380 	for (res = res0; res; res = res->ai_next) {
381 		struct pollfd *pfdp;
382 
383 		if (res->ai_family == AF_INET)
384 			pfdp = &pfd[PFD_INET];
385 		else {
386 			/*
387 			 * XXX AF_INET6 is skipped on purpose, need to
388 			 * fix '@' handling first.
389 			 */
390 			continue;
391 		}
392 
393 		if (pfdp->fd >= 0)
394 			continue;
395 
396 		fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
397 		if (fd < 0)
398 			continue;
399 
400 		if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) {
401 			logerror("bind");
402 			close(fd);
403 			if (!Debug)
404 				die(0);
405 			fd = -1;
406 			continue;
407 		}
408 
409 		InetInuse = 1;
410 		pfdp->fd = fd;
411 		if (SecureMode)
412 			shutdown(pfdp->fd, SHUT_RD);
413 		else {
414 			double_rbuf(pfdp->fd);
415 			pfdp->events = POLLIN;
416 		}
417 	}
418 
419 	freeaddrinfo(res0);
420 
421 #ifndef SUN_LEN
422 #define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
423 #endif
424 	for (i = 0; i < nfunix; i++) {
425 		if ((fd = unix_socket(funixn[i], SOCK_DGRAM, 0666)) == -1) {
426 			if (i == 0 && !Debug)
427 				die(0);
428 			continue;
429 		}
430 		double_rbuf(fd);
431 		pfd[PFD_UNIX_0 + i].fd = fd;
432 		pfd[PFD_UNIX_0 + i].events = POLLIN;
433 	}
434 
435 	if (ctlsock_path != NULL) {
436 		fd = unix_socket(ctlsock_path, SOCK_STREAM, 0600);
437 		if (fd != -1) {
438 			if (listen(fd, 16) == -1) {
439 				logerror("ctlsock listen");
440 				die(0);
441 			}
442 			pfd[PFD_CTLSOCK].fd = fd;
443 			pfd[PFD_CTLSOCK].events = POLLIN;
444 		} else if (!Debug)
445 			die(0);
446 	}
447 
448 	if ((fd = open(_PATH_KLOG, O_RDONLY, 0)) == -1) {
449 		dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
450 	} else {
451 		pfd[PFD_KLOG].fd = fd;
452 		pfd[PFD_KLOG].events = POLLIN;
453 	}
454 
455 	dprintf("off & running....\n");
456 
457 	chdir("/");
458 
459 	tzset();
460 
461 	if (!Debug) {
462 		char c;
463 
464 		pipe(lockpipe);
465 
466 		switch(fork()) {
467 		case -1:
468 			exit(1);
469 		case 0:
470 			setsid();
471 			close(lockpipe[0]);
472 			break;
473 		default:
474 			close(lockpipe[1]);
475 			read(lockpipe[0], &c, 1);
476 			_exit(0);
477 		}
478 	}
479 
480 	/* tuck my process id away */
481 	if (!Debug) {
482 		fp = fopen(_PATH_LOGPID, "w");
483 		if (fp != NULL) {
484 			fprintf(fp, "%ld\n", (long)getpid());
485 			(void) fclose(fp);
486 		}
487 	}
488 
489 	/* Privilege separation begins here */
490 	if (priv_init(ConfFile, NoDNS, lockpipe[1], nullfd, argv) < 0)
491 		errx(1, "unable to privsep");
492 
493 	/* Process is now unprivileged and inside a chroot */
494 	init();
495 
496 	Startup = 0;
497 
498 	/* Allocate ctl socket reply buffer if we have a ctl socket */
499 	if (pfd[PFD_CTLSOCK].fd != -1 &&
500 	    (ctl_reply = malloc(CTL_REPLY_MAXSIZE)) == NULL) {
501 		logerror("Couldn't allocate ctlsock reply buffer");
502 		die(0);
503 	}
504 	reply_text = ctl_reply + CTL_HDR_LEN;
505 
506 	if (!Debug) {
507 		dup2(nullfd, STDIN_FILENO);
508 		dup2(nullfd, STDOUT_FILENO);
509 		dup2(nullfd, STDERR_FILENO);
510 		if (nullfd > 2)
511 			close(nullfd);
512 		close(lockpipe[1]);
513 	}
514 
515 	/*
516 	 * Signal to the priv process that the initial config parsing is done
517 	 * so that it will reject any future attempts to open more files
518 	 */
519 	priv_config_parse_done();
520 
521 	(void)signal(SIGHUP, doinit);
522 	(void)signal(SIGTERM, dodie);
523 	(void)signal(SIGINT, Debug ? dodie : SIG_IGN);
524 	(void)signal(SIGQUIT, Debug ? dodie : SIG_IGN);
525 	(void)signal(SIGCHLD, reapchild);
526 	(void)signal(SIGALRM, domark);
527 	(void)signal(SIGPIPE, SIG_IGN);
528 	(void)alarm(TIMERINTVL);
529 
530 	logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: start", LocalHostName, ADDDATE);
531 	dprintf("syslogd: started\n");
532 
533 	for (;;) {
534 		if (MarkSet)
535 			markit();
536 		if (WantDie)
537 			die(WantDie);
538 
539 		if (DoInit) {
540 			init();
541 			DoInit = 0;
542 
543 			logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart",
544 			    LocalHostName, ADDDATE);
545 			dprintf("syslogd: restarted\n");
546 		}
547 
548 		switch (poll(pfd, PFD_UNIX_0 + nfunix, -1)) {
549 		case 0:
550 			continue;
551 		case -1:
552 			if (errno != EINTR)
553 				logerror("poll");
554 			continue;
555 		}
556 
557 		if ((pfd[PFD_KLOG].revents & POLLIN) != 0) {
558 			i = read(pfd[PFD_KLOG].fd, line, linesize - 1);
559 			if (i > 0) {
560 				line[i] = '\0';
561 				printsys(line);
562 			} else if (i < 0 && errno != EINTR) {
563 				logerror("klog");
564 				pfd[PFD_KLOG].fd = -1;
565 				pfd[PFD_KLOG].events = 0;
566 			}
567 		}
568 		if ((pfd[PFD_INET].revents & POLLIN) != 0) {
569 			len = sizeof(frominet);
570 			i = recvfrom(pfd[PFD_INET].fd, line, MAXLINE, 0,
571 			    (struct sockaddr *)&frominet, &len);
572 			if (i > 0) {
573 				line[i] = '\0';
574 				cvthname(&frominet, resolve,
575 				    sizeof resolve);
576 				dprintf("cvthname res: %s\n", resolve);
577 				printline(resolve, line);
578 			} else if (i < 0 && errno != EINTR)
579 				logerror("recvfrom inet");
580 		}
581 		if ((pfd[PFD_CTLSOCK].revents & POLLIN) != 0)
582 			ctlsock_accept_handler();
583 		if ((pfd[PFD_CTLCONN].revents & POLLIN) != 0)
584 			ctlconn_read_handler();
585 		if ((pfd[PFD_CTLCONN].revents & POLLOUT) != 0)
586 			ctlconn_write_handler();
587 
588 		for (i = 0; i < nfunix; i++) {
589 			if ((pfd[PFD_UNIX_0 + i].revents & POLLIN) != 0) {
590 				ssize_t rlen;
591 
592 				len = sizeof(fromunix);
593 				rlen = recvfrom(pfd[PFD_UNIX_0 + i].fd, line,
594 				    MAXLINE, 0, (struct sockaddr *)&fromunix,
595 				    &len);
596 				if (rlen > 0) {
597 					line[rlen] = '\0';
598 					printline(LocalHostName, line);
599 				} else if (rlen == -1 && errno != EINTR)
600 					logerror("recvfrom unix");
601 			}
602 		}
603 	}
604 	/* NOTREACHED */
605 	free(pfd);
606 	return (0);
607 }
608 
609 void
610 usage(void)
611 {
612 
613 	(void)fprintf(stderr,
614 	    "usage: syslogd [-dnu] [-a path] [-f config_file] [-m mark_interval]\n"
615 	    "               [-p log_socket] [-s reporting_socket]\n");
616 	exit(1);
617 }
618 
619 /*
620  * Take a raw input line, decode the message, and print the message
621  * on the appropriate log files.
622  */
623 void
624 printline(char *hname, char *msg)
625 {
626 	int pri;
627 	char *p, *q, line[MAXLINE + 1];
628 
629 	/* test for special codes */
630 	pri = DEFUPRI;
631 	p = msg;
632 	if (*p == '<') {
633 		pri = 0;
634 		while (isdigit(*++p))
635 			pri = 10 * pri + (*p - '0');
636 		if (*p == '>')
637 			++p;
638 	}
639 	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
640 		pri = DEFUPRI;
641 
642 	/*
643 	 * Don't allow users to log kernel messages.
644 	 * NOTE: since LOG_KERN == 0 this will also match
645 	 * messages with no facility specified.
646 	 */
647 	if (LOG_FAC(pri) == LOG_KERN)
648 		pri = LOG_USER | LOG_PRI(pri);
649 
650 	for (q = line; *p && q < &line[sizeof(line) - 4]; p++) {
651 		if (*p == '\n')
652 			*q++ = ' ';
653 		else
654 			q = vis(q, *p, 0, 0);
655 	}
656 	*q = '\0';
657 
658 	logmsg(pri, line, hname, 0);
659 }
660 
661 /*
662  * Take a raw input line from /dev/klog, split and format similar to syslog().
663  */
664 void
665 printsys(char *msg)
666 {
667 	int c, pri, flags;
668 	char *lp, *p, *q, line[MAXLINE + 1];
669 
670 	(void)snprintf(line, sizeof line, "%s: ", _PATH_UNIX);
671 	lp = line + strlen(line);
672 	for (p = msg; *p != '\0'; ) {
673 		flags = SYNC_FILE | ADDDATE;	/* fsync file after write */
674 		pri = DEFSPRI;
675 		if (*p == '<') {
676 			pri = 0;
677 			while (isdigit(*++p))
678 				pri = 10 * pri + (*p - '0');
679 			if (*p == '>')
680 				++p;
681 		} else {
682 			/* kernel printf's come out on console */
683 			flags |= IGN_CONS;
684 		}
685 		if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
686 			pri = DEFSPRI;
687 
688 		q = lp;
689 		while (*p && (c = *p++) != '\n' && q < &line[sizeof(line) - 4])
690 			q = vis(q, c, 0, 0);
691 
692 		logmsg(pri, line, LocalHostName, flags);
693 	}
694 }
695 
696 time_t	now;
697 
698 /*
699  * Log a message to the appropriate log files, users, etc. based on
700  * the priority.
701  */
702 void
703 logmsg(int pri, char *msg, char *from, int flags)
704 {
705 	struct filed *f;
706 	int fac, msglen, prilev, i;
707 	sigset_t mask, omask;
708 	char *timestamp;
709 	char prog[NAME_MAX+1];
710 
711 	dprintf("logmsg: pri 0%o, flags 0x%x, from %s, msg %s\n",
712 	    pri, flags, from, msg);
713 
714 	sigemptyset(&mask);
715 	sigaddset(&mask, SIGALRM);
716 	sigaddset(&mask, SIGHUP);
717 	sigprocmask(SIG_BLOCK, &mask, &omask);
718 
719 	/*
720 	 * Check to see if msg looks non-standard.
721 	 */
722 	msglen = strlen(msg);
723 	if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
724 	    msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
725 		flags |= ADDDATE;
726 
727 	(void)time(&now);
728 	if (flags & ADDDATE)
729 		timestamp = ctime(&now) + 4;
730 	else {
731 		timestamp = msg;
732 		msg += 16;
733 		msglen -= 16;
734 	}
735 
736 	/* extract facility and priority level */
737 	if (flags & MARK)
738 		fac = LOG_NFACILITIES;
739 	else
740 		fac = LOG_FAC(pri);
741 	prilev = LOG_PRI(pri);
742 
743 	/* extract program name */
744 	for(i = 0; i < NAME_MAX; i++) {
745 		if (!isalnum(msg[i]) && msg[i] != '-')
746 			break;
747 		prog[i] = msg[i];
748 	}
749 	prog[i] = 0;
750 
751 	/* log the message to the particular outputs */
752 	if (!Initialized) {
753 		f = &consfile;
754 		f->f_file = priv_open_tty(ctty);
755 
756 		if (f->f_file >= 0) {
757 			fprintlog(f, flags, msg);
758 			(void)close(f->f_file);
759 			f->f_file = -1;
760 		}
761 		(void)sigprocmask(SIG_SETMASK, &omask, NULL);
762 		return;
763 	}
764 	for (f = Files; f; f = f->f_next) {
765 		/* skip messages that are incorrect priority */
766 		if (f->f_pmask[fac] < prilev ||
767 		    f->f_pmask[fac] == INTERNAL_NOPRI)
768 			continue;
769 
770 		/* skip messages with the incorrect program name */
771 		if (f->f_program)
772 			if (strcmp(prog, f->f_program) != 0)
773 				continue;
774 
775 		if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
776 			continue;
777 
778 		/* don't output marks to recently written files */
779 		if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
780 			continue;
781 
782 		/*
783 		 * suppress duplicate lines to this file
784 		 */
785 		if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
786 		    !strcmp(msg, f->f_prevline) &&
787 		    !strcmp(from, f->f_prevhost)) {
788 			strlcpy(f->f_lasttime, timestamp, 16);
789 			f->f_prevcount++;
790 			dprintf("msg repeated %d times, %ld sec of %d\n",
791 			    f->f_prevcount, (long)(now - f->f_time),
792 			    repeatinterval[f->f_repeatcount]);
793 			/*
794 			 * If domark would have logged this by now,
795 			 * flush it now (so we don't hold isolated messages),
796 			 * but back off so we'll flush less often
797 			 * in the future.
798 			 */
799 			if (now > REPEATTIME(f)) {
800 				fprintlog(f, flags, (char *)NULL);
801 				BACKOFF(f);
802 			}
803 		} else {
804 			/* new line, save it */
805 			if (f->f_prevcount)
806 				fprintlog(f, 0, (char *)NULL);
807 			f->f_repeatcount = 0;
808 			f->f_prevpri = pri;
809 			strlcpy(f->f_lasttime, timestamp, 16);
810 			strlcpy(f->f_prevhost, from,
811 			    sizeof(f->f_prevhost));
812 			if (msglen < MAXSVLINE) {
813 				f->f_prevlen = msglen;
814 				strlcpy(f->f_prevline, msg, sizeof(f->f_prevline));
815 				fprintlog(f, flags, (char *)NULL);
816 			} else {
817 				f->f_prevline[0] = 0;
818 				f->f_prevlen = 0;
819 				fprintlog(f, flags, msg);
820 			}
821 		}
822 
823 		if (f->f_quick)
824 			break;
825 	}
826 	(void)sigprocmask(SIG_SETMASK, &omask, NULL);
827 }
828 
829 void
830 fprintlog(struct filed *f, int flags, char *msg)
831 {
832 	struct iovec iov[6];
833 	struct iovec *v;
834 	int l, retryonce;
835 	char line[MAXLINE + 1], repbuf[80], greetings[500];
836 
837 	v = iov;
838 	if (f->f_type == F_WALL) {
839 		if ((l = snprintf(greetings, sizeof(greetings),
840 		    "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
841 		    f->f_prevhost, ctime(&now))) >= sizeof(greetings) ||
842 		    l == -1)
843 			l = strlen(greetings);
844 		v->iov_base = greetings;
845 		v->iov_len = l;
846 		v++;
847 		v->iov_base = "";
848 		v->iov_len = 0;
849 		v++;
850 	} else {
851 		v->iov_base = f->f_lasttime;
852 		v->iov_len = 15;
853 		v++;
854 		v->iov_base = " ";
855 		v->iov_len = 1;
856 		v++;
857 	}
858 	v->iov_base = f->f_prevhost;
859 	v->iov_len = strlen(v->iov_base);
860 	v++;
861 	v->iov_base = " ";
862 	v->iov_len = 1;
863 	v++;
864 
865 	if (msg) {
866 		v->iov_base = msg;
867 		v->iov_len = strlen(msg);
868 	} else if (f->f_prevcount > 1) {
869 		if ((l = snprintf(repbuf, sizeof(repbuf),
870 		    "last message repeated %d times", f->f_prevcount)) >=
871 		    sizeof(repbuf) || l == -1)
872 			l = strlen(repbuf);
873 		v->iov_base = repbuf;
874 		v->iov_len = l;
875 	} else {
876 		v->iov_base = f->f_prevline;
877 		v->iov_len = f->f_prevlen;
878 	}
879 	v++;
880 
881 	dprintf("Logging to %s", TypeNames[f->f_type]);
882 	f->f_time = now;
883 
884 	switch (f->f_type) {
885 	case F_UNUSED:
886 		dprintf("\n");
887 		break;
888 
889 	case F_FORW:
890 		dprintf(" %s\n", f->f_un.f_forw.f_hname);
891 		if ((l = snprintf(line, sizeof(line), "<%d>%.15s %s",
892 		    f->f_prevpri, (char *)iov[0].iov_base,
893 		    (char *)iov[4].iov_base)) >= sizeof(line) || l == -1)
894 			l = strlen(line);
895 		if (sendto(pfd[PFD_INET].fd, line, l, 0,
896 		    (struct sockaddr *)&f->f_un.f_forw.f_addr,
897 		    f->f_un.f_forw.f_addr.ss_len) != l) {
898 			switch (errno) {
899 			case EHOSTDOWN:
900 			case EHOSTUNREACH:
901 			case ENETDOWN:
902 			case ENOBUFS:
903 				/* silently dropped */
904 				break;
905 			default:
906 				f->f_type = F_UNUSED;
907 				logerror("sendto");
908 				break;
909 			}
910 		}
911 		break;
912 
913 	case F_CONSOLE:
914 		if (flags & IGN_CONS) {
915 			dprintf(" (ignored)\n");
916 			break;
917 		}
918 		/* FALLTHROUGH */
919 
920 	case F_TTY:
921 	case F_FILE:
922 	case F_PIPE:
923 		dprintf(" %s\n", f->f_un.f_fname);
924 		if (f->f_type != F_FILE && f->f_type != F_PIPE) {
925 			v->iov_base = "\r\n";
926 			v->iov_len = 2;
927 		} else {
928 			v->iov_base = "\n";
929 			v->iov_len = 1;
930 		}
931 		retryonce = 0;
932 	again:
933 		if (writev(f->f_file, iov, 6) < 0) {
934 			int e = errno;
935 
936 			/* pipe is non-blocking. log and drop message if full */
937 			if (e == EAGAIN && f->f_type == F_PIPE) {
938 				if (now - f->f_lasterrtime > 120) {
939 					f->f_lasterrtime = now;
940 					logerror(f->f_un.f_fname);
941 				}
942 				break;
943 			}
944 
945 			(void)close(f->f_file);
946 			/*
947 			 * Check for errors on TTY's or program pipes.
948 			 * Errors happen due to loss of tty or died programs.
949 			 */
950 			if (e == EAGAIN) {
951 				/*
952 				 * Silently drop messages on blocked write.
953 				 * This can happen when logging to a locked tty.
954 				 */
955 				break;
956 			} else if ((e == EIO || e == EBADF) &&
957 			    f->f_type != F_FILE && f->f_type != F_PIPE &&
958 			    !retryonce) {
959 				f->f_file = priv_open_tty(f->f_un.f_fname);
960 				retryonce = 1;
961 				if (f->f_file < 0) {
962 					f->f_type = F_UNUSED;
963 					logerror(f->f_un.f_fname);
964 				} else
965 					goto again;
966 			} else if ((e == EPIPE || e == EBADF) &&
967 			    f->f_type == F_PIPE && !retryonce) {
968 				f->f_file = priv_open_log(f->f_un.f_fname);
969 				retryonce = 1;
970 				if (f->f_file < 0) {
971 					f->f_type = F_UNUSED;
972 					logerror(f->f_un.f_fname);
973 				} else
974 					goto again;
975 			} else {
976 				f->f_type = F_UNUSED;
977 				f->f_file = -1;
978 				errno = e;
979 				logerror(f->f_un.f_fname);
980 			}
981 		} else if (flags & SYNC_FILE)
982 			(void)fsync(f->f_file);
983 		break;
984 
985 	case F_USERS:
986 	case F_WALL:
987 		dprintf("\n");
988 		v->iov_base = "\r\n";
989 		v->iov_len = 2;
990 		wallmsg(f, iov);
991 		break;
992 
993 	case F_MEMBUF:
994 		dprintf("\n");
995 		snprintf(line, sizeof(line), "%.15s %s %s",
996 		    (char *)iov[0].iov_base, (char *)iov[2].iov_base,
997 		    (char *)iov[4].iov_base);
998 		if (ringbuf_append_line(f->f_un.f_mb.f_rb, line) == 1)
999 			f->f_un.f_mb.f_overflow = 1;
1000 		if (f->f_un.f_mb.f_attached)
1001 			logto_ctlconn(line);
1002 		break;
1003 	}
1004 	f->f_prevcount = 0;
1005 }
1006 
1007 /*
1008  *  WALLMSG -- Write a message to the world at large
1009  *
1010  *	Write the specified message to either the entire
1011  *	world, or a list of approved users.
1012  */
1013 void
1014 wallmsg(struct filed *f, struct iovec *iov)
1015 {
1016 	struct utmp ut;
1017 	char line[sizeof(ut.ut_line) + 1], *p;
1018 	static int reenter;			/* avoid calling ourselves */
1019 	FILE *uf;
1020 	int i;
1021 
1022 	if (reenter++)
1023 		return;
1024 	if ((uf = priv_open_utmp()) == NULL) {
1025 		logerror(_PATH_UTMP);
1026 		reenter = 0;
1027 		return;
1028 	}
1029 	/* NOSTRICT */
1030 	while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) {
1031 		if (ut.ut_name[0] == '\0')
1032 			continue;
1033 		/* must use strncpy since ut_* may not be NUL terminated */
1034 		strncpy(line, ut.ut_line, sizeof(line) - 1);
1035 		line[sizeof(line) - 1] = '\0';
1036 		if (f->f_type == F_WALL) {
1037 			if ((p = ttymsg(iov, 6, line, TTYMSGTIME)) != NULL) {
1038 				errno = 0;	/* already in msg */
1039 				logerror(p);
1040 			}
1041 			continue;
1042 		}
1043 		/* should we send the message to this user? */
1044 		for (i = 0; i < MAXUNAMES; i++) {
1045 			if (!f->f_un.f_uname[i][0])
1046 				break;
1047 			if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
1048 			    UT_NAMESIZE)) {
1049 				if ((p = ttymsg(iov, 6, line, TTYMSGTIME))
1050 								!= NULL) {
1051 					errno = 0;	/* already in msg */
1052 					logerror(p);
1053 				}
1054 				break;
1055 			}
1056 		}
1057 	}
1058 	(void)fclose(uf);
1059 	reenter = 0;
1060 }
1061 
1062 /* ARGSUSED */
1063 void
1064 reapchild(int signo)
1065 {
1066 	int save_errno = errno;
1067 	int status;
1068 
1069 	while (waitpid(-1, &status, WNOHANG) > 0)
1070 		;
1071 	errno = save_errno;
1072 }
1073 
1074 /*
1075  * Return a printable representation of a host address.
1076  */
1077 void
1078 cvthname(struct sockaddr_in *f, char *result, size_t res_len)
1079 {
1080 	sigset_t omask, nmask;
1081 	char *p, *ip;
1082 	int ret_len;
1083 
1084 	if (f->sin_family != AF_INET) {
1085 		dprintf("Malformed from address\n");
1086 		strlcpy(result, "???", res_len);
1087 		return;
1088 	}
1089 
1090 	ip = inet_ntoa(f->sin_addr);
1091 	dprintf("cvthname(%s)\n", ip);
1092 	if (NoDNS) {
1093 		strlcpy(result, ip, res_len);
1094 		return;
1095 	}
1096 
1097 	sigemptyset(&nmask);
1098 	sigaddset(&nmask, SIGHUP);
1099 	sigprocmask(SIG_BLOCK, &nmask, &omask);
1100 
1101 	ret_len = priv_gethostbyaddr((char *)&f->sin_addr,
1102 		sizeof(struct in_addr), f->sin_family, result, res_len);
1103 
1104 	sigprocmask(SIG_SETMASK, &omask, NULL);
1105 	if (ret_len == 0) {
1106 		dprintf("Host name for your address (%s) unknown\n", ip);
1107 		strlcpy(result, ip, res_len);
1108 	} else if ((p = strchr(result, '.')) && strcmp(p + 1, LocalDomain) == 0)
1109 		*p = '\0';
1110 }
1111 
1112 void
1113 dodie(int signo)
1114 {
1115 	WantDie = signo;
1116 }
1117 
1118 /* ARGSUSED */
1119 void
1120 domark(int signo)
1121 {
1122 	MarkSet = 1;
1123 }
1124 
1125 /* ARGSUSED */
1126 void
1127 doinit(int signo)
1128 {
1129 	DoInit = 1;
1130 }
1131 
1132 /*
1133  * Print syslogd errors some place.
1134  */
1135 void
1136 logerror(const char *type)
1137 {
1138 	char buf[100];
1139 
1140 	if (errno)
1141 		(void)snprintf(buf, sizeof(buf), "syslogd: %s: %s",
1142 		    type, strerror(errno));
1143 	else
1144 		(void)snprintf(buf, sizeof(buf), "syslogd: %s", type);
1145 	errno = 0;
1146 	dprintf("%s\n", buf);
1147 	if (Startup)
1148 		fprintf(stderr, "%s\n", buf);
1149 	else
1150 		logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
1151 }
1152 
1153 void
1154 die(int signo)
1155 {
1156 	struct filed *f;
1157 	int was_initialized = Initialized;
1158 	char buf[100];
1159 
1160 	Initialized = 0;		/* Don't log SIGCHLDs */
1161 	alarm(0);
1162 	for (f = Files; f != NULL; f = f->f_next) {
1163 		/* flush any pending output */
1164 		if (f->f_prevcount)
1165 			fprintlog(f, 0, (char *)NULL);
1166 	}
1167 	Initialized = was_initialized;
1168 	if (signo) {
1169 		dprintf("syslogd: exiting on signal %d\n", signo);
1170 		(void)snprintf(buf, sizeof buf, "exiting on signal %d", signo);
1171 		errno = 0;
1172 		logerror(buf);
1173 	}
1174 	dprintf("[unpriv] syslogd child about to exit\n");
1175 	exit(0);
1176 }
1177 
1178 /*
1179  *  INIT -- Initialize syslogd from configuration table
1180  */
1181 void
1182 init(void)
1183 {
1184 	char cline[LINE_MAX], prog[NAME_MAX+1], *p;
1185 	struct filed *f, *next, **nextp, *mb, *m;
1186 	FILE *cf;
1187 	int i;
1188 
1189 	dprintf("init\n");
1190 
1191 	/* If config file has been modified, then just die to restart */
1192 	if (priv_config_modified()) {
1193 		dprintf("config file changed: dying\n");
1194 		die(0);
1195 	}
1196 
1197 	/*
1198 	 *  Close all open log files.
1199 	 */
1200 	Initialized = 0;
1201 	mb = NULL;
1202 	for (f = Files; f != NULL; f = next) {
1203 		/* flush any pending output */
1204 		if (f->f_prevcount)
1205 			fprintlog(f, 0, (char *)NULL);
1206 
1207 		switch (f->f_type) {
1208 		case F_FILE:
1209 		case F_TTY:
1210 		case F_CONSOLE:
1211 		case F_PIPE:
1212 			(void)close(f->f_file);
1213 			break;
1214 		case F_FORW:
1215 			break;
1216 		}
1217 		next = f->f_next;
1218 		if (f->f_program)
1219 			free(f->f_program);
1220 		if (f->f_type == F_MEMBUF) {
1221 			f->f_next = mb;
1222 			f->f_program = NULL;
1223 			dprintf("add %p to mb: %p\n", f, mb);
1224 			mb = f;
1225 		} else
1226 			free((char *)f);
1227 	}
1228 	Files = NULL;
1229 	nextp = &Files;
1230 
1231 	/* open the configuration file */
1232 	if ((cf = priv_open_config()) == NULL) {
1233 		dprintf("cannot open %s\n", ConfFile);
1234 		*nextp = cfline("*.ERR\t/dev/console", "*");
1235 		(*nextp)->f_next = cfline("*.PANIC\t*", "*");
1236 		Initialized = 1;
1237 		return;
1238 	}
1239 
1240 	/*
1241 	 *  Foreach line in the conf table, open that file.
1242 	 */
1243 	f = NULL;
1244 	strlcpy(prog, "*", sizeof(prog));
1245 	while (fgets(cline, sizeof(cline), cf) != NULL) {
1246 		/*
1247 		 * check for end-of-section, comments, strip off trailing
1248 		 * spaces and newline character. !prog is treated
1249 		 * specially: the following lines apply only to that program.
1250 		 */
1251 		for (p = cline; isspace(*p); ++p)
1252 			continue;
1253 		if (*p == '\0' || *p == '#')
1254 			continue;
1255 		if (*p == '!') {
1256 			p++;
1257 			while (isspace(*p))
1258 				p++;
1259 			if (!*p || (*p == '*' && (!p[1] || isspace(p[1])))) {
1260 				strlcpy(prog, "*", sizeof(prog));
1261 				continue;
1262 			}
1263 			for (i = 0; i < NAME_MAX; i++) {
1264 				if (!isalnum(p[i]) && p[i] != '-' && p[i] != '!')
1265 					break;
1266 				prog[i] = p[i];
1267 			}
1268 			prog[i] = 0;
1269 			continue;
1270 		}
1271 		p = cline + strlen(cline);
1272 		while (p > cline)
1273 			if (!isspace(*--p)) {
1274 				p++;
1275 				break;
1276 			}
1277 		*p = '\0';
1278 		f = cfline(cline, prog);
1279 		if (f != NULL) {
1280 			*nextp = f;
1281 			nextp = &f->f_next;
1282 		}
1283 	}
1284 
1285 	/* Match and initialize the memory buffers */
1286 	for (f = Files; f != NULL; f = f->f_next) {
1287 		if (f->f_type != F_MEMBUF)
1288 			continue;
1289 		dprintf("Initialize membuf %s at %p\n", f->f_un.f_mb.f_mname, f);
1290 
1291 		for (m = mb; m != NULL; m = m->f_next) {
1292 			if (m->f_un.f_mb.f_rb == NULL)
1293 				continue;
1294 			if (strcmp(m->f_un.f_mb.f_mname,
1295 			    f->f_un.f_mb.f_mname) == 0)
1296 				break;
1297 		}
1298 		if (m == NULL) {
1299 			dprintf("Membuf no match\n");
1300 			f->f_un.f_mb.f_rb = ringbuf_init(f->f_un.f_mb.f_len);
1301 			if (f->f_un.f_mb.f_rb == NULL) {
1302 				f->f_type = F_UNUSED;
1303 				logerror("Failed to allocate membuf");
1304 			}
1305 		} else {
1306 			dprintf("Membuf match f:%p, m:%p\n", f, m);
1307 			f->f_un = m->f_un;
1308 			m->f_un.f_mb.f_rb = NULL;
1309 		}
1310 	}
1311 
1312 	/* make sure remaining buffers are freed */
1313 	while (mb != NULL) {
1314 		m = mb;
1315 		if (m->f_un.f_mb.f_rb != NULL) {
1316 			logerror("Mismatched membuf");
1317 			ringbuf_free(m->f_un.f_mb.f_rb);
1318 		}
1319 		dprintf("Freeing membuf %p\n", m);
1320 
1321 		mb = m->f_next;
1322 		free(m);
1323 	}
1324 
1325 	/* close the configuration file */
1326 	(void)fclose(cf);
1327 
1328 	Initialized = 1;
1329 
1330 	if (Debug) {
1331 		for (f = Files; f; f = f->f_next) {
1332 			for (i = 0; i <= LOG_NFACILITIES; i++)
1333 				if (f->f_pmask[i] == INTERNAL_NOPRI)
1334 					printf("X ");
1335 				else
1336 					printf("%d ", f->f_pmask[i]);
1337 			printf("%s: ", TypeNames[f->f_type]);
1338 			switch (f->f_type) {
1339 			case F_FILE:
1340 			case F_TTY:
1341 			case F_CONSOLE:
1342 			case F_PIPE:
1343 				printf("%s", f->f_un.f_fname);
1344 				break;
1345 
1346 			case F_FORW:
1347 				printf("%s", f->f_un.f_forw.f_hname);
1348 				break;
1349 
1350 			case F_USERS:
1351 				for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
1352 					printf("%s, ", f->f_un.f_uname[i]);
1353 				break;
1354 
1355 			case F_MEMBUF:
1356 				printf("%s", f->f_un.f_mb.f_mname);
1357 				break;
1358 
1359 			}
1360 			if (f->f_program)
1361 				printf(" (%s)", f->f_program);
1362 			printf("\n");
1363 		}
1364 	}
1365 }
1366 
1367 #define progmatches(p1, p2) \
1368 	(p1 == p2 || (p1 != NULL && p2 != NULL && strcmp(p1, p2) == 0))
1369 
1370 /*
1371  * Spot a line with a duplicate file, pipe, console, tty, or membuf target.
1372  */
1373 struct filed *
1374 find_dup(struct filed *f)
1375 {
1376 	struct filed *list;
1377 
1378 	for (list = Files; list; list = list->f_next) {
1379 		if (list->f_quick || f->f_quick)
1380 			continue;
1381 		switch (list->f_type) {
1382 		case F_FILE:
1383 		case F_TTY:
1384 		case F_CONSOLE:
1385 		case F_PIPE:
1386 			if (strcmp(list->f_un.f_fname, f->f_un.f_fname) == 0 &&
1387 			    progmatches(list->f_program, f->f_program))
1388 				return (list);
1389 			break;
1390 		case F_MEMBUF:
1391 			if (strcmp(list->f_un.f_mb.f_mname,
1392 			    f->f_un.f_mb.f_mname) == 0 &&
1393 			    progmatches(list->f_program, f->f_program))
1394 				return (list);
1395 			break;
1396 		}
1397 	}
1398 	return (NULL);
1399 }
1400 
1401 /*
1402  * Crack a configuration file line
1403  */
1404 struct filed *
1405 cfline(char *line, char *prog)
1406 {
1407 	int i, pri, addr_len;
1408 	size_t rb_len;
1409 	char *bp, *p, *q, *cp;
1410 	char buf[MAXLINE], ebuf[100];
1411 	struct filed *xf, *f, *d;
1412 
1413 	dprintf("cfline(\"%s\", f, \"%s\")\n", line, prog);
1414 
1415 	errno = 0;	/* keep strerror() stuff out of logerror messages */
1416 
1417 	if ((f = calloc(1, sizeof(*f))) == NULL) {
1418 		logerror("Couldn't allocate struct filed");
1419 		die(0);
1420 	}
1421 	for (i = 0; i <= LOG_NFACILITIES; i++)
1422 		f->f_pmask[i] = INTERNAL_NOPRI;
1423 
1424 	/* save program name if any */
1425 	if (*prog == '!') {
1426 		f->f_quick = 1;
1427 		prog++;
1428 	} else
1429 		f->f_quick = 0;
1430 	if (!strcmp(prog, "*"))
1431 		prog = NULL;
1432 	else {
1433 		f->f_program = calloc(1, strlen(prog)+1);
1434 		if (f->f_program)
1435 			strlcpy(f->f_program, prog, strlen(prog)+1);
1436 	}
1437 
1438 	/* scan through the list of selectors */
1439 	for (p = line; *p && *p != '\t';) {
1440 
1441 		/* find the end of this facility name list */
1442 		for (q = p; *q && *q != '\t' && *q++ != '.'; )
1443 			continue;
1444 
1445 		/* collect priority name */
1446 		for (bp = buf; *q && !strchr("\t,;", *q); )
1447 			*bp++ = *q++;
1448 		*bp = '\0';
1449 
1450 		/* skip cruft */
1451 		while (*q && strchr(", ;", *q))
1452 			q++;
1453 
1454 		/* decode priority name */
1455 		if (*buf == '*')
1456 			pri = LOG_PRIMASK + 1;
1457 		else {
1458 			/* ignore trailing spaces */
1459 			for (i=strlen(buf)-1; i >= 0 && buf[i] == ' '; i--) {
1460 				buf[i]='\0';
1461 			}
1462 
1463 			pri = decode(buf, prioritynames);
1464 			if (pri < 0) {
1465 				(void)snprintf(ebuf, sizeof ebuf,
1466 				    "unknown priority name \"%s\"", buf);
1467 				logerror(ebuf);
1468 				free(f);
1469 				return (NULL);
1470 			}
1471 		}
1472 
1473 		/* scan facilities */
1474 		while (*p && !strchr("\t.;", *p)) {
1475 			for (bp = buf; *p && !strchr("\t,;.", *p); )
1476 				*bp++ = *p++;
1477 			*bp = '\0';
1478 			if (*buf == '*')
1479 				for (i = 0; i < LOG_NFACILITIES; i++)
1480 					f->f_pmask[i] = pri;
1481 			else {
1482 				i = decode(buf, facilitynames);
1483 				if (i < 0) {
1484 					(void)snprintf(ebuf, sizeof(ebuf),
1485 					    "unknown facility name \"%s\"",
1486 					    buf);
1487 					logerror(ebuf);
1488 					free(f);
1489 					return (NULL);
1490 				}
1491 				f->f_pmask[i >> 3] = pri;
1492 			}
1493 			while (*p == ',' || *p == ' ')
1494 				p++;
1495 		}
1496 
1497 		p = q;
1498 	}
1499 
1500 	/* skip to action part */
1501 	while (*p == '\t')
1502 		p++;
1503 
1504 	switch (*p) {
1505 	case '@':
1506 		if (!InetInuse)
1507 			break;
1508 		if ((cp = strrchr(++p, ':')) != NULL)
1509 			*cp++ = '\0';
1510 		if ((strlcpy(f->f_un.f_forw.f_hname, p,
1511 		    sizeof(f->f_un.f_forw.f_hname)) >=
1512 		    sizeof(f->f_un.f_forw.f_hname))) {
1513 			snprintf(ebuf, sizeof(ebuf), "hostname too long \"%s\"",
1514 			    p);
1515 			logerror(ebuf);
1516 			break;
1517 		}
1518 		addr_len = priv_gethostserv(f->f_un.f_forw.f_hname,
1519 		    cp == NULL ? "syslog" : cp,
1520 		    (struct sockaddr*)&f->f_un.f_forw.f_addr,
1521 		    sizeof(f->f_un.f_forw.f_addr));
1522 		if (addr_len < 1) {
1523 			snprintf(ebuf, sizeof(ebuf), "bad hostname \"%s\"", p);
1524 			logerror(ebuf);
1525 			break;
1526 		}
1527 		f->f_type = F_FORW;
1528 		break;
1529 
1530 	case '/':
1531 	case '|':
1532 		(void)strlcpy(f->f_un.f_fname, p, sizeof(f->f_un.f_fname));
1533 		d = find_dup(f);
1534 		if (d != NULL) {
1535 			for (i = 0; i <= LOG_NFACILITIES; i++)
1536 				if (f->f_pmask[i] != INTERNAL_NOPRI)
1537 					d->f_pmask[i] = f->f_pmask[i];
1538 			free(f);
1539 			return (NULL);
1540 		}
1541 		if (strcmp(p, ctty) == 0)
1542 			f->f_file = priv_open_tty(p);
1543 		else
1544 			f->f_file = priv_open_log(p);
1545 		if (f->f_file < 0) {
1546 			f->f_type = F_UNUSED;
1547 			logerror(p);
1548 			break;
1549 		}
1550 		if (isatty(f->f_file)) {
1551 			if (strcmp(p, ctty) == 0)
1552 				f->f_type = F_CONSOLE;
1553 			else
1554 				f->f_type = F_TTY;
1555 		} else {
1556 			if (*p == '|')
1557 				f->f_type = F_PIPE;
1558 			else {
1559 				f->f_type = F_FILE;
1560 
1561 				/* Clear O_NONBLOCK flag on f->f_file */
1562 				if ((i = fcntl(f->f_file, F_GETFL, 0)) != -1) {
1563 					i &= ~O_NONBLOCK;
1564 					fcntl(f->f_file, F_SETFL, i);
1565 				}
1566 			}
1567 		}
1568 		break;
1569 
1570 	case '*':
1571 		f->f_type = F_WALL;
1572 		break;
1573 
1574 	case ':':
1575 		f->f_type = F_MEMBUF;
1576 
1577 		/* Parse buffer size (in kb) */
1578 		errno = 0;
1579 		rb_len = strtoul(++p, &q, 0);
1580 		if (*p == '\0' || (errno == ERANGE && rb_len == ULONG_MAX) ||
1581 		    *q != ':' || rb_len == 0) {
1582 			f->f_type = F_UNUSED;
1583 			logerror(p);
1584 			break;
1585 		}
1586 		q++;
1587 		rb_len *= 1024;
1588 
1589 		/* Copy buffer name */
1590 		for(i = 0; i < sizeof(f->f_un.f_mb.f_mname) - 1; i++) {
1591 			if (!isalnum(q[i]))
1592 				break;
1593 			f->f_un.f_mb.f_mname[i] = q[i];
1594 		}
1595 
1596 		/* Make sure buffer name is unique */
1597 		xf = find_dup(f);
1598 
1599 		/* Error on missing or non-unique name, or bad buffer length */
1600 		if (i == 0 || rb_len > MAX_MEMBUF || xf != NULL) {
1601 			f->f_type = F_UNUSED;
1602 			logerror(p);
1603 			break;
1604 		}
1605 
1606 		/* Set buffer length */
1607 		rb_len = MAX(rb_len, MIN_MEMBUF);
1608 		f->f_un.f_mb.f_len = rb_len;
1609 		f->f_un.f_mb.f_overflow = 0;
1610 		f->f_un.f_mb.f_attached = 0;
1611 		break;
1612 
1613 	default:
1614 		for (i = 0; i < MAXUNAMES && *p; i++) {
1615 			for (q = p; *q && *q != ','; )
1616 				q++;
1617 			(void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
1618 			if ((q - p) > UT_NAMESIZE)
1619 				f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
1620 			else
1621 				f->f_un.f_uname[i][q - p] = '\0';
1622 			while (*q == ',' || *q == ' ')
1623 				q++;
1624 			p = q;
1625 		}
1626 		f->f_type = F_USERS;
1627 		break;
1628 	}
1629 	return (f);
1630 }
1631 
1632 
1633 /*
1634  * Retrieve the size of the kernel message buffer, via sysctl.
1635  */
1636 int
1637 getmsgbufsize(void)
1638 {
1639 	int msgbufsize, mib[2];
1640 	size_t size;
1641 
1642 	mib[0] = CTL_KERN;
1643 	mib[1] = KERN_MSGBUFSIZE;
1644 	size = sizeof msgbufsize;
1645 	if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) {
1646 		dprintf("couldn't get kern.msgbufsize\n");
1647 		return (0);
1648 	}
1649 	return (msgbufsize);
1650 }
1651 
1652 /*
1653  *  Decode a symbolic name to a numeric value
1654  */
1655 int
1656 decode(const char *name, const CODE *codetab)
1657 {
1658 	const CODE *c;
1659 	char *p, buf[40];
1660 
1661 	if (isdigit(*name))
1662 		return (atoi(name));
1663 
1664 	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
1665 		if (isupper(*name))
1666 			*p = tolower(*name);
1667 		else
1668 			*p = *name;
1669 	}
1670 	*p = '\0';
1671 	for (c = codetab; c->c_name; c++)
1672 		if (!strcmp(buf, c->c_name))
1673 			return (c->c_val);
1674 
1675 	return (-1);
1676 }
1677 
1678 void
1679 markit(void)
1680 {
1681 	struct filed *f;
1682 
1683 	now = time((time_t *)NULL);
1684 	MarkSeq += TIMERINTVL;
1685 	if (MarkSeq >= MarkInterval) {
1686 		logmsg(LOG_INFO, "-- MARK --",
1687 		    LocalHostName, ADDDATE|MARK);
1688 		MarkSeq = 0;
1689 	}
1690 
1691 	for (f = Files; f; f = f->f_next) {
1692 		if (f->f_prevcount && now >= REPEATTIME(f)) {
1693 			dprintf("flush %s: repeated %d times, %d sec.\n",
1694 			    TypeNames[f->f_type], f->f_prevcount,
1695 			    repeatinterval[f->f_repeatcount]);
1696 			fprintlog(f, 0, (char *)NULL);
1697 			BACKOFF(f);
1698 		}
1699 	}
1700 	MarkSet = 0;
1701 	(void)alarm(TIMERINTVL);
1702 }
1703 
1704 int
1705 unix_socket(char *path, int type, mode_t mode)
1706 {
1707 	struct sockaddr_un s_un;
1708 	char errbuf[512];
1709 	int fd;
1710 	mode_t old_umask;
1711 
1712 	memset(&s_un, 0, sizeof(s_un));
1713 	s_un.sun_family = AF_UNIX;
1714 	if (strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)) >
1715 	    sizeof(s_un.sun_path)) {
1716 		snprintf(errbuf, sizeof(errbuf), "socket path too long: %s",
1717 		    path);
1718 		logerror(errbuf);
1719 		die(0);
1720 	}
1721 
1722 	if ((fd = socket(AF_UNIX, type, 0)) == -1) {
1723 		logerror("socket");
1724 		return (-1);
1725 	}
1726 
1727 	if (Debug) {
1728 		if (connect(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == 0 ||
1729 		    errno == EPROTOTYPE) {
1730 			close(fd);
1731 			errno = EISCONN;
1732 			logerror("connect");
1733 			return (-1);
1734 		}
1735 	}
1736 
1737 	old_umask = umask(0177);
1738 
1739 	unlink(path);
1740 	if (bind(fd, (struct sockaddr *)&s_un, SUN_LEN(&s_un)) == -1) {
1741 		snprintf(errbuf, sizeof(errbuf), "cannot bind %s", path);
1742 		logerror(errbuf);
1743 		umask(old_umask);
1744 		close(fd);
1745 		return (-1);
1746 	}
1747 
1748 	umask(old_umask);
1749 
1750 	if (chmod(path, mode) == -1) {
1751 		snprintf(errbuf, sizeof(errbuf), "cannot chmod %s", path);
1752 		logerror(errbuf);
1753 		close(fd);
1754 		unlink(path);
1755 		return (-1);
1756 	}
1757 
1758 	return (fd);
1759 }
1760 
1761 void
1762 double_rbuf(int fd)
1763 {
1764 	socklen_t slen, len;
1765 
1766 	slen = sizeof(len);
1767 	if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, &slen) == 0) {
1768 		len *= 2;
1769 		setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, slen);
1770 	}
1771 }
1772 
1773 static void
1774 ctlconn_cleanup(void)
1775 {
1776 	struct filed *f;
1777 
1778 	if (pfd[PFD_CTLCONN].fd != -1)
1779 		close(pfd[PFD_CTLCONN].fd);
1780 
1781 	pfd[PFD_CTLCONN].fd = -1;
1782 	pfd[PFD_CTLCONN].events = pfd[PFD_CTLCONN].revents = 0;
1783 
1784 	pfd[PFD_CTLSOCK].events = POLLIN;
1785 
1786 	if (ctl_state == CTL_WRITING_CONT_REPLY)
1787 		for (f = Files; f != NULL; f = f->f_next)
1788 			if (f->f_type == F_MEMBUF)
1789 				f->f_un.f_mb.f_attached = 0;
1790 
1791 	ctl_state = ctl_cmd_bytes = ctl_reply_offset = ctl_reply_size = 0;
1792 }
1793 
1794 void
1795 ctlsock_accept_handler(void)
1796 {
1797 	int fd, flags;
1798 
1799 	dprintf("Accepting control connection\n");
1800 	fd = accept(pfd[PFD_CTLSOCK].fd, NULL, NULL);
1801 	if (fd == -1) {
1802 		if (errno != EINTR && errno != ECONNABORTED)
1803 			logerror("accept ctlsock");
1804 		return;
1805 	}
1806 
1807 	ctlconn_cleanup();
1808 
1809 	/* Only one connection at a time */
1810 	pfd[PFD_CTLSOCK].events = pfd[PFD_CTLSOCK].revents = 0;
1811 
1812 	if ((flags = fcntl(fd, F_GETFL)) == -1 ||
1813 	    fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
1814 		logerror("fcntl ctlconn");
1815 		close(fd);
1816 		return;
1817 	}
1818 
1819 	pfd[PFD_CTLCONN].fd = fd;
1820 	pfd[PFD_CTLCONN].events = POLLIN;
1821 	ctl_state = CTL_READING_CMD;
1822 	ctl_cmd_bytes = 0;
1823 }
1824 
1825 static struct filed
1826 *find_membuf_log(const char *name)
1827 {
1828 	struct filed *f;
1829 
1830 	for (f = Files; f != NULL; f = f->f_next) {
1831 		if (f->f_type == F_MEMBUF &&
1832 		    strcmp(f->f_un.f_mb.f_mname, name) == 0)
1833 			break;
1834 	}
1835 	return (f);
1836 }
1837 
1838 void
1839 ctlconn_read_handler(void)
1840 {
1841 	ssize_t n;
1842 	struct filed *f;
1843 	u_int32_t flags = 0;
1844 	struct ctl_reply_hdr *reply_hdr = (struct ctl_reply_hdr *)ctl_reply;
1845 
1846 	if (ctl_state == CTL_WRITING_REPLY ||
1847 	    ctl_state == CTL_WRITING_CONT_REPLY) {
1848 		/* client has closed the connection */
1849 		ctlconn_cleanup();
1850 		return;
1851 	}
1852 
1853  retry:
1854 	n = read(pfd[PFD_CTLCONN].fd, (char*)&ctl_cmd + ctl_cmd_bytes,
1855 	    sizeof(ctl_cmd) - ctl_cmd_bytes);
1856 	switch (n) {
1857 	case -1:
1858 		if (errno == EINTR)
1859 			goto retry;
1860 		logerror("ctlconn read");
1861 		/* FALLTHROUGH */
1862 	case 0:
1863 		ctlconn_cleanup();
1864 		return;
1865 	default:
1866 		ctl_cmd_bytes += n;
1867 	}
1868 
1869 	if (ctl_cmd_bytes < sizeof(ctl_cmd))
1870 		return;
1871 
1872 	if (ntohl(ctl_cmd.version) != CTL_VERSION) {
1873 		logerror("Unknown client protocol version");
1874 		ctlconn_cleanup();
1875 		return;
1876 	}
1877 
1878 	/* Ensure that logname is \0 terminated */
1879 	if (memchr(ctl_cmd.logname, '\0', sizeof(ctl_cmd.logname)) == NULL) {
1880 		logerror("Corrupt ctlsock command");
1881 		ctlconn_cleanup();
1882 		return;
1883 	}
1884 
1885 	*reply_text = '\0';
1886 
1887 	ctl_reply_size = ctl_reply_offset = 0;
1888 	memset(reply_hdr, '\0', sizeof(*reply_hdr));
1889 
1890 	ctl_cmd.cmd = ntohl(ctl_cmd.cmd);
1891 	dprintf("ctlcmd %x logname \"%s\"\n", ctl_cmd.cmd, ctl_cmd.logname);
1892 
1893 	switch (ctl_cmd.cmd) {
1894 	case CMD_READ:
1895 	case CMD_READ_CLEAR:
1896 	case CMD_READ_CONT:
1897 	case CMD_FLAGS:
1898 		f = find_membuf_log(ctl_cmd.logname);
1899 		if (f == NULL) {
1900 			strlcpy(reply_text, "No such log\n", MAX_MEMBUF);
1901 		} else {
1902 			if (ctl_cmd.cmd != CMD_FLAGS) {
1903 				ringbuf_to_string(reply_text, MAX_MEMBUF,
1904 				    f->f_un.f_mb.f_rb);
1905 			}
1906 			if (f->f_un.f_mb.f_overflow)
1907 				flags |= CTL_HDR_FLAG_OVERFLOW;
1908 			if (ctl_cmd.cmd == CMD_READ_CLEAR) {
1909 				ringbuf_clear(f->f_un.f_mb.f_rb);
1910 				f->f_un.f_mb.f_overflow = 0;
1911 			}
1912 			if (ctl_cmd.cmd == CMD_READ_CONT) {
1913 				f->f_un.f_mb.f_attached = 1;
1914 				tailify_replytext(reply_text,
1915 				    ctl_cmd.lines > 0 ? ctl_cmd.lines : 10);
1916 			} else if (ctl_cmd.lines > 0) {
1917 				tailify_replytext(reply_text, ctl_cmd.lines);
1918 			}
1919 		}
1920 		break;
1921 	case CMD_CLEAR:
1922 		f = find_membuf_log(ctl_cmd.logname);
1923 		if (f == NULL) {
1924 			strlcpy(reply_text, "No such log\n", MAX_MEMBUF);
1925 		} else {
1926 			ringbuf_clear(f->f_un.f_mb.f_rb);
1927 			if (f->f_un.f_mb.f_overflow)
1928 				flags |= CTL_HDR_FLAG_OVERFLOW;
1929 			f->f_un.f_mb.f_overflow = 0;
1930 			strlcpy(reply_text, "Log cleared\n", MAX_MEMBUF);
1931 		}
1932 		break;
1933 	case CMD_LIST:
1934 		for (f = Files; f != NULL; f = f->f_next) {
1935 			if (f->f_type == F_MEMBUF) {
1936 				strlcat(reply_text, f->f_un.f_mb.f_mname,
1937 				    MAX_MEMBUF);
1938 				if (f->f_un.f_mb.f_overflow) {
1939 					strlcat(reply_text, "*", MAX_MEMBUF);
1940 					flags |= CTL_HDR_FLAG_OVERFLOW;
1941 				}
1942 				strlcat(reply_text, " ", MAX_MEMBUF);
1943 			}
1944 		}
1945 		strlcat(reply_text, "\n", MAX_MEMBUF);
1946 		break;
1947 	default:
1948 		logerror("Unsupported ctlsock command");
1949 		ctlconn_cleanup();
1950 		return;
1951 	}
1952 	reply_hdr->version = htonl(CTL_VERSION);
1953 	reply_hdr->flags = htonl(flags);
1954 
1955 	ctl_reply_size = CTL_REPLY_SIZE;
1956 	dprintf("ctlcmd reply length %lu\n", (u_long)ctl_reply_size);
1957 
1958 	/* Otherwise, set up to write out reply */
1959 	ctl_state = (ctl_cmd.cmd == CMD_READ_CONT) ?
1960 	    CTL_WRITING_CONT_REPLY : CTL_WRITING_REPLY;
1961 
1962 	pfd[PFD_CTLCONN].events = POLLOUT;
1963 
1964 	/* monitor terminating syslogc */
1965 	pfd[PFD_CTLCONN].events |= POLLIN;
1966 
1967 	/* another syslogc can kick us out */
1968 	if (ctl_state == CTL_WRITING_CONT_REPLY)
1969 		pfd[PFD_CTLSOCK].events = POLLIN;
1970 
1971 }
1972 
1973 void
1974 ctlconn_write_handler(void)
1975 {
1976 	ssize_t n;
1977 
1978 	if (!(ctl_state == CTL_WRITING_REPLY ||
1979 	    ctl_state == CTL_WRITING_CONT_REPLY)) {
1980 		/* Shouldn't be here! */
1981 		logerror("ctlconn_write with bad ctl_state");
1982 		ctlconn_cleanup();
1983 		return;
1984 	}
1985  retry:
1986 	n = write(pfd[PFD_CTLCONN].fd, ctl_reply + ctl_reply_offset,
1987 	    ctl_reply_size - ctl_reply_offset);
1988 	switch (n) {
1989 	case -1:
1990 		if (errno == EINTR)
1991 			goto retry;
1992 		if (errno != EPIPE)
1993 			logerror("ctlconn write");
1994 		/* FALLTHROUGH */
1995 	case 0:
1996 		ctlconn_cleanup();
1997 		return;
1998 	default:
1999 		ctl_reply_offset += n;
2000 	}
2001 	if (ctl_reply_offset >= ctl_reply_size) {
2002 		/*
2003 		 * Make space in the buffer for continous writes.
2004 		 * Set offset behind reply header to skip it
2005 		 */
2006 		if (ctl_state == CTL_WRITING_CONT_REPLY) {
2007 			*reply_text = '\0';
2008 			ctl_reply_offset = ctl_reply_size = CTL_REPLY_SIZE;
2009 
2010 			/* Now is a good time to report dropped lines */
2011 			if (membuf_drop) {
2012 				strlcat(reply_text, "<ENOBUFS>\n", MAX_MEMBUF);
2013 				ctl_reply_size = CTL_REPLY_SIZE;
2014 				membuf_drop = 0;
2015 			} else {
2016 				/* Nothing left to write */
2017 				pfd[PFD_CTLCONN].events = POLLIN;
2018 			}
2019 		} else
2020 			ctlconn_cleanup();
2021 	}
2022 }
2023 
2024 /* Shorten replytext to number of lines */
2025 void
2026 tailify_replytext(char *replytext, int lines)
2027 {
2028 	char *start, *nl;
2029 	int count = 0;
2030 	start = nl = replytext;
2031 
2032 	while ((nl = strchr(nl, '\n')) != NULL) {
2033 		nl++;
2034 		if (++count > lines) {
2035 			start = strchr(start, '\n');
2036 			start++;
2037 		}
2038 	}
2039 	if (start != replytext) {
2040 		int len = strlen(start);
2041 		memmove(replytext, start, len);
2042 		*(replytext + len) = '\0';
2043 	}
2044 }
2045 
2046 void
2047 logto_ctlconn(char *line)
2048 {
2049 	size_t l;
2050 
2051 	if (membuf_drop)
2052 		return;
2053 
2054 	l = strlen(line);
2055 	if (l + 2 > (CTL_REPLY_MAXSIZE - ctl_reply_size)) {
2056 		/* remember line drops for later report */
2057 		membuf_drop = 1;
2058 		return;
2059 	}
2060 	memcpy(ctl_reply + ctl_reply_size, line, l);
2061 	memcpy(ctl_reply + ctl_reply_size + l, "\n", 2);
2062 	ctl_reply_size += l + 1;
2063 	pfd[PFD_CTLCONN].events |= POLLOUT;
2064 }
2065