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