syslogd.c revision 346404
1/*
2 * Copyright (c) 1983, 1988, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29/*-
30 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
31 *
32 * Copyright (c) 2018 Prodrive Technologies, https://prodrive-technologies.com/
33 * Author: Ed Schouten <ed@FreeBSD.org>
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 *    notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 *    notice, this list of conditions and the following disclaimer in the
42 *    documentation and/or other materials provided with the distribution.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57#ifndef lint
58static const char copyright[] =
59"@(#) Copyright (c) 1983, 1988, 1993, 1994\n\
60	The Regents of the University of California.  All rights reserved.\n";
61#endif /* not lint */
62
63#ifndef lint
64#if 0
65static char sccsid[] = "@(#)syslogd.c	8.3 (Berkeley) 4/4/94";
66#endif
67#endif /* not lint */
68
69#include <sys/cdefs.h>
70__FBSDID("$FreeBSD: stable/11/usr.sbin/syslogd/syslogd.c 346404 2019-04-19 17:29:20Z bz $");
71
72/*
73 *  syslogd -- log system messages
74 *
75 * This program implements a system log. It takes a series of lines.
76 * Each line may have a priority, signified as "<n>" as
77 * the first characters of the line.  If this is
78 * not present, a default priority is used.
79 *
80 * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
81 * cause it to reread its configuration file.
82 *
83 * Defined Constants:
84 *
85 * MAXLINE -- the maximum line length that can be handled.
86 * DEFUPRI -- the default priority for user messages
87 * DEFSPRI -- the default priority for kernel messages
88 *
89 * Author: Eric Allman
90 * extensive changes by Ralph Campbell
91 * more extensive changes by Eric Allman (again)
92 * Extension to log by program name as well as facility and priority
93 *   by Peter da Silva.
94 * -u and -v by Harlan Stenn.
95 * Priority comparison code by Harlan Stenn.
96 */
97
98/* Maximum number of characters in time of last occurrence */
99#define	MAXLINE		2048		/* maximum line length */
100#define	MAXSVLINE	MAXLINE		/* maximum saved line length */
101#define	DEFUPRI		(LOG_USER|LOG_NOTICE)
102#define	DEFSPRI		(LOG_KERN|LOG_CRIT)
103#define	TIMERINTVL	30		/* interval for checking flush, mark */
104#define	TTYMSGTIME	1		/* timeout passed to ttymsg */
105#define	RCVBUF_MINSIZE	(80 * 1024)	/* minimum size of dgram rcv buffer */
106
107#include <sys/param.h>
108#include <sys/ioctl.h>
109#include <sys/mman.h>
110#include <sys/queue.h>
111#include <sys/resource.h>
112#include <sys/socket.h>
113#include <sys/stat.h>
114#include <sys/syslimits.h>
115#include <sys/time.h>
116#include <sys/uio.h>
117#include <sys/un.h>
118#include <sys/wait.h>
119
120#if defined(INET) || defined(INET6)
121#include <netinet/in.h>
122#include <arpa/inet.h>
123#endif
124
125#include <assert.h>
126#include <ctype.h>
127#include <dirent.h>
128#include <err.h>
129#include <errno.h>
130#include <fcntl.h>
131#include <fnmatch.h>
132#include <libutil.h>
133#include <limits.h>
134#include <netdb.h>
135#include <paths.h>
136#include <signal.h>
137#include <stdbool.h>
138#include <stdio.h>
139#include <stdlib.h>
140#include <string.h>
141#include <sysexits.h>
142#include <unistd.h>
143#include <utmpx.h>
144
145#include "pathnames.h"
146#include "ttymsg.h"
147
148#define SYSLOG_NAMES
149#include <sys/syslog.h>
150
151static const char *ConfFile = _PATH_LOGCONF;
152static const char *PidFile = _PATH_LOGPID;
153static const char ctty[] = _PATH_CONSOLE;
154static const char include_str[] = "include";
155static const char include_ext[] = ".conf";
156
157#define	dprintf		if (Debug) printf
158
159#define	MAXUNAMES	20	/* maximum number of user names */
160
161#define	sstosa(ss)	((struct sockaddr *)(ss))
162#ifdef INET
163#define	sstosin(ss)	((struct sockaddr_in *)(void *)(ss))
164#define	satosin(sa)	((struct sockaddr_in *)(void *)(sa))
165#endif
166#ifdef INET6
167#define	sstosin6(ss)	((struct sockaddr_in6 *)(void *)(ss))
168#define	satosin6(sa)	((struct sockaddr_in6 *)(void *)(sa))
169#define	s6_addr32	__u6_addr.__u6_addr32
170#define	IN6_ARE_MASKED_ADDR_EQUAL(d, a, m)	(	\
171	(((d)->s6_addr32[0] ^ (a)->s6_addr32[0]) & (m)->s6_addr32[0]) == 0 && \
172	(((d)->s6_addr32[1] ^ (a)->s6_addr32[1]) & (m)->s6_addr32[1]) == 0 && \
173	(((d)->s6_addr32[2] ^ (a)->s6_addr32[2]) & (m)->s6_addr32[2]) == 0 && \
174	(((d)->s6_addr32[3] ^ (a)->s6_addr32[3]) & (m)->s6_addr32[3]) == 0 )
175#endif
176/*
177 * List of peers and sockets for binding.
178 */
179struct peer {
180	const char	*pe_name;
181	const char	*pe_serv;
182	mode_t		pe_mode;
183	STAILQ_ENTRY(peer)	next;
184};
185static STAILQ_HEAD(, peer) pqueue = STAILQ_HEAD_INITIALIZER(pqueue);
186
187struct socklist {
188	struct sockaddr_storage	sl_ss;
189	int			sl_socket;
190	struct peer		*sl_peer;
191	int			(*sl_recv)(struct socklist *);
192	STAILQ_ENTRY(socklist)	next;
193};
194static STAILQ_HEAD(, socklist) shead = STAILQ_HEAD_INITIALIZER(shead);
195
196/*
197 * Flags to logmsg().
198 */
199
200#define	IGN_CONS	0x001	/* don't print on console */
201#define	SYNC_FILE	0x002	/* do fsync on file after printing */
202#define	MARK		0x008	/* this message is a mark */
203
204/* Timestamps of log entries. */
205struct logtime {
206	struct tm	tm;
207	suseconds_t	usec;
208};
209
210/* Traditional syslog timestamp format. */
211#define	RFC3164_DATELEN	15
212#define	RFC3164_DATEFMT	"%b %e %H:%M:%S"
213
214/*
215 * This structure represents the files that will have log
216 * copies printed.
217 * We require f_file to be valid if f_type is F_FILE, F_CONSOLE, F_TTY
218 * or if f_type is F_PIPE and f_pid > 0.
219 */
220
221struct filed {
222	STAILQ_ENTRY(filed)	next;	/* next in linked list */
223	short	f_type;			/* entry type, see below */
224	short	f_file;			/* file descriptor */
225	time_t	f_time;			/* time this was last written */
226	char	*f_host;		/* host from which to recd. */
227	u_char	f_pmask[LOG_NFACILITIES+1];	/* priority mask */
228	u_char	f_pcmp[LOG_NFACILITIES+1];	/* compare priority */
229#define PRI_LT	0x1
230#define PRI_EQ	0x2
231#define PRI_GT	0x4
232	char	*f_program;		/* program this applies to */
233	union {
234		char	f_uname[MAXUNAMES][MAXLOGNAME];
235		struct {
236			char	f_hname[MAXHOSTNAMELEN];
237			struct addrinfo *f_addr;
238
239		} f_forw;		/* forwarding address */
240		char	f_fname[MAXPATHLEN];
241		struct {
242			char	f_pname[MAXPATHLEN];
243			pid_t	f_pid;
244		} f_pipe;
245	} f_un;
246#define	fu_uname	f_un.f_uname
247#define	fu_forw_hname	f_un.f_forw.f_hname
248#define	fu_forw_addr	f_un.f_forw.f_addr
249#define	fu_fname	f_un.f_fname
250#define	fu_pipe_pname	f_un.f_pipe.f_pname
251#define	fu_pipe_pid	f_un.f_pipe.f_pid
252	char	f_prevline[MAXSVLINE];		/* last message logged */
253	struct logtime f_lasttime;		/* time of last occurrence */
254	int	f_prevpri;			/* pri of f_prevline */
255	size_t	f_prevlen;			/* length of f_prevline */
256	int	f_prevcount;			/* repetition cnt of prevline */
257	u_int	f_repeatcount;			/* number of "repeated" msgs */
258	int	f_flags;			/* file-specific flags */
259#define	FFLAG_SYNC 0x01
260#define	FFLAG_NEEDSYNC	0x02
261};
262
263/*
264 * Queue of about-to-be dead processes we should watch out for.
265 */
266struct deadq_entry {
267	pid_t				dq_pid;
268	int				dq_timeout;
269	TAILQ_ENTRY(deadq_entry)	dq_entries;
270};
271static TAILQ_HEAD(, deadq_entry) deadq_head =
272    TAILQ_HEAD_INITIALIZER(deadq_head);
273
274/*
275 * The timeout to apply to processes waiting on the dead queue.  Unit
276 * of measure is `mark intervals', i.e. 20 minutes by default.
277 * Processes on the dead queue will be terminated after that time.
278 */
279
280#define	 DQ_TIMO_INIT	2
281
282/*
283 * Struct to hold records of network addresses that are allowed to log
284 * to us.
285 */
286struct allowedpeer {
287	int isnumeric;
288	u_short port;
289	union {
290		struct {
291			struct sockaddr_storage addr;
292			struct sockaddr_storage mask;
293		} numeric;
294		char *name;
295	} u;
296#define a_addr u.numeric.addr
297#define a_mask u.numeric.mask
298#define a_name u.name
299	STAILQ_ENTRY(allowedpeer)	next;
300};
301static STAILQ_HEAD(, allowedpeer) aphead = STAILQ_HEAD_INITIALIZER(aphead);
302
303
304/*
305 * Intervals at which we flush out "message repeated" messages,
306 * in seconds after previous message is logged.  After each flush,
307 * we move to the next interval until we reach the largest.
308 */
309static int repeatinterval[] = { 30, 120, 600 };	/* # of secs before flush */
310#define	MAXREPEAT	(nitems(repeatinterval) - 1)
311#define	REPEATTIME(f)	((f)->f_time + repeatinterval[(f)->f_repeatcount])
312#define	BACKOFF(f)	do {						\
313				if (++(f)->f_repeatcount > MAXREPEAT)	\
314					(f)->f_repeatcount = MAXREPEAT;	\
315			} while (0)
316
317/* values for f_type */
318#define F_UNUSED	0		/* unused entry */
319#define F_FILE		1		/* regular file */
320#define F_TTY		2		/* terminal */
321#define F_CONSOLE	3		/* console terminal */
322#define F_FORW		4		/* remote machine */
323#define F_USERS		5		/* list of users */
324#define F_WALL		6		/* everyone logged on */
325#define F_PIPE		7		/* pipe to program */
326
327static const char *TypeNames[] = {
328	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
329	"FORW",		"USERS",	"WALL",		"PIPE"
330};
331
332static STAILQ_HEAD(, filed) fhead =
333    STAILQ_HEAD_INITIALIZER(fhead);	/* Log files that we write to */
334static struct filed consfile;	/* Console */
335
336static int	Debug;		/* debug flag */
337static int	Foreground = 0;	/* Run in foreground, instead of daemonizing */
338static int	resolve = 1;	/* resolve hostname */
339static char	LocalHostName[MAXHOSTNAMELEN];	/* our hostname */
340static const char *LocalDomain;	/* our local domain name */
341static int	Initialized;	/* set when we have initialized ourselves */
342static int	MarkInterval = 20 * 60;	/* interval between marks in seconds */
343static int	MarkSeq;	/* mark sequence number */
344static int	NoBind;		/* don't bind() as suggested by RFC 3164 */
345static int	SecureMode;	/* when true, receive only unix domain socks */
346#ifdef INET6
347static int	family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
348#else
349static int	family = PF_INET; /* protocol family (IPv4 only) */
350#endif
351static int	mask_C1 = 1;	/* mask characters from 0x80 - 0x9F */
352static int	send_to_all;	/* send message to all IPv4/IPv6 addresses */
353static int	use_bootfile;	/* log entire bootfile for every kern msg */
354static int	no_compress;	/* don't compress messages (1=pipes, 2=all) */
355static int	logflags = O_WRONLY|O_APPEND; /* flags used to open log files */
356
357static char	bootfile[MAXLINE+1]; /* booted kernel file */
358
359static int	RemoteAddDate;	/* Always set the date on remote messages */
360static int	RemoteHostname;	/* Log remote hostname from the message */
361
362static int	UniquePriority;	/* Only log specified priority? */
363static int	LogFacPri;	/* Put facility and priority in log message: */
364				/* 0=no, 1=numeric, 2=names */
365static int	KeepKernFac;	/* Keep remotely logged kernel facility */
366static int	needdofsync = 0; /* Are any file(s) waiting to be fsynced? */
367static struct pidfh *pfh;
368static int	sigpipe[2];	/* Pipe to catch a signal during select(). */
369static bool	RFC3164OutputFormat = true; /* Use legacy format by default. */
370
371static volatile sig_atomic_t MarkSet, WantDie, WantInitialize, WantReapchild;
372
373struct iovlist;
374
375static int	allowaddr(char *);
376static int	addfile(struct filed *);
377static int	addpeer(struct peer *);
378static int	addsock(struct sockaddr *, socklen_t, struct socklist *);
379static struct filed *cfline(const char *, const char *, const char *);
380static const char *cvthname(struct sockaddr *);
381static void	deadq_enter(pid_t, const char *);
382static int	deadq_remove(struct deadq_entry *);
383static int	deadq_removebypid(pid_t);
384static int	decode(const char *, const CODE *);
385static void	die(int) __dead2;
386static void	dodie(int);
387static void	dofsync(void);
388static void	domark(int);
389static void	fprintlog_first(struct filed *, const char *, const char *,
390    const char *, const char *, const char *, const char *, int);
391static void	fprintlog_write(struct filed *, struct iovlist *, int);
392static void	fprintlog_successive(struct filed *, int);
393static void	init(int);
394static void	logerror(const char *);
395static void	logmsg(int, const struct logtime *, const char *, const char *,
396    const char *, const char *, const char *, const char *, int);
397static void	log_deadchild(pid_t, int, const char *);
398static void	markit(void);
399static int	socksetup(struct peer *);
400static int	socklist_recv_file(struct socklist *);
401static int	socklist_recv_sock(struct socklist *);
402static int	socklist_recv_signal(struct socklist *);
403static void	sighandler(int);
404static int	skip_message(const char *, const char *, int);
405static void	parsemsg(const char *, char *);
406static void	printsys(char *);
407static int	p_open(const char *, pid_t *);
408static void	reapchild(int);
409static const char *ttymsg_check(struct iovec *, int, char *, int);
410static void	usage(void);
411static int	validate(struct sockaddr *, const char *);
412static void	unmapped(struct sockaddr *);
413static void	wallmsg(struct filed *, struct iovec *, const int iovlen);
414static int	waitdaemon(int);
415static void	timedout(int);
416static void	increase_rcvbuf(int);
417
418static void
419close_filed(struct filed *f)
420{
421
422	if (f == NULL || f->f_file == -1)
423		return;
424
425	switch (f->f_type) {
426	case F_FORW:
427		if (f->f_un.f_forw.f_addr) {
428			freeaddrinfo(f->f_un.f_forw.f_addr);
429			f->f_un.f_forw.f_addr = NULL;
430		}
431		/* FALLTHROUGH */
432
433	case F_FILE:
434	case F_TTY:
435	case F_CONSOLE:
436		f->f_type = F_UNUSED;
437		break;
438	case F_PIPE:
439		f->fu_pipe_pid = 0;
440		break;
441	}
442	(void)close(f->f_file);
443	f->f_file = -1;
444}
445
446static int
447addfile(struct filed *f0)
448{
449	struct filed *f;
450
451	f = calloc(1, sizeof(*f));
452	if (f == NULL)
453		err(1, "malloc failed");
454	*f = *f0;
455	STAILQ_INSERT_TAIL(&fhead, f, next);
456
457	return (0);
458}
459
460static int
461addpeer(struct peer *pe0)
462{
463	struct peer *pe;
464
465	pe = calloc(1, sizeof(*pe));
466	if (pe == NULL)
467		err(1, "malloc failed");
468	*pe = *pe0;
469	STAILQ_INSERT_TAIL(&pqueue, pe, next);
470
471	return (0);
472}
473
474static int
475addsock(struct sockaddr *sa, socklen_t sa_len, struct socklist *sl0)
476{
477	struct socklist *sl;
478
479	sl = calloc(1, sizeof(*sl));
480	if (sl == NULL)
481		err(1, "malloc failed");
482	*sl = *sl0;
483	if (sa != NULL && sa_len > 0)
484		memcpy(&sl->sl_ss, sa, sa_len);
485	STAILQ_INSERT_TAIL(&shead, sl, next);
486
487	return (0);
488}
489
490int
491main(int argc, char *argv[])
492{
493	int ch, i, s, fdsrmax = 0, bflag = 0, pflag = 0, Sflag = 0;
494	fd_set *fdsr = NULL;
495	struct timeval tv, *tvp;
496	struct peer *pe;
497	struct socklist *sl;
498	pid_t ppid = 1, spid;
499	char *p;
500
501	if (madvise(NULL, 0, MADV_PROTECT) != 0)
502		dprintf("madvise() failed: %s\n", strerror(errno));
503
504	while ((ch = getopt(argc, argv, "468Aa:b:cCdf:FHkl:m:nNoO:p:P:sS:Tuv"))
505	    != -1)
506		switch (ch) {
507#ifdef INET
508		case '4':
509			family = PF_INET;
510			break;
511#endif
512#ifdef INET6
513		case '6':
514			family = PF_INET6;
515			break;
516#endif
517		case '8':
518			mask_C1 = 0;
519			break;
520		case 'A':
521			send_to_all++;
522			break;
523		case 'a':		/* allow specific network addresses only */
524			if (allowaddr(optarg) == -1)
525				usage();
526			break;
527		case 'b':
528			bflag = 1;
529			p = strchr(optarg, ']');
530			if (p != NULL)
531				p = strchr(p + 1, ':');
532			else {
533				p = strchr(optarg, ':');
534				if (p != NULL && strchr(p + 1, ':') != NULL)
535					p = NULL; /* backward compatibility */
536			}
537			if (p == NULL) {
538				/* A hostname or filename only. */
539				addpeer(&(struct peer){
540					.pe_name = optarg,
541					.pe_serv = "syslog"
542				});
543			} else {
544				/* The case of "name:service". */
545				*p++ = '\0';
546				addpeer(&(struct peer){
547					.pe_serv = p,
548					.pe_name = (strlen(optarg) == 0) ?
549					    NULL : optarg,
550				});
551			}
552			break;
553		case 'c':
554			no_compress++;
555			break;
556		case 'C':
557			logflags |= O_CREAT;
558			break;
559		case 'd':		/* debug */
560			Debug++;
561			break;
562		case 'f':		/* configuration file */
563			ConfFile = optarg;
564			break;
565		case 'F':		/* run in foreground instead of daemon */
566			Foreground++;
567			break;
568		case 'H':
569			RemoteHostname = 1;
570			break;
571		case 'k':		/* keep remote kern fac */
572			KeepKernFac = 1;
573			break;
574		case 'l':
575		case 'p':
576		case 'S':
577		    {
578			long	perml;
579			mode_t	mode;
580			char	*name, *ep;
581
582			if (ch == 'l')
583				mode = DEFFILEMODE;
584			else if (ch == 'p') {
585				mode = DEFFILEMODE;
586				pflag = 1;
587			} else {
588				mode = S_IRUSR | S_IWUSR;
589				Sflag = 1;
590			}
591			if (optarg[0] == '/')
592				name = optarg;
593			else if ((name = strchr(optarg, ':')) != NULL) {
594				*name++ = '\0';
595				if (name[0] != '/')
596					errx(1, "socket name must be absolute "
597					    "path");
598				if (isdigit(*optarg)) {
599					perml = strtol(optarg, &ep, 8);
600				    if (*ep || perml < 0 ||
601					perml & ~(S_IRWXU|S_IRWXG|S_IRWXO))
602					    errx(1, "invalid mode %s, exiting",
603						optarg);
604				    mode = (mode_t )perml;
605				} else
606					errx(1, "invalid mode %s, exiting",
607					    optarg);
608			} else
609				errx(1, "invalid filename %s, exiting",
610				    optarg);
611			addpeer(&(struct peer){
612				.pe_name = name,
613				.pe_mode = mode
614			});
615			break;
616		   }
617		case 'm':		/* mark interval */
618			MarkInterval = atoi(optarg) * 60;
619			break;
620		case 'N':
621			NoBind = 1;
622			SecureMode = 1;
623			break;
624		case 'n':
625			resolve = 0;
626			break;
627		case 'O':
628			if (strcmp(optarg, "bsd") == 0 ||
629			    strcmp(optarg, "rfc3164") == 0)
630				RFC3164OutputFormat = true;
631			else if (strcmp(optarg, "syslog") == 0 ||
632			    strcmp(optarg, "rfc5424") == 0)
633				RFC3164OutputFormat = false;
634			else
635				usage();
636			break;
637		case 'o':
638			use_bootfile = 1;
639			break;
640		case 'P':		/* path for alt. PID */
641			PidFile = optarg;
642			break;
643		case 's':		/* no network mode */
644			SecureMode++;
645			break;
646		case 'T':
647			RemoteAddDate = 1;
648			break;
649		case 'u':		/* only log specified priority */
650			UniquePriority++;
651			break;
652		case 'v':		/* log facility and priority */
653		  	LogFacPri++;
654			break;
655		default:
656			usage();
657		}
658	if ((argc -= optind) != 0)
659		usage();
660
661	/* Pipe to catch a signal during select(). */
662	s = pipe2(sigpipe, O_CLOEXEC);
663	if (s < 0) {
664		err(1, "cannot open a pipe for signals");
665	} else {
666		addsock(NULL, 0, &(struct socklist){
667		    .sl_socket = sigpipe[0],
668		    .sl_recv = socklist_recv_signal
669		});
670	}
671
672	/* Listen by default: /dev/klog. */
673	s = open(_PATH_KLOG, O_RDONLY | O_NONBLOCK | O_CLOEXEC, 0);
674	if (s < 0) {
675		dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
676	} else {
677		addsock(NULL, 0, &(struct socklist){
678			.sl_socket = s,
679			.sl_recv = socklist_recv_file,
680		});
681	}
682	/* Listen by default: *:514 if no -b flag. */
683	if (bflag == 0)
684		addpeer(&(struct peer){
685			.pe_serv = "syslog"
686		});
687	/* Listen by default: /var/run/log if no -p flag. */
688	if (pflag == 0)
689		addpeer(&(struct peer){
690			.pe_name = _PATH_LOG,
691			.pe_mode = DEFFILEMODE,
692		});
693	/* Listen by default: /var/run/logpriv if no -S flag. */
694	if (Sflag == 0)
695		addpeer(&(struct peer){
696			.pe_name = _PATH_LOG_PRIV,
697			.pe_mode = S_IRUSR | S_IWUSR,
698		});
699	STAILQ_FOREACH(pe, &pqueue, next)
700		socksetup(pe);
701
702	pfh = pidfile_open(PidFile, 0600, &spid);
703	if (pfh == NULL) {
704		if (errno == EEXIST)
705			errx(1, "syslogd already running, pid: %d", spid);
706		warn("cannot open pid file");
707	}
708
709	if ((!Foreground) && (!Debug)) {
710		ppid = waitdaemon(30);
711		if (ppid < 0) {
712			warn("could not become daemon");
713			pidfile_remove(pfh);
714			exit(1);
715		}
716	} else if (Debug)
717		setlinebuf(stdout);
718
719	consfile.f_type = F_CONSOLE;
720	(void)strlcpy(consfile.fu_fname, ctty + sizeof _PATH_DEV - 1,
721	    sizeof(consfile.fu_fname));
722	(void)strlcpy(bootfile, getbootfile(), sizeof(bootfile));
723	(void)signal(SIGTERM, dodie);
724	(void)signal(SIGINT, Debug ? dodie : SIG_IGN);
725	(void)signal(SIGQUIT, Debug ? dodie : SIG_IGN);
726	(void)signal(SIGHUP, sighandler);
727	(void)signal(SIGCHLD, sighandler);
728	(void)signal(SIGALRM, domark);
729	(void)signal(SIGPIPE, SIG_IGN);	/* We'll catch EPIPE instead. */
730	(void)alarm(TIMERINTVL);
731
732	/* tuck my process id away */
733	pidfile_write(pfh);
734
735	dprintf("off & running....\n");
736
737	tvp = &tv;
738	tv.tv_sec = tv.tv_usec = 0;
739
740	STAILQ_FOREACH(sl, &shead, next) {
741		if (sl->sl_socket > fdsrmax)
742			fdsrmax = sl->sl_socket;
743	}
744	fdsr = (fd_set *)calloc(howmany(fdsrmax+1, NFDBITS),
745	    sizeof(*fdsr));
746	if (fdsr == NULL)
747		errx(1, "calloc fd_set");
748
749	for (;;) {
750		if (Initialized == 0)
751			init(0);
752		else if (WantInitialize)
753			init(WantInitialize);
754		if (WantReapchild)
755			reapchild(WantReapchild);
756		if (MarkSet)
757			markit();
758		if (WantDie) {
759			free(fdsr);
760			die(WantDie);
761		}
762
763		bzero(fdsr, howmany(fdsrmax+1, NFDBITS) *
764		    sizeof(*fdsr));
765
766		STAILQ_FOREACH(sl, &shead, next) {
767			if (sl->sl_socket != -1 && sl->sl_recv != NULL)
768				FD_SET(sl->sl_socket, fdsr);
769		}
770		i = select(fdsrmax + 1, fdsr, NULL, NULL,
771		    needdofsync ? &tv : tvp);
772		switch (i) {
773		case 0:
774			dofsync();
775			needdofsync = 0;
776			if (tvp) {
777				tvp = NULL;
778				if (ppid != 1)
779					kill(ppid, SIGALRM);
780			}
781			continue;
782		case -1:
783			if (errno != EINTR)
784				logerror("select");
785			continue;
786		}
787		STAILQ_FOREACH(sl, &shead, next) {
788			if (FD_ISSET(sl->sl_socket, fdsr))
789				(*sl->sl_recv)(sl);
790		}
791	}
792	free(fdsr);
793}
794
795static int
796socklist_recv_signal(struct socklist *sl __unused)
797{
798	ssize_t len;
799	int i, nsig, signo;
800
801	if (ioctl(sigpipe[0], FIONREAD, &i) != 0) {
802		logerror("ioctl(FIONREAD)");
803		err(1, "signal pipe read failed");
804	}
805	nsig = i / sizeof(signo);
806	dprintf("# of received signals = %d\n", nsig);
807	for (i = 0; i < nsig; i++) {
808		len = read(sigpipe[0], &signo, sizeof(signo));
809		if (len != sizeof(signo)) {
810			logerror("signal pipe read failed");
811			err(1, "signal pipe read failed");
812		}
813		dprintf("Received signal: %d from fd=%d\n", signo,
814		    sigpipe[0]);
815		switch (signo) {
816		case SIGHUP:
817			WantInitialize = 1;
818			break;
819		case SIGCHLD:
820			WantReapchild = 1;
821			break;
822		}
823	}
824	return (0);
825}
826
827static int
828socklist_recv_sock(struct socklist *sl)
829{
830	struct sockaddr_storage ss;
831	struct sockaddr *sa = (struct sockaddr *)&ss;
832	socklen_t sslen;
833	const char *hname;
834	char line[MAXLINE + 1];
835	int len;
836
837	sslen = sizeof(ss);
838	len = recvfrom(sl->sl_socket, line, sizeof(line) - 1, 0, sa, &sslen);
839	dprintf("received sa_len = %d\n", sslen);
840	if (len == 0)
841		return (-1);
842	if (len < 0) {
843		if (errno != EINTR)
844			logerror("recvfrom");
845		return (-1);
846	}
847	/* Received valid data. */
848	line[len] = '\0';
849	if (sl->sl_ss.ss_family == AF_LOCAL)
850		hname = LocalHostName;
851	else {
852		hname = cvthname(sa);
853		unmapped(sa);
854		if (validate(sa, hname) == 0) {
855			dprintf("Message from %s was ignored.", hname);
856			return (-1);
857		}
858	}
859	parsemsg(hname, line);
860
861	return (0);
862}
863
864static void
865unmapped(struct sockaddr *sa)
866{
867#if defined(INET) && defined(INET6)
868	struct sockaddr_in6 *sin6;
869	struct sockaddr_in sin;
870
871	if (sa == NULL ||
872	    sa->sa_family != AF_INET6 ||
873	    sa->sa_len != sizeof(*sin6))
874		return;
875	sin6 = satosin6(sa);
876	if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
877		return;
878	sin = (struct sockaddr_in){
879		.sin_family = AF_INET,
880		.sin_len = sizeof(sin),
881		.sin_port = sin6->sin6_port
882	};
883	memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
884	    sizeof(sin.sin_addr));
885	memcpy(sa, &sin, sizeof(sin));
886#else
887	if (sa == NULL)
888		return;
889#endif
890}
891
892static void
893usage(void)
894{
895
896	fprintf(stderr,
897		"usage: syslogd [-468ACcdFHknosTuv] [-a allowed_peer]\n"
898		"               [-b bind_address] [-f config_file]\n"
899		"               [-l [mode:]path] [-m mark_interval]\n"
900		"               [-O format] [-P pid_file] [-p log_socket]\n"
901		"               [-S logpriv_socket]\n");
902	exit(1);
903}
904
905/*
906 * Removes characters from log messages that are unsafe to display.
907 * TODO: Permit UTF-8 strings that include a BOM per RFC 5424?
908 */
909static void
910parsemsg_remove_unsafe_characters(const char *in, char *out, size_t outlen)
911{
912	char *q;
913	int c;
914
915	q = out;
916	while ((c = (unsigned char)*in++) != '\0' && q < out + outlen - 4) {
917		if (mask_C1 && (c & 0x80) && c < 0xA0) {
918			c &= 0x7F;
919			*q++ = 'M';
920			*q++ = '-';
921		}
922		if (isascii(c) && iscntrl(c)) {
923			if (c == '\n') {
924				*q++ = ' ';
925			} else if (c == '\t') {
926				*q++ = '\t';
927			} else {
928				*q++ = '^';
929				*q++ = c ^ 0100;
930			}
931		} else {
932			*q++ = c;
933		}
934	}
935	*q = '\0';
936}
937
938/*
939 * Parses a syslog message according to RFC 5424, assuming that PRI and
940 * VERSION (i.e., "<%d>1 ") have already been parsed by parsemsg(). The
941 * parsed result is passed to logmsg().
942 */
943static void
944parsemsg_rfc5424(const char *from, int pri, char *msg)
945{
946	const struct logtime *timestamp;
947	struct logtime timestamp_remote;
948	const char *omsg, *hostname, *app_name, *procid, *msgid,
949	    *structured_data;
950	char line[MAXLINE + 1];
951
952#define	FAIL_IF(field, expr) do {					\
953	if (expr) {							\
954		dprintf("Failed to parse " field " from %s: %s\n",	\
955		    from, omsg);					\
956		return;							\
957	}								\
958} while (0)
959#define	PARSE_CHAR(field, sep) do {					\
960	FAIL_IF(field, *msg != sep);					\
961	++msg;								\
962} while (0)
963#define	IF_NOT_NILVALUE(var)						\
964	if (msg[0] == '-' && msg[1] == ' ') {				\
965		msg += 2;						\
966		var = NULL;						\
967	} else if (msg[0] == '-' && msg[1] == '\0') {			\
968		++msg;							\
969		var = NULL;						\
970	} else
971
972	omsg = msg;
973	IF_NOT_NILVALUE(timestamp) {
974		/* Parse RFC 3339-like timestamp. */
975#define	PARSE_NUMBER(dest, length, min, max) do {			\
976	int i, v;							\
977									\
978	v = 0;								\
979	for (i = 0; i < length; ++i) {					\
980		FAIL_IF("TIMESTAMP", *msg < '0' || *msg > '9');		\
981		v = v * 10 + *msg++ - '0';				\
982	}								\
983	FAIL_IF("TIMESTAMP", v < min || v > max);			\
984	dest = v;							\
985} while (0)
986		/* Date and time. */
987		memset(&timestamp_remote, 0, sizeof(timestamp_remote));
988		PARSE_NUMBER(timestamp_remote.tm.tm_year, 4, 0, 9999);
989		timestamp_remote.tm.tm_year -= 1900;
990		PARSE_CHAR("TIMESTAMP", '-');
991		PARSE_NUMBER(timestamp_remote.tm.tm_mon, 2, 1, 12);
992		--timestamp_remote.tm.tm_mon;
993		PARSE_CHAR("TIMESTAMP", '-');
994		PARSE_NUMBER(timestamp_remote.tm.tm_mday, 2, 1, 31);
995		PARSE_CHAR("TIMESTAMP", 'T');
996		PARSE_NUMBER(timestamp_remote.tm.tm_hour, 2, 0, 23);
997		PARSE_CHAR("TIMESTAMP", ':');
998		PARSE_NUMBER(timestamp_remote.tm.tm_min, 2, 0, 59);
999		PARSE_CHAR("TIMESTAMP", ':');
1000		PARSE_NUMBER(timestamp_remote.tm.tm_sec, 2, 0, 59);
1001		/* Perform normalization. */
1002		timegm(&timestamp_remote.tm);
1003		/* Optional: fractional seconds. */
1004		if (msg[0] == '.' && msg[1] >= '0' && msg[1] <= '9') {
1005			int i;
1006
1007			++msg;
1008			for (i = 100000; i != 0; i /= 10) {
1009				if (*msg < '0' || *msg > '9')
1010					break;
1011				timestamp_remote.usec += (*msg++ - '0') * i;
1012			}
1013		}
1014		/* Timezone. */
1015		if (*msg == 'Z') {
1016			/* UTC. */
1017			++msg;
1018		} else {
1019			int sign, tz_hour, tz_min;
1020
1021			/* Local time zone offset. */
1022			FAIL_IF("TIMESTAMP", *msg != '-' && *msg != '+');
1023			sign = *msg++ == '-' ? -1 : 1;
1024			PARSE_NUMBER(tz_hour, 2, 0, 23);
1025			PARSE_CHAR("TIMESTAMP", ':');
1026			PARSE_NUMBER(tz_min, 2, 0, 59);
1027			timestamp_remote.tm.tm_gmtoff =
1028			    sign * (tz_hour * 3600 + tz_min * 60);
1029		}
1030#undef PARSE_NUMBER
1031		PARSE_CHAR("TIMESTAMP", ' ');
1032		timestamp = RemoteAddDate ? NULL : &timestamp_remote;
1033	}
1034
1035	/* String fields part of the HEADER. */
1036#define	PARSE_STRING(field, var)					\
1037	IF_NOT_NILVALUE(var) {						\
1038		var = msg;						\
1039		while (*msg >= '!' && *msg <= '~')			\
1040			++msg;						\
1041		FAIL_IF(field, var == msg);				\
1042		PARSE_CHAR(field, ' ');					\
1043		msg[-1] = '\0';						\
1044	}
1045	PARSE_STRING("HOSTNAME", hostname);
1046	if (hostname == NULL || !RemoteHostname)
1047		hostname = from;
1048	PARSE_STRING("APP-NAME", app_name);
1049	PARSE_STRING("PROCID", procid);
1050	PARSE_STRING("MSGID", msgid);
1051#undef PARSE_STRING
1052
1053	/* Structured data. */
1054#define	PARSE_SD_NAME() do {						\
1055	const char *start;						\
1056									\
1057	start = msg;							\
1058	while (*msg >= '!' && *msg <= '~' && *msg != '=' &&		\
1059	    *msg != ']' && *msg != '"')					\
1060		++msg;							\
1061	FAIL_IF("STRUCTURED-NAME", start == msg);			\
1062} while (0)
1063	IF_NOT_NILVALUE(structured_data) {
1064		/* SD-ELEMENT. */
1065		while (*msg == '[') {
1066			++msg;
1067			/* SD-ID. */
1068			PARSE_SD_NAME();
1069			/* SD-PARAM. */
1070			while (*msg == ' ') {
1071				++msg;
1072				/* PARAM-NAME. */
1073				PARSE_SD_NAME();
1074				PARSE_CHAR("STRUCTURED-NAME", '=');
1075				PARSE_CHAR("STRUCTURED-NAME", '"');
1076				while (*msg != '"') {
1077					FAIL_IF("STRUCTURED-NAME",
1078					    *msg == '\0');
1079					if (*msg++ == '\\') {
1080						FAIL_IF("STRUCTURED-NAME",
1081						    *msg == '\0');
1082						++msg;
1083					}
1084				}
1085				++msg;
1086			}
1087			PARSE_CHAR("STRUCTURED-NAME", ']');
1088		}
1089		PARSE_CHAR("STRUCTURED-NAME", ' ');
1090		msg[-1] = '\0';
1091	}
1092#undef PARSE_SD_NAME
1093
1094#undef FAIL_IF
1095#undef PARSE_CHAR
1096#undef IF_NOT_NILVALUE
1097
1098	parsemsg_remove_unsafe_characters(msg, line, sizeof(line));
1099	logmsg(pri, timestamp, hostname, app_name, procid, msgid,
1100	    structured_data, line, 0);
1101}
1102
1103/*
1104 * Trims the application name ("TAG" in RFC 3164 terminology) and
1105 * process ID from a message if present.
1106 */
1107static void
1108parsemsg_rfc3164_app_name_procid(char **msg, const char **app_name,
1109    const char **procid) {
1110	char *m, *app_name_begin, *procid_begin;
1111	size_t app_name_length, procid_length;
1112
1113	m = *msg;
1114
1115	/* Application name. */
1116	app_name_begin = m;
1117	app_name_length = strspn(m,
1118	    "abcdefghijklmnopqrstuvwxyz"
1119	    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1120	    "0123456789"
1121	    "_-/");
1122	if (app_name_length == 0)
1123		goto bad;
1124	m += app_name_length;
1125
1126	/* Process identifier (optional). */
1127	if (*m == '[') {
1128		procid_begin = ++m;
1129		procid_length = strspn(m, "0123456789");
1130		if (procid_length == 0)
1131			goto bad;
1132		m += procid_length;
1133		if (*m++ != ']')
1134			goto bad;
1135	} else {
1136		procid_begin = NULL;
1137		procid_length = 0;
1138	}
1139
1140	/* Separator. */
1141	if (m[0] != ':' || m[1] != ' ')
1142		goto bad;
1143
1144	/* Split strings from input. */
1145	app_name_begin[app_name_length] = '\0';
1146	if (procid_begin != 0)
1147		procid_begin[procid_length] = '\0';
1148
1149	*msg = m + 2;
1150	*app_name = app_name_begin;
1151	*procid = procid_begin;
1152	return;
1153bad:
1154	*app_name = NULL;
1155	*procid = NULL;
1156}
1157
1158/*
1159 * Parses a syslog message according to RFC 3164, assuming that PRI
1160 * (i.e., "<%d>") has already been parsed by parsemsg(). The parsed
1161 * result is passed to logmsg().
1162 */
1163static void
1164parsemsg_rfc3164(const char *from, int pri, char *msg)
1165{
1166	struct tm tm_parsed;
1167	const struct logtime *timestamp;
1168	struct logtime timestamp_remote;
1169	const char *app_name, *procid;
1170	size_t i, msglen;
1171	char line[MAXLINE + 1];
1172
1173	/*
1174	 * Parse the TIMESTAMP provided by the remote side. If none is
1175	 * found, assume this is not an RFC 3164 formatted message,
1176	 * only containing a TAG and a MSG.
1177	 */
1178	timestamp = NULL;
1179	if (strptime(msg, RFC3164_DATEFMT, &tm_parsed) ==
1180	    msg + RFC3164_DATELEN && msg[RFC3164_DATELEN] == ' ') {
1181		msg += RFC3164_DATELEN + 1;
1182		if (!RemoteAddDate) {
1183			struct tm tm_now;
1184			time_t t_now;
1185			int year;
1186
1187			/*
1188			 * As the timestamp does not contain the year
1189			 * number, daylight saving time information, nor
1190			 * a time zone, attempt to infer it. Due to
1191			 * clock skews, the timestamp may even be part
1192			 * of the next year. Use the last year for which
1193			 * the timestamp is at most one week in the
1194			 * future.
1195			 *
1196			 * This loop can only run for at most three
1197			 * iterations before terminating.
1198			 */
1199			t_now = time(NULL);
1200			localtime_r(&t_now, &tm_now);
1201			for (year = tm_now.tm_year + 1;; --year) {
1202				assert(year >= tm_now.tm_year - 1);
1203				timestamp_remote.tm = tm_parsed;
1204				timestamp_remote.tm.tm_year = year;
1205				timestamp_remote.tm.tm_isdst = -1;
1206				timestamp_remote.usec = 0;
1207				if (mktime(&timestamp_remote.tm) <
1208				    t_now + 7 * 24 * 60 * 60)
1209					break;
1210			}
1211			timestamp = &timestamp_remote;
1212		}
1213
1214		/*
1215		 * A single space character MUST also follow the HOSTNAME field.
1216		 */
1217		msglen = strlen(msg);
1218		for (i = 0; i < MIN(MAXHOSTNAMELEN, msglen); i++) {
1219			if (msg[i] == ' ') {
1220				if (RemoteHostname) {
1221					msg[i] = '\0';
1222					from = msg;
1223				}
1224				msg += i + 1;
1225				break;
1226			}
1227			/*
1228			 * Support non RFC compliant messages, without hostname.
1229			 */
1230			if (msg[i] == ':')
1231				break;
1232		}
1233		if (i == MIN(MAXHOSTNAMELEN, msglen)) {
1234			dprintf("Invalid HOSTNAME from %s: %s\n", from, msg);
1235			return;
1236		}
1237	}
1238
1239	/* Remove the TAG, if present. */
1240	parsemsg_rfc3164_app_name_procid(&msg, &app_name, &procid);
1241	parsemsg_remove_unsafe_characters(msg, line, sizeof(line));
1242	logmsg(pri, timestamp, from, app_name, procid, NULL, NULL, line, 0);
1243}
1244
1245/*
1246 * Takes a raw input line, extracts PRI and determines whether the
1247 * message is formatted according to RFC 3164 or RFC 5424. Continues
1248 * parsing of addition fields in the message according to those
1249 * standards and prints the message on the appropriate log files.
1250 */
1251static void
1252parsemsg(const char *from, char *msg)
1253{
1254	char *q;
1255	long n;
1256	size_t i;
1257	int pri;
1258
1259	/* Parse PRI. */
1260	if (msg[0] != '<' || !isdigit(msg[1])) {
1261		dprintf("Invalid PRI from %s\n", from);
1262		return;
1263	}
1264	for (i = 2; i <= 4; i++) {
1265		if (msg[i] == '>')
1266			break;
1267		if (!isdigit(msg[i])) {
1268			dprintf("Invalid PRI header from %s\n", from);
1269			return;
1270		}
1271	}
1272	if (msg[i] != '>') {
1273		dprintf("Invalid PRI header from %s\n", from);
1274		return;
1275	}
1276	errno = 0;
1277	n = strtol(msg + 1, &q, 10);
1278	if (errno != 0 || *q != msg[i] || n < 0 || n >= INT_MAX) {
1279		dprintf("Invalid PRI %ld from %s: %s\n",
1280		    n, from, strerror(errno));
1281		return;
1282	}
1283	pri = n;
1284	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
1285		pri = DEFUPRI;
1286
1287	/*
1288	 * Don't allow users to log kernel messages.
1289	 * NOTE: since LOG_KERN == 0 this will also match
1290	 *       messages with no facility specified.
1291	 */
1292	if ((pri & LOG_FACMASK) == LOG_KERN && !KeepKernFac)
1293		pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
1294
1295	/* Parse VERSION. */
1296	msg += i + 1;
1297	if (msg[0] == '1' && msg[1] == ' ')
1298		parsemsg_rfc5424(from, pri, msg + 2);
1299	else
1300		parsemsg_rfc3164(from, pri, msg);
1301}
1302
1303/*
1304 * Read /dev/klog while data are available, split into lines.
1305 */
1306static int
1307socklist_recv_file(struct socklist *sl)
1308{
1309	char *p, *q, line[MAXLINE + 1];
1310	int len, i;
1311
1312	len = 0;
1313	for (;;) {
1314		i = read(sl->sl_socket, line + len, MAXLINE - 1 - len);
1315		if (i > 0) {
1316			line[i + len] = '\0';
1317		} else {
1318			if (i < 0 && errno != EINTR && errno != EAGAIN) {
1319				logerror("klog");
1320				close(sl->sl_socket);
1321				sl->sl_socket = -1;
1322			}
1323			break;
1324		}
1325
1326		for (p = line; (q = strchr(p, '\n')) != NULL; p = q + 1) {
1327			*q = '\0';
1328			printsys(p);
1329		}
1330		len = strlen(p);
1331		if (len >= MAXLINE - 1) {
1332			printsys(p);
1333			len = 0;
1334		}
1335		if (len > 0)
1336			memmove(line, p, len + 1);
1337	}
1338	if (len > 0)
1339		printsys(line);
1340
1341	return (len);
1342}
1343
1344/*
1345 * Take a raw input line from /dev/klog, format similar to syslog().
1346 */
1347static void
1348printsys(char *msg)
1349{
1350	char *p, *q;
1351	long n;
1352	int flags, isprintf, pri;
1353
1354	flags = SYNC_FILE;	/* fsync after write */
1355	p = msg;
1356	pri = DEFSPRI;
1357	isprintf = 1;
1358	if (*p == '<') {
1359		errno = 0;
1360		n = strtol(p + 1, &q, 10);
1361		if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) {
1362			p = q + 1;
1363			pri = n;
1364			isprintf = 0;
1365		}
1366	}
1367	/*
1368	 * Kernel printf's and LOG_CONSOLE messages have been displayed
1369	 * on the console already.
1370	 */
1371	if (isprintf || (pri & LOG_FACMASK) == LOG_CONSOLE)
1372		flags |= IGN_CONS;
1373	if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
1374		pri = DEFSPRI;
1375	logmsg(pri, NULL, LocalHostName, "kernel", NULL, NULL, NULL, p, flags);
1376}
1377
1378static time_t	now;
1379
1380/*
1381 * Match a program or host name against a specification.
1382 * Return a non-0 value if the message must be ignored
1383 * based on the specification.
1384 */
1385static int
1386skip_message(const char *name, const char *spec, int checkcase)
1387{
1388	const char *s;
1389	char prev, next;
1390	int exclude = 0;
1391	/* Behaviour on explicit match */
1392
1393	if (spec == NULL)
1394		return 0;
1395	switch (*spec) {
1396	case '-':
1397		exclude = 1;
1398		/*FALLTHROUGH*/
1399	case '+':
1400		spec++;
1401		break;
1402	default:
1403		break;
1404	}
1405	if (checkcase)
1406		s = strstr (spec, name);
1407	else
1408		s = strcasestr (spec, name);
1409
1410	if (s != NULL) {
1411		prev = (s == spec ? ',' : *(s - 1));
1412		next = *(s + strlen (name));
1413
1414		if (prev == ',' && (next == '\0' || next == ','))
1415			/* Explicit match: skip iff the spec is an
1416			   exclusive one. */
1417			return exclude;
1418	}
1419
1420	/* No explicit match for this name: skip the message iff
1421	   the spec is an inclusive one. */
1422	return !exclude;
1423}
1424
1425/*
1426 * Logs a message to the appropriate log files, users, etc. based on the
1427 * priority. Log messages are always formatted according to RFC 3164,
1428 * even if they were in RFC 5424 format originally, The MSGID and
1429 * STRUCTURED-DATA fields are thus discarded for the time being.
1430 */
1431static void
1432logmsg(int pri, const struct logtime *timestamp, const char *hostname,
1433    const char *app_name, const char *procid, const char *msgid,
1434    const char *structured_data, const char *msg, int flags)
1435{
1436	struct timeval tv;
1437	struct logtime timestamp_now;
1438	struct filed *f;
1439	size_t savedlen;
1440	int fac, prilev;
1441	char saved[MAXSVLINE];
1442
1443	dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
1444	    pri, flags, hostname, msg);
1445
1446	(void)gettimeofday(&tv, NULL);
1447	now = tv.tv_sec;
1448	if (timestamp == NULL) {
1449		localtime_r(&now, &timestamp_now.tm);
1450		timestamp_now.usec = tv.tv_usec;
1451		timestamp = &timestamp_now;
1452	}
1453
1454	/* extract facility and priority level */
1455	if (flags & MARK)
1456		fac = LOG_NFACILITIES;
1457	else
1458		fac = LOG_FAC(pri);
1459
1460	/* Check maximum facility number. */
1461	if (fac > LOG_NFACILITIES)
1462		return;
1463
1464	prilev = LOG_PRI(pri);
1465
1466	/* log the message to the particular outputs */
1467	if (!Initialized) {
1468		f = &consfile;
1469		/*
1470		 * Open in non-blocking mode to avoid hangs during open
1471		 * and close(waiting for the port to drain).
1472		 */
1473		f->f_file = open(ctty, O_WRONLY | O_NONBLOCK, 0);
1474
1475		if (f->f_file >= 0) {
1476			f->f_lasttime = *timestamp;
1477			fprintlog_first(f, hostname, app_name, procid, msgid,
1478			    structured_data, msg, flags);
1479			close(f->f_file);
1480			f->f_file = -1;
1481		}
1482		return;
1483	}
1484
1485	/*
1486	 * Store all of the fields of the message, except the timestamp,
1487	 * in a single string. This string is used to detect duplicate
1488	 * messages.
1489	 */
1490	assert(hostname != NULL);
1491	assert(msg != NULL);
1492	savedlen = snprintf(saved, sizeof(saved),
1493	    "%d %s %s %s %s %s %s", pri, hostname,
1494	    app_name == NULL ? "-" : app_name, procid == NULL ? "-" : procid,
1495	    msgid == NULL ? "-" : msgid,
1496	    structured_data == NULL ? "-" : structured_data, msg);
1497
1498	STAILQ_FOREACH(f, &fhead, next) {
1499		/* skip messages that are incorrect priority */
1500		if (!(((f->f_pcmp[fac] & PRI_EQ) && (f->f_pmask[fac] == prilev))
1501		     ||((f->f_pcmp[fac] & PRI_LT) && (f->f_pmask[fac] < prilev))
1502		     ||((f->f_pcmp[fac] & PRI_GT) && (f->f_pmask[fac] > prilev))
1503		     )
1504		    || f->f_pmask[fac] == INTERNAL_NOPRI)
1505			continue;
1506
1507		/* skip messages with the incorrect hostname */
1508		if (skip_message(hostname, f->f_host, 0))
1509			continue;
1510
1511		/* skip messages with the incorrect program name */
1512		if (skip_message(app_name == NULL ? "" : app_name,
1513		    f->f_program, 1))
1514			continue;
1515
1516		/* skip message to console if it has already been printed */
1517		if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
1518			continue;
1519
1520		/* don't output marks to recently written files */
1521		if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
1522			continue;
1523
1524		/*
1525		 * suppress duplicate lines to this file
1526		 */
1527		if (no_compress - (f->f_type != F_PIPE) < 1 &&
1528		    (flags & MARK) == 0 && savedlen == f->f_prevlen &&
1529		    strcmp(saved, f->f_prevline) == 0) {
1530			f->f_lasttime = *timestamp;
1531			f->f_prevcount++;
1532			dprintf("msg repeated %d times, %ld sec of %d\n",
1533			    f->f_prevcount, (long)(now - f->f_time),
1534			    repeatinterval[f->f_repeatcount]);
1535			/*
1536			 * If domark would have logged this by now,
1537			 * flush it now (so we don't hold isolated messages),
1538			 * but back off so we'll flush less often
1539			 * in the future.
1540			 */
1541			if (now > REPEATTIME(f)) {
1542				fprintlog_successive(f, flags);
1543				BACKOFF(f);
1544			}
1545		} else {
1546			/* new line, save it */
1547			if (f->f_prevcount)
1548				fprintlog_successive(f, 0);
1549			f->f_repeatcount = 0;
1550			f->f_prevpri = pri;
1551			f->f_lasttime = *timestamp;
1552			static_assert(sizeof(f->f_prevline) == sizeof(saved),
1553			    "Space to store saved line incorrect");
1554			(void)strcpy(f->f_prevline, saved);
1555			f->f_prevlen = savedlen;
1556			fprintlog_first(f, hostname, app_name, procid, msgid,
1557			    structured_data, msg, flags);
1558		}
1559	}
1560}
1561
1562static void
1563dofsync(void)
1564{
1565	struct filed *f;
1566
1567	STAILQ_FOREACH(f, &fhead, next) {
1568		if ((f->f_type == F_FILE) &&
1569		    (f->f_flags & FFLAG_NEEDSYNC)) {
1570			f->f_flags &= ~FFLAG_NEEDSYNC;
1571			(void)fsync(f->f_file);
1572		}
1573	}
1574}
1575
1576/*
1577 * List of iovecs to which entries can be appended.
1578 * Used for constructing the message to be logged.
1579 */
1580struct iovlist {
1581	struct iovec	iov[TTYMSG_IOV_MAX];
1582	size_t		iovcnt;
1583	size_t		totalsize;
1584};
1585
1586static void
1587iovlist_init(struct iovlist *il)
1588{
1589
1590	il->iovcnt = 0;
1591	il->totalsize = 0;
1592}
1593
1594static void
1595iovlist_append(struct iovlist *il, const char *str)
1596{
1597	size_t size;
1598
1599	/* Discard components if we've run out of iovecs. */
1600	if (il->iovcnt < nitems(il->iov)) {
1601		size = strlen(str);
1602		il->iov[il->iovcnt++] = (struct iovec){
1603			.iov_base	= __DECONST(char *, str),
1604			.iov_len	= size,
1605		};
1606		il->totalsize += size;
1607	}
1608}
1609
1610#if defined(INET) || defined(INET6)
1611static void
1612iovlist_truncate(struct iovlist *il, size_t size)
1613{
1614	struct iovec *last;
1615	size_t diff;
1616
1617	while (il->totalsize > size) {
1618		diff = il->totalsize - size;
1619		last = &il->iov[il->iovcnt - 1];
1620		if (diff >= last->iov_len) {
1621			/* Remove the last iovec entirely. */
1622			--il->iovcnt;
1623			il->totalsize -= last->iov_len;
1624		} else {
1625			/* Remove the last iovec partially. */
1626			last->iov_len -= diff;
1627			il->totalsize -= diff;
1628		}
1629	}
1630}
1631#endif
1632
1633static void
1634fprintlog_write(struct filed *f, struct iovlist *il, int flags)
1635{
1636	struct msghdr msghdr;
1637	struct addrinfo *r;
1638	struct socklist *sl;
1639	const char *msgret;
1640	ssize_t lsent;
1641
1642	switch (f->f_type) {
1643	case F_FORW:
1644		/* Truncate messages to RFC 5426 recommended size. */
1645		dprintf(" %s", f->fu_forw_hname);
1646		switch (f->fu_forw_addr->ai_addr->sa_family) {
1647#ifdef INET
1648		case AF_INET:
1649			dprintf(":%d\n",
1650			    ntohs(satosin(f->fu_forw_addr->ai_addr)->sin_port));
1651			iovlist_truncate(il, 480);
1652			break;
1653#endif
1654#ifdef INET6
1655		case AF_INET6:
1656			dprintf(":%d\n",
1657			    ntohs(satosin6(f->fu_forw_addr->ai_addr)->sin6_port));
1658			iovlist_truncate(il, 1180);
1659			break;
1660#endif
1661		default:
1662			dprintf("\n");
1663		}
1664
1665		lsent = 0;
1666		for (r = f->fu_forw_addr; r; r = r->ai_next) {
1667			memset(&msghdr, 0, sizeof(msghdr));
1668			msghdr.msg_name = r->ai_addr;
1669			msghdr.msg_namelen = r->ai_addrlen;
1670			msghdr.msg_iov = il->iov;
1671			msghdr.msg_iovlen = il->iovcnt;
1672			STAILQ_FOREACH(sl, &shead, next) {
1673				if (sl->sl_ss.ss_family == AF_LOCAL ||
1674				    sl->sl_ss.ss_family == AF_UNSPEC ||
1675				    sl->sl_socket < 0)
1676					continue;
1677				lsent = sendmsg(sl->sl_socket, &msghdr, 0);
1678				if (lsent == (ssize_t)il->totalsize)
1679					break;
1680			}
1681			if (lsent == (ssize_t)il->totalsize && !send_to_all)
1682				break;
1683		}
1684		dprintf("lsent/totalsize: %zd/%zu\n", lsent, il->totalsize);
1685		if (lsent != (ssize_t)il->totalsize) {
1686			int e = errno;
1687			logerror("sendto");
1688			errno = e;
1689			switch (errno) {
1690			case ENOBUFS:
1691			case ENETDOWN:
1692			case ENETUNREACH:
1693			case EHOSTUNREACH:
1694			case EHOSTDOWN:
1695			case EADDRNOTAVAIL:
1696				break;
1697			/* case EBADF: */
1698			/* case EACCES: */
1699			/* case ENOTSOCK: */
1700			/* case EFAULT: */
1701			/* case EMSGSIZE: */
1702			/* case EAGAIN: */
1703			/* case ENOBUFS: */
1704			/* case ECONNREFUSED: */
1705			default:
1706				dprintf("removing entry: errno=%d\n", e);
1707				f->f_type = F_UNUSED;
1708				break;
1709			}
1710		}
1711		break;
1712
1713	case F_FILE:
1714		dprintf(" %s\n", f->fu_fname);
1715		iovlist_append(il, "\n");
1716		if (writev(f->f_file, il->iov, il->iovcnt) < 0) {
1717			/*
1718			 * If writev(2) fails for potentially transient errors
1719			 * like the filesystem being full, ignore it.
1720			 * Otherwise remove this logfile from the list.
1721			 */
1722			if (errno != ENOSPC) {
1723				int e = errno;
1724				close_filed(f);
1725				errno = e;
1726				logerror(f->fu_fname);
1727			}
1728		} else if ((flags & SYNC_FILE) && (f->f_flags & FFLAG_SYNC)) {
1729			f->f_flags |= FFLAG_NEEDSYNC;
1730			needdofsync = 1;
1731		}
1732		break;
1733
1734	case F_PIPE:
1735		dprintf(" %s\n", f->fu_pipe_pname);
1736		iovlist_append(il, "\n");
1737		if (f->fu_pipe_pid == 0) {
1738			if ((f->f_file = p_open(f->fu_pipe_pname,
1739						&f->fu_pipe_pid)) < 0) {
1740				logerror(f->fu_pipe_pname);
1741				break;
1742			}
1743		}
1744		if (writev(f->f_file, il->iov, il->iovcnt) < 0) {
1745			int e = errno;
1746
1747			deadq_enter(f->fu_pipe_pid, f->fu_pipe_pname);
1748			close_filed(f);
1749			errno = e;
1750			logerror(f->fu_pipe_pname);
1751		}
1752		break;
1753
1754	case F_CONSOLE:
1755		if (flags & IGN_CONS) {
1756			dprintf(" (ignored)\n");
1757			break;
1758		}
1759		/* FALLTHROUGH */
1760
1761	case F_TTY:
1762		dprintf(" %s%s\n", _PATH_DEV, f->fu_fname);
1763		iovlist_append(il, "\r\n");
1764		errno = 0;	/* ttymsg() only sometimes returns an errno */
1765		if ((msgret = ttymsg(il->iov, il->iovcnt, f->fu_fname, 10))) {
1766			f->f_type = F_UNUSED;
1767			logerror(msgret);
1768		}
1769		break;
1770
1771	case F_USERS:
1772	case F_WALL:
1773		dprintf("\n");
1774		iovlist_append(il, "\r\n");
1775		wallmsg(f, il->iov, il->iovcnt);
1776		break;
1777	}
1778}
1779
1780static void
1781fprintlog_rfc5424(struct filed *f, const char *hostname, const char *app_name,
1782    const char *procid, const char *msgid, const char *structured_data,
1783    const char *msg, int flags)
1784{
1785	struct iovlist il;
1786	suseconds_t usec;
1787	int i;
1788	char timebuf[33], priority_number[5];
1789
1790	iovlist_init(&il);
1791	if (f->f_type == F_WALL)
1792		iovlist_append(&il, "\r\n\aMessage from syslogd ...\r\n");
1793	iovlist_append(&il, "<");
1794	snprintf(priority_number, sizeof(priority_number), "%d", f->f_prevpri);
1795	iovlist_append(&il, priority_number);
1796	iovlist_append(&il, ">1 ");
1797	if (strftime(timebuf, sizeof(timebuf), "%FT%T.______%z",
1798	    &f->f_lasttime.tm) == sizeof(timebuf) - 2) {
1799		/* Add colon to the time zone offset, which %z doesn't do. */
1800		timebuf[32] = '\0';
1801		timebuf[31] = timebuf[30];
1802		timebuf[30] = timebuf[29];
1803		timebuf[29] = ':';
1804
1805		/* Overwrite space for microseconds with actual value. */
1806		usec = f->f_lasttime.usec;
1807		for (i = 25; i >= 20; --i) {
1808			timebuf[i] = usec % 10 + '0';
1809			usec /= 10;
1810		}
1811		iovlist_append(&il, timebuf);
1812	} else
1813		iovlist_append(&il, "-");
1814	iovlist_append(&il, " ");
1815	iovlist_append(&il, hostname);
1816	iovlist_append(&il, " ");
1817	iovlist_append(&il, app_name == NULL ? "-" : app_name);
1818	iovlist_append(&il, " ");
1819	iovlist_append(&il, procid == NULL ? "-" : procid);
1820	iovlist_append(&il, " ");
1821	iovlist_append(&il, msgid == NULL ? "-" : msgid);
1822	iovlist_append(&il, " ");
1823	iovlist_append(&il, structured_data == NULL ? "-" : structured_data);
1824	iovlist_append(&il, " ");
1825	iovlist_append(&il, msg);
1826
1827	fprintlog_write(f, &il, flags);
1828}
1829
1830static void
1831fprintlog_rfc3164(struct filed *f, const char *hostname, const char *app_name,
1832    const char *procid, const char *msg, int flags)
1833{
1834	struct iovlist il;
1835	const CODE *c;
1836	int facility, priority;
1837	char timebuf[RFC3164_DATELEN + 1], facility_number[5],
1838	    priority_number[5];
1839	bool facility_found, priority_found;
1840
1841	if (strftime(timebuf, sizeof(timebuf), RFC3164_DATEFMT,
1842	    &f->f_lasttime.tm) == 0)
1843		timebuf[0] = '\0';
1844
1845	iovlist_init(&il);
1846	switch (f->f_type) {
1847	case F_FORW:
1848		/* Message forwarded over the network. */
1849		iovlist_append(&il, "<");
1850		snprintf(priority_number, sizeof(priority_number), "%d",
1851		    f->f_prevpri);
1852		iovlist_append(&il, priority_number);
1853		iovlist_append(&il, ">");
1854		iovlist_append(&il, timebuf);
1855		if (strcasecmp(hostname, LocalHostName) != 0) {
1856			iovlist_append(&il, " Forwarded from ");
1857			iovlist_append(&il, hostname);
1858			iovlist_append(&il, ":");
1859		}
1860		iovlist_append(&il, " ");
1861		break;
1862
1863	case F_WALL:
1864		/* Message written to terminals. */
1865		iovlist_append(&il, "\r\n\aMessage from syslogd@");
1866		iovlist_append(&il, hostname);
1867		iovlist_append(&il, " at ");
1868		iovlist_append(&il, timebuf);
1869		iovlist_append(&il, " ...\r\n");
1870		break;
1871
1872	default:
1873		/* Message written to files. */
1874		iovlist_append(&il, timebuf);
1875		iovlist_append(&il, " ");
1876
1877		if (LogFacPri) {
1878			iovlist_append(&il, "<");
1879
1880			facility = f->f_prevpri & LOG_FACMASK;
1881			facility_found = false;
1882			if (LogFacPri > 1) {
1883				for (c = facilitynames; c->c_name; c++) {
1884					if (c->c_val == facility) {
1885						iovlist_append(&il, c->c_name);
1886						facility_found = true;
1887						break;
1888					}
1889				}
1890			}
1891			if (!facility_found) {
1892				snprintf(facility_number,
1893				    sizeof(facility_number), "%d",
1894				    LOG_FAC(facility));
1895				iovlist_append(&il, facility_number);
1896			}
1897
1898			iovlist_append(&il, ".");
1899
1900			priority = LOG_PRI(f->f_prevpri);
1901			priority_found = false;
1902			if (LogFacPri > 1) {
1903				for (c = prioritynames; c->c_name; c++) {
1904					if (c->c_val == priority) {
1905						iovlist_append(&il, c->c_name);
1906						priority_found = true;
1907						break;
1908					}
1909				}
1910			}
1911			if (!priority_found) {
1912				snprintf(priority_number,
1913				    sizeof(priority_number), "%d", priority);
1914				iovlist_append(&il, priority_number);
1915			}
1916
1917			iovlist_append(&il, "> ");
1918		}
1919
1920		iovlist_append(&il, hostname);
1921		iovlist_append(&il, " ");
1922		break;
1923	}
1924
1925	/* Message body with application name and process ID prefixed. */
1926	if (app_name != NULL) {
1927		iovlist_append(&il, app_name);
1928		if (procid != NULL) {
1929			iovlist_append(&il, "[");
1930			iovlist_append(&il, procid);
1931			iovlist_append(&il, "]");
1932		}
1933		iovlist_append(&il, ": ");
1934	}
1935	iovlist_append(&il, msg);
1936
1937	fprintlog_write(f, &il, flags);
1938}
1939
1940static void
1941fprintlog_first(struct filed *f, const char *hostname, const char *app_name,
1942    const char *procid, const char *msgid __unused,
1943    const char *structured_data __unused, const char *msg, int flags)
1944{
1945
1946	dprintf("Logging to %s", TypeNames[f->f_type]);
1947	f->f_time = now;
1948	f->f_prevcount = 0;
1949	if (f->f_type == F_UNUSED) {
1950		dprintf("\n");
1951		return;
1952	}
1953
1954	if (RFC3164OutputFormat)
1955		fprintlog_rfc3164(f, hostname, app_name, procid, msg, flags);
1956	else
1957		fprintlog_rfc5424(f, hostname, app_name, procid, msgid,
1958		    structured_data, msg, flags);
1959}
1960
1961/*
1962 * Prints a message to a log file that the previously logged message was
1963 * received multiple times.
1964 */
1965static void
1966fprintlog_successive(struct filed *f, int flags)
1967{
1968	char msg[100];
1969
1970	assert(f->f_prevcount > 0);
1971	snprintf(msg, sizeof(msg), "last message repeated %d times",
1972	    f->f_prevcount);
1973	fprintlog_first(f, LocalHostName, "syslogd", NULL, NULL, NULL, msg,
1974	    flags);
1975}
1976
1977/*
1978 *  WALLMSG -- Write a message to the world at large
1979 *
1980 *	Write the specified message to either the entire
1981 *	world, or a list of approved users.
1982 */
1983static void
1984wallmsg(struct filed *f, struct iovec *iov, const int iovlen)
1985{
1986	static int reenter;			/* avoid calling ourselves */
1987	struct utmpx *ut;
1988	int i;
1989	const char *p;
1990
1991	if (reenter++)
1992		return;
1993	setutxent();
1994	/* NOSTRICT */
1995	while ((ut = getutxent()) != NULL) {
1996		if (ut->ut_type != USER_PROCESS)
1997			continue;
1998		if (f->f_type == F_WALL) {
1999			if ((p = ttymsg(iov, iovlen, ut->ut_line,
2000			    TTYMSGTIME)) != NULL) {
2001				errno = 0;	/* already in msg */
2002				logerror(p);
2003			}
2004			continue;
2005		}
2006		/* should we send the message to this user? */
2007		for (i = 0; i < MAXUNAMES; i++) {
2008			if (!f->fu_uname[i][0])
2009				break;
2010			if (!strcmp(f->fu_uname[i], ut->ut_user)) {
2011				if ((p = ttymsg_check(iov, iovlen, ut->ut_line,
2012				    TTYMSGTIME)) != NULL) {
2013					errno = 0;	/* already in msg */
2014					logerror(p);
2015				}
2016				break;
2017			}
2018		}
2019	}
2020	endutxent();
2021	reenter = 0;
2022}
2023
2024/*
2025 * Wrapper routine for ttymsg() that checks the terminal for messages enabled.
2026 */
2027static const char *
2028ttymsg_check(struct iovec *iov, int iovcnt, char *line, int tmout)
2029{
2030	static char device[1024];
2031	static char errbuf[1024];
2032	struct stat sb;
2033
2034	(void) snprintf(device, sizeof(device), "%s%s", _PATH_DEV, line);
2035
2036	if (stat(device, &sb) < 0) {
2037		(void) snprintf(errbuf, sizeof(errbuf),
2038		    "%s: %s", device, strerror(errno));
2039		return (errbuf);
2040	}
2041	if ((sb.st_mode & S_IWGRP) == 0)
2042		/* Messages disabled. */
2043		return (NULL);
2044	return ttymsg(iov, iovcnt, line, tmout);
2045}
2046
2047static void
2048reapchild(int signo __unused)
2049{
2050	int status;
2051	pid_t pid;
2052	struct filed *f;
2053
2054	while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) {
2055		/* First, look if it's a process from the dead queue. */
2056		if (deadq_removebypid(pid))
2057			continue;
2058
2059		/* Now, look in list of active processes. */
2060		STAILQ_FOREACH(f, &fhead, next) {
2061			if (f->f_type == F_PIPE &&
2062			    f->fu_pipe_pid == pid) {
2063				close_filed(f);
2064				log_deadchild(pid, status, f->fu_pipe_pname);
2065				break;
2066			}
2067		}
2068	}
2069	WantReapchild = 0;
2070}
2071
2072/*
2073 * Return a printable representation of a host address.
2074 */
2075static const char *
2076cvthname(struct sockaddr *f)
2077{
2078	int error, hl;
2079	static char hname[NI_MAXHOST], ip[NI_MAXHOST];
2080
2081	dprintf("cvthname(%d) len = %d\n", f->sa_family, f->sa_len);
2082	error = getnameinfo(f, f->sa_len, ip, sizeof(ip), NULL, 0,
2083		    NI_NUMERICHOST);
2084	if (error) {
2085		dprintf("Malformed from address %s\n", gai_strerror(error));
2086		return ("???");
2087	}
2088	dprintf("cvthname(%s)\n", ip);
2089
2090	if (!resolve)
2091		return (ip);
2092
2093	error = getnameinfo(f, f->sa_len, hname, sizeof(hname),
2094		    NULL, 0, NI_NAMEREQD);
2095	if (error) {
2096		dprintf("Host name for your address (%s) unknown\n", ip);
2097		return (ip);
2098	}
2099	hl = strlen(hname);
2100	if (hl > 0 && hname[hl-1] == '.')
2101		hname[--hl] = '\0';
2102	trimdomain(hname, hl);
2103	return (hname);
2104}
2105
2106static void
2107dodie(int signo)
2108{
2109
2110	WantDie = signo;
2111}
2112
2113static void
2114domark(int signo __unused)
2115{
2116
2117	MarkSet = 1;
2118}
2119
2120/*
2121 * Print syslogd errors some place.
2122 */
2123static void
2124logerror(const char *msg)
2125{
2126	char buf[512];
2127	static int recursed = 0;
2128
2129	/* If there's an error while trying to log an error, give up. */
2130	if (recursed)
2131		return;
2132	recursed++;
2133	if (errno != 0) {
2134		(void)snprintf(buf, sizeof(buf), "%s: %s", msg,
2135		    strerror(errno));
2136		msg = buf;
2137	}
2138	errno = 0;
2139	dprintf("%s\n", buf);
2140	logmsg(LOG_SYSLOG|LOG_ERR, NULL, LocalHostName, "syslogd", NULL, NULL,
2141	    NULL, msg, 0);
2142	recursed--;
2143}
2144
2145static void
2146die(int signo)
2147{
2148	struct filed *f;
2149	struct socklist *sl;
2150	char buf[100];
2151
2152	STAILQ_FOREACH(f, &fhead, next) {
2153		/* flush any pending output */
2154		if (f->f_prevcount)
2155			fprintlog_successive(f, 0);
2156		if (f->f_type == F_PIPE && f->fu_pipe_pid > 0)
2157			close_filed(f);
2158	}
2159	if (signo) {
2160		dprintf("syslogd: exiting on signal %d\n", signo);
2161		(void)snprintf(buf, sizeof(buf), "exiting on signal %d", signo);
2162		errno = 0;
2163		logerror(buf);
2164	}
2165	STAILQ_FOREACH(sl, &shead, next) {
2166		if (sl->sl_ss.ss_family == AF_LOCAL)
2167			unlink(sl->sl_peer->pe_name);
2168	}
2169	pidfile_remove(pfh);
2170
2171	exit(1);
2172}
2173
2174static int
2175configfiles(const struct dirent *dp)
2176{
2177	const char *p;
2178	size_t ext_len;
2179
2180	if (dp->d_name[0] == '.')
2181		return (0);
2182
2183	ext_len = sizeof(include_ext) -1;
2184
2185	if (dp->d_namlen <= ext_len)
2186		return (0);
2187
2188	p = &dp->d_name[dp->d_namlen - ext_len];
2189	if (strcmp(p, include_ext) != 0)
2190		return (0);
2191
2192	return (1);
2193}
2194
2195static void
2196readconfigfile(FILE *cf, int allow_includes)
2197{
2198	FILE *cf2;
2199	struct filed *f;
2200	struct dirent **ent;
2201	char cline[LINE_MAX];
2202	char host[MAXHOSTNAMELEN];
2203	char prog[LINE_MAX];
2204	char file[MAXPATHLEN];
2205	char *p, *tmp;
2206	int i, nents;
2207	size_t include_len;
2208
2209	/*
2210	 *  Foreach line in the conf table, open that file.
2211	 */
2212	include_len = sizeof(include_str) -1;
2213	(void)strlcpy(host, "*", sizeof(host));
2214	(void)strlcpy(prog, "*", sizeof(prog));
2215	while (fgets(cline, sizeof(cline), cf) != NULL) {
2216		/*
2217		 * check for end-of-section, comments, strip off trailing
2218		 * spaces and newline character. #!prog is treated specially:
2219		 * following lines apply only to that program.
2220		 */
2221		for (p = cline; isspace(*p); ++p)
2222			continue;
2223		if (*p == 0)
2224			continue;
2225		if (allow_includes &&
2226		    strncmp(p, include_str, include_len) == 0 &&
2227		    isspace(p[include_len])) {
2228			p += include_len;
2229			while (isspace(*p))
2230				p++;
2231			tmp = p;
2232			while (*tmp != '\0' && !isspace(*tmp))
2233				tmp++;
2234			*tmp = '\0';
2235			dprintf("Trying to include files in '%s'\n", p);
2236			nents = scandir(p, &ent, configfiles, alphasort);
2237			if (nents == -1) {
2238				dprintf("Unable to open '%s': %s\n", p,
2239				    strerror(errno));
2240				continue;
2241			}
2242			for (i = 0; i < nents; i++) {
2243				if (snprintf(file, sizeof(file), "%s/%s", p,
2244				    ent[i]->d_name) >= (int)sizeof(file)) {
2245					dprintf("ignoring path too long: "
2246					    "'%s/%s'\n", p, ent[i]->d_name);
2247					free(ent[i]);
2248					continue;
2249				}
2250				free(ent[i]);
2251				cf2 = fopen(file, "r");
2252				if (cf2 == NULL)
2253					continue;
2254				dprintf("reading %s\n", file);
2255				readconfigfile(cf2, 0);
2256				fclose(cf2);
2257			}
2258			free(ent);
2259			continue;
2260		}
2261		if (*p == '#') {
2262			p++;
2263			if (*p != '!' && *p != '+' && *p != '-')
2264				continue;
2265		}
2266		if (*p == '+' || *p == '-') {
2267			host[0] = *p++;
2268			while (isspace(*p))
2269				p++;
2270			if ((!*p) || (*p == '*')) {
2271				(void)strlcpy(host, "*", sizeof(host));
2272				continue;
2273			}
2274			if (*p == '@')
2275				p = LocalHostName;
2276			for (i = 1; i < MAXHOSTNAMELEN - 1; i++) {
2277				if (!isalnum(*p) && *p != '.' && *p != '-'
2278				    && *p != ',' && *p != ':' && *p != '%')
2279					break;
2280				host[i] = *p++;
2281			}
2282			host[i] = '\0';
2283			continue;
2284		}
2285		if (*p == '!') {
2286			p++;
2287			while (isspace(*p)) p++;
2288			if ((!*p) || (*p == '*')) {
2289				(void)strlcpy(prog, "*", sizeof(prog));
2290				continue;
2291			}
2292			for (i = 0; i < LINE_MAX - 1; i++) {
2293				if (!isprint(p[i]) || isspace(p[i]))
2294					break;
2295				prog[i] = p[i];
2296			}
2297			prog[i] = 0;
2298			continue;
2299		}
2300		for (p = cline + 1; *p != '\0'; p++) {
2301			if (*p != '#')
2302				continue;
2303			if (*(p - 1) == '\\') {
2304				strcpy(p - 1, p);
2305				p--;
2306				continue;
2307			}
2308			*p = '\0';
2309			break;
2310		}
2311		for (i = strlen(cline) - 1; i >= 0 && isspace(cline[i]); i--)
2312			cline[i] = '\0';
2313		f = cfline(cline, prog, host);
2314		if (f != NULL)
2315			addfile(f);
2316		free(f);
2317	}
2318}
2319
2320static void
2321sighandler(int signo)
2322{
2323
2324	/* Send an wake-up signal to the select() loop. */
2325	write(sigpipe[1], &signo, sizeof(signo));
2326}
2327
2328/*
2329 *  INIT -- Initialize syslogd from configuration table
2330 */
2331static void
2332init(int signo)
2333{
2334	int i;
2335	FILE *cf;
2336	struct filed *f;
2337	char *p;
2338	char oldLocalHostName[MAXHOSTNAMELEN];
2339	char hostMsg[2*MAXHOSTNAMELEN+40];
2340	char bootfileMsg[LINE_MAX];
2341
2342	dprintf("init\n");
2343	WantInitialize = 0;
2344
2345	/*
2346	 * Load hostname (may have changed).
2347	 */
2348	if (signo != 0)
2349		(void)strlcpy(oldLocalHostName, LocalHostName,
2350		    sizeof(oldLocalHostName));
2351	if (gethostname(LocalHostName, sizeof(LocalHostName)))
2352		err(EX_OSERR, "gethostname() failed");
2353	if ((p = strchr(LocalHostName, '.')) != NULL) {
2354		/* RFC 5424 prefers logging FQDNs. */
2355		if (RFC3164OutputFormat)
2356			*p = '\0';
2357		LocalDomain = p + 1;
2358	} else {
2359		LocalDomain = "";
2360	}
2361
2362	/*
2363	 * Load / reload timezone data (in case it changed).
2364	 *
2365	 * Just calling tzset() again does not work, the timezone code
2366	 * caches the result.  However, by setting the TZ variable, one
2367	 * can defeat the caching and have the timezone code really
2368	 * reload the timezone data.  Respect any initial setting of
2369	 * TZ, in case the system is configured specially.
2370	 */
2371	dprintf("loading timezone data via tzset()\n");
2372	if (getenv("TZ")) {
2373		tzset();
2374	} else {
2375		setenv("TZ", ":/etc/localtime", 1);
2376		tzset();
2377		unsetenv("TZ");
2378	}
2379
2380	/*
2381	 *  Close all open log files.
2382	 */
2383	Initialized = 0;
2384	STAILQ_FOREACH(f, &fhead, next) {
2385		/* flush any pending output */
2386		if (f->f_prevcount)
2387			fprintlog_successive(f, 0);
2388
2389		switch (f->f_type) {
2390		case F_FILE:
2391		case F_FORW:
2392		case F_CONSOLE:
2393		case F_TTY:
2394			close_filed(f);
2395			break;
2396		case F_PIPE:
2397			deadq_enter(f->fu_pipe_pid, f->fu_pipe_pname);
2398			close_filed(f);
2399			break;
2400		}
2401	}
2402	while(!STAILQ_EMPTY(&fhead)) {
2403		f = STAILQ_FIRST(&fhead);
2404		STAILQ_REMOVE_HEAD(&fhead, next);
2405		free(f->f_program);
2406		free(f->f_host);
2407		free(f);
2408	}
2409
2410	/* open the configuration file */
2411	if ((cf = fopen(ConfFile, "r")) == NULL) {
2412		dprintf("cannot open %s\n", ConfFile);
2413		f = cfline("*.ERR\t/dev/console", "*", "*");
2414		if (f != NULL)
2415			addfile(f);
2416		free(f);
2417		f = cfline("*.PANIC\t*", "*", "*");
2418		if (f != NULL)
2419			addfile(f);
2420		free(f);
2421		Initialized = 1;
2422
2423		return;
2424	}
2425
2426	readconfigfile(cf, 1);
2427
2428	/* close the configuration file */
2429	(void)fclose(cf);
2430
2431	Initialized = 1;
2432
2433	if (Debug) {
2434		int port;
2435		STAILQ_FOREACH(f, &fhead, next) {
2436			for (i = 0; i <= LOG_NFACILITIES; i++)
2437				if (f->f_pmask[i] == INTERNAL_NOPRI)
2438					printf("X ");
2439				else
2440					printf("%d ", f->f_pmask[i]);
2441			printf("%s: ", TypeNames[f->f_type]);
2442			switch (f->f_type) {
2443			case F_FILE:
2444				printf("%s", f->fu_fname);
2445				break;
2446
2447			case F_CONSOLE:
2448			case F_TTY:
2449				printf("%s%s", _PATH_DEV, f->fu_fname);
2450				break;
2451
2452			case F_FORW:
2453				switch (f->fu_forw_addr->ai_addr->sa_family) {
2454#ifdef INET
2455				case AF_INET:
2456					port = ntohs(satosin(f->fu_forw_addr->ai_addr)->sin_port);
2457					break;
2458#endif
2459#ifdef INET6
2460				case AF_INET6:
2461					port = ntohs(satosin6(f->fu_forw_addr->ai_addr)->sin6_port);
2462					break;
2463#endif
2464				default:
2465					port = 0;
2466				}
2467				if (port != 514) {
2468					printf("%s:%d",
2469						f->fu_forw_hname, port);
2470				} else {
2471					printf("%s", f->fu_forw_hname);
2472				}
2473				break;
2474
2475			case F_PIPE:
2476				printf("%s", f->fu_pipe_pname);
2477				break;
2478
2479			case F_USERS:
2480				for (i = 0; i < MAXUNAMES && *f->fu_uname[i]; i++)
2481					printf("%s, ", f->fu_uname[i]);
2482				break;
2483			}
2484			if (f->f_program)
2485				printf(" (%s)", f->f_program);
2486			printf("\n");
2487		}
2488	}
2489
2490	logmsg(LOG_SYSLOG | LOG_INFO, NULL, LocalHostName, "syslogd", NULL,
2491	    NULL, NULL, "restart", 0);
2492	dprintf("syslogd: restarted\n");
2493	/*
2494	 * Log a change in hostname, but only on a restart.
2495	 */
2496	if (signo != 0 && strcmp(oldLocalHostName, LocalHostName) != 0) {
2497		(void)snprintf(hostMsg, sizeof(hostMsg),
2498		    "hostname changed, \"%s\" to \"%s\"",
2499		    oldLocalHostName, LocalHostName);
2500		logmsg(LOG_SYSLOG | LOG_INFO, NULL, LocalHostName, "syslogd",
2501		    NULL, NULL, NULL, hostMsg, 0);
2502		dprintf("%s\n", hostMsg);
2503	}
2504	/*
2505	 * Log the kernel boot file if we aren't going to use it as
2506	 * the prefix, and if this is *not* a restart.
2507	 */
2508	if (signo == 0 && !use_bootfile) {
2509		(void)snprintf(bootfileMsg, sizeof(bootfileMsg),
2510		    "kernel boot file is %s", bootfile);
2511		logmsg(LOG_KERN | LOG_INFO, NULL, LocalHostName, "syslogd",
2512		    NULL, NULL, NULL, bootfileMsg, 0);
2513		dprintf("%s\n", bootfileMsg);
2514	}
2515}
2516
2517/*
2518 * Crack a configuration file line
2519 */
2520static struct filed *
2521cfline(const char *line, const char *prog, const char *host)
2522{
2523	struct filed *f;
2524	struct addrinfo hints, *res;
2525	int error, i, pri, syncfile;
2526	const char *p, *q;
2527	char *bp;
2528	char buf[MAXLINE], ebuf[100];
2529
2530	dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host);
2531
2532	f = calloc(1, sizeof(*f));
2533	if (f == NULL) {
2534		logerror("malloc");
2535		exit(1);
2536	}
2537	errno = 0;	/* keep strerror() stuff out of logerror messages */
2538
2539	for (i = 0; i <= LOG_NFACILITIES; i++)
2540		f->f_pmask[i] = INTERNAL_NOPRI;
2541
2542	/* save hostname if any */
2543	if (host && *host == '*')
2544		host = NULL;
2545	if (host) {
2546		int hl;
2547
2548		f->f_host = strdup(host);
2549		if (f->f_host == NULL) {
2550			logerror("strdup");
2551			exit(1);
2552		}
2553		hl = strlen(f->f_host);
2554		if (hl > 0 && f->f_host[hl-1] == '.')
2555			f->f_host[--hl] = '\0';
2556		trimdomain(f->f_host, hl);
2557	}
2558
2559	/* save program name if any */
2560	if (prog && *prog == '*')
2561		prog = NULL;
2562	if (prog) {
2563		f->f_program = strdup(prog);
2564		if (f->f_program == NULL) {
2565			logerror("strdup");
2566			exit(1);
2567		}
2568	}
2569
2570	/* scan through the list of selectors */
2571	for (p = line; *p && *p != '\t' && *p != ' ';) {
2572		int pri_done;
2573		int pri_cmp;
2574		int pri_invert;
2575
2576		/* find the end of this facility name list */
2577		for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; )
2578			continue;
2579
2580		/* get the priority comparison */
2581		pri_cmp = 0;
2582		pri_done = 0;
2583		pri_invert = 0;
2584		if (*q == '!') {
2585			pri_invert = 1;
2586			q++;
2587		}
2588		while (!pri_done) {
2589			switch (*q) {
2590			case '<':
2591				pri_cmp |= PRI_LT;
2592				q++;
2593				break;
2594			case '=':
2595				pri_cmp |= PRI_EQ;
2596				q++;
2597				break;
2598			case '>':
2599				pri_cmp |= PRI_GT;
2600				q++;
2601				break;
2602			default:
2603				pri_done++;
2604				break;
2605			}
2606		}
2607
2608		/* collect priority name */
2609		for (bp = buf; *q && !strchr("\t,; ", *q); )
2610			*bp++ = *q++;
2611		*bp = '\0';
2612
2613		/* skip cruft */
2614		while (strchr(",;", *q))
2615			q++;
2616
2617		/* decode priority name */
2618		if (*buf == '*') {
2619			pri = LOG_PRIMASK;
2620			pri_cmp = PRI_LT | PRI_EQ | PRI_GT;
2621		} else {
2622			/* Ignore trailing spaces. */
2623			for (i = strlen(buf) - 1; i >= 0 && buf[i] == ' '; i--)
2624				buf[i] = '\0';
2625
2626			pri = decode(buf, prioritynames);
2627			if (pri < 0) {
2628				errno = 0;
2629				(void)snprintf(ebuf, sizeof ebuf,
2630				    "unknown priority name \"%s\"", buf);
2631				logerror(ebuf);
2632				free(f);
2633				return (NULL);
2634			}
2635		}
2636		if (!pri_cmp)
2637			pri_cmp = (UniquePriority)
2638				  ? (PRI_EQ)
2639				  : (PRI_EQ | PRI_GT)
2640				  ;
2641		if (pri_invert)
2642			pri_cmp ^= PRI_LT | PRI_EQ | PRI_GT;
2643
2644		/* scan facilities */
2645		while (*p && !strchr("\t.; ", *p)) {
2646			for (bp = buf; *p && !strchr("\t,;. ", *p); )
2647				*bp++ = *p++;
2648			*bp = '\0';
2649
2650			if (*buf == '*') {
2651				for (i = 0; i < LOG_NFACILITIES; i++) {
2652					f->f_pmask[i] = pri;
2653					f->f_pcmp[i] = pri_cmp;
2654				}
2655			} else {
2656				i = decode(buf, facilitynames);
2657				if (i < 0) {
2658					errno = 0;
2659					(void)snprintf(ebuf, sizeof ebuf,
2660					    "unknown facility name \"%s\"",
2661					    buf);
2662					logerror(ebuf);
2663					free(f);
2664					return (NULL);
2665				}
2666				f->f_pmask[i >> 3] = pri;
2667				f->f_pcmp[i >> 3] = pri_cmp;
2668			}
2669			while (*p == ',' || *p == ' ')
2670				p++;
2671		}
2672
2673		p = q;
2674	}
2675
2676	/* skip to action part */
2677	while (*p == '\t' || *p == ' ')
2678		p++;
2679
2680	if (*p == '-') {
2681		syncfile = 0;
2682		p++;
2683	} else
2684		syncfile = 1;
2685
2686	switch (*p) {
2687	case '@':
2688		{
2689			char *tp;
2690			char endkey = ':';
2691			/*
2692			 * scan forward to see if there is a port defined.
2693			 * so we can't use strlcpy..
2694			 */
2695			i = sizeof(f->fu_forw_hname);
2696			tp = f->fu_forw_hname;
2697			p++;
2698
2699			/*
2700			 * an ipv6 address should start with a '[' in that case
2701			 * we should scan for a ']'
2702			 */
2703			if (*p == '[') {
2704				p++;
2705				endkey = ']';
2706			}
2707			while (*p && (*p != endkey) && (i-- > 0)) {
2708				*tp++ = *p++;
2709			}
2710			if (endkey == ']' && *p == endkey)
2711				p++;
2712			*tp = '\0';
2713		}
2714		/* See if we copied a domain and have a port */
2715		if (*p == ':')
2716			p++;
2717		else
2718			p = NULL;
2719
2720		hints = (struct addrinfo){
2721			.ai_family = family,
2722			.ai_socktype = SOCK_DGRAM
2723		};
2724		error = getaddrinfo(f->fu_forw_hname,
2725				p ? p : "syslog", &hints, &res);
2726		if (error) {
2727			logerror(gai_strerror(error));
2728			break;
2729		}
2730		f->fu_forw_addr = res;
2731		f->f_type = F_FORW;
2732		break;
2733
2734	case '/':
2735		if ((f->f_file = open(p, logflags, 0600)) < 0) {
2736			f->f_type = F_UNUSED;
2737			logerror(p);
2738			break;
2739		}
2740		if (syncfile)
2741			f->f_flags |= FFLAG_SYNC;
2742		if (isatty(f->f_file)) {
2743			if (strcmp(p, ctty) == 0)
2744				f->f_type = F_CONSOLE;
2745			else
2746				f->f_type = F_TTY;
2747			(void)strlcpy(f->fu_fname, p + sizeof(_PATH_DEV) - 1,
2748			    sizeof(f->fu_fname));
2749		} else {
2750			(void)strlcpy(f->fu_fname, p, sizeof(f->fu_fname));
2751			f->f_type = F_FILE;
2752		}
2753		break;
2754
2755	case '|':
2756		f->fu_pipe_pid = 0;
2757		(void)strlcpy(f->fu_pipe_pname, p + 1,
2758		    sizeof(f->fu_pipe_pname));
2759		f->f_type = F_PIPE;
2760		break;
2761
2762	case '*':
2763		f->f_type = F_WALL;
2764		break;
2765
2766	default:
2767		for (i = 0; i < MAXUNAMES && *p; i++) {
2768			for (q = p; *q && *q != ','; )
2769				q++;
2770			(void)strncpy(f->fu_uname[i], p, MAXLOGNAME - 1);
2771			if ((q - p) >= MAXLOGNAME)
2772				f->fu_uname[i][MAXLOGNAME - 1] = '\0';
2773			else
2774				f->fu_uname[i][q - p] = '\0';
2775			while (*q == ',' || *q == ' ')
2776				q++;
2777			p = q;
2778		}
2779		f->f_type = F_USERS;
2780		break;
2781	}
2782	return (f);
2783}
2784
2785
2786/*
2787 *  Decode a symbolic name to a numeric value
2788 */
2789static int
2790decode(const char *name, const CODE *codetab)
2791{
2792	const CODE *c;
2793	char *p, buf[40];
2794
2795	if (isdigit(*name))
2796		return (atoi(name));
2797
2798	for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
2799		if (isupper(*name))
2800			*p = tolower(*name);
2801		else
2802			*p = *name;
2803	}
2804	*p = '\0';
2805	for (c = codetab; c->c_name; c++)
2806		if (!strcmp(buf, c->c_name))
2807			return (c->c_val);
2808
2809	return (-1);
2810}
2811
2812static void
2813markit(void)
2814{
2815	struct filed *f;
2816	struct deadq_entry *dq, *dq0;
2817
2818	now = time((time_t *)NULL);
2819	MarkSeq += TIMERINTVL;
2820	if (MarkSeq >= MarkInterval) {
2821		logmsg(LOG_INFO, NULL, LocalHostName, NULL, NULL, NULL, NULL,
2822		    "-- MARK --", MARK);
2823		MarkSeq = 0;
2824	}
2825
2826	STAILQ_FOREACH(f, &fhead, next) {
2827		if (f->f_prevcount && now >= REPEATTIME(f)) {
2828			dprintf("flush %s: repeated %d times, %d sec.\n",
2829			    TypeNames[f->f_type], f->f_prevcount,
2830			    repeatinterval[f->f_repeatcount]);
2831			fprintlog_successive(f, 0);
2832			BACKOFF(f);
2833		}
2834	}
2835
2836	/* Walk the dead queue, and see if we should signal somebody. */
2837	TAILQ_FOREACH_SAFE(dq, &deadq_head, dq_entries, dq0) {
2838		switch (dq->dq_timeout) {
2839		case 0:
2840			/* Already signalled once, try harder now. */
2841			if (kill(dq->dq_pid, SIGKILL) != 0)
2842				(void)deadq_remove(dq);
2843			break;
2844
2845		case 1:
2846			/*
2847			 * Timed out on dead queue, send terminate
2848			 * signal.  Note that we leave the removal
2849			 * from the dead queue to reapchild(), which
2850			 * will also log the event (unless the process
2851			 * didn't even really exist, in case we simply
2852			 * drop it from the dead queue).
2853			 */
2854			if (kill(dq->dq_pid, SIGTERM) != 0)
2855				(void)deadq_remove(dq);
2856			else
2857				dq->dq_timeout--;
2858			break;
2859		default:
2860			dq->dq_timeout--;
2861		}
2862	}
2863	MarkSet = 0;
2864	(void)alarm(TIMERINTVL);
2865}
2866
2867/*
2868 * fork off and become a daemon, but wait for the child to come online
2869 * before returning to the parent, or we get disk thrashing at boot etc.
2870 * Set a timer so we don't hang forever if it wedges.
2871 */
2872static int
2873waitdaemon(int maxwait)
2874{
2875	int fd;
2876	int status;
2877	pid_t pid, childpid;
2878
2879	switch (childpid = fork()) {
2880	case -1:
2881		return (-1);
2882	case 0:
2883		break;
2884	default:
2885		signal(SIGALRM, timedout);
2886		alarm(maxwait);
2887		while ((pid = wait3(&status, 0, NULL)) != -1) {
2888			if (WIFEXITED(status))
2889				errx(1, "child pid %d exited with return code %d",
2890					pid, WEXITSTATUS(status));
2891			if (WIFSIGNALED(status))
2892				errx(1, "child pid %d exited on signal %d%s",
2893					pid, WTERMSIG(status),
2894					WCOREDUMP(status) ? " (core dumped)" :
2895					"");
2896			if (pid == childpid)	/* it's gone... */
2897				break;
2898		}
2899		exit(0);
2900	}
2901
2902	if (setsid() == -1)
2903		return (-1);
2904
2905	(void)chdir("/");
2906	if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
2907		(void)dup2(fd, STDIN_FILENO);
2908		(void)dup2(fd, STDOUT_FILENO);
2909		(void)dup2(fd, STDERR_FILENO);
2910		if (fd > STDERR_FILENO)
2911			(void)close(fd);
2912	}
2913	return (getppid());
2914}
2915
2916/*
2917 * We get a SIGALRM from the child when it's running and finished doing it's
2918 * fsync()'s or O_SYNC writes for all the boot messages.
2919 *
2920 * We also get a signal from the kernel if the timer expires, so check to
2921 * see what happened.
2922 */
2923static void
2924timedout(int sig __unused)
2925{
2926	int left;
2927	left = alarm(0);
2928	signal(SIGALRM, SIG_DFL);
2929	if (left == 0)
2930		errx(1, "timed out waiting for child");
2931	else
2932		_exit(0);
2933}
2934
2935/*
2936 * Add `s' to the list of allowable peer addresses to accept messages
2937 * from.
2938 *
2939 * `s' is a string in the form:
2940 *
2941 *    [*]domainname[:{servicename|portnumber|*}]
2942 *
2943 * or
2944 *
2945 *    netaddr/maskbits[:{servicename|portnumber|*}]
2946 *
2947 * Returns -1 on error, 0 if the argument was valid.
2948 */
2949static int
2950#if defined(INET) || defined(INET6)
2951allowaddr(char *s)
2952#else
2953allowaddr(char *s __unused)
2954#endif
2955{
2956#if defined(INET) || defined(INET6)
2957	char *cp1, *cp2;
2958	struct allowedpeer *ap;
2959	struct servent *se;
2960	int masklen = -1;
2961	struct addrinfo hints, *res = NULL;
2962#ifdef INET
2963	in_addr_t *addrp, *maskp;
2964#endif
2965#ifdef INET6
2966	uint32_t *addr6p, *mask6p;
2967#endif
2968	char ip[NI_MAXHOST];
2969
2970	ap = calloc(1, sizeof(*ap));
2971	if (ap == NULL)
2972		err(1, "malloc failed");
2973
2974#ifdef INET6
2975	if (*s != '[' || (cp1 = strchr(s + 1, ']')) == NULL)
2976#endif
2977		cp1 = s;
2978	if ((cp1 = strrchr(cp1, ':'))) {
2979		/* service/port provided */
2980		*cp1++ = '\0';
2981		if (strlen(cp1) == 1 && *cp1 == '*')
2982			/* any port allowed */
2983			ap->port = 0;
2984		else if ((se = getservbyname(cp1, "udp"))) {
2985			ap->port = ntohs(se->s_port);
2986		} else {
2987			ap->port = strtol(cp1, &cp2, 0);
2988			/* port not numeric */
2989			if (*cp2 != '\0')
2990				goto err;
2991		}
2992	} else {
2993		if ((se = getservbyname("syslog", "udp")))
2994			ap->port = ntohs(se->s_port);
2995		else
2996			/* sanity, should not happen */
2997			ap->port = 514;
2998	}
2999
3000	if ((cp1 = strchr(s, '/')) != NULL &&
3001	    strspn(cp1 + 1, "0123456789") == strlen(cp1 + 1)) {
3002		*cp1 = '\0';
3003		if ((masklen = atoi(cp1 + 1)) < 0)
3004			goto err;
3005	}
3006#ifdef INET6
3007	if (*s == '[') {
3008		cp2 = s + strlen(s) - 1;
3009		if (*cp2 == ']') {
3010			++s;
3011			*cp2 = '\0';
3012		} else {
3013			cp2 = NULL;
3014		}
3015	} else {
3016		cp2 = NULL;
3017	}
3018#endif
3019	hints = (struct addrinfo){
3020		.ai_family = PF_UNSPEC,
3021		.ai_socktype = SOCK_DGRAM,
3022		.ai_flags = AI_PASSIVE | AI_NUMERICHOST
3023	};
3024	if (getaddrinfo(s, NULL, &hints, &res) == 0) {
3025		ap->isnumeric = 1;
3026		memcpy(&ap->a_addr, res->ai_addr, res->ai_addrlen);
3027		ap->a_mask = (struct sockaddr_storage){
3028			.ss_family = res->ai_family,
3029			.ss_len = res->ai_addrlen
3030		};
3031		switch (res->ai_family) {
3032#ifdef INET
3033		case AF_INET:
3034			maskp = &sstosin(&ap->a_mask)->sin_addr.s_addr;
3035			addrp = &sstosin(&ap->a_addr)->sin_addr.s_addr;
3036			if (masklen < 0) {
3037				/* use default netmask */
3038				if (IN_CLASSA(ntohl(*addrp)))
3039					*maskp = htonl(IN_CLASSA_NET);
3040				else if (IN_CLASSB(ntohl(*addrp)))
3041					*maskp = htonl(IN_CLASSB_NET);
3042				else
3043					*maskp = htonl(IN_CLASSC_NET);
3044			} else if (masklen == 0) {
3045				*maskp = 0;
3046			} else if (masklen <= 32) {
3047				/* convert masklen to netmask */
3048				*maskp = htonl(~((1 << (32 - masklen)) - 1));
3049			} else {
3050				goto err;
3051			}
3052			/* Lose any host bits in the network number. */
3053			*addrp &= *maskp;
3054			break;
3055#endif
3056#ifdef INET6
3057		case AF_INET6:
3058			if (masklen > 128)
3059				goto err;
3060
3061			if (masklen < 0)
3062				masklen = 128;
3063			mask6p = (uint32_t *)&sstosin6(&ap->a_mask)->sin6_addr.s6_addr32[0];
3064			addr6p = (uint32_t *)&sstosin6(&ap->a_addr)->sin6_addr.s6_addr32[0];
3065			/* convert masklen to netmask */
3066			while (masklen > 0) {
3067				if (masklen < 32) {
3068					*mask6p =
3069					    htonl(~(0xffffffff >> masklen));
3070					*addr6p &= *mask6p;
3071					break;
3072				} else {
3073					*mask6p++ = 0xffffffff;
3074					addr6p++;
3075					masklen -= 32;
3076				}
3077			}
3078			break;
3079#endif
3080		default:
3081			goto err;
3082		}
3083		freeaddrinfo(res);
3084	} else {
3085		/* arg `s' is domain name */
3086		ap->isnumeric = 0;
3087		ap->a_name = s;
3088		if (cp1)
3089			*cp1 = '/';
3090#ifdef INET6
3091		if (cp2) {
3092			*cp2 = ']';
3093			--s;
3094		}
3095#endif
3096	}
3097	STAILQ_INSERT_TAIL(&aphead, ap, next);
3098
3099	if (Debug) {
3100		printf("allowaddr: rule ");
3101		if (ap->isnumeric) {
3102			printf("numeric, ");
3103			getnameinfo(sstosa(&ap->a_addr),
3104				    (sstosa(&ap->a_addr))->sa_len,
3105				    ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
3106			printf("addr = %s, ", ip);
3107			getnameinfo(sstosa(&ap->a_mask),
3108				    (sstosa(&ap->a_mask))->sa_len,
3109				    ip, sizeof ip, NULL, 0, NI_NUMERICHOST);
3110			printf("mask = %s; ", ip);
3111		} else {
3112			printf("domainname = %s; ", ap->a_name);
3113		}
3114		printf("port = %d\n", ap->port);
3115	}
3116
3117	return (0);
3118err:
3119	if (res != NULL)
3120		freeaddrinfo(res);
3121	free(ap);
3122#endif
3123	return (-1);
3124}
3125
3126/*
3127 * Validate that the remote peer has permission to log to us.
3128 */
3129static int
3130validate(struct sockaddr *sa, const char *hname)
3131{
3132	int i;
3133	char name[NI_MAXHOST], ip[NI_MAXHOST], port[NI_MAXSERV];
3134	struct allowedpeer *ap;
3135#ifdef INET
3136	struct sockaddr_in *sin4, *a4p = NULL, *m4p = NULL;
3137#endif
3138#ifdef INET6
3139	struct sockaddr_in6 *sin6, *a6p = NULL, *m6p = NULL;
3140#endif
3141	struct addrinfo hints, *res;
3142	u_short sport;
3143	int num = 0;
3144
3145	STAILQ_FOREACH(ap, &aphead, next) {
3146		num++;
3147	}
3148	dprintf("# of validation rule: %d\n", num);
3149	if (num == 0)
3150		/* traditional behaviour, allow everything */
3151		return (1);
3152
3153	(void)strlcpy(name, hname, sizeof(name));
3154	hints = (struct addrinfo){
3155		.ai_family = PF_UNSPEC,
3156		.ai_socktype = SOCK_DGRAM,
3157		.ai_flags = AI_PASSIVE | AI_NUMERICHOST
3158	};
3159	if (getaddrinfo(name, NULL, &hints, &res) == 0)
3160		freeaddrinfo(res);
3161	else if (strchr(name, '.') == NULL) {
3162		strlcat(name, ".", sizeof name);
3163		strlcat(name, LocalDomain, sizeof name);
3164	}
3165	if (getnameinfo(sa, sa->sa_len, ip, sizeof(ip), port, sizeof(port),
3166			NI_NUMERICHOST | NI_NUMERICSERV) != 0)
3167		return (0);	/* for safety, should not occur */
3168	dprintf("validate: dgram from IP %s, port %s, name %s;\n",
3169		ip, port, name);
3170	sport = atoi(port);
3171
3172	/* now, walk down the list */
3173	i = 0;
3174	STAILQ_FOREACH(ap, &aphead, next) {
3175		i++;
3176		if (ap->port != 0 && ap->port != sport) {
3177			dprintf("rejected in rule %d due to port mismatch.\n",
3178			    i);
3179			continue;
3180		}
3181
3182		if (ap->isnumeric) {
3183			if (ap->a_addr.ss_family != sa->sa_family) {
3184				dprintf("rejected in rule %d due to address family mismatch.\n", i);
3185				continue;
3186			}
3187#ifdef INET
3188			else if (ap->a_addr.ss_family == AF_INET) {
3189				sin4 = satosin(sa);
3190				a4p = satosin(&ap->a_addr);
3191				m4p = satosin(&ap->a_mask);
3192				if ((sin4->sin_addr.s_addr & m4p->sin_addr.s_addr)
3193				    != a4p->sin_addr.s_addr) {
3194					dprintf("rejected in rule %d due to IP mismatch.\n", i);
3195					continue;
3196				}
3197			}
3198#endif
3199#ifdef INET6
3200			else if (ap->a_addr.ss_family == AF_INET6) {
3201				sin6 = satosin6(sa);
3202				a6p = satosin6(&ap->a_addr);
3203				m6p = satosin6(&ap->a_mask);
3204				if (a6p->sin6_scope_id != 0 &&
3205				    sin6->sin6_scope_id != a6p->sin6_scope_id) {
3206					dprintf("rejected in rule %d due to scope mismatch.\n", i);
3207					continue;
3208				}
3209				if (!IN6_ARE_MASKED_ADDR_EQUAL(&sin6->sin6_addr,
3210				    &a6p->sin6_addr, &m6p->sin6_addr)) {
3211					dprintf("rejected in rule %d due to IP mismatch.\n", i);
3212					continue;
3213				}
3214			}
3215#endif
3216			else
3217				continue;
3218		} else {
3219			if (fnmatch(ap->a_name, name, FNM_NOESCAPE) ==
3220			    FNM_NOMATCH) {
3221				dprintf("rejected in rule %d due to name "
3222				    "mismatch.\n", i);
3223				continue;
3224			}
3225		}
3226		dprintf("accepted in rule %d.\n", i);
3227		return (1);	/* hooray! */
3228	}
3229	return (0);
3230}
3231
3232/*
3233 * Fairly similar to popen(3), but returns an open descriptor, as
3234 * opposed to a FILE *.
3235 */
3236static int
3237p_open(const char *prog, pid_t *rpid)
3238{
3239	int pfd[2], nulldesc;
3240	pid_t pid;
3241	char *argv[4]; /* sh -c cmd NULL */
3242	char errmsg[200];
3243
3244	if (pipe(pfd) == -1)
3245		return (-1);
3246	if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1)
3247		/* we are royally screwed anyway */
3248		return (-1);
3249
3250	switch ((pid = fork())) {
3251	case -1:
3252		close(nulldesc);
3253		return (-1);
3254
3255	case 0:
3256		(void)setsid();	/* Avoid catching SIGHUPs. */
3257		argv[0] = strdup("sh");
3258		argv[1] = strdup("-c");
3259		argv[2] = strdup(prog);
3260		argv[3] = NULL;
3261		if (argv[0] == NULL || argv[1] == NULL || argv[2] == NULL) {
3262			logerror("strdup");
3263			exit(1);
3264		}
3265
3266		alarm(0);
3267
3268		/* Restore signals marked as SIG_IGN. */
3269		(void)signal(SIGINT, SIG_DFL);
3270		(void)signal(SIGQUIT, SIG_DFL);
3271		(void)signal(SIGPIPE, SIG_DFL);
3272
3273		dup2(pfd[0], STDIN_FILENO);
3274		dup2(nulldesc, STDOUT_FILENO);
3275		dup2(nulldesc, STDERR_FILENO);
3276		closefrom(STDERR_FILENO + 1);
3277
3278		(void)execvp(_PATH_BSHELL, argv);
3279		_exit(255);
3280	}
3281	close(nulldesc);
3282	close(pfd[0]);
3283	/*
3284	 * Avoid blocking on a hung pipe.  With O_NONBLOCK, we are
3285	 * supposed to get an EWOULDBLOCK on writev(2), which is
3286	 * caught by the logic above anyway, which will in turn close
3287	 * the pipe, and fork a new logging subprocess if necessary.
3288	 * The stale subprocess will be killed some time later unless
3289	 * it terminated itself due to closing its input pipe (so we
3290	 * get rid of really dead puppies).
3291	 */
3292	if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) {
3293		/* This is bad. */
3294		(void)snprintf(errmsg, sizeof errmsg,
3295			       "Warning: cannot change pipe to PID %d to "
3296			       "non-blocking behaviour.",
3297			       (int)pid);
3298		logerror(errmsg);
3299	}
3300	*rpid = pid;
3301	return (pfd[1]);
3302}
3303
3304static void
3305deadq_enter(pid_t pid, const char *name)
3306{
3307	struct deadq_entry *dq;
3308	int status;
3309
3310	if (pid == 0)
3311		return;
3312	/*
3313	 * Be paranoid, if we can't signal the process, don't enter it
3314	 * into the dead queue (perhaps it's already dead).  If possible,
3315	 * we try to fetch and log the child's status.
3316	 */
3317	if (kill(pid, 0) != 0) {
3318		if (waitpid(pid, &status, WNOHANG) > 0)
3319			log_deadchild(pid, status, name);
3320		return;
3321	}
3322
3323	dq = malloc(sizeof(*dq));
3324	if (dq == NULL) {
3325		logerror("malloc");
3326		exit(1);
3327	}
3328	*dq = (struct deadq_entry){
3329		.dq_pid = pid,
3330		.dq_timeout = DQ_TIMO_INIT
3331	};
3332	TAILQ_INSERT_TAIL(&deadq_head, dq, dq_entries);
3333}
3334
3335static int
3336deadq_remove(struct deadq_entry *dq)
3337{
3338	if (dq != NULL) {
3339		TAILQ_REMOVE(&deadq_head, dq, dq_entries);
3340		free(dq);
3341		return (1);
3342	}
3343
3344	return (0);
3345}
3346
3347static int
3348deadq_removebypid(pid_t pid)
3349{
3350	struct deadq_entry *dq;
3351
3352	TAILQ_FOREACH(dq, &deadq_head, dq_entries) {
3353		if (dq->dq_pid == pid)
3354			break;
3355	}
3356	return (deadq_remove(dq));
3357}
3358
3359static void
3360log_deadchild(pid_t pid, int status, const char *name)
3361{
3362	int code;
3363	char buf[256];
3364	const char *reason;
3365
3366	errno = 0; /* Keep strerror() stuff out of logerror messages. */
3367	if (WIFSIGNALED(status)) {
3368		reason = "due to signal";
3369		code = WTERMSIG(status);
3370	} else {
3371		reason = "with status";
3372		code = WEXITSTATUS(status);
3373		if (code == 0)
3374			return;
3375	}
3376	(void)snprintf(buf, sizeof buf,
3377		       "Logging subprocess %d (%s) exited %s %d.",
3378		       pid, name, reason, code);
3379	logerror(buf);
3380}
3381
3382static int
3383socksetup(struct peer *pe)
3384{
3385	struct addrinfo hints, *res, *res0;
3386	int error;
3387	char *cp;
3388	int (*sl_recv)(struct socklist *);
3389	/*
3390	 * We have to handle this case for backwards compatibility:
3391	 * If there are two (or more) colons but no '[' and ']',
3392	 * assume this is an inet6 address without a service.
3393	 */
3394	if (pe->pe_name != NULL) {
3395#ifdef INET6
3396		if (pe->pe_name[0] == '[' &&
3397		    (cp = strchr(pe->pe_name + 1, ']')) != NULL) {
3398			pe->pe_name = &pe->pe_name[1];
3399			*cp = '\0';
3400			if (cp[1] == ':' && cp[2] != '\0')
3401				pe->pe_serv = cp + 2;
3402		} else {
3403#endif
3404			cp = strchr(pe->pe_name, ':');
3405			if (cp != NULL && strchr(cp + 1, ':') == NULL) {
3406				*cp = '\0';
3407				if (cp[1] != '\0')
3408					pe->pe_serv = cp + 1;
3409				if (cp == pe->pe_name)
3410					pe->pe_name = NULL;
3411			}
3412#ifdef INET6
3413		}
3414#endif
3415	}
3416	hints = (struct addrinfo){
3417		.ai_family = AF_UNSPEC,
3418		.ai_socktype = SOCK_DGRAM,
3419		.ai_flags = AI_PASSIVE
3420	};
3421	if (pe->pe_name != NULL)
3422		dprintf("Trying peer: %s\n", pe->pe_name);
3423	if (pe->pe_serv == NULL)
3424		pe->pe_serv = "syslog";
3425	error = getaddrinfo(pe->pe_name, pe->pe_serv, &hints, &res0);
3426	if (error) {
3427		char *msgbuf;
3428
3429		asprintf(&msgbuf, "getaddrinfo failed for %s%s: %s",
3430		    pe->pe_name == NULL ? "" : pe->pe_name, pe->pe_serv,
3431		    gai_strerror(error));
3432		errno = 0;
3433		if (msgbuf == NULL)
3434			logerror(gai_strerror(error));
3435		else
3436			logerror(msgbuf);
3437		free(msgbuf);
3438		die(0);
3439	}
3440	for (res = res0; res != NULL; res = res->ai_next) {
3441		int s;
3442
3443		if (res->ai_family != AF_LOCAL &&
3444		    SecureMode > 1) {
3445			/* Only AF_LOCAL in secure mode. */
3446			continue;
3447		}
3448		if (family != AF_UNSPEC &&
3449		    res->ai_family != AF_LOCAL && res->ai_family != family)
3450			continue;
3451
3452		s = socket(res->ai_family, res->ai_socktype,
3453		    res->ai_protocol);
3454		if (s < 0) {
3455			logerror("socket");
3456			error++;
3457			continue;
3458		}
3459#ifdef INET6
3460		if (res->ai_family == AF_INET6) {
3461			if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
3462			       &(int){1}, sizeof(int)) < 0) {
3463				logerror("setsockopt(IPV6_V6ONLY)");
3464				close(s);
3465				error++;
3466				continue;
3467			}
3468		}
3469#endif
3470		if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
3471		    &(int){1}, sizeof(int)) < 0) {
3472			logerror("setsockopt(SO_REUSEADDR)");
3473			close(s);
3474			error++;
3475			continue;
3476		}
3477
3478		/*
3479		 * Bind INET and UNIX-domain sockets.
3480		 *
3481		 * A UNIX-domain socket is always bound to a pathname
3482		 * regardless of -N flag.
3483		 *
3484		 * For INET sockets, RFC 3164 recommends that client
3485		 * side message should come from the privileged syslogd port.
3486		 *
3487		 * If the system administrator chooses not to obey
3488		 * this, we can skip the bind() step so that the
3489		 * system will choose a port for us.
3490		 */
3491		if (res->ai_family == AF_LOCAL)
3492			unlink(pe->pe_name);
3493		if (res->ai_family == AF_LOCAL ||
3494		    NoBind == 0 || pe->pe_name != NULL) {
3495			if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
3496				logerror("bind");
3497				close(s);
3498				error++;
3499				continue;
3500			}
3501			if (res->ai_family == AF_LOCAL ||
3502			    SecureMode == 0)
3503				increase_rcvbuf(s);
3504		}
3505		if (res->ai_family == AF_LOCAL &&
3506		    chmod(pe->pe_name, pe->pe_mode) < 0) {
3507			dprintf("chmod %s: %s\n", pe->pe_name,
3508			    strerror(errno));
3509			close(s);
3510			error++;
3511			continue;
3512		}
3513		dprintf("new socket fd is %d\n", s);
3514		if (res->ai_socktype != SOCK_DGRAM) {
3515			listen(s, 5);
3516		}
3517		sl_recv = socklist_recv_sock;
3518#if defined(INET) || defined(INET6)
3519		if (SecureMode && (res->ai_family == AF_INET ||
3520		    res->ai_family == AF_INET6)) {
3521			dprintf("shutdown\n");
3522			/* Forbid communication in secure mode. */
3523			if (shutdown(s, SHUT_RD) < 0 &&
3524			    errno != ENOTCONN) {
3525				logerror("shutdown");
3526				if (!Debug)
3527					die(0);
3528			}
3529			sl_recv = NULL;
3530		} else
3531#endif
3532			dprintf("listening on socket\n");
3533		dprintf("sending on socket\n");
3534		addsock(res->ai_addr, res->ai_addrlen,
3535		    &(struct socklist){
3536			.sl_socket = s,
3537			.sl_peer = pe,
3538			.sl_recv = sl_recv
3539		});
3540	}
3541	freeaddrinfo(res0);
3542
3543	return(error);
3544}
3545
3546static void
3547increase_rcvbuf(int fd)
3548{
3549	socklen_t len;
3550
3551	if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len,
3552	    &(socklen_t){sizeof(len)}) == 0) {
3553		if (len < RCVBUF_MINSIZE) {
3554			len = RCVBUF_MINSIZE;
3555			setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len));
3556		}
3557	}
3558}
3559