xref: /freebsd/usr.sbin/bsdinstall/runconsoles/child.c (revision a2464ee12761660f50d0b6f59f233949ebcacc87)
1*a2464ee1SJessica Clarke /*-
2*a2464ee1SJessica Clarke  * SPDX-License-Identifier: BSD-2-Clause
3*a2464ee1SJessica Clarke  *
4*a2464ee1SJessica Clarke  * Copyright (c) 2022 Jessica Clarke <jrtc27@FreeBSD.org>
5*a2464ee1SJessica Clarke  *
6*a2464ee1SJessica Clarke  * Redistribution and use in source and binary forms, with or without
7*a2464ee1SJessica Clarke  * modification, are permitted provided that the following conditions
8*a2464ee1SJessica Clarke  * are met:
9*a2464ee1SJessica Clarke  * 1. Redistributions of source code must retain the above copyright
10*a2464ee1SJessica Clarke  *    notice, this list of conditions and the following disclaimer.
11*a2464ee1SJessica Clarke  * 2. Redistributions in binary form must reproduce the above copyright
12*a2464ee1SJessica Clarke  *    notice, this list of conditions and the following disclaimer in the
13*a2464ee1SJessica Clarke  *    documentation and/or other materials provided with the distribution.
14*a2464ee1SJessica Clarke  *
15*a2464ee1SJessica Clarke  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*a2464ee1SJessica Clarke  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*a2464ee1SJessica Clarke  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*a2464ee1SJessica Clarke  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*a2464ee1SJessica Clarke  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*a2464ee1SJessica Clarke  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*a2464ee1SJessica Clarke  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*a2464ee1SJessica Clarke  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*a2464ee1SJessica Clarke  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*a2464ee1SJessica Clarke  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*a2464ee1SJessica Clarke  * SUCH DAMAGE.
26*a2464ee1SJessica Clarke  */
27*a2464ee1SJessica Clarke 
28*a2464ee1SJessica Clarke #include <sys/param.h>
29*a2464ee1SJessica Clarke #include <sys/errno.h>
30*a2464ee1SJessica Clarke #include <sys/procctl.h>
31*a2464ee1SJessica Clarke #include <sys/queue.h>
32*a2464ee1SJessica Clarke #include <sys/resource.h>
33*a2464ee1SJessica Clarke #include <sys/sysctl.h>
34*a2464ee1SJessica Clarke #include <sys/wait.h>
35*a2464ee1SJessica Clarke 
36*a2464ee1SJessica Clarke #include <err.h>
37*a2464ee1SJessica Clarke #include <errno.h>
38*a2464ee1SJessica Clarke #include <fcntl.h>
39*a2464ee1SJessica Clarke #include <signal.h>
40*a2464ee1SJessica Clarke #include <stdarg.h>
41*a2464ee1SJessica Clarke #include <stdbool.h>
42*a2464ee1SJessica Clarke #include <stdio.h>
43*a2464ee1SJessica Clarke #include <stdlib.h>
44*a2464ee1SJessica Clarke #include <string.h>
45*a2464ee1SJessica Clarke #include <sysexits.h>
46*a2464ee1SJessica Clarke #include <termios.h>
47*a2464ee1SJessica Clarke #include <ttyent.h>
48*a2464ee1SJessica Clarke #include <unistd.h>
49*a2464ee1SJessica Clarke 
50*a2464ee1SJessica Clarke #include "common.h"
51*a2464ee1SJessica Clarke #include "child.h"
52*a2464ee1SJessica Clarke 
53*a2464ee1SJessica Clarke /* -1: not started, 0: reaped */
54*a2464ee1SJessica Clarke static volatile pid_t grandchild_pid = -1;
55*a2464ee1SJessica Clarke static volatile int grandchild_status;
56*a2464ee1SJessica Clarke 
57*a2464ee1SJessica Clarke static struct pipe_barrier wait_grandchild_barrier;
58*a2464ee1SJessica Clarke static struct pipe_barrier wait_all_descendants_barrier;
59*a2464ee1SJessica Clarke 
60*a2464ee1SJessica Clarke static void
kill_descendants(int sig)61*a2464ee1SJessica Clarke kill_descendants(int sig)
62*a2464ee1SJessica Clarke {
63*a2464ee1SJessica Clarke 	struct procctl_reaper_kill rk;
64*a2464ee1SJessica Clarke 
65*a2464ee1SJessica Clarke 	rk.rk_sig = sig;
66*a2464ee1SJessica Clarke 	rk.rk_flags = 0;
67*a2464ee1SJessica Clarke 	procctl(P_PID, getpid(), PROC_REAP_KILL, &rk);
68*a2464ee1SJessica Clarke }
69*a2464ee1SJessica Clarke 
70*a2464ee1SJessica Clarke static void
sigalrm_handler(int sig __unused)71*a2464ee1SJessica Clarke sigalrm_handler(int sig __unused)
72*a2464ee1SJessica Clarke {
73*a2464ee1SJessica Clarke 	int saved_errno;
74*a2464ee1SJessica Clarke 
75*a2464ee1SJessica Clarke 	saved_errno = errno;
76*a2464ee1SJessica Clarke 	kill_descendants(SIGKILL);
77*a2464ee1SJessica Clarke 	errno = saved_errno;
78*a2464ee1SJessica Clarke }
79*a2464ee1SJessica Clarke 
80*a2464ee1SJessica Clarke static void
wait_all_descendants(void)81*a2464ee1SJessica Clarke wait_all_descendants(void)
82*a2464ee1SJessica Clarke {
83*a2464ee1SJessica Clarke 	sigset_t set, oset;
84*a2464ee1SJessica Clarke 
85*a2464ee1SJessica Clarke 	err_set_exit(NULL);
86*a2464ee1SJessica Clarke 
87*a2464ee1SJessica Clarke 	/*
88*a2464ee1SJessica Clarke 	 * We may be run in a context where SIGALRM is blocked; temporarily
89*a2464ee1SJessica Clarke 	 * unblock so we can SIGKILL. Similarly, SIGCHLD may be blocked, but if
90*a2464ee1SJessica Clarke 	 * we're waiting on the pipe we need to make sure it's not.
91*a2464ee1SJessica Clarke 	 */
92*a2464ee1SJessica Clarke 	sigemptyset(&set);
93*a2464ee1SJessica Clarke 	sigaddset(&set, SIGALRM);
94*a2464ee1SJessica Clarke 	sigaddset(&set, SIGCHLD);
95*a2464ee1SJessica Clarke 	sigprocmask(SIG_UNBLOCK, &set, &oset);
96*a2464ee1SJessica Clarke 	alarm(KILL_TIMEOUT);
97*a2464ee1SJessica Clarke 	pipe_barrier_wait(&wait_all_descendants_barrier);
98*a2464ee1SJessica Clarke 	alarm(0);
99*a2464ee1SJessica Clarke 	sigprocmask(SIG_SETMASK, &oset, NULL);
100*a2464ee1SJessica Clarke }
101*a2464ee1SJessica Clarke 
102*a2464ee1SJessica Clarke static void
sigchld_handler(int sig __unused)103*a2464ee1SJessica Clarke sigchld_handler(int sig __unused)
104*a2464ee1SJessica Clarke {
105*a2464ee1SJessica Clarke 	int status, saved_errno;
106*a2464ee1SJessica Clarke 	pid_t pid;
107*a2464ee1SJessica Clarke 
108*a2464ee1SJessica Clarke 	saved_errno = errno;
109*a2464ee1SJessica Clarke 
110*a2464ee1SJessica Clarke 	while ((void)(pid = waitpid(-1, &status, WNOHANG)),
111*a2464ee1SJessica Clarke 	    pid != -1 && pid != 0) {
112*a2464ee1SJessica Clarke 		/* NB: No need to check grandchild_pid due to the pid checks */
113*a2464ee1SJessica Clarke 		if (pid == grandchild_pid) {
114*a2464ee1SJessica Clarke 			grandchild_status = status;
115*a2464ee1SJessica Clarke 			grandchild_pid = 0;
116*a2464ee1SJessica Clarke 			pipe_barrier_ready(&wait_grandchild_barrier);
117*a2464ee1SJessica Clarke 		}
118*a2464ee1SJessica Clarke 	}
119*a2464ee1SJessica Clarke 
120*a2464ee1SJessica Clarke 	/*
121*a2464ee1SJessica Clarke 	 * Another process calling kill(..., SIGCHLD) could cause us to get
122*a2464ee1SJessica Clarke 	 * here before we've spawned the grandchild; only ready when we have no
123*a2464ee1SJessica Clarke 	 * children if the grandchild has been reaped.
124*a2464ee1SJessica Clarke 	 */
125*a2464ee1SJessica Clarke 	if (pid == -1 && errno == ECHILD && grandchild_pid == 0)
126*a2464ee1SJessica Clarke 		pipe_barrier_ready(&wait_all_descendants_barrier);
127*a2464ee1SJessica Clarke 
128*a2464ee1SJessica Clarke 	errno = saved_errno;
129*a2464ee1SJessica Clarke }
130*a2464ee1SJessica Clarke 
131*a2464ee1SJessica Clarke static void
exit_signal_handler(int sig)132*a2464ee1SJessica Clarke exit_signal_handler(int sig)
133*a2464ee1SJessica Clarke {
134*a2464ee1SJessica Clarke 	int saved_errno;
135*a2464ee1SJessica Clarke 
136*a2464ee1SJessica Clarke 	/*
137*a2464ee1SJessica Clarke 	 * If we get killed before we've started the grandchild then just exit
138*a2464ee1SJessica Clarke 	 * with that signal, otherwise kill all our descendants with that
139*a2464ee1SJessica Clarke 	 * signal and let the main program pick up the grandchild's death.
140*a2464ee1SJessica Clarke 	 */
141*a2464ee1SJessica Clarke 	if (grandchild_pid == -1) {
142*a2464ee1SJessica Clarke 		reproduce_signal_death(sig);
143*a2464ee1SJessica Clarke 		exit(EXIT_FAILURE);
144*a2464ee1SJessica Clarke 	}
145*a2464ee1SJessica Clarke 
146*a2464ee1SJessica Clarke 	saved_errno = errno;
147*a2464ee1SJessica Clarke 	kill_descendants(sig);
148*a2464ee1SJessica Clarke 	errno = saved_errno;
149*a2464ee1SJessica Clarke }
150*a2464ee1SJessica Clarke 
151*a2464ee1SJessica Clarke static void
kill_wait_all_descendants(int sig)152*a2464ee1SJessica Clarke kill_wait_all_descendants(int sig)
153*a2464ee1SJessica Clarke {
154*a2464ee1SJessica Clarke 	kill_descendants(sig);
155*a2464ee1SJessica Clarke 	wait_all_descendants();
156*a2464ee1SJessica Clarke }
157*a2464ee1SJessica Clarke 
158*a2464ee1SJessica Clarke static void
kill_wait_all_descendants_err_exit(int eval __unused)159*a2464ee1SJessica Clarke kill_wait_all_descendants_err_exit(int eval __unused)
160*a2464ee1SJessica Clarke {
161*a2464ee1SJessica Clarke 	kill_wait_all_descendants(SIGTERM);
162*a2464ee1SJessica Clarke }
163*a2464ee1SJessica Clarke 
164*a2464ee1SJessica Clarke static void __dead2
grandchild_run(const char ** argv,const sigset_t * oset)165*a2464ee1SJessica Clarke grandchild_run(const char **argv, const sigset_t *oset)
166*a2464ee1SJessica Clarke {
167*a2464ee1SJessica Clarke 	sig_t orig;
168*a2464ee1SJessica Clarke 
169*a2464ee1SJessica Clarke 	/* Restore signals */
170*a2464ee1SJessica Clarke 	orig = signal(SIGALRM, SIG_DFL);
171*a2464ee1SJessica Clarke 	if (orig == SIG_ERR)
172*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not restore SIGALRM");
173*a2464ee1SJessica Clarke 	orig = signal(SIGCHLD, SIG_DFL);
174*a2464ee1SJessica Clarke 	if (orig == SIG_ERR)
175*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not restore SIGCHLD");
176*a2464ee1SJessica Clarke 	orig = signal(SIGTERM, SIG_DFL);
177*a2464ee1SJessica Clarke 	if (orig == SIG_ERR)
178*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not restore SIGTERM");
179*a2464ee1SJessica Clarke 	orig = signal(SIGINT, SIG_DFL);
180*a2464ee1SJessica Clarke 	if (orig == SIG_ERR)
181*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not restore SIGINT");
182*a2464ee1SJessica Clarke 	orig = signal(SIGQUIT, SIG_DFL);
183*a2464ee1SJessica Clarke 	if (orig == SIG_ERR)
184*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not restore SIGQUIT");
185*a2464ee1SJessica Clarke 	orig = signal(SIGPIPE, SIG_DFL);
186*a2464ee1SJessica Clarke 	if (orig == SIG_ERR)
187*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not restore SIGPIPE");
188*a2464ee1SJessica Clarke 	orig = signal(SIGTTOU, SIG_DFL);
189*a2464ee1SJessica Clarke 	if (orig == SIG_ERR)
190*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not restore SIGTTOU");
191*a2464ee1SJessica Clarke 
192*a2464ee1SJessica Clarke 	/* Now safe to unmask signals */
193*a2464ee1SJessica Clarke 	sigprocmask(SIG_SETMASK, oset, NULL);
194*a2464ee1SJessica Clarke 
195*a2464ee1SJessica Clarke 	/* Only run with stdin/stdout/stderr */
196*a2464ee1SJessica Clarke 	closefrom(3);
197*a2464ee1SJessica Clarke 
198*a2464ee1SJessica Clarke 	/* Ready to execute the requested program */
199*a2464ee1SJessica Clarke 	execvp(argv[0], __DECONST(char * const *, argv));
200*a2464ee1SJessica Clarke 	err(EX_OSERR, "cannot execvp %s", argv[0]);
201*a2464ee1SJessica Clarke }
202*a2464ee1SJessica Clarke 
203*a2464ee1SJessica Clarke static int
wait_grandchild_descendants(void)204*a2464ee1SJessica Clarke wait_grandchild_descendants(void)
205*a2464ee1SJessica Clarke {
206*a2464ee1SJessica Clarke 	pipe_barrier_wait(&wait_grandchild_barrier);
207*a2464ee1SJessica Clarke 
208*a2464ee1SJessica Clarke 	/*
209*a2464ee1SJessica Clarke 	 * Once the grandchild itself has exited, kill any lingering
210*a2464ee1SJessica Clarke 	 * descendants and wait until we've reaped them all.
211*a2464ee1SJessica Clarke 	 */
212*a2464ee1SJessica Clarke 	kill_wait_all_descendants(SIGTERM);
213*a2464ee1SJessica Clarke 
214*a2464ee1SJessica Clarke 	if (grandchild_pid != 0)
215*a2464ee1SJessica Clarke 		errx(EX_SOFTWARE, "failed to reap grandchild");
216*a2464ee1SJessica Clarke 
217*a2464ee1SJessica Clarke 	return (grandchild_status);
218*a2464ee1SJessica Clarke }
219*a2464ee1SJessica Clarke 
220*a2464ee1SJessica Clarke void
child_leader_run(const char * name,int fd,bool new_session,const char ** argv,const sigset_t * oset,struct pipe_barrier * start_children_barrier)221*a2464ee1SJessica Clarke child_leader_run(const char *name, int fd, bool new_session, const char **argv,
222*a2464ee1SJessica Clarke     const sigset_t *oset, struct pipe_barrier *start_children_barrier)
223*a2464ee1SJessica Clarke {
224*a2464ee1SJessica Clarke 	struct pipe_barrier start_grandchild_barrier;
225*a2464ee1SJessica Clarke 	pid_t pid, sid, pgid;
226*a2464ee1SJessica Clarke 	struct sigaction sa;
227*a2464ee1SJessica Clarke 	int error, status;
228*a2464ee1SJessica Clarke 	sigset_t set;
229*a2464ee1SJessica Clarke 
230*a2464ee1SJessica Clarke 	setproctitle("%s [%s]", getprogname(), name);
231*a2464ee1SJessica Clarke 
232*a2464ee1SJessica Clarke 	error = procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL);
233*a2464ee1SJessica Clarke 	if (error != 0)
234*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not acquire reaper status");
235*a2464ee1SJessica Clarke 
236*a2464ee1SJessica Clarke 	/*
237*a2464ee1SJessica Clarke 	 * Set up our own signal handlers for everything the parent overrides
238*a2464ee1SJessica Clarke 	 * other than SIGPIPE and SIGTTOU which we leave as ignored, since we
239*a2464ee1SJessica Clarke 	 * also use pipe-based synchronisation and want to be able to print
240*a2464ee1SJessica Clarke 	 * errors.
241*a2464ee1SJessica Clarke 	 */
242*a2464ee1SJessica Clarke 	sa.sa_flags = SA_RESTART;
243*a2464ee1SJessica Clarke 	sa.sa_handler = sigchld_handler;
244*a2464ee1SJessica Clarke 	sigfillset(&sa.sa_mask);
245*a2464ee1SJessica Clarke 	error = sigaction(SIGCHLD, &sa, NULL);
246*a2464ee1SJessica Clarke 	if (error != 0)
247*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not enable SIGCHLD handler");
248*a2464ee1SJessica Clarke 	sa.sa_handler = sigalrm_handler;
249*a2464ee1SJessica Clarke 	error = sigaction(SIGALRM, &sa, NULL);
250*a2464ee1SJessica Clarke 	if (error != 0)
251*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not enable SIGALRM handler");
252*a2464ee1SJessica Clarke 	sa.sa_handler = exit_signal_handler;
253*a2464ee1SJessica Clarke 	error = sigaction(SIGTERM, &sa, NULL);
254*a2464ee1SJessica Clarke 	if (error != 0)
255*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not enable SIGTERM handler");
256*a2464ee1SJessica Clarke 	error = sigaction(SIGINT, &sa, NULL);
257*a2464ee1SJessica Clarke 	if (error != 0)
258*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not enable SIGINT handler");
259*a2464ee1SJessica Clarke 	error = sigaction(SIGQUIT, &sa, NULL);
260*a2464ee1SJessica Clarke 	if (error != 0)
261*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not enable SIGQUIT handler");
262*a2464ee1SJessica Clarke 
263*a2464ee1SJessica Clarke 	/*
264*a2464ee1SJessica Clarke 	 * Now safe to unmask signals. Note that creating the barriers used by
265*a2464ee1SJessica Clarke 	 * the SIGCHLD handler with signals unmasked is safe since they won't
266*a2464ee1SJessica Clarke 	 * be used if the grandchild hasn't been forked (and reaped), which
267*a2464ee1SJessica Clarke 	 * comes later.
268*a2464ee1SJessica Clarke 	 */
269*a2464ee1SJessica Clarke 	sigprocmask(SIG_SETMASK, oset, NULL);
270*a2464ee1SJessica Clarke 
271*a2464ee1SJessica Clarke 	error = pipe_barrier_init(&start_grandchild_barrier);
272*a2464ee1SJessica Clarke 	if (error != 0)
273*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not create start grandchild barrier");
274*a2464ee1SJessica Clarke 
275*a2464ee1SJessica Clarke 	error = pipe_barrier_init(&wait_grandchild_barrier);
276*a2464ee1SJessica Clarke 	if (error != 0)
277*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not create wait grandchild barrier");
278*a2464ee1SJessica Clarke 
279*a2464ee1SJessica Clarke 	error = pipe_barrier_init(&wait_all_descendants_barrier);
280*a2464ee1SJessica Clarke 	if (error != 0)
281*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not create wait all descendants barrier");
282*a2464ee1SJessica Clarke 
283*a2464ee1SJessica Clarke 	/*
284*a2464ee1SJessica Clarke 	 * Create a new session if this is on a different terminal to
285*a2464ee1SJessica Clarke 	 * the current one, otherwise just create a new process group to keep
286*a2464ee1SJessica Clarke 	 * things as similar as possible between the two cases.
287*a2464ee1SJessica Clarke 	 */
288*a2464ee1SJessica Clarke 	if (new_session) {
289*a2464ee1SJessica Clarke 		sid = setsid();
290*a2464ee1SJessica Clarke 		pgid = sid;
291*a2464ee1SJessica Clarke 		if (sid == -1)
292*a2464ee1SJessica Clarke 			err(EX_OSERR, "could not create session");
293*a2464ee1SJessica Clarke 	} else {
294*a2464ee1SJessica Clarke 		sid = -1;
295*a2464ee1SJessica Clarke 		pgid = getpid();
296*a2464ee1SJessica Clarke 		error = setpgid(0, pgid);
297*a2464ee1SJessica Clarke 		if (error == -1)
298*a2464ee1SJessica Clarke 			err(EX_OSERR, "could not create process group");
299*a2464ee1SJessica Clarke 	}
300*a2464ee1SJessica Clarke 
301*a2464ee1SJessica Clarke 	/* Wait until parent is ready for us to start */
302*a2464ee1SJessica Clarke 	pipe_barrier_destroy_ready(start_children_barrier);
303*a2464ee1SJessica Clarke 	pipe_barrier_wait(start_children_barrier);
304*a2464ee1SJessica Clarke 
305*a2464ee1SJessica Clarke 	/*
306*a2464ee1SJessica Clarke 	 * Use the console for stdin/stdout/stderr.
307*a2464ee1SJessica Clarke 	 *
308*a2464ee1SJessica Clarke 	 * NB: dup2(2) is a no-op if the two fds are equal, and the call to
309*a2464ee1SJessica Clarke 	 * closefrom(2) later in the grandchild will close the fd if it isn't
310*a2464ee1SJessica Clarke 	 * one of stdin/stdout/stderr already. This means we do not need to
311*a2464ee1SJessica Clarke 	 * handle that special case differently.
312*a2464ee1SJessica Clarke 	 */
313*a2464ee1SJessica Clarke 	error = dup2(fd, STDIN_FILENO);
314*a2464ee1SJessica Clarke 	if (error == -1)
315*a2464ee1SJessica Clarke 		err(EX_IOERR, "could not dup %s to stdin", name);
316*a2464ee1SJessica Clarke 	error = dup2(fd, STDOUT_FILENO);
317*a2464ee1SJessica Clarke 	if (error == -1)
318*a2464ee1SJessica Clarke 		err(EX_IOERR, "could not dup %s to stdout", name);
319*a2464ee1SJessica Clarke 	error = dup2(fd, STDERR_FILENO);
320*a2464ee1SJessica Clarke 	if (error == -1)
321*a2464ee1SJessica Clarke 		err(EX_IOERR, "could not dup %s to stderr", name);
322*a2464ee1SJessica Clarke 
323*a2464ee1SJessica Clarke 	/*
324*a2464ee1SJessica Clarke 	 * If we created a new session, make the console our controlling
325*a2464ee1SJessica Clarke 	 * terminal. Either way, also make this the foreground process group.
326*a2464ee1SJessica Clarke 	 */
327*a2464ee1SJessica Clarke 	if (new_session) {
328*a2464ee1SJessica Clarke 		error = tcsetsid(STDIN_FILENO, sid);
329*a2464ee1SJessica Clarke 		if (error != 0)
330*a2464ee1SJessica Clarke 			err(EX_IOERR, "could not set session for %s", name);
331*a2464ee1SJessica Clarke 	} else {
332*a2464ee1SJessica Clarke 		error = tcsetpgrp(STDIN_FILENO, pgid);
333*a2464ee1SJessica Clarke 		if (error != 0)
334*a2464ee1SJessica Clarke 			err(EX_IOERR, "could not set process group for %s",
335*a2464ee1SJessica Clarke 			    name);
336*a2464ee1SJessica Clarke 	}
337*a2464ee1SJessica Clarke 
338*a2464ee1SJessica Clarke 	/*
339*a2464ee1SJessica Clarke 	 * Temporarily block signals again; forking, setting grandchild_pid and
340*a2464ee1SJessica Clarke 	 * calling err_set_exit need to all be atomic for similar reasons as
341*a2464ee1SJessica Clarke 	 * the parent when forking us.
342*a2464ee1SJessica Clarke 	 */
343*a2464ee1SJessica Clarke 	sigfillset(&set);
344*a2464ee1SJessica Clarke 	sigprocmask(SIG_BLOCK, &set, NULL);
345*a2464ee1SJessica Clarke 	pid = fork();
346*a2464ee1SJessica Clarke 	if (pid == -1)
347*a2464ee1SJessica Clarke 		err(EX_OSERR, "could not fork");
348*a2464ee1SJessica Clarke 
349*a2464ee1SJessica Clarke 	if (pid == 0) {
350*a2464ee1SJessica Clarke 		/*
351*a2464ee1SJessica Clarke 		 * We need to destroy the ready ends so we don't block these
352*a2464ee1SJessica Clarke 		 * child leader-only self-pipes, and might as well destroy the
353*a2464ee1SJessica Clarke 		 * wait ends too given we're not going to use them.
354*a2464ee1SJessica Clarke 		 */
355*a2464ee1SJessica Clarke 		pipe_barrier_destroy(&wait_grandchild_barrier);
356*a2464ee1SJessica Clarke 		pipe_barrier_destroy(&wait_all_descendants_barrier);
357*a2464ee1SJessica Clarke 
358*a2464ee1SJessica Clarke 		/* Wait until the parent has put us in a new process group */
359*a2464ee1SJessica Clarke 		pipe_barrier_destroy_ready(&start_grandchild_barrier);
360*a2464ee1SJessica Clarke 		pipe_barrier_wait(&start_grandchild_barrier);
361*a2464ee1SJessica Clarke 		grandchild_run(argv, oset);
362*a2464ee1SJessica Clarke 	}
363*a2464ee1SJessica Clarke 
364*a2464ee1SJessica Clarke 	grandchild_pid = pid;
365*a2464ee1SJessica Clarke 
366*a2464ee1SJessica Clarke 	/*
367*a2464ee1SJessica Clarke 	 * Now the grandchild exists make sure to clean it up, and any of its
368*a2464ee1SJessica Clarke 	 * descendants, on exit.
369*a2464ee1SJessica Clarke 	 */
370*a2464ee1SJessica Clarke 	err_set_exit(kill_wait_all_descendants_err_exit);
371*a2464ee1SJessica Clarke 
372*a2464ee1SJessica Clarke 	sigprocmask(SIG_SETMASK, oset, NULL);
373*a2464ee1SJessica Clarke 
374*a2464ee1SJessica Clarke 	/* Start the grandchild and wait for it and its descendants to exit */
375*a2464ee1SJessica Clarke 	pipe_barrier_ready(&start_grandchild_barrier);
376*a2464ee1SJessica Clarke 
377*a2464ee1SJessica Clarke 	status = wait_grandchild_descendants();
378*a2464ee1SJessica Clarke 
379*a2464ee1SJessica Clarke 	if (WIFSIGNALED(status))
380*a2464ee1SJessica Clarke 		reproduce_signal_death(WTERMSIG(status));
381*a2464ee1SJessica Clarke 
382*a2464ee1SJessica Clarke 	if (WIFEXITED(status))
383*a2464ee1SJessica Clarke 		exit(WEXITSTATUS(status));
384*a2464ee1SJessica Clarke 
385*a2464ee1SJessica Clarke 	exit(EXIT_FAILURE);
386*a2464ee1SJessica Clarke }
387