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