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