xref: /openbsd/usr.sbin/snmpd/proc.c (revision 2269e292)
1*2269e292Stobhe /*	$OpenBSD: proc.c,v 1.32 2024/04/09 15:48:01 tobhe Exp $	*/
260996bedSreyk 
360996bedSreyk /*
47be2c8aaSrzalamena  * Copyright (c) 2010 - 2016 Reyk Floeter <reyk@openbsd.org>
560996bedSreyk  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
660996bedSreyk  *
760996bedSreyk  * Permission to use, copy, modify, and distribute this software for any
860996bedSreyk  * purpose with or without fee is hereby granted, provided that the above
960996bedSreyk  * copyright notice and this permission notice appear in all copies.
1060996bedSreyk  *
1160996bedSreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1260996bedSreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1360996bedSreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1460996bedSreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1560996bedSreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1660996bedSreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1760996bedSreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1860996bedSreyk  */
1960996bedSreyk 
2060996bedSreyk #include <sys/socket.h>
2160996bedSreyk #include <sys/wait.h>
2260996bedSreyk 
237be2c8aaSrzalamena #include <fcntl.h>
2460996bedSreyk #include <stdio.h>
2560996bedSreyk #include <stdlib.h>
26a9292d2aSmartijn #include <stdint.h>
2760996bedSreyk #include <unistd.h>
2821032f8aSreyk #include <string.h>
2921032f8aSreyk #include <errno.h>
3021032f8aSreyk #include <signal.h>
319f020842Sbluhm #include <paths.h>
3260996bedSreyk #include <pwd.h>
3321032f8aSreyk #include <event.h>
340f12961aSreyk #include <imsg.h>
3560996bedSreyk 
36a9292d2aSmartijn #include "log.h"
3760996bedSreyk #include "snmpd.h"
3860996bedSreyk 
399f020842Sbluhm void	 proc_exec(struct privsep *, struct privsep_proc *, unsigned int, int,
40*2269e292Stobhe 	    char **);
417be2c8aaSrzalamena void	 proc_setup(struct privsep *, struct privsep_proc *, unsigned int);
427be2c8aaSrzalamena void	 proc_open(struct privsep *, int, int);
437be2c8aaSrzalamena void	 proc_accept(struct privsep *, int, enum privsep_procid,
447be2c8aaSrzalamena 	    unsigned int);
4521032f8aSreyk void	 proc_close(struct privsep *);
4660996bedSreyk void	 proc_shutdown(struct privsep_proc *);
4760996bedSreyk void	 proc_sig_handler(int, short, void *);
4821032f8aSreyk void	 proc_range(struct privsep *, enum privsep_procid, int *, int *);
493f75f466Sreyk int	 proc_dispatch_null(int, struct privsep_proc *, struct imsg *);
5060996bedSreyk 
517be2c8aaSrzalamena enum privsep_procid
proc_getid(struct privsep_proc * procs,unsigned int nproc,const char * proc_name)527be2c8aaSrzalamena proc_getid(struct privsep_proc *procs, unsigned int nproc,
537be2c8aaSrzalamena     const char *proc_name)
5421032f8aSreyk {
557be2c8aaSrzalamena 	struct privsep_proc	*p;
567be2c8aaSrzalamena 	unsigned int		 proc;
577be2c8aaSrzalamena 
587be2c8aaSrzalamena 	for (proc = 0; proc < nproc; proc++) {
597be2c8aaSrzalamena 		p = &procs[proc];
607be2c8aaSrzalamena 		if (strcmp(p->p_title, proc_name))
617be2c8aaSrzalamena 			continue;
627be2c8aaSrzalamena 
637be2c8aaSrzalamena 		return (p->p_id);
647be2c8aaSrzalamena 	}
657be2c8aaSrzalamena 
667be2c8aaSrzalamena 	return (PROC_MAX);
677be2c8aaSrzalamena }
687be2c8aaSrzalamena 
697be2c8aaSrzalamena void
proc_exec(struct privsep * ps,struct privsep_proc * procs,unsigned int nproc,int argc,char ** argv)707be2c8aaSrzalamena proc_exec(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc,
71*2269e292Stobhe     int argc, char **argv)
727be2c8aaSrzalamena {
737be2c8aaSrzalamena 	unsigned int		 proc, nargc, i, proc_i;
747be2c8aaSrzalamena 	char			**nargv;
757be2c8aaSrzalamena 	struct privsep_proc	*p;
767be2c8aaSrzalamena 	char			 num[32];
777be2c8aaSrzalamena 	int			 fd;
787be2c8aaSrzalamena 
797be2c8aaSrzalamena 	/* Prepare the new process argv. */
807be2c8aaSrzalamena 	nargv = calloc(argc + 5, sizeof(char *));
817be2c8aaSrzalamena 	if (nargv == NULL)
827be2c8aaSrzalamena 		fatal("%s: calloc", __func__);
837be2c8aaSrzalamena 
847be2c8aaSrzalamena 	/* Copy call argument first. */
857be2c8aaSrzalamena 	nargc = 0;
867be2c8aaSrzalamena 	nargv[nargc++] = argv[0];
877be2c8aaSrzalamena 
887be2c8aaSrzalamena 	/* Set process name argument and save the position. */
897be2c8aaSrzalamena 	nargv[nargc++] = "-P";
907be2c8aaSrzalamena 	proc_i = nargc;
917be2c8aaSrzalamena 	nargc++;
927be2c8aaSrzalamena 
937be2c8aaSrzalamena 	/* Point process instance arg to stack and copy the original args. */
947be2c8aaSrzalamena 	nargv[nargc++] = "-I";
957be2c8aaSrzalamena 	nargv[nargc++] = num;
967be2c8aaSrzalamena 	for (i = 1; i < (unsigned int) argc; i++)
977be2c8aaSrzalamena 		nargv[nargc++] = argv[i];
987be2c8aaSrzalamena 
997be2c8aaSrzalamena 	nargv[nargc] = NULL;
1007be2c8aaSrzalamena 
1017be2c8aaSrzalamena 	for (proc = 0; proc < nproc; proc++) {
1027be2c8aaSrzalamena 		p = &procs[proc];
1037be2c8aaSrzalamena 
1047be2c8aaSrzalamena 		/* Update args with process title. */
1057be2c8aaSrzalamena 		nargv[proc_i] = (char *)(uintptr_t)p->p_title;
1067be2c8aaSrzalamena 
1077be2c8aaSrzalamena 		/* Fire children processes. */
1087be2c8aaSrzalamena 		for (i = 0; i < ps->ps_instances[p->p_id]; i++) {
1097be2c8aaSrzalamena 			/* Update the process instance number. */
1107be2c8aaSrzalamena 			snprintf(num, sizeof(num), "%u", i);
1117be2c8aaSrzalamena 
1127be2c8aaSrzalamena 			fd = ps->ps_pipes[p->p_id][i].pp_pipes[PROC_PARENT][0];
1137be2c8aaSrzalamena 			ps->ps_pipes[p->p_id][i].pp_pipes[PROC_PARENT][0] = -1;
1147be2c8aaSrzalamena 
1157be2c8aaSrzalamena 			switch (fork()) {
1167be2c8aaSrzalamena 			case -1:
1177be2c8aaSrzalamena 				fatal("%s: fork", __func__);
1187be2c8aaSrzalamena 				break;
1197be2c8aaSrzalamena 			case 0:
1207be2c8aaSrzalamena 				/* Prepare parent socket. */
1217be2c8aaSrzalamena 				if (fd != PROC_PARENT_SOCK_FILENO) {
1227be2c8aaSrzalamena 					if (dup2(fd, PROC_PARENT_SOCK_FILENO)
1237be2c8aaSrzalamena 					    == -1)
1247be2c8aaSrzalamena 						fatal("dup2");
1257be2c8aaSrzalamena 				} else if (fcntl(fd, F_SETFD, 0) == -1)
1267be2c8aaSrzalamena 					fatal("fcntl");
1277be2c8aaSrzalamena 
1287be2c8aaSrzalamena 				execvp(argv[0], nargv);
1297be2c8aaSrzalamena 				fatal("%s: execvp", __func__);
1307be2c8aaSrzalamena 				break;
1317be2c8aaSrzalamena 			default:
1327be2c8aaSrzalamena 				/* Close child end. */
1337be2c8aaSrzalamena 				close(fd);
1347be2c8aaSrzalamena 				break;
1357be2c8aaSrzalamena 			}
1367be2c8aaSrzalamena 		}
1377be2c8aaSrzalamena 	}
1387be2c8aaSrzalamena 	free(nargv);
1397be2c8aaSrzalamena }
1407be2c8aaSrzalamena 
1417be2c8aaSrzalamena void
proc_connect(struct privsep * ps)1427be2c8aaSrzalamena proc_connect(struct privsep *ps)
1437be2c8aaSrzalamena {
1447be2c8aaSrzalamena 	struct imsgev		*iev;
1457be2c8aaSrzalamena 	unsigned int		 src, dst, inst;
1467be2c8aaSrzalamena 
1477be2c8aaSrzalamena 	/* Don't distribute any sockets if we are not really going to run. */
1487be2c8aaSrzalamena 	if (ps->ps_noaction)
1497be2c8aaSrzalamena 		return;
1507be2c8aaSrzalamena 
1517be2c8aaSrzalamena 	for (dst = 0; dst < PROC_MAX; dst++) {
1527be2c8aaSrzalamena 		/* We don't communicate with ourselves. */
1537be2c8aaSrzalamena 		if (dst == PROC_PARENT)
1547be2c8aaSrzalamena 			continue;
1557be2c8aaSrzalamena 
1567be2c8aaSrzalamena 		for (inst = 0; inst < ps->ps_instances[dst]; inst++) {
1577be2c8aaSrzalamena 			iev = &ps->ps_ievs[dst][inst];
1587be2c8aaSrzalamena 			imsg_init(&iev->ibuf, ps->ps_pp->pp_pipes[dst][inst]);
1597be2c8aaSrzalamena 			event_set(&iev->ev, iev->ibuf.fd, iev->events,
1607be2c8aaSrzalamena 			    iev->handler, iev->data);
1617be2c8aaSrzalamena 			event_add(&iev->ev, NULL);
1627be2c8aaSrzalamena 		}
1637be2c8aaSrzalamena 	}
1647be2c8aaSrzalamena 
1657be2c8aaSrzalamena 	/* Distribute the socketpair()s for everyone. */
1667be2c8aaSrzalamena 	for (src = 0; src < PROC_MAX; src++)
1677be2c8aaSrzalamena 		for (dst = src; dst < PROC_MAX; dst++) {
1687be2c8aaSrzalamena 			/* Parent already distributed its fds. */
1697be2c8aaSrzalamena 			if (src == PROC_PARENT || dst == PROC_PARENT)
1707be2c8aaSrzalamena 				continue;
1717be2c8aaSrzalamena 
1727be2c8aaSrzalamena 			proc_open(ps, src, dst);
1737be2c8aaSrzalamena 		}
1747be2c8aaSrzalamena }
1757be2c8aaSrzalamena 
1767be2c8aaSrzalamena void
proc_init(struct privsep * ps,struct privsep_proc * procs,unsigned int nproc,int debug,int argc,char ** argv,enum privsep_procid proc_id)1777be2c8aaSrzalamena proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc,
1789f020842Sbluhm     int debug, int argc, char **argv, enum privsep_procid proc_id)
1797be2c8aaSrzalamena {
1807be2c8aaSrzalamena 	struct privsep_proc	*p = NULL;
1817be2c8aaSrzalamena 	struct privsep_pipes	*pa, *pb;
1827be2c8aaSrzalamena 	unsigned int		 proc;
1837be2c8aaSrzalamena 	unsigned int		 dst;
1847be2c8aaSrzalamena 	int			 fds[2];
1857be2c8aaSrzalamena 
1867be2c8aaSrzalamena 	/* Don't initiate anything if we are not really going to run. */
1877be2c8aaSrzalamena 	if (ps->ps_noaction)
1887be2c8aaSrzalamena 		return;
1897be2c8aaSrzalamena 
1907be2c8aaSrzalamena 	if (proc_id == PROC_PARENT) {
1917be2c8aaSrzalamena 		privsep_process = PROC_PARENT;
1927be2c8aaSrzalamena 		proc_setup(ps, procs, nproc);
1937be2c8aaSrzalamena 
19428fef5efStobhe 		if (!debug && daemon(0, 0) == -1)
19528fef5efStobhe 			fatal("failed to daemonize");
19628fef5efStobhe 
1977be2c8aaSrzalamena 		/*
1987be2c8aaSrzalamena 		 * Create the children sockets so we can use them
1997be2c8aaSrzalamena 		 * to distribute the rest of the socketpair()s using
2007be2c8aaSrzalamena 		 * proc_connect() later.
2017be2c8aaSrzalamena 		 */
2027be2c8aaSrzalamena 		for (dst = 0; dst < PROC_MAX; dst++) {
2037be2c8aaSrzalamena 			/* Don't create socket for ourselves. */
2047be2c8aaSrzalamena 			if (dst == PROC_PARENT)
2057be2c8aaSrzalamena 				continue;
2067be2c8aaSrzalamena 
2077be2c8aaSrzalamena 			for (proc = 0; proc < ps->ps_instances[dst]; proc++) {
2087be2c8aaSrzalamena 				pa = &ps->ps_pipes[PROC_PARENT][0];
2097be2c8aaSrzalamena 				pb = &ps->ps_pipes[dst][proc];
2107be2c8aaSrzalamena 				if (socketpair(AF_UNIX,
2117be2c8aaSrzalamena 				    SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
2127be2c8aaSrzalamena 				    PF_UNSPEC, fds) == -1)
2137be2c8aaSrzalamena 					fatal("%s: socketpair", __func__);
2147be2c8aaSrzalamena 
2157be2c8aaSrzalamena 				pa->pp_pipes[dst][proc] = fds[0];
2167be2c8aaSrzalamena 				pb->pp_pipes[PROC_PARENT][0] = fds[1];
2177be2c8aaSrzalamena 			}
2187be2c8aaSrzalamena 		}
2197be2c8aaSrzalamena 
2207be2c8aaSrzalamena 		/* Engage! */
221*2269e292Stobhe 		proc_exec(ps, procs, nproc, argc, argv);
2227be2c8aaSrzalamena 		return;
2237be2c8aaSrzalamena 	}
2247be2c8aaSrzalamena 
2257be2c8aaSrzalamena 	/* Initialize a child */
2267be2c8aaSrzalamena 	for (proc = 0; proc < nproc; proc++) {
2277be2c8aaSrzalamena 		if (procs[proc].p_id != proc_id)
2287be2c8aaSrzalamena 			continue;
2297be2c8aaSrzalamena 		p = &procs[proc];
2307be2c8aaSrzalamena 		break;
2317be2c8aaSrzalamena 	}
2327be2c8aaSrzalamena 	if (p == NULL || p->p_init == NULL)
2337be2c8aaSrzalamena 		fatalx("%s: process %d missing process initialization",
2347be2c8aaSrzalamena 		    __func__, proc_id);
2357be2c8aaSrzalamena 
2367be2c8aaSrzalamena 	p->p_init(ps, p);
2377be2c8aaSrzalamena 
2387be2c8aaSrzalamena 	fatalx("failed to initiate child process");
2397be2c8aaSrzalamena }
2407be2c8aaSrzalamena 
2417be2c8aaSrzalamena void
proc_accept(struct privsep * ps,int fd,enum privsep_procid dst,unsigned int n)2427be2c8aaSrzalamena proc_accept(struct privsep *ps, int fd, enum privsep_procid dst,
2437be2c8aaSrzalamena     unsigned int n)
2447be2c8aaSrzalamena {
2457be2c8aaSrzalamena 	struct privsep_pipes	*pp = ps->ps_pp;
2467be2c8aaSrzalamena 	struct imsgev		*iev;
2477be2c8aaSrzalamena 
2487be2c8aaSrzalamena 	if (ps->ps_ievs[dst] == NULL) {
2497be2c8aaSrzalamena #if DEBUG > 1
2507be2c8aaSrzalamena 		log_debug("%s: %s src %d %d to dst %d %d not connected",
2517be2c8aaSrzalamena 		    __func__, ps->ps_title[privsep_process],
2527be2c8aaSrzalamena 		    privsep_process, ps->ps_instance + 1,
2537be2c8aaSrzalamena 		    dst, n + 1);
2547be2c8aaSrzalamena #endif
2557be2c8aaSrzalamena 		close(fd);
2567be2c8aaSrzalamena 		return;
2577be2c8aaSrzalamena 	}
2587be2c8aaSrzalamena 
2597be2c8aaSrzalamena 	if (pp->pp_pipes[dst][n] != -1) {
2607be2c8aaSrzalamena 		log_warnx("%s: duplicated descriptor", __func__);
2617be2c8aaSrzalamena 		close(fd);
2627be2c8aaSrzalamena 		return;
2637be2c8aaSrzalamena 	} else
2647be2c8aaSrzalamena 		pp->pp_pipes[dst][n] = fd;
2657be2c8aaSrzalamena 
2667be2c8aaSrzalamena 	iev = &ps->ps_ievs[dst][n];
2677be2c8aaSrzalamena 	imsg_init(&iev->ibuf, fd);
2687be2c8aaSrzalamena 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
2697be2c8aaSrzalamena 	event_add(&iev->ev, NULL);
2707be2c8aaSrzalamena }
2717be2c8aaSrzalamena 
2727be2c8aaSrzalamena void
proc_setup(struct privsep * ps,struct privsep_proc * procs,unsigned int nproc)2737be2c8aaSrzalamena proc_setup(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc)
2747be2c8aaSrzalamena {
2757be2c8aaSrzalamena 	unsigned int		 i, j, src, dst, id;
27621032f8aSreyk 	struct privsep_pipes	*pp;
27721032f8aSreyk 
2787be2c8aaSrzalamena 	/* Initialize parent title, ps_instances and procs. */
2797be2c8aaSrzalamena 	ps->ps_title[PROC_PARENT] = "parent";
2807be2c8aaSrzalamena 
2817be2c8aaSrzalamena 	for (src = 0; src < PROC_MAX; src++)
2827be2c8aaSrzalamena 		/* Default to 1 process instance */
2837be2c8aaSrzalamena 		if (ps->ps_instances[src] < 1)
2847be2c8aaSrzalamena 			ps->ps_instances[src] = 1;
2857be2c8aaSrzalamena 
2867be2c8aaSrzalamena 	for (src = 0; src < nproc; src++) {
2877be2c8aaSrzalamena 		procs[src].p_ps = ps;
2887be2c8aaSrzalamena 		if (procs[src].p_cb == NULL)
2897be2c8aaSrzalamena 			procs[src].p_cb = proc_dispatch_null;
2907be2c8aaSrzalamena 
2917be2c8aaSrzalamena 		id = procs[src].p_id;
2927be2c8aaSrzalamena 		ps->ps_title[id] = procs[src].p_title;
2937be2c8aaSrzalamena 		if ((ps->ps_ievs[id] = calloc(ps->ps_instances[id],
2947be2c8aaSrzalamena 		    sizeof(struct imsgev))) == NULL)
2957be2c8aaSrzalamena 			fatal("%s: calloc", __func__);
2967be2c8aaSrzalamena 
2977be2c8aaSrzalamena 		/* With this set up, we are ready to call imsg_init(). */
2987be2c8aaSrzalamena 		for (i = 0; i < ps->ps_instances[id]; i++) {
2997be2c8aaSrzalamena 			ps->ps_ievs[id][i].handler = proc_dispatch;
3007be2c8aaSrzalamena 			ps->ps_ievs[id][i].events = EV_READ;
3017be2c8aaSrzalamena 			ps->ps_ievs[id][i].proc = &procs[src];
3027be2c8aaSrzalamena 			ps->ps_ievs[id][i].data = &ps->ps_ievs[id][i];
3037be2c8aaSrzalamena 		}
3047be2c8aaSrzalamena 	}
3057be2c8aaSrzalamena 
30660996bedSreyk 	/*
30721032f8aSreyk 	 * Allocate pipes for all process instances (incl. parent)
30821032f8aSreyk 	 *
30921032f8aSreyk 	 * - ps->ps_pipes: N:M mapping
31021032f8aSreyk 	 * N source processes connected to M destination processes:
31121032f8aSreyk 	 * [src][instances][dst][instances], for example
31221032f8aSreyk 	 * [PROC_RELAY][3][PROC_CA][3]
31321032f8aSreyk 	 *
31421032f8aSreyk 	 * - ps->ps_pp: per-process 1:M part of ps->ps_pipes
31521032f8aSreyk 	 * Each process instance has a destination array of socketpair fds:
31621032f8aSreyk 	 * [dst][instances], for example
31721032f8aSreyk 	 * [PROC_PARENT][0]
31821032f8aSreyk 	 */
31921032f8aSreyk 	for (src = 0; src < PROC_MAX; src++) {
32021032f8aSreyk 		/* Allocate destination array for each process */
3217be2c8aaSrzalamena 		if ((ps->ps_pipes[src] = calloc(ps->ps_instances[src],
32221032f8aSreyk 		    sizeof(struct privsep_pipes))) == NULL)
3237be2c8aaSrzalamena 			fatal("%s: calloc", __func__);
32421032f8aSreyk 
3257be2c8aaSrzalamena 		for (i = 0; i < ps->ps_instances[src]; i++) {
32621032f8aSreyk 			pp = &ps->ps_pipes[src][i];
32721032f8aSreyk 
32821032f8aSreyk 			for (dst = 0; dst < PROC_MAX; dst++) {
32921032f8aSreyk 				/* Allocate maximum fd integers */
33021032f8aSreyk 				if ((pp->pp_pipes[dst] =
3317be2c8aaSrzalamena 				    calloc(ps->ps_instances[dst],
33221032f8aSreyk 				    sizeof(int))) == NULL)
3337be2c8aaSrzalamena 					fatal("%s: calloc", __func__);
33421032f8aSreyk 
33521032f8aSreyk 				/* Mark fd as unused */
3367be2c8aaSrzalamena 				for (j = 0; j < ps->ps_instances[dst]; j++)
33721032f8aSreyk 					pp->pp_pipes[dst][j] = -1;
33821032f8aSreyk 			}
33921032f8aSreyk 		}
34021032f8aSreyk 	}
34121032f8aSreyk 
3427be2c8aaSrzalamena 	ps->ps_pp = &ps->ps_pipes[privsep_process][ps->ps_instance];
34360996bedSreyk }
34460996bedSreyk 
34560996bedSreyk void
proc_kill(struct privsep * ps)34660996bedSreyk proc_kill(struct privsep *ps)
34760996bedSreyk {
3487be2c8aaSrzalamena 	char		*cause;
34960996bedSreyk 	pid_t		 pid;
3507be2c8aaSrzalamena 	int		 len, status;
35160996bedSreyk 
35260996bedSreyk 	if (privsep_process != PROC_PARENT)
35360996bedSreyk 		return;
35460996bedSreyk 
3557be2c8aaSrzalamena 	proc_close(ps);
35660996bedSreyk 
35760996bedSreyk 	do {
3587be2c8aaSrzalamena 		pid = waitpid(WAIT_ANY, &status, 0);
3597be2c8aaSrzalamena 		if (pid <= 0)
3607be2c8aaSrzalamena 			continue;
36121032f8aSreyk 
3627be2c8aaSrzalamena 		if (WIFSIGNALED(status)) {
3637be2c8aaSrzalamena 			len = asprintf(&cause, "terminated; signal %d",
3647be2c8aaSrzalamena 			    WTERMSIG(status));
3657be2c8aaSrzalamena 		} else if (WIFEXITED(status)) {
3667be2c8aaSrzalamena 			if (WEXITSTATUS(status) != 0)
3677be2c8aaSrzalamena 				len = asprintf(&cause, "exited abnormally");
3687be2c8aaSrzalamena 			else
3697be2c8aaSrzalamena 				len = 0;
3707be2c8aaSrzalamena 		} else
3717be2c8aaSrzalamena 			len = -1;
3727be2c8aaSrzalamena 
3737be2c8aaSrzalamena 		if (len == 0) {
3747be2c8aaSrzalamena 			/* child exited OK, don't print a warning message */
3757be2c8aaSrzalamena 		} else if (len != -1) {
3767be2c8aaSrzalamena 			log_warnx("lost child: pid %u %s", pid, cause);
3777be2c8aaSrzalamena 			free(cause);
3787be2c8aaSrzalamena 		} else
3797be2c8aaSrzalamena 			log_warnx("lost child: pid %u", pid);
3807be2c8aaSrzalamena 	} while (pid != -1 || (pid == -1 && errno == EINTR));
38160996bedSreyk }
38260996bedSreyk 
38360996bedSreyk void
proc_open(struct privsep * ps,int src,int dst)3847be2c8aaSrzalamena proc_open(struct privsep *ps, int src, int dst)
38560996bedSreyk {
38621032f8aSreyk 	struct privsep_pipes	*pa, *pb;
3877be2c8aaSrzalamena 	struct privsep_fd	 pf;
38821032f8aSreyk 	int			 fds[2];
3897be2c8aaSrzalamena 	unsigned int		 i, j;
39060996bedSreyk 
3917be2c8aaSrzalamena 	/* Exchange pipes between process. */
39221032f8aSreyk 	for (i = 0; i < ps->ps_instances[src]; i++) {
3937be2c8aaSrzalamena 		for (j = 0; j < ps->ps_instances[dst]; j++) {
3947be2c8aaSrzalamena 			/* Don't create sockets for ourself. */
3957be2c8aaSrzalamena 			if (src == dst && i == j)
3967be2c8aaSrzalamena 				continue;
3977be2c8aaSrzalamena 
39821032f8aSreyk 			pa = &ps->ps_pipes[src][i];
3997be2c8aaSrzalamena 			pb = &ps->ps_pipes[dst][j];
4005f0d8540Sreyk 			if (socketpair(AF_UNIX,
4017be2c8aaSrzalamena 			    SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
40221032f8aSreyk 			    PF_UNSPEC, fds) == -1)
4037be2c8aaSrzalamena 				fatal("%s: socketpair", __func__);
40421032f8aSreyk 
4057be2c8aaSrzalamena 			pa->pp_pipes[dst][j] = fds[0];
40621032f8aSreyk 			pb->pp_pipes[src][i] = fds[1];
40760996bedSreyk 
4087be2c8aaSrzalamena 			pf.pf_procid = src;
4097be2c8aaSrzalamena 			pf.pf_instance = i;
4107be2c8aaSrzalamena 			if (proc_compose_imsg(ps, dst, j, IMSG_CTL_PROCFD,
4117be2c8aaSrzalamena 			    -1, pb->pp_pipes[src][i], &pf, sizeof(pf)) == -1)
4127be2c8aaSrzalamena 				fatal("%s: proc_compose_imsg", __func__);
4137be2c8aaSrzalamena 
4147be2c8aaSrzalamena 			pf.pf_procid = dst;
4157be2c8aaSrzalamena 			pf.pf_instance = j;
4167be2c8aaSrzalamena 			if (proc_compose_imsg(ps, src, i, IMSG_CTL_PROCFD,
4177be2c8aaSrzalamena 			    -1, pa->pp_pipes[dst][j], &pf, sizeof(pf)) == -1)
4187be2c8aaSrzalamena 				fatal("%s: proc_compose_imsg", __func__);
41921032f8aSreyk 
42021032f8aSreyk 			/*
4217be2c8aaSrzalamena 			 * We have to flush to send the descriptors and close
4227be2c8aaSrzalamena 			 * them to avoid the fd ramp on startup.
42321032f8aSreyk 			 */
4247be2c8aaSrzalamena 			if (proc_flush_imsg(ps, src, i) == -1 ||
4257be2c8aaSrzalamena 			    proc_flush_imsg(ps, dst, j) == -1)
4267be2c8aaSrzalamena 				fatal("%s: imsg_flush", __func__);
42760996bedSreyk 		}
42860996bedSreyk 	}
42960996bedSreyk }
43060996bedSreyk 
43121032f8aSreyk void
proc_close(struct privsep * ps)43221032f8aSreyk proc_close(struct privsep *ps)
43321032f8aSreyk {
43432c142bfSreyk 	unsigned int		 dst, n;
43521032f8aSreyk 	struct privsep_pipes	*pp;
43660996bedSreyk 
43721032f8aSreyk 	if (ps == NULL)
43821032f8aSreyk 		return;
43921032f8aSreyk 
44021032f8aSreyk 	pp = ps->ps_pp;
44121032f8aSreyk 
44221032f8aSreyk 	for (dst = 0; dst < PROC_MAX; dst++) {
44321032f8aSreyk 		if (ps->ps_ievs[dst] == NULL)
44421032f8aSreyk 			continue;
44521032f8aSreyk 
44621032f8aSreyk 		for (n = 0; n < ps->ps_instances[dst]; n++) {
44721032f8aSreyk 			if (pp->pp_pipes[dst][n] == -1)
44821032f8aSreyk 				continue;
44921032f8aSreyk 
45021032f8aSreyk 			/* Cancel the fd, close and invalidate the fd */
45121032f8aSreyk 			event_del(&(ps->ps_ievs[dst][n].ev));
45221032f8aSreyk 			imsg_clear(&(ps->ps_ievs[dst][n].ibuf));
45321032f8aSreyk 			close(pp->pp_pipes[dst][n]);
45421032f8aSreyk 			pp->pp_pipes[dst][n] = -1;
45521032f8aSreyk 		}
45621032f8aSreyk 		free(ps->ps_ievs[dst]);
45760996bedSreyk 	}
45860996bedSreyk }
45960996bedSreyk 
46060996bedSreyk void
proc_shutdown(struct privsep_proc * p)46160996bedSreyk proc_shutdown(struct privsep_proc *p)
46260996bedSreyk {
46360996bedSreyk 	struct privsep	*ps = p->p_ps;
46421032f8aSreyk 
46560996bedSreyk 	if (p->p_shutdown != NULL)
46621032f8aSreyk 		(*p->p_shutdown)();
46760996bedSreyk 
46821032f8aSreyk 	proc_close(ps);
46960996bedSreyk 
47021032f8aSreyk 	log_info("%s exiting, pid %d", p->p_title, getpid());
47121032f8aSreyk 
4727be2c8aaSrzalamena 	exit(0);
47360996bedSreyk }
47460996bedSreyk 
47560996bedSreyk void
proc_sig_handler(int sig,short event,void * arg)47660996bedSreyk proc_sig_handler(int sig, short event, void *arg)
47760996bedSreyk {
47860996bedSreyk 	struct privsep_proc	*p = arg;
47960996bedSreyk 
48060996bedSreyk 	switch (sig) {
48160996bedSreyk 	case SIGINT:
48260996bedSreyk 	case SIGTERM:
48360996bedSreyk 		proc_shutdown(p);
48460996bedSreyk 		break;
48560996bedSreyk 	case SIGCHLD:
48660996bedSreyk 	case SIGHUP:
48760996bedSreyk 	case SIGPIPE:
4885f2be52bSreyk 	case SIGUSR1:
48960996bedSreyk 		/* ignore */
49060996bedSreyk 		break;
49160996bedSreyk 	default:
492566d2cadSbenno 		fatalx("%s: unexpected signal", __func__);
49360996bedSreyk 		/* NOTREACHED */
49460996bedSreyk 	}
49560996bedSreyk }
49660996bedSreyk 
4977be2c8aaSrzalamena void
proc_run(struct privsep * ps,struct privsep_proc * p,struct privsep_proc * procs,unsigned int nproc,void (* run)(struct privsep *,struct privsep_proc *,void *),void * arg)49860996bedSreyk proc_run(struct privsep *ps, struct privsep_proc *p,
49932c142bfSreyk     struct privsep_proc *procs, unsigned int nproc,
5003f75f466Sreyk     void (*run)(struct privsep *, struct privsep_proc *, void *), void *arg)
50160996bedSreyk {
50260996bedSreyk 	struct passwd		*pw;
50360996bedSreyk 	const char		*root;
50460996bedSreyk 
5050f12961aSreyk 	log_procinit(p->p_title);
5060f12961aSreyk 
5077be2c8aaSrzalamena 	/* Use non-standard user */
5087be2c8aaSrzalamena 	if (p->p_pw != NULL)
5097be2c8aaSrzalamena 		pw = p->p_pw;
5107be2c8aaSrzalamena 	else
5117be2c8aaSrzalamena 		pw = ps->ps_pw;
5127be2c8aaSrzalamena 
51360996bedSreyk 	/* Change root directory */
51460996bedSreyk 	if (p->p_chroot != NULL)
51560996bedSreyk 		root = p->p_chroot;
51660996bedSreyk 	else
51760996bedSreyk 		root = pw->pw_dir;
51860996bedSreyk 
51960996bedSreyk 	if (chroot(root) == -1)
520566d2cadSbenno 		fatal("%s: chroot", __func__);
52160996bedSreyk 	if (chdir("/") == -1)
522566d2cadSbenno 		fatal("%s: chdir(\"/\")", __func__);
52360996bedSreyk 
52460996bedSreyk 	privsep_process = p->p_id;
52560996bedSreyk 
52660996bedSreyk 	setproctitle("%s", p->p_title);
52760996bedSreyk 
52860996bedSreyk 	if (setgroups(1, &pw->pw_gid) ||
52960996bedSreyk 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
53060996bedSreyk 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
531566d2cadSbenno 		fatal("%s: cannot drop privileges", __func__);
53260996bedSreyk 
53360996bedSreyk 	event_init();
53460996bedSreyk 
53560996bedSreyk 	signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p);
53660996bedSreyk 	signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p);
53760996bedSreyk 	signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p);
53860996bedSreyk 	signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p);
53960996bedSreyk 	signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p);
5405f2be52bSreyk 	signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p);
54160996bedSreyk 
54260996bedSreyk 	signal_add(&ps->ps_evsigint, NULL);
54360996bedSreyk 	signal_add(&ps->ps_evsigterm, NULL);
54460996bedSreyk 	signal_add(&ps->ps_evsigchld, NULL);
54560996bedSreyk 	signal_add(&ps->ps_evsighup, NULL);
54660996bedSreyk 	signal_add(&ps->ps_evsigpipe, NULL);
5475f2be52bSreyk 	signal_add(&ps->ps_evsigusr1, NULL);
54860996bedSreyk 
5497be2c8aaSrzalamena 	proc_setup(ps, procs, nproc);
5507be2c8aaSrzalamena 	proc_accept(ps, PROC_PARENT_SOCK_FILENO, PROC_PARENT, 0);
5517be2c8aaSrzalamena 	DPRINTF("%s: %s %d/%d, pid %d", __func__, p->p_title,
5527be2c8aaSrzalamena 	    ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid());
5537be2c8aaSrzalamena 
5543f75f466Sreyk 	if (run != NULL)
5553f75f466Sreyk 		run(ps, p, arg);
55660996bedSreyk 
55760996bedSreyk 	event_dispatch();
55860996bedSreyk 
55960996bedSreyk 	proc_shutdown(p);
56060996bedSreyk }
56160996bedSreyk 
56260996bedSreyk void
proc_dispatch(int fd,short event,void * arg)56360996bedSreyk proc_dispatch(int fd, short event, void *arg)
56460996bedSreyk {
56521032f8aSreyk 	struct imsgev		*iev = arg;
56621032f8aSreyk 	struct privsep_proc	*p = iev->proc;
56760996bedSreyk 	struct privsep		*ps = p->p_ps;
56860996bedSreyk 	struct imsgbuf		*ibuf;
56960996bedSreyk 	struct imsg		 imsg;
57060996bedSreyk 	ssize_t			 n;
57160996bedSreyk 	int			 verbose;
57260996bedSreyk 	const char		*title;
5737be2c8aaSrzalamena 	struct privsep_fd	 pf;
57460996bedSreyk 
57560996bedSreyk 	title = ps->ps_title[privsep_process];
57660996bedSreyk 	ibuf = &iev->ibuf;
57760996bedSreyk 
57860996bedSreyk 	if (event & EV_READ) {
5792c684640Sclaudio 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
5807be2c8aaSrzalamena 			fatal("%s: imsg_read", __func__);
58160996bedSreyk 		if (n == 0) {
58260996bedSreyk 			/* this pipe is dead, so remove the event handler */
58360996bedSreyk 			event_del(&iev->ev);
58460996bedSreyk 			event_loopexit(NULL);
58560996bedSreyk 			return;
58660996bedSreyk 		}
58760996bedSreyk 	}
58860996bedSreyk 
58960996bedSreyk 	if (event & EV_WRITE) {
5907be2c8aaSrzalamena 		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
5917be2c8aaSrzalamena 			fatal("%s: msgbuf_write", __func__);
5927be2c8aaSrzalamena 		if (n == 0) {
5937be2c8aaSrzalamena 			/* this pipe is dead, so remove the event handler */
5947be2c8aaSrzalamena 			event_del(&iev->ev);
5957be2c8aaSrzalamena 			event_loopexit(NULL);
5967be2c8aaSrzalamena 			return;
5977be2c8aaSrzalamena 		}
59860996bedSreyk 	}
59960996bedSreyk 
60060996bedSreyk 	for (;;) {
60160996bedSreyk 		if ((n = imsg_get(ibuf, &imsg)) == -1)
6027be2c8aaSrzalamena 			fatal("%s: imsg_get", __func__);
60360996bedSreyk 		if (n == 0)
60460996bedSreyk 			break;
60560996bedSreyk 
60621032f8aSreyk #if DEBUG > 1
60766094308Sreyk 		log_debug("%s: %s %d got imsg %d peerid %d from %s %d",
60821032f8aSreyk 		    __func__, title, ps->ps_instance + 1,
6097be2c8aaSrzalamena 		    imsg.hdr.type, imsg.hdr.peerid, p->p_title, imsg.hdr.pid);
61021032f8aSreyk #endif
61121032f8aSreyk 
61260996bedSreyk 		/*
61360996bedSreyk 		 * Check the message with the program callback
61460996bedSreyk 		 */
61560996bedSreyk 		if ((p->p_cb)(fd, p, &imsg) == 0) {
61660996bedSreyk 			/* Message was handled by the callback, continue */
61760996bedSreyk 			imsg_free(&imsg);
61860996bedSreyk 			continue;
61960996bedSreyk 		}
62060996bedSreyk 
62160996bedSreyk 		/*
62260996bedSreyk 		 * Generic message handling
62360996bedSreyk 		 */
62460996bedSreyk 		switch (imsg.hdr.type) {
62560996bedSreyk 		case IMSG_CTL_VERBOSE:
62660996bedSreyk 			IMSG_SIZE_CHECK(&imsg, &verbose);
62760996bedSreyk 			memcpy(&verbose, imsg.data, sizeof(verbose));
628871fc12cSreyk 			log_setverbose(verbose);
62960996bedSreyk 			break;
6307be2c8aaSrzalamena 		case IMSG_CTL_PROCFD:
6317be2c8aaSrzalamena 			IMSG_SIZE_CHECK(&imsg, &pf);
6327be2c8aaSrzalamena 			memcpy(&pf, imsg.data, sizeof(pf));
633e60163e5Sclaudio 			proc_accept(ps, imsg_get_fd(&imsg), pf.pf_procid,
6347be2c8aaSrzalamena 			    pf.pf_instance);
6357be2c8aaSrzalamena 			break;
63660996bedSreyk 		default:
6377be2c8aaSrzalamena 			fatalx("%s: %s %d got invalid imsg %d peerid %d "
63866094308Sreyk 			    "from %s %d",
63921032f8aSreyk 			    __func__, title, ps->ps_instance + 1,
64066094308Sreyk 			    imsg.hdr.type, imsg.hdr.peerid,
6417be2c8aaSrzalamena 			    p->p_title, imsg.hdr.pid);
64260996bedSreyk 		}
64360996bedSreyk 		imsg_free(&imsg);
64460996bedSreyk 	}
64560996bedSreyk 	imsg_event_add(iev);
64660996bedSreyk }
64760996bedSreyk 
6483f75f466Sreyk int
proc_dispatch_null(int fd,struct privsep_proc * p,struct imsg * imsg)6493f75f466Sreyk proc_dispatch_null(int fd, struct privsep_proc *p, struct imsg *imsg)
6503f75f466Sreyk {
6513f75f466Sreyk 	return (-1);
6523f75f466Sreyk }
6533f75f466Sreyk 
65421032f8aSreyk /*
65521032f8aSreyk  * imsg helper functions
65621032f8aSreyk  */
65721032f8aSreyk 
65860996bedSreyk void
imsg_event_add(struct imsgev * iev)65960996bedSreyk imsg_event_add(struct imsgev *iev)
66060996bedSreyk {
66160996bedSreyk 	if (iev->handler == NULL) {
66260996bedSreyk 		imsg_flush(&iev->ibuf);
66360996bedSreyk 		return;
66460996bedSreyk 	}
66560996bedSreyk 
66660996bedSreyk 	iev->events = EV_READ;
66760996bedSreyk 	if (iev->ibuf.w.queued)
66860996bedSreyk 		iev->events |= EV_WRITE;
66960996bedSreyk 
67060996bedSreyk 	event_del(&iev->ev);
67160996bedSreyk 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
67260996bedSreyk 	event_add(&iev->ev, NULL);
67360996bedSreyk }
67460996bedSreyk 
67560996bedSreyk int
imsg_compose_event(struct imsgev * iev,uint16_t type,uint32_t peerid,pid_t pid,int fd,void * data,uint16_t datalen)67632c142bfSreyk imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
67732c142bfSreyk     pid_t pid, int fd, void *data, uint16_t datalen)
67860996bedSreyk {
67960996bedSreyk 	int	ret;
68060996bedSreyk 
68160996bedSreyk 	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
68260996bedSreyk 	    pid, fd, data, datalen)) == -1)
68360996bedSreyk 		return (ret);
68460996bedSreyk 	imsg_event_add(iev);
68560996bedSreyk 	return (ret);
68660996bedSreyk }
68760996bedSreyk 
68860996bedSreyk int
imsg_composev_event(struct imsgev * iev,uint16_t type,uint32_t peerid,pid_t pid,int fd,const struct iovec * iov,int iovcnt)68932c142bfSreyk imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
69060996bedSreyk     pid_t pid, int fd, const struct iovec *iov, int iovcnt)
69160996bedSreyk {
69260996bedSreyk 	int	ret;
69360996bedSreyk 
69460996bedSreyk 	if ((ret = imsg_composev(&iev->ibuf, type, peerid,
69560996bedSreyk 	    pid, fd, iov, iovcnt)) == -1)
69660996bedSreyk 		return (ret);
69760996bedSreyk 	imsg_event_add(iev);
69860996bedSreyk 	return (ret);
69960996bedSreyk }
70060996bedSreyk 
70121032f8aSreyk void
proc_range(struct privsep * ps,enum privsep_procid id,int * n,int * m)70221032f8aSreyk proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m)
70360996bedSreyk {
70421032f8aSreyk 	if (*n == -1) {
70521032f8aSreyk 		/* Use a range of all target instances */
70621032f8aSreyk 		*n = 0;
70721032f8aSreyk 		*m = ps->ps_instances[id];
70821032f8aSreyk 	} else {
70921032f8aSreyk 		/* Use only a single slot of the specified peer process */
71021032f8aSreyk 		*m = *n + 1;
71121032f8aSreyk 	}
71260996bedSreyk }
71360996bedSreyk 
71460996bedSreyk int
proc_compose_imsg(struct privsep * ps,enum privsep_procid id,int n,uint16_t type,uint32_t peerid,int fd,void * data,uint16_t datalen)71521032f8aSreyk proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n,
7169ac7219fSreyk     uint16_t type, uint32_t peerid, int fd, void *data, uint16_t datalen)
71721032f8aSreyk {
71821032f8aSreyk 	int	 m;
71921032f8aSreyk 
72021032f8aSreyk 	proc_range(ps, id, &n, &m);
72121032f8aSreyk 	for (; n < m; n++) {
72221032f8aSreyk 		if (imsg_compose_event(&ps->ps_ievs[id][n],
7237be2c8aaSrzalamena 		    type, peerid, ps->ps_instance + 1, fd, data, datalen) == -1)
72421032f8aSreyk 			return (-1);
72521032f8aSreyk 	}
72621032f8aSreyk 
72721032f8aSreyk 	return (0);
72821032f8aSreyk }
72921032f8aSreyk 
73021032f8aSreyk int
proc_compose(struct privsep * ps,enum privsep_procid id,uint16_t type,void * data,uint16_t datalen)7319ac7219fSreyk proc_compose(struct privsep *ps, enum privsep_procid id,
7329ac7219fSreyk     uint16_t type, void *data, uint16_t datalen)
7339ac7219fSreyk {
7349ac7219fSreyk 	return (proc_compose_imsg(ps, id, -1, type, -1, -1, data, datalen));
7359ac7219fSreyk }
7369ac7219fSreyk 
7379ac7219fSreyk int
proc_composev_imsg(struct privsep * ps,enum privsep_procid id,int n,uint16_t type,uint32_t peerid,int fd,const struct iovec * iov,int iovcnt)73821032f8aSreyk proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n,
7399ac7219fSreyk     uint16_t type, uint32_t peerid, int fd, const struct iovec *iov, int iovcnt)
74060996bedSreyk {
74121032f8aSreyk 	int	 m;
74221032f8aSreyk 
74321032f8aSreyk 	proc_range(ps, id, &n, &m);
74421032f8aSreyk 	for (; n < m; n++)
74521032f8aSreyk 		if (imsg_composev_event(&ps->ps_ievs[id][n],
7467be2c8aaSrzalamena 		    type, peerid, ps->ps_instance + 1, fd, iov, iovcnt) == -1)
74721032f8aSreyk 			return (-1);
74821032f8aSreyk 
74921032f8aSreyk 	return (0);
75060996bedSreyk }
75160996bedSreyk 
75260996bedSreyk int
proc_composev(struct privsep * ps,enum privsep_procid id,uint16_t type,const struct iovec * iov,int iovcnt)7539ac7219fSreyk proc_composev(struct privsep *ps, enum privsep_procid id,
7549ac7219fSreyk     uint16_t type, const struct iovec *iov, int iovcnt)
7559ac7219fSreyk {
7569ac7219fSreyk 	return (proc_composev_imsg(ps, id, -1, type, -1, -1, iov, iovcnt));
7579ac7219fSreyk }
7589ac7219fSreyk 
75921032f8aSreyk struct imsgbuf *
proc_ibuf(struct privsep * ps,enum privsep_procid id,int n)76021032f8aSreyk proc_ibuf(struct privsep *ps, enum privsep_procid id, int n)
76121032f8aSreyk {
76221032f8aSreyk 	int	 m;
76321032f8aSreyk 
76421032f8aSreyk 	proc_range(ps, id, &n, &m);
76521032f8aSreyk 	return (&ps->ps_ievs[id][n].ibuf);
76621032f8aSreyk }
76721032f8aSreyk 
76821032f8aSreyk struct imsgev *
proc_iev(struct privsep * ps,enum privsep_procid id,int n)76921032f8aSreyk proc_iev(struct privsep *ps, enum privsep_procid id, int n)
77021032f8aSreyk {
77121032f8aSreyk 	int	 m;
77221032f8aSreyk 
77321032f8aSreyk 	proc_range(ps, id, &n, &m);
77421032f8aSreyk 	return (&ps->ps_ievs[id][n]);
77521032f8aSreyk }
7767be2c8aaSrzalamena 
7777be2c8aaSrzalamena /* This function should only be called with care as it breaks async I/O */
7787be2c8aaSrzalamena int
proc_flush_imsg(struct privsep * ps,enum privsep_procid id,int n)7797be2c8aaSrzalamena proc_flush_imsg(struct privsep *ps, enum privsep_procid id, int n)
7807be2c8aaSrzalamena {
7817be2c8aaSrzalamena 	struct imsgbuf	*ibuf;
7827be2c8aaSrzalamena 	int		 m, ret = 0;
7837be2c8aaSrzalamena 
7847be2c8aaSrzalamena 	proc_range(ps, id, &n, &m);
7857be2c8aaSrzalamena 	for (; n < m; n++) {
7867be2c8aaSrzalamena 		if ((ibuf = proc_ibuf(ps, id, n)) == NULL)
7877be2c8aaSrzalamena 			return (-1);
7887be2c8aaSrzalamena 		do {
7897be2c8aaSrzalamena 			ret = imsg_flush(ibuf);
7907be2c8aaSrzalamena 		} while (ret == -1 && errno == EAGAIN);
7917be2c8aaSrzalamena 		if (ret == -1)
7927be2c8aaSrzalamena 			break;
7937be2c8aaSrzalamena 		imsg_event_add(&ps->ps_ievs[id][n]);
7947be2c8aaSrzalamena 	}
7957be2c8aaSrzalamena 
7967be2c8aaSrzalamena 	return (ret);
7977be2c8aaSrzalamena }
798