xref: /openbsd-src/usr.sbin/vmd/proc.c (revision 0a9d031fce78c0ebce0995b311938b1c87b1e208)
1*0a9d031fSclaudio /*	$OpenBSD: proc.c,v 1.33 2024/11/21 13:39:34 claudio Exp $	*/
2af96af6cSreyk 
3af96af6cSreyk /*
45921535cSreyk  * Copyright (c) 2010 - 2016 Reyk Floeter <reyk@openbsd.org>
5af96af6cSreyk  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
6af96af6cSreyk  *
7af96af6cSreyk  * Permission to use, copy, modify, and distribute this software for any
8af96af6cSreyk  * purpose with or without fee is hereby granted, provided that the above
9af96af6cSreyk  * copyright notice and this permission notice appear in all copies.
10af96af6cSreyk  *
11af96af6cSreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12af96af6cSreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13af96af6cSreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14af96af6cSreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15af96af6cSreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16af96af6cSreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17af96af6cSreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18af96af6cSreyk  */
19af96af6cSreyk 
20af96af6cSreyk #include <sys/types.h>
21af96af6cSreyk #include <sys/queue.h>
22af96af6cSreyk #include <sys/socket.h>
23af96af6cSreyk #include <sys/wait.h>
24af96af6cSreyk 
2568dc821bSrzalamena #include <fcntl.h>
26af96af6cSreyk #include <stdio.h>
27af96af6cSreyk #include <stdlib.h>
28af96af6cSreyk #include <unistd.h>
29af96af6cSreyk #include <string.h>
30af96af6cSreyk #include <errno.h>
31af96af6cSreyk #include <signal.h>
32af96af6cSreyk #include <pwd.h>
33af96af6cSreyk #include <event.h>
34af96af6cSreyk #include <imsg.h>
35af96af6cSreyk 
36bcc679a1Sreyk #include "proc.h"
37af96af6cSreyk 
38a9955862Sbluhm void	 proc_exec(struct privsep *, struct privsep_proc *, unsigned int, int,
392269e292Stobhe 	    char **);
40bcc679a1Sreyk void	 proc_setup(struct privsep *, struct privsep_proc *, unsigned int);
41bcc679a1Sreyk void	 proc_open(struct privsep *, int, int);
42bcc679a1Sreyk void	 proc_accept(struct privsep *, int, enum privsep_procid,
43bcc679a1Sreyk 	    unsigned int);
44af96af6cSreyk void	 proc_close(struct privsep *);
45af96af6cSreyk void	 proc_shutdown(struct privsep_proc *);
46af96af6cSreyk void	 proc_sig_handler(int, short, void *);
47af96af6cSreyk void	 proc_range(struct privsep *, enum privsep_procid, int *, int *);
48af96af6cSreyk int	 proc_dispatch_null(int, struct privsep_proc *, struct imsg *);
49af96af6cSreyk 
50bcc679a1Sreyk enum privsep_procid
51bcc679a1Sreyk proc_getid(struct privsep_proc *procs, unsigned int nproc,
52bcc679a1Sreyk     const char *proc_name)
53af96af6cSreyk {
54bcc679a1Sreyk 	struct privsep_proc	*p;
55bcc679a1Sreyk 	unsigned int		 proc;
56bcc679a1Sreyk 
57bcc679a1Sreyk 	for (proc = 0; proc < nproc; proc++) {
58bcc679a1Sreyk 		p = &procs[proc];
59bcc679a1Sreyk 		if (strcmp(p->p_title, proc_name))
60bcc679a1Sreyk 			continue;
61bcc679a1Sreyk 
62bcc679a1Sreyk 		return (p->p_id);
63bcc679a1Sreyk 	}
64bcc679a1Sreyk 
65bcc679a1Sreyk 	return (PROC_MAX);
66bcc679a1Sreyk }
67bcc679a1Sreyk 
68bcc679a1Sreyk void
69bcc679a1Sreyk proc_exec(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc,
702269e292Stobhe     int argc, char **argv)
71bcc679a1Sreyk {
72bcc679a1Sreyk 	unsigned int		 proc, nargc, i, proc_i;
73bcc679a1Sreyk 	char			**nargv;
74bcc679a1Sreyk 	struct privsep_proc	*p;
75bcc679a1Sreyk 	char			 num[32];
76bcc679a1Sreyk 	int			 fd;
77bcc679a1Sreyk 
78bcc679a1Sreyk 	/* Prepare the new process argv. */
79bcc679a1Sreyk 	nargv = calloc(argc + 5, sizeof(char *));
80bcc679a1Sreyk 	if (nargv == NULL)
81bcc679a1Sreyk 		fatal("%s: calloc", __func__);
82bcc679a1Sreyk 
83bcc679a1Sreyk 	/* Copy call argument first. */
84bcc679a1Sreyk 	nargc = 0;
85bcc679a1Sreyk 	nargv[nargc++] = argv[0];
86bcc679a1Sreyk 
87bcc679a1Sreyk 	/* Set process name argument and save the position. */
88bcc679a1Sreyk 	nargv[nargc++] = "-P";
89bcc679a1Sreyk 	proc_i = nargc;
90bcc679a1Sreyk 	nargc++;
91bcc679a1Sreyk 
92bcc679a1Sreyk 	/* Point process instance arg to stack and copy the original args. */
93bcc679a1Sreyk 	nargv[nargc++] = "-I";
94bcc679a1Sreyk 	nargv[nargc++] = num;
95bcc679a1Sreyk 	for (i = 1; i < (unsigned int) argc; i++)
96bcc679a1Sreyk 		nargv[nargc++] = argv[i];
97bcc679a1Sreyk 
98bcc679a1Sreyk 	nargv[nargc] = NULL;
99bcc679a1Sreyk 
100bcc679a1Sreyk 	for (proc = 0; proc < nproc; proc++) {
101bcc679a1Sreyk 		p = &procs[proc];
102bcc679a1Sreyk 
103bcc679a1Sreyk 		/* Update args with process title. */
104bcc679a1Sreyk 		nargv[proc_i] = (char *)(uintptr_t)p->p_title;
105bcc679a1Sreyk 
106bcc679a1Sreyk 		/* Fire children processes. */
107bcc679a1Sreyk 		for (i = 0; i < ps->ps_instances[p->p_id]; i++) {
108bcc679a1Sreyk 			/* Update the process instance number. */
109bcc679a1Sreyk 			snprintf(num, sizeof(num), "%u", i);
110bcc679a1Sreyk 
111bcc679a1Sreyk 			fd = ps->ps_pipes[p->p_id][i].pp_pipes[PROC_PARENT][0];
112bcc679a1Sreyk 			ps->ps_pipes[p->p_id][i].pp_pipes[PROC_PARENT][0] = -1;
113bcc679a1Sreyk 
114bcc679a1Sreyk 			switch (fork()) {
115bcc679a1Sreyk 			case -1:
116bcc679a1Sreyk 				fatal("%s: fork", __func__);
117bcc679a1Sreyk 				break;
118bcc679a1Sreyk 			case 0:
119bcc679a1Sreyk 				/* Prepare parent socket. */
12068dc821bSrzalamena 				if (fd != PROC_PARENT_SOCK_FILENO) {
12168dc821bSrzalamena 					if (dup2(fd, PROC_PARENT_SOCK_FILENO)
12268dc821bSrzalamena 					    == -1)
12368dc821bSrzalamena 						fatal("dup2");
12468dc821bSrzalamena 				} else if (fcntl(fd, F_SETFD, 0) == -1)
12568dc821bSrzalamena 					fatal("fcntl");
126bcc679a1Sreyk 
127bcc679a1Sreyk 				execvp(argv[0], nargv);
128bcc679a1Sreyk 				fatal("%s: execvp", __func__);
129bcc679a1Sreyk 				break;
130bcc679a1Sreyk 			default:
131bcc679a1Sreyk 				/* Close child end. */
132bcc679a1Sreyk 				close(fd);
133bcc679a1Sreyk 				break;
134bcc679a1Sreyk 			}
135bcc679a1Sreyk 		}
136bcc679a1Sreyk 	}
137bcc679a1Sreyk 	free(nargv);
138bcc679a1Sreyk }
139bcc679a1Sreyk 
140bcc679a1Sreyk void
141bcc679a1Sreyk proc_connect(struct privsep *ps)
142bcc679a1Sreyk {
143bcc679a1Sreyk 	struct imsgev		*iev;
14487e1f53bSrzalamena 	unsigned int		 src, dst, inst;
145bcc679a1Sreyk 
14687e1f53bSrzalamena 	/* Don't distribute any sockets if we are not really going to run. */
14787e1f53bSrzalamena 	if (ps->ps_noaction)
14887e1f53bSrzalamena 		return;
149bcc679a1Sreyk 
15087e1f53bSrzalamena 	for (dst = 0; dst < PROC_MAX; dst++) {
15187e1f53bSrzalamena 		/* We don't communicate with ourselves. */
15287e1f53bSrzalamena 		if (dst == PROC_PARENT)
153bcc679a1Sreyk 			continue;
154bcc679a1Sreyk 
15587e1f53bSrzalamena 		for (inst = 0; inst < ps->ps_instances[dst]; inst++) {
15687e1f53bSrzalamena 			iev = &ps->ps_ievs[dst][inst];
157*0a9d031fSclaudio 			if (imsgbuf_init(&iev->ibuf,
158*0a9d031fSclaudio 			    ps->ps_pp->pp_pipes[dst][inst]) == -1)
159*0a9d031fSclaudio 				fatal("imsgbuf_init");
160*0a9d031fSclaudio 			imsgbuf_allow_fdpass(&iev->ibuf);
161bcc679a1Sreyk 			event_set(&iev->ev, iev->ibuf.fd, iev->events,
162bcc679a1Sreyk 			    iev->handler, iev->data);
163bcc679a1Sreyk 			event_add(&iev->ev, NULL);
164bcc679a1Sreyk 		}
165bcc679a1Sreyk 	}
166bcc679a1Sreyk 
16787e1f53bSrzalamena 	/* Distribute the socketpair()s for everyone. */
16887e1f53bSrzalamena 	for (src = 0; src < PROC_MAX; src++)
16987e1f53bSrzalamena 		for (dst = src; dst < PROC_MAX; dst++) {
17087e1f53bSrzalamena 			/* Parent already distributed its fds. */
17187e1f53bSrzalamena 			if (src == PROC_PARENT || dst == PROC_PARENT)
172bcc679a1Sreyk 				continue;
173bcc679a1Sreyk 
17487e1f53bSrzalamena 			proc_open(ps, src, dst);
175bcc679a1Sreyk 		}
176bcc679a1Sreyk }
177bcc679a1Sreyk 
178bcc679a1Sreyk void
179bcc679a1Sreyk proc_init(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc,
180a9955862Sbluhm     int debug, int argc, char **argv, enum privsep_procid proc_id)
181bcc679a1Sreyk {
182bcc679a1Sreyk 	struct privsep_proc	*p = NULL;
18387e1f53bSrzalamena 	struct privsep_pipes	*pa, *pb;
184bcc679a1Sreyk 	unsigned int		 proc;
18587e1f53bSrzalamena 	unsigned int		 dst;
18687e1f53bSrzalamena 	int			 fds[2];
18787e1f53bSrzalamena 
18887e1f53bSrzalamena 	/* Don't initiate anything if we are not really going to run. */
18987e1f53bSrzalamena 	if (ps->ps_noaction)
19087e1f53bSrzalamena 		return;
191bcc679a1Sreyk 
192bcc679a1Sreyk 	if (proc_id == PROC_PARENT) {
193bcc679a1Sreyk 		privsep_process = PROC_PARENT;
194bcc679a1Sreyk 		proc_setup(ps, procs, nproc);
195bcc679a1Sreyk 
196dac1ed25Stobhe 		if (!debug && daemon(0, 0) == -1)
197dac1ed25Stobhe 			fatal("failed to daemonize");
198dac1ed25Stobhe 
19987e1f53bSrzalamena 		/*
20087e1f53bSrzalamena 		 * Create the children sockets so we can use them
20187e1f53bSrzalamena 		 * to distribute the rest of the socketpair()s using
20287e1f53bSrzalamena 		 * proc_connect() later.
20387e1f53bSrzalamena 		 */
20487e1f53bSrzalamena 		for (dst = 0; dst < PROC_MAX; dst++) {
20587e1f53bSrzalamena 			/* Don't create socket for ourselves. */
20687e1f53bSrzalamena 			if (dst == PROC_PARENT)
20787e1f53bSrzalamena 				continue;
20887e1f53bSrzalamena 
20987e1f53bSrzalamena 			for (proc = 0; proc < ps->ps_instances[dst]; proc++) {
21087e1f53bSrzalamena 				pa = &ps->ps_pipes[PROC_PARENT][0];
21187e1f53bSrzalamena 				pb = &ps->ps_pipes[dst][proc];
21287e1f53bSrzalamena 				if (socketpair(AF_UNIX,
21387e1f53bSrzalamena 				    SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
21487e1f53bSrzalamena 				    PF_UNSPEC, fds) == -1)
21587e1f53bSrzalamena 					fatal("%s: socketpair", __func__);
21687e1f53bSrzalamena 
21787e1f53bSrzalamena 				pa->pp_pipes[dst][proc] = fds[0];
21887e1f53bSrzalamena 				pb->pp_pipes[PROC_PARENT][0] = fds[1];
21987e1f53bSrzalamena 			}
22087e1f53bSrzalamena 		}
221bcc679a1Sreyk 
222bcc679a1Sreyk 		/* Engage! */
2232269e292Stobhe 		proc_exec(ps, procs, nproc, argc, argv);
224bcc679a1Sreyk 		return;
225bcc679a1Sreyk 	}
226bcc679a1Sreyk 
227bcc679a1Sreyk 	/* Initialize a child */
228bcc679a1Sreyk 	for (proc = 0; proc < nproc; proc++) {
229bcc679a1Sreyk 		if (procs[proc].p_id != proc_id)
230bcc679a1Sreyk 			continue;
231bcc679a1Sreyk 		p = &procs[proc];
232bcc679a1Sreyk 		break;
233bcc679a1Sreyk 	}
234bcc679a1Sreyk 	if (p == NULL || p->p_init == NULL)
235bcc679a1Sreyk 		fatalx("%s: process %d missing process initialization",
236bcc679a1Sreyk 		    __func__, proc_id);
237bcc679a1Sreyk 
238bcc679a1Sreyk 	p->p_init(ps, p);
239bcc679a1Sreyk 
240bcc679a1Sreyk 	fatalx("failed to initiate child process");
241bcc679a1Sreyk }
242bcc679a1Sreyk 
243bcc679a1Sreyk void
244bcc679a1Sreyk proc_accept(struct privsep *ps, int fd, enum privsep_procid dst,
245bcc679a1Sreyk     unsigned int n)
246bcc679a1Sreyk {
247bcc679a1Sreyk 	struct privsep_pipes	*pp = ps->ps_pp;
248bcc679a1Sreyk 	struct imsgev		*iev;
249bcc679a1Sreyk 
250bcc679a1Sreyk 	if (ps->ps_ievs[dst] == NULL) {
251bcc679a1Sreyk #if DEBUG > 1
252bcc679a1Sreyk 		log_debug("%s: %s src %d %d to dst %d %d not connected",
253bcc679a1Sreyk 		    __func__, ps->ps_title[privsep_process],
254bcc679a1Sreyk 		    privsep_process, ps->ps_instance + 1,
255bcc679a1Sreyk 		    dst, n + 1);
256bcc679a1Sreyk #endif
257bcc679a1Sreyk 		close(fd);
258bcc679a1Sreyk 		return;
259bcc679a1Sreyk 	}
260bcc679a1Sreyk 
261bcc679a1Sreyk 	if (pp->pp_pipes[dst][n] != -1) {
262bcc679a1Sreyk 		log_warnx("%s: duplicated descriptor", __func__);
263bcc679a1Sreyk 		close(fd);
264bcc679a1Sreyk 		return;
265bcc679a1Sreyk 	} else
266bcc679a1Sreyk 		pp->pp_pipes[dst][n] = fd;
267bcc679a1Sreyk 
268bcc679a1Sreyk 	iev = &ps->ps_ievs[dst][n];
269*0a9d031fSclaudio 	if (imsgbuf_init(&iev->ibuf, fd) == -1)
270*0a9d031fSclaudio 		fatal("imsgbuf_init");
271*0a9d031fSclaudio 	imsgbuf_allow_fdpass(&iev->ibuf);
272bcc679a1Sreyk 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
273bcc679a1Sreyk 	event_add(&iev->ev, NULL);
274bcc679a1Sreyk }
275bcc679a1Sreyk 
276bcc679a1Sreyk void
277bcc679a1Sreyk proc_setup(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc)
278bcc679a1Sreyk {
279bcc679a1Sreyk 	unsigned int		 i, j, src, dst, id;
280bcc679a1Sreyk 	struct privsep_pipes	*pp;
281bcc679a1Sreyk 
282bcc679a1Sreyk 	/* Initialize parent title, ps_instances and procs. */
28308d0da61Sdv 	ps->ps_title[PROC_PARENT] = "vmd";
284bcc679a1Sreyk 
285bcc679a1Sreyk 	for (src = 0; src < PROC_MAX; src++)
286bcc679a1Sreyk 		/* Default to 1 process instance */
287bcc679a1Sreyk 		if (ps->ps_instances[src] < 1)
288bcc679a1Sreyk 			ps->ps_instances[src] = 1;
289bcc679a1Sreyk 
290bcc679a1Sreyk 	for (src = 0; src < nproc; src++) {
291bcc679a1Sreyk 		procs[src].p_ps = ps;
292bcc679a1Sreyk 		if (procs[src].p_cb == NULL)
293bcc679a1Sreyk 			procs[src].p_cb = proc_dispatch_null;
294bcc679a1Sreyk 
295bcc679a1Sreyk 		id = procs[src].p_id;
296bcc679a1Sreyk 		ps->ps_title[id] = procs[src].p_title;
297bcc679a1Sreyk 		if ((ps->ps_ievs[id] = calloc(ps->ps_instances[id],
298bcc679a1Sreyk 		    sizeof(struct imsgev))) == NULL)
29987e1f53bSrzalamena 			fatal("%s: calloc", __func__);
300bcc679a1Sreyk 
301dd7efffeSclaudio 		/* With this set up, we are ready to call imsgbuf_init(). */
302bcc679a1Sreyk 		for (i = 0; i < ps->ps_instances[id]; i++) {
303bcc679a1Sreyk 			ps->ps_ievs[id][i].handler = proc_dispatch;
304bcc679a1Sreyk 			ps->ps_ievs[id][i].events = EV_READ;
305bcc679a1Sreyk 			ps->ps_ievs[id][i].proc = &procs[src];
306bcc679a1Sreyk 			ps->ps_ievs[id][i].data = &ps->ps_ievs[id][i];
307bcc679a1Sreyk 		}
308bcc679a1Sreyk 	}
309af96af6cSreyk 
310af96af6cSreyk 	/*
311af96af6cSreyk 	 * Allocate pipes for all process instances (incl. parent)
312af96af6cSreyk 	 *
313af96af6cSreyk 	 * - ps->ps_pipes: N:M mapping
314af96af6cSreyk 	 * N source processes connected to M destination processes:
315af96af6cSreyk 	 * [src][instances][dst][instances], for example
316af96af6cSreyk 	 * [PROC_RELAY][3][PROC_CA][3]
317af96af6cSreyk 	 *
318af96af6cSreyk 	 * - ps->ps_pp: per-process 1:M part of ps->ps_pipes
319af96af6cSreyk 	 * Each process instance has a destination array of socketpair fds:
320af96af6cSreyk 	 * [dst][instances], for example
321af96af6cSreyk 	 * [PROC_PARENT][0]
322af96af6cSreyk 	 */
323af96af6cSreyk 	for (src = 0; src < PROC_MAX; src++) {
324af96af6cSreyk 		/* Allocate destination array for each process */
325bcc679a1Sreyk 		if ((ps->ps_pipes[src] = calloc(ps->ps_instances[src],
326af96af6cSreyk 		    sizeof(struct privsep_pipes))) == NULL)
327bcc679a1Sreyk 			fatal("%s: calloc", __func__);
328af96af6cSreyk 
329bcc679a1Sreyk 		for (i = 0; i < ps->ps_instances[src]; i++) {
330af96af6cSreyk 			pp = &ps->ps_pipes[src][i];
331af96af6cSreyk 
332af96af6cSreyk 			for (dst = 0; dst < PROC_MAX; dst++) {
333af96af6cSreyk 				/* Allocate maximum fd integers */
334af96af6cSreyk 				if ((pp->pp_pipes[dst] =
335bcc679a1Sreyk 				    calloc(ps->ps_instances[dst],
336af96af6cSreyk 				    sizeof(int))) == NULL)
337bcc679a1Sreyk 					fatal("%s: calloc", __func__);
338af96af6cSreyk 
339af96af6cSreyk 				/* Mark fd as unused */
340bcc679a1Sreyk 				for (j = 0; j < ps->ps_instances[dst]; j++)
341af96af6cSreyk 					pp->pp_pipes[dst][j] = -1;
342af96af6cSreyk 			}
343af96af6cSreyk 		}
344af96af6cSreyk 	}
345af96af6cSreyk 
346bcc679a1Sreyk 	ps->ps_pp = &ps->ps_pipes[privsep_process][ps->ps_instance];
347af96af6cSreyk }
348af96af6cSreyk 
349af96af6cSreyk void
350af96af6cSreyk proc_kill(struct privsep *ps)
351af96af6cSreyk {
352bcc679a1Sreyk 	char		*cause;
353af96af6cSreyk 	pid_t		 pid;
354bcc679a1Sreyk 	int		 len, status;
355af96af6cSreyk 
356af96af6cSreyk 	if (privsep_process != PROC_PARENT)
357af96af6cSreyk 		return;
358af96af6cSreyk 
359bcc679a1Sreyk 	proc_close(ps);
360af96af6cSreyk 
361af96af6cSreyk 	do {
362bcc679a1Sreyk 		pid = waitpid(WAIT_ANY, &status, 0);
363bcc679a1Sreyk 		if (pid <= 0)
364bcc679a1Sreyk 			continue;
365af96af6cSreyk 
366bcc679a1Sreyk 		if (WIFSIGNALED(status)) {
367bcc679a1Sreyk 			len = asprintf(&cause, "terminated; signal %d",
368bcc679a1Sreyk 			    WTERMSIG(status));
369bcc679a1Sreyk 		} else if (WIFEXITED(status)) {
370bcc679a1Sreyk 			if (WEXITSTATUS(status) != 0)
371bcc679a1Sreyk 				len = asprintf(&cause, "exited abnormally");
372bcc679a1Sreyk 			else
373bcc679a1Sreyk 				len = 0;
374bcc679a1Sreyk 		} else
375bcc679a1Sreyk 			len = -1;
376bcc679a1Sreyk 
377bcc679a1Sreyk 		if (len == 0) {
378bcc679a1Sreyk 			/* child exited OK, don't print a warning message */
379bcc679a1Sreyk 		} else if (len != -1) {
380bcc679a1Sreyk 			log_warnx("lost child: pid %u %s", pid, cause);
381bcc679a1Sreyk 			free(cause);
382bcc679a1Sreyk 		} else
383bcc679a1Sreyk 			log_warnx("lost child: pid %u", pid);
384bcc679a1Sreyk 	} while (pid != -1 || (pid == -1 && errno == EINTR));
385af96af6cSreyk }
386af96af6cSreyk 
387af96af6cSreyk void
388bcc679a1Sreyk proc_open(struct privsep *ps, int src, int dst)
389af96af6cSreyk {
390af96af6cSreyk 	struct privsep_pipes	*pa, *pb;
39187e1f53bSrzalamena 	struct privsep_fd	 pf;
392af96af6cSreyk 	int			 fds[2];
393bcc679a1Sreyk 	unsigned int		 i, j;
394af96af6cSreyk 
39587e1f53bSrzalamena 	/* Exchange pipes between process. */
396af96af6cSreyk 	for (i = 0; i < ps->ps_instances[src]; i++) {
397bcc679a1Sreyk 		for (j = 0; j < ps->ps_instances[dst]; j++) {
398bcc679a1Sreyk 			/* Don't create sockets for ourself. */
399bcc679a1Sreyk 			if (src == dst && i == j)
400bcc679a1Sreyk 				continue;
401af96af6cSreyk 
402bcc679a1Sreyk 			pa = &ps->ps_pipes[src][i];
403bcc679a1Sreyk 			pb = &ps->ps_pipes[dst][j];
404af96af6cSreyk 			if (socketpair(AF_UNIX,
405bcc679a1Sreyk 			    SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
406af96af6cSreyk 			    PF_UNSPEC, fds) == -1)
40787e1f53bSrzalamena 				fatal("%s: socketpair", __func__);
408af96af6cSreyk 
409bcc679a1Sreyk 			pa->pp_pipes[dst][j] = fds[0];
410af96af6cSreyk 			pb->pp_pipes[src][i] = fds[1];
41187e1f53bSrzalamena 
41287e1f53bSrzalamena 			pf.pf_procid = src;
41387e1f53bSrzalamena 			pf.pf_instance = i;
41487e1f53bSrzalamena 			if (proc_compose_imsg(ps, dst, j, IMSG_CTL_PROCFD,
41587e1f53bSrzalamena 			    -1, pb->pp_pipes[src][i], &pf, sizeof(pf)) == -1)
41687e1f53bSrzalamena 				fatal("%s: proc_compose_imsg", __func__);
41787e1f53bSrzalamena 
41887e1f53bSrzalamena 			pf.pf_procid = dst;
41987e1f53bSrzalamena 			pf.pf_instance = j;
42087e1f53bSrzalamena 			if (proc_compose_imsg(ps, src, i, IMSG_CTL_PROCFD,
42187e1f53bSrzalamena 			    -1, pa->pp_pipes[dst][j], &pf, sizeof(pf)) == -1)
42287e1f53bSrzalamena 				fatal("%s: proc_compose_imsg", __func__);
42387e1f53bSrzalamena 
42487e1f53bSrzalamena 			/*
42587e1f53bSrzalamena 			 * We have to flush to send the descriptors and close
42687e1f53bSrzalamena 			 * them to avoid the fd ramp on startup.
42787e1f53bSrzalamena 			 */
428d2491206Srzalamena 			if (proc_flush_imsg(ps, src, i) == -1 ||
429d2491206Srzalamena 			    proc_flush_imsg(ps, dst, j) == -1)
430dd7efffeSclaudio 				fatal("%s: proc_flush_imsg", __func__);
431af96af6cSreyk 		}
432af96af6cSreyk 	}
433af96af6cSreyk }
434af96af6cSreyk 
435af96af6cSreyk void
436af96af6cSreyk proc_close(struct privsep *ps)
437af96af6cSreyk {
438af96af6cSreyk 	unsigned int		 dst, n;
439af96af6cSreyk 	struct privsep_pipes	*pp;
440af96af6cSreyk 
441af96af6cSreyk 	if (ps == NULL)
442af96af6cSreyk 		return;
443af96af6cSreyk 
444af96af6cSreyk 	pp = ps->ps_pp;
445af96af6cSreyk 
446af96af6cSreyk 	for (dst = 0; dst < PROC_MAX; dst++) {
447af96af6cSreyk 		if (ps->ps_ievs[dst] == NULL)
448af96af6cSreyk 			continue;
449af96af6cSreyk 
450af96af6cSreyk 		for (n = 0; n < ps->ps_instances[dst]; n++) {
451af96af6cSreyk 			if (pp->pp_pipes[dst][n] == -1)
452af96af6cSreyk 				continue;
453af96af6cSreyk 
454af96af6cSreyk 			/* Cancel the fd, close and invalidate the fd */
455af96af6cSreyk 			event_del(&(ps->ps_ievs[dst][n].ev));
456dd7efffeSclaudio 			imsgbuf_clear(&(ps->ps_ievs[dst][n].ibuf));
457af96af6cSreyk 			close(pp->pp_pipes[dst][n]);
458af96af6cSreyk 			pp->pp_pipes[dst][n] = -1;
459af96af6cSreyk 		}
460af96af6cSreyk 		free(ps->ps_ievs[dst]);
461af96af6cSreyk 	}
462af96af6cSreyk }
463af96af6cSreyk 
464af96af6cSreyk void
465af96af6cSreyk proc_shutdown(struct privsep_proc *p)
466af96af6cSreyk {
467af96af6cSreyk 	struct privsep	*ps = p->p_ps;
468af96af6cSreyk 
469af96af6cSreyk 	if (p->p_shutdown != NULL)
470af96af6cSreyk 		(*p->p_shutdown)();
471af96af6cSreyk 
472af96af6cSreyk 	proc_close(ps);
473af96af6cSreyk 
474af96af6cSreyk 	log_info("%s exiting, pid %d", p->p_title, getpid());
475af96af6cSreyk 
476bcc679a1Sreyk 	exit(0);
477af96af6cSreyk }
478af96af6cSreyk 
479af96af6cSreyk void
480af96af6cSreyk proc_sig_handler(int sig, short event, void *arg)
481af96af6cSreyk {
482af96af6cSreyk 	struct privsep_proc	*p = arg;
483af96af6cSreyk 
484af96af6cSreyk 	switch (sig) {
485af96af6cSreyk 	case SIGINT:
486af96af6cSreyk 	case SIGTERM:
487af96af6cSreyk 		proc_shutdown(p);
488af96af6cSreyk 		break;
489af96af6cSreyk 	case SIGCHLD:
490af96af6cSreyk 	case SIGHUP:
491af96af6cSreyk 	case SIGPIPE:
492af96af6cSreyk 	case SIGUSR1:
493af96af6cSreyk 		/* ignore */
494af96af6cSreyk 		break;
495af96af6cSreyk 	default:
496566d2cadSbenno 		fatalx("%s: unexpected signal", __func__);
497af96af6cSreyk 		/* NOTREACHED */
498af96af6cSreyk 	}
499af96af6cSreyk }
500af96af6cSreyk 
501bcc679a1Sreyk void
502af96af6cSreyk proc_run(struct privsep *ps, struct privsep_proc *p,
503af96af6cSreyk     struct privsep_proc *procs, unsigned int nproc,
504af96af6cSreyk     void (*run)(struct privsep *, struct privsep_proc *, void *), void *arg)
505af96af6cSreyk {
5065921535cSreyk 	struct passwd		*pw;
507af96af6cSreyk 	const char		*root;
508af96af6cSreyk 	struct control_sock	*rcs;
509af96af6cSreyk 
51008d0da61Sdv 	log_procinit("%s", p->p_title);
511af96af6cSreyk 
512af96af6cSreyk 	if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) {
513af96af6cSreyk 		if (control_init(ps, &ps->ps_csock) == -1)
51487e1f53bSrzalamena 			fatalx("%s: control_init", __func__);
515af96af6cSreyk 		TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry)
516af96af6cSreyk 			if (control_init(ps, rcs) == -1)
51787e1f53bSrzalamena 				fatalx("%s: control_init", __func__);
518af96af6cSreyk 	}
519af96af6cSreyk 
5205921535cSreyk 	/* Use non-standard user */
5215921535cSreyk 	if (p->p_pw != NULL)
5225921535cSreyk 		pw = p->p_pw;
5235921535cSreyk 	else
5245921535cSreyk 		pw = ps->ps_pw;
5255921535cSreyk 
526af96af6cSreyk 	/* Change root directory */
527af96af6cSreyk 	if (p->p_chroot != NULL)
528af96af6cSreyk 		root = p->p_chroot;
529af96af6cSreyk 	else
530af96af6cSreyk 		root = pw->pw_dir;
531af96af6cSreyk 
532af96af6cSreyk 	if (chroot(root) == -1)
533566d2cadSbenno 		fatal("%s: chroot", __func__);
534af96af6cSreyk 	if (chdir("/") == -1)
535566d2cadSbenno 		fatal("%s: chdir(\"/\")", __func__);
536af96af6cSreyk 
537af96af6cSreyk 	privsep_process = p->p_id;
538af96af6cSreyk 
539af96af6cSreyk 	setproctitle("%s", p->p_title);
540af96af6cSreyk 
541af96af6cSreyk 	if (setgroups(1, &pw->pw_gid) ||
542af96af6cSreyk 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
543af96af6cSreyk 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
544566d2cadSbenno 		fatal("%s: cannot drop privileges", __func__);
545af96af6cSreyk 
546af96af6cSreyk 	event_init();
547af96af6cSreyk 
548af96af6cSreyk 	signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p);
549af96af6cSreyk 	signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p);
550af96af6cSreyk 	signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p);
551af96af6cSreyk 	signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p);
552af96af6cSreyk 	signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p);
553af96af6cSreyk 	signal_set(&ps->ps_evsigusr1, SIGUSR1, proc_sig_handler, p);
554af96af6cSreyk 
555af96af6cSreyk 	signal_add(&ps->ps_evsigint, NULL);
556af96af6cSreyk 	signal_add(&ps->ps_evsigterm, NULL);
557af96af6cSreyk 	signal_add(&ps->ps_evsigchld, NULL);
558af96af6cSreyk 	signal_add(&ps->ps_evsighup, NULL);
559af96af6cSreyk 	signal_add(&ps->ps_evsigpipe, NULL);
560af96af6cSreyk 	signal_add(&ps->ps_evsigusr1, NULL);
561af96af6cSreyk 
562bcc679a1Sreyk 	proc_setup(ps, procs, nproc);
563bcc679a1Sreyk 	proc_accept(ps, PROC_PARENT_SOCK_FILENO, PROC_PARENT, 0);
564af96af6cSreyk 	if (p->p_id == PROC_CONTROL && ps->ps_instance == 0) {
565af96af6cSreyk 		if (control_listen(&ps->ps_csock) == -1)
56687e1f53bSrzalamena 			fatalx("%s: control_listen", __func__);
567af96af6cSreyk 		TAILQ_FOREACH(rcs, &ps->ps_rcsocks, cs_entry)
568af96af6cSreyk 			if (control_listen(rcs) == -1)
56987e1f53bSrzalamena 				fatalx("%s: control_listen", __func__);
570af96af6cSreyk 	}
571af96af6cSreyk 
572bcc679a1Sreyk 	DPRINTF("%s: %s %d/%d, pid %d", __func__, p->p_title,
573bcc679a1Sreyk 	    ps->ps_instance + 1, ps->ps_instances[p->p_id], getpid());
574bcc679a1Sreyk 
575af96af6cSreyk 	if (run != NULL)
576af96af6cSreyk 		run(ps, p, arg);
577af96af6cSreyk 
578af96af6cSreyk 	event_dispatch();
579af96af6cSreyk 
580af96af6cSreyk 	proc_shutdown(p);
581af96af6cSreyk }
582af96af6cSreyk 
583af96af6cSreyk void
584af96af6cSreyk proc_dispatch(int fd, short event, void *arg)
585af96af6cSreyk {
586af96af6cSreyk 	struct imsgev		*iev = arg;
587af96af6cSreyk 	struct privsep_proc	*p = iev->proc;
588af96af6cSreyk 	struct privsep		*ps = p->p_ps;
589af96af6cSreyk 	struct imsgbuf		*ibuf;
590af96af6cSreyk 	struct imsg		 imsg;
591af96af6cSreyk 	ssize_t			 n;
592af96af6cSreyk 	int			 verbose;
593af96af6cSreyk 	const char		*title;
594bcc679a1Sreyk 	struct privsep_fd	 pf;
595af96af6cSreyk 
596af96af6cSreyk 	title = ps->ps_title[privsep_process];
597af96af6cSreyk 	ibuf = &iev->ibuf;
598af96af6cSreyk 
599af96af6cSreyk 	if (event & EV_READ) {
600d12ef5f3Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
601dd7efffeSclaudio 			fatal("%s: imsgbuf_read", __func__);
602af96af6cSreyk 		if (n == 0) {
603af96af6cSreyk 			/* this pipe is dead, so remove the event handler */
604af96af6cSreyk 			event_del(&iev->ev);
605af96af6cSreyk 			event_loopexit(NULL);
606af96af6cSreyk 			return;
607af96af6cSreyk 		}
608af96af6cSreyk 	}
609af96af6cSreyk 
610af96af6cSreyk 	if (event & EV_WRITE) {
611dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
612c1aa9554Sclaudio 			if (errno == EPIPE) {
613c1aa9554Sclaudio 				/* this pipe is dead, remove the handler */
61487e1f53bSrzalamena 				event_del(&iev->ev);
61587e1f53bSrzalamena 				event_loopexit(NULL);
61687e1f53bSrzalamena 				return;
61787e1f53bSrzalamena 			}
618dd7efffeSclaudio 			fatal("%s: imsgbuf_write", __func__);
619c1aa9554Sclaudio 		}
620af96af6cSreyk 	}
621af96af6cSreyk 
622af96af6cSreyk 	for (;;) {
623af96af6cSreyk 		if ((n = imsg_get(ibuf, &imsg)) == -1)
62487e1f53bSrzalamena 			fatal("%s: imsg_get", __func__);
625af96af6cSreyk 		if (n == 0)
626af96af6cSreyk 			break;
627af96af6cSreyk 
628af96af6cSreyk #if DEBUG > 1
62966094308Sreyk 		log_debug("%s: %s %d got imsg %d peerid %d from %s %d",
630af96af6cSreyk 		    __func__, title, ps->ps_instance + 1,
631bcc679a1Sreyk 		    imsg.hdr.type, imsg.hdr.peerid, p->p_title, imsg.hdr.pid);
632af96af6cSreyk #endif
633af96af6cSreyk 
634af96af6cSreyk 		/*
635af96af6cSreyk 		 * Check the message with the program callback
636af96af6cSreyk 		 */
637af96af6cSreyk 		if ((p->p_cb)(fd, p, &imsg) == 0) {
638af96af6cSreyk 			/* Message was handled by the callback, continue */
639af96af6cSreyk 			imsg_free(&imsg);
640af96af6cSreyk 			continue;
641af96af6cSreyk 		}
642af96af6cSreyk 
643af96af6cSreyk 		/*
644af96af6cSreyk 		 * Generic message handling
645af96af6cSreyk 		 */
646af96af6cSreyk 		switch (imsg.hdr.type) {
647af96af6cSreyk 		case IMSG_CTL_VERBOSE:
648af96af6cSreyk 			IMSG_SIZE_CHECK(&imsg, &verbose);
649af96af6cSreyk 			memcpy(&verbose, imsg.data, sizeof(verbose));
650871fc12cSreyk 			log_setverbose(verbose);
651af96af6cSreyk 			break;
652bcc679a1Sreyk 		case IMSG_CTL_PROCFD:
653bcc679a1Sreyk 			IMSG_SIZE_CHECK(&imsg, &pf);
654bcc679a1Sreyk 			memcpy(&pf, imsg.data, sizeof(pf));
65553027660Sclaudio 			proc_accept(ps, imsg_get_fd(&imsg), pf.pf_procid,
656bcc679a1Sreyk 			    pf.pf_instance);
657bcc679a1Sreyk 			break;
658af96af6cSreyk 		default:
65987e1f53bSrzalamena 			fatalx("%s: %s %d got invalid imsg %d peerid %d "
66066094308Sreyk 			    "from %s %d",
661af96af6cSreyk 			    __func__, title, ps->ps_instance + 1,
66266094308Sreyk 			    imsg.hdr.type, imsg.hdr.peerid,
663bcc679a1Sreyk 			    p->p_title, imsg.hdr.pid);
664af96af6cSreyk 		}
665af96af6cSreyk 		imsg_free(&imsg);
666af96af6cSreyk 	}
667af96af6cSreyk 	imsg_event_add(iev);
668af96af6cSreyk }
669af96af6cSreyk 
670af96af6cSreyk int
671af96af6cSreyk proc_dispatch_null(int fd, struct privsep_proc *p, struct imsg *imsg)
672af96af6cSreyk {
673af96af6cSreyk 	return (-1);
674af96af6cSreyk }
675af96af6cSreyk 
676af96af6cSreyk /*
677af96af6cSreyk  * imsg helper functions
678af96af6cSreyk  */
679af96af6cSreyk void
680af96af6cSreyk imsg_event_add(struct imsgev *iev)
681af96af6cSreyk {
682a246f7a0Sdv 	imsg_event_add2(iev, NULL);
683a246f7a0Sdv }
684a246f7a0Sdv 
685a246f7a0Sdv void
686a246f7a0Sdv imsg_event_add2(struct imsgev *iev, struct event_base *ev_base)
687a246f7a0Sdv {
688af96af6cSreyk 	if (iev->handler == NULL) {
689dd7efffeSclaudio 		imsgbuf_flush(&iev->ibuf);
690af96af6cSreyk 		return;
691af96af6cSreyk 	}
692af96af6cSreyk 
693af96af6cSreyk 	iev->events = EV_READ;
69431be28caSclaudio 	if (imsgbuf_queuelen(&iev->ibuf) > 0)
695af96af6cSreyk 		iev->events |= EV_WRITE;
696af96af6cSreyk 
697af96af6cSreyk 	event_del(&iev->ev);
698af96af6cSreyk 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
699a246f7a0Sdv 	if (ev_base != NULL)
700a246f7a0Sdv 		event_base_set(ev_base, &iev->ev);
701af96af6cSreyk 	event_add(&iev->ev, NULL);
702af96af6cSreyk }
703af96af6cSreyk 
704af96af6cSreyk int
705af96af6cSreyk imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
706af96af6cSreyk     pid_t pid, int fd, void *data, uint16_t datalen)
707af96af6cSreyk {
708a246f7a0Sdv 	return imsg_compose_event2(iev, type, peerid, pid, fd, data, datalen,
709a246f7a0Sdv 	    NULL);
710a246f7a0Sdv }
711a246f7a0Sdv 
712a246f7a0Sdv int
713a246f7a0Sdv imsg_compose_event2(struct imsgev *iev, uint16_t type, uint32_t peerid,
714a246f7a0Sdv     pid_t pid, int fd, void *data, uint16_t datalen, struct event_base *ev_base)
715a246f7a0Sdv {
716af96af6cSreyk 	int	ret;
717af96af6cSreyk 
718af96af6cSreyk 	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
719af96af6cSreyk 	    pid, fd, data, datalen)) == -1)
720af96af6cSreyk 		return (ret);
721a246f7a0Sdv 	imsg_event_add2(iev, ev_base);
722af96af6cSreyk 	return (ret);
723af96af6cSreyk }
724af96af6cSreyk 
725af96af6cSreyk int
726af96af6cSreyk imsg_composev_event(struct imsgev *iev, uint16_t type, uint32_t peerid,
727af96af6cSreyk     pid_t pid, int fd, const struct iovec *iov, int iovcnt)
728af96af6cSreyk {
729af96af6cSreyk 	int	ret;
730af96af6cSreyk 
731af96af6cSreyk 	if ((ret = imsg_composev(&iev->ibuf, type, peerid,
732af96af6cSreyk 	    pid, fd, iov, iovcnt)) == -1)
733af96af6cSreyk 		return (ret);
734af96af6cSreyk 	imsg_event_add(iev);
735af96af6cSreyk 	return (ret);
736af96af6cSreyk }
737af96af6cSreyk 
738af96af6cSreyk void
739af96af6cSreyk proc_range(struct privsep *ps, enum privsep_procid id, int *n, int *m)
740af96af6cSreyk {
741af96af6cSreyk 	if (*n == -1) {
742af96af6cSreyk 		/* Use a range of all target instances */
743af96af6cSreyk 		*n = 0;
744af96af6cSreyk 		*m = ps->ps_instances[id];
745af96af6cSreyk 	} else {
746af96af6cSreyk 		/* Use only a single slot of the specified peer process */
747af96af6cSreyk 		*m = *n + 1;
748af96af6cSreyk 	}
749af96af6cSreyk }
750af96af6cSreyk 
751af96af6cSreyk int
752af96af6cSreyk proc_compose_imsg(struct privsep *ps, enum privsep_procid id, int n,
7535c759b1bSreyk     uint16_t type, uint32_t peerid, int fd, void *data, uint16_t datalen)
754af96af6cSreyk {
755af96af6cSreyk 	int	 m;
756af96af6cSreyk 
757af96af6cSreyk 	proc_range(ps, id, &n, &m);
758af96af6cSreyk 	for (; n < m; n++) {
759af96af6cSreyk 		if (imsg_compose_event(&ps->ps_ievs[id][n],
760bcc679a1Sreyk 		    type, peerid, ps->ps_instance + 1, fd, data, datalen) == -1)
761af96af6cSreyk 			return (-1);
762af96af6cSreyk 	}
763af96af6cSreyk 
764af96af6cSreyk 	return (0);
765af96af6cSreyk }
766af96af6cSreyk 
767af96af6cSreyk int
76841b2bea6Sreyk proc_compose(struct privsep *ps, enum privsep_procid id,
76941b2bea6Sreyk     uint16_t type, void *data, uint16_t datalen)
77041b2bea6Sreyk {
77141b2bea6Sreyk 	return (proc_compose_imsg(ps, id, -1, type, -1, -1, data, datalen));
77241b2bea6Sreyk }
77341b2bea6Sreyk 
77441b2bea6Sreyk int
775af96af6cSreyk proc_composev_imsg(struct privsep *ps, enum privsep_procid id, int n,
7765c759b1bSreyk     uint16_t type, uint32_t peerid, int fd, const struct iovec *iov, int iovcnt)
777af96af6cSreyk {
778af96af6cSreyk 	int	 m;
779af96af6cSreyk 
780af96af6cSreyk 	proc_range(ps, id, &n, &m);
781af96af6cSreyk 	for (; n < m; n++)
782af96af6cSreyk 		if (imsg_composev_event(&ps->ps_ievs[id][n],
783bcc679a1Sreyk 		    type, peerid, ps->ps_instance + 1, fd, iov, iovcnt) == -1)
784af96af6cSreyk 			return (-1);
785af96af6cSreyk 
786af96af6cSreyk 	return (0);
787af96af6cSreyk }
788af96af6cSreyk 
789af96af6cSreyk int
79041b2bea6Sreyk proc_composev(struct privsep *ps, enum privsep_procid id,
79141b2bea6Sreyk     uint16_t type, const struct iovec *iov, int iovcnt)
79241b2bea6Sreyk {
79341b2bea6Sreyk 	return (proc_composev_imsg(ps, id, -1, type, -1, -1, iov, iovcnt));
79441b2bea6Sreyk }
79541b2bea6Sreyk 
79641b2bea6Sreyk int
797af96af6cSreyk proc_forward_imsg(struct privsep *ps, struct imsg *imsg,
798af96af6cSreyk     enum privsep_procid id, int n)
799af96af6cSreyk {
800af96af6cSreyk 	return (proc_compose_imsg(ps, id, n, imsg->hdr.type,
80153027660Sclaudio 	    imsg->hdr.peerid, imsg_get_fd(imsg), imsg->data,
80253027660Sclaudio 	    IMSG_DATA_SIZE(imsg)));
803af96af6cSreyk }
804af96af6cSreyk 
805af96af6cSreyk struct imsgbuf *
806af96af6cSreyk proc_ibuf(struct privsep *ps, enum privsep_procid id, int n)
807af96af6cSreyk {
808af96af6cSreyk 	int	 m;
809af96af6cSreyk 
810af96af6cSreyk 	proc_range(ps, id, &n, &m);
811af96af6cSreyk 	return (&ps->ps_ievs[id][n].ibuf);
812af96af6cSreyk }
813af96af6cSreyk 
814af96af6cSreyk struct imsgev *
815af96af6cSreyk proc_iev(struct privsep *ps, enum privsep_procid id, int n)
816af96af6cSreyk {
817af96af6cSreyk 	int	 m;
818af96af6cSreyk 
819af96af6cSreyk 	proc_range(ps, id, &n, &m);
820af96af6cSreyk 	return (&ps->ps_ievs[id][n]);
821af96af6cSreyk }
822d2491206Srzalamena 
823d2491206Srzalamena /* This function should only be called with care as it breaks async I/O */
824d2491206Srzalamena int
825d2491206Srzalamena proc_flush_imsg(struct privsep *ps, enum privsep_procid id, int n)
826d2491206Srzalamena {
827d2491206Srzalamena 	struct imsgbuf	*ibuf;
828d2491206Srzalamena 	int		 m, ret = 0;
829d2491206Srzalamena 
830d2491206Srzalamena 	proc_range(ps, id, &n, &m);
831d2491206Srzalamena 	for (; n < m; n++) {
832d2491206Srzalamena 		if ((ibuf = proc_ibuf(ps, id, n)) == NULL)
833d2491206Srzalamena 			return (-1);
834dd7efffeSclaudio 		if ((ret = imsgbuf_flush(ibuf)) == -1)
835d2491206Srzalamena 			break;
836d2491206Srzalamena 		imsg_event_add(&ps->ps_ievs[id][n]);
837d2491206Srzalamena 	}
838d2491206Srzalamena 
839d2491206Srzalamena 	return (ret);
840d2491206Srzalamena }
841