1*bdce9d03Scheloha /* $OpenBSD: init.c,v 1.72 2022/09/10 00:49:47 cheloha Exp $ */
24b826ba8Sderaadt /* $NetBSD: init.c,v 1.22 1996/05/15 23:29:33 jtc Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*-
5df930be7Sderaadt * Copyright (c) 1991, 1993
6df930be7Sderaadt * The Regents of the University of California. All rights reserved.
7df930be7Sderaadt *
8df930be7Sderaadt * This code is derived from software contributed to Berkeley by
9df930be7Sderaadt * Donn Seeley at Berkeley Software Design, Inc.
10df930be7Sderaadt *
11df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
12df930be7Sderaadt * modification, are permitted provided that the following conditions
13df930be7Sderaadt * are met:
14df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
15df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
16df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
17df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
18df930be7Sderaadt * documentation and/or other materials provided with the distribution.
191ef0d710Smillert * 3. Neither the name of the University nor the names of its contributors
20df930be7Sderaadt * may be used to endorse or promote products derived from this software
21df930be7Sderaadt * without specific prior written permission.
22df930be7Sderaadt *
23df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33df930be7Sderaadt * SUCH DAMAGE.
34df930be7Sderaadt */
35df930be7Sderaadt
36b9fc9a72Sderaadt #include <sys/types.h>
37ab091da3Sderaadt #include <sys/reboot.h>
38ae0936ccSguenther #include <sys/sysctl.h>
39ae0936ccSguenther #include <sys/time.h>
40ce842bbcSnicm #include <sys/tree.h>
41ae0936ccSguenther #include <sys/wait.h>
421c794bc1Shalex #include <machine/cpu.h>
43df930be7Sderaadt
44f290c528Sdcoppa #include <err.h>
45df930be7Sderaadt #include <errno.h>
46df930be7Sderaadt #include <fcntl.h>
47ce842bbcSnicm #include <limits.h>
48bd61d3e8Smillert #include <login_cap.h>
49df930be7Sderaadt #include <signal.h>
50e7beb4a7Smillert #include <stdarg.h>
51df930be7Sderaadt #include <stdio.h>
52df930be7Sderaadt #include <stdlib.h>
53df930be7Sderaadt #include <string.h>
54df930be7Sderaadt #include <syslog.h>
55df930be7Sderaadt #include <time.h>
56df930be7Sderaadt #include <ttyent.h>
57df930be7Sderaadt #include <unistd.h>
584b826ba8Sderaadt #include <util.h>
59df930be7Sderaadt
60df930be7Sderaadt #ifdef SECURE
61df930be7Sderaadt #include <pwd.h>
62c43387b9Sgsoares #include <readpassphrase.h>
63df930be7Sderaadt #endif
64df930be7Sderaadt
65df930be7Sderaadt #include "pathnames.h"
66df930be7Sderaadt
67df930be7Sderaadt /*
68df930be7Sderaadt * Sleep times; used to prevent thrashing.
69df930be7Sderaadt */
70df930be7Sderaadt #define GETTY_SPACING 5 /* N secs minimum getty spacing */
71df930be7Sderaadt #define GETTY_SLEEP 30 /* sleep N secs after spacing problem */
72df930be7Sderaadt #define WINDOW_WAIT 3 /* wait N secs after starting window */
73df930be7Sderaadt #define STALL_TIMEOUT 30 /* wait N secs after warning */
74df930be7Sderaadt #define DEATH_WATCH 10 /* wait N secs for procs to die */
75df930be7Sderaadt
76fed231abSmillert /*
77fed231abSmillert * User-based resource limits.
78fed231abSmillert */
79fed231abSmillert #define RESOURCE_RC "daemon"
80fed231abSmillert #define RESOURCE_WINDOW "default"
81fed231abSmillert #define RESOURCE_GETTY "default"
82fed231abSmillert
8323d2d19cSmillert #ifndef DEFAULT_STATE
8423d2d19cSmillert #define DEFAULT_STATE runcom
8523d2d19cSmillert #endif
8623d2d19cSmillert
87c72b5b24Smillert void handle(sig_t, ...);
88c72b5b24Smillert void delset(sigset_t *, ...);
89df930be7Sderaadt
90c72b5b24Smillert void stall(char *, ...);
91c72b5b24Smillert void warning(char *, ...);
92c72b5b24Smillert void emergency(char *, ...);
93c72b5b24Smillert void disaster(int);
94df930be7Sderaadt
955085bfb6Smillert typedef enum {
965085bfb6Smillert invalid_state,
975085bfb6Smillert single_user,
985085bfb6Smillert runcom,
995085bfb6Smillert read_ttys,
1005085bfb6Smillert multi_user,
1015085bfb6Smillert clean_ttys,
1025085bfb6Smillert catatonia,
1035085bfb6Smillert death,
1045085bfb6Smillert do_reboot,
1055085bfb6Smillert hard_death,
1065085bfb6Smillert nice_death
1075085bfb6Smillert } state_t;
1085085bfb6Smillert typedef state_t (*state_func_t)(void);
109df930be7Sderaadt
1105085bfb6Smillert state_t f_single_user(void);
1115085bfb6Smillert state_t f_runcom(void);
1125085bfb6Smillert state_t f_read_ttys(void);
1135085bfb6Smillert state_t f_multi_user(void);
1145085bfb6Smillert state_t f_clean_ttys(void);
1155085bfb6Smillert state_t f_catatonia(void);
1165085bfb6Smillert state_t f_death(void);
1175085bfb6Smillert state_t f_do_reboot(void);
1185085bfb6Smillert state_t f_hard_death(void);
1195085bfb6Smillert state_t f_nice_death(void);
1205085bfb6Smillert
1215085bfb6Smillert state_func_t state_funcs[] = {
1225085bfb6Smillert NULL,
1235085bfb6Smillert f_single_user,
1245085bfb6Smillert f_runcom,
1255085bfb6Smillert f_read_ttys,
1265085bfb6Smillert f_multi_user,
1275085bfb6Smillert f_clean_ttys,
1285085bfb6Smillert f_catatonia,
1295085bfb6Smillert f_death,
1305085bfb6Smillert f_do_reboot,
1315085bfb6Smillert f_hard_death,
1325085bfb6Smillert f_nice_death
1335085bfb6Smillert };
134df930be7Sderaadt
135df930be7Sderaadt enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT;
136df930be7Sderaadt
137c72b5b24Smillert void transition(state_t);
1385085bfb6Smillert volatile sig_atomic_t requested_transition = DEFAULT_STATE;
139df930be7Sderaadt
140c72b5b24Smillert void setctty(char *);
141df930be7Sderaadt
142df930be7Sderaadt typedef struct init_session {
143df930be7Sderaadt int se_index; /* index of entry in ttys file */
144df930be7Sderaadt pid_t se_process; /* controlling process */
145eb10f49cScheloha struct timespec se_started; /* used to avoid thrashing */
146df930be7Sderaadt int se_flags; /* status of session */
147df930be7Sderaadt #define SE_SHUTDOWN 0x1 /* session won't be restarted */
148df930be7Sderaadt #define SE_PRESENT 0x2 /* session is in /etc/ttys */
1498bf92784Sderaadt #define SE_DEVEXISTS 0x4 /* open does not result in ENODEV */
150df930be7Sderaadt char *se_device; /* filename of port */
151df930be7Sderaadt char *se_getty; /* what to run on that port */
152df930be7Sderaadt char **se_getty_argv; /* pre-parsed argument array */
153df930be7Sderaadt char *se_window; /* window system (started only once) */
154df930be7Sderaadt char **se_window_argv; /* pre-parsed argument array */
155df930be7Sderaadt struct init_session *se_prev;
156df930be7Sderaadt struct init_session *se_next;
157ce842bbcSnicm RB_ENTRY(init_session) se_entry;
158df930be7Sderaadt } session_t;
159df930be7Sderaadt
160ce842bbcSnicm static int cmp_sessions(session_t *, session_t *);
161ce842bbcSnicm RB_HEAD(session_tree, init_session) session_tree = RB_INITIALIZER(session_tree);
162ce842bbcSnicm RB_PROTOTYPE(session_tree, init_session, se_entry, cmp_sessions);
163ce842bbcSnicm RB_GENERATE(session_tree, init_session, se_entry, cmp_sessions);
164ce842bbcSnicm
165c72b5b24Smillert void free_session(session_t *);
166c72b5b24Smillert session_t *new_session(session_t *, int, struct ttyent *);
167df930be7Sderaadt session_t *sessions;
168df930be7Sderaadt
169c72b5b24Smillert char **construct_argv(char *);
170c72b5b24Smillert void start_window_system(session_t *);
171c72b5b24Smillert void collect_child(pid_t);
172c72b5b24Smillert pid_t start_getty(session_t *);
173c72b5b24Smillert void transition_handler(int);
174c72b5b24Smillert void alrm_handler(int);
175c72b5b24Smillert void setsecuritylevel(int);
176bd61d3e8Smillert void setprocresources(char *);
177c72b5b24Smillert int getsecuritylevel(void);
178c72b5b24Smillert int setupargv(session_t *, struct ttyent *);
179*bdce9d03Scheloha
180*bdce9d03Scheloha volatile sig_atomic_t clang;
181df930be7Sderaadt
182c72b5b24Smillert void clear_session_logs(session_t *);
183df930be7Sderaadt
184c72b5b24Smillert void add_session(session_t *);
185c72b5b24Smillert void del_session(session_t *);
186c72b5b24Smillert session_t *find_session(pid_t);
187df930be7Sderaadt
188df930be7Sderaadt /*
189df930be7Sderaadt * The mother of all processes.
190df930be7Sderaadt */
191df930be7Sderaadt int
main(int argc,char * argv[])192bc52e260Sderaadt main(int argc, char *argv[])
193df930be7Sderaadt {
194178d191eSbluhm int c, fd;
195df930be7Sderaadt struct sigaction sa;
196df930be7Sderaadt sigset_t mask;
197df930be7Sderaadt
198df930be7Sderaadt /* Dispose of random users. */
199b1fde1a1Scheloha if (getuid() != 0)
200b1fde1a1Scheloha errc(1, EPERM, NULL);
201df930be7Sderaadt
202df930be7Sderaadt /* System V users like to reexec init. */
203b1fde1a1Scheloha if (getpid() != 1)
204b1fde1a1Scheloha errx(1, "already running");
205df930be7Sderaadt
206df930be7Sderaadt /*
207178d191eSbluhm * Paranoia.
208178d191eSbluhm */
209b7041c07Sderaadt if ((fd = open(_PATH_DEVNULL, O_RDWR)) != -1) {
210178d191eSbluhm (void)dup2(fd, STDIN_FILENO);
211178d191eSbluhm (void)dup2(fd, STDOUT_FILENO);
212178d191eSbluhm (void)dup2(fd, STDERR_FILENO);
213178d191eSbluhm if (fd > 2)
214178d191eSbluhm (void)close(fd);
215178d191eSbluhm }
216178d191eSbluhm
217178d191eSbluhm /*
218df930be7Sderaadt * Note that this does NOT open a file...
219df930be7Sderaadt * Does 'init' deserve its own facility number?
220df930be7Sderaadt */
221df930be7Sderaadt openlog("init", LOG_CONS|LOG_ODELAY, LOG_AUTH);
222df930be7Sderaadt
223df930be7Sderaadt /*
224df930be7Sderaadt * Create an initial session.
225df930be7Sderaadt */
226df69c215Sderaadt if (setsid() == -1)
227df930be7Sderaadt warning("initial setsid() failed: %m");
228df930be7Sderaadt
229df930be7Sderaadt /*
230df930be7Sderaadt * Establish an initial user so that programs running
231df930be7Sderaadt * single user do not freak out and die (like passwd).
232df930be7Sderaadt */
233df69c215Sderaadt if (setlogin("root") == -1)
234df930be7Sderaadt warning("setlogin() failed: %m");
235df930be7Sderaadt
236df930be7Sderaadt /*
237df930be7Sderaadt * This code assumes that we always get arguments through flags,
238df930be7Sderaadt * never through bits set in some random machine register.
239df930be7Sderaadt */
240df930be7Sderaadt while ((c = getopt(argc, argv, "sf")) != -1)
241df930be7Sderaadt switch (c) {
242df930be7Sderaadt case 's':
243df930be7Sderaadt requested_transition = single_user;
244df930be7Sderaadt break;
245df930be7Sderaadt case 'f':
246df930be7Sderaadt runcom_mode = FASTBOOT;
247df930be7Sderaadt break;
248df930be7Sderaadt default:
249df930be7Sderaadt warning("unrecognized flag '-%c'", c);
250df930be7Sderaadt break;
251df930be7Sderaadt }
252df930be7Sderaadt
253df930be7Sderaadt if (optind != argc)
254df930be7Sderaadt warning("ignoring excess arguments");
255df930be7Sderaadt
256df930be7Sderaadt /*
257df930be7Sderaadt * We catch or block signals rather than ignore them,
258df930be7Sderaadt * so that they get reset on exec.
259df930be7Sderaadt */
260df930be7Sderaadt handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV,
2619a190421Scheloha SIGBUS, SIGSYS, SIGXCPU, SIGXFSZ, 0);
262bff23b0cSdlg handle(transition_handler, SIGHUP, SIGINT, SIGTERM, SIGTSTP,
263dee114d4Sdlg SIGUSR1, SIGUSR2, 0);
264df930be7Sderaadt handle(alrm_handler, SIGALRM, 0);
265df930be7Sderaadt sigfillset(&mask);
266df930be7Sderaadt delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS,
267bff23b0cSdlg SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGTERM, SIGUSR1, SIGUSR2,
268bdbecee4Sderaadt SIGTSTP, SIGALRM, 0);
2697674422fSkstailey sigprocmask(SIG_SETMASK, &mask, NULL);
27064fbf2d7Sderaadt memset(&sa, 0, sizeof sa);
271df930be7Sderaadt sigemptyset(&sa.sa_mask);
272df930be7Sderaadt sa.sa_flags = 0;
273df930be7Sderaadt sa.sa_handler = SIG_IGN;
2747674422fSkstailey (void) sigaction(SIGTTIN, &sa, NULL);
2757674422fSkstailey (void) sigaction(SIGTTOU, &sa, NULL);
276df930be7Sderaadt
277df930be7Sderaadt /*
278df930be7Sderaadt * Start the state machine.
279df930be7Sderaadt */
280df930be7Sderaadt transition(requested_transition);
281df930be7Sderaadt
282df930be7Sderaadt /*
283df930be7Sderaadt * Should never reach here.
284df930be7Sderaadt */
285824827eeSmillert exit(1);
286df930be7Sderaadt }
287df930be7Sderaadt
288df930be7Sderaadt /*
289df930be7Sderaadt * Associate a function with a signal handler.
290df930be7Sderaadt */
291df930be7Sderaadt void
handle(sig_t handler,...)292df930be7Sderaadt handle(sig_t handler, ...)
293df930be7Sderaadt {
294df930be7Sderaadt int sig;
295df930be7Sderaadt struct sigaction sa;
2961db781b7Sderaadt sigset_t mask_everything;
297df930be7Sderaadt va_list ap;
298df930be7Sderaadt
299df930be7Sderaadt va_start(ap, handler);
300df930be7Sderaadt
30164fbf2d7Sderaadt memset(&sa, 0, sizeof sa);
302df930be7Sderaadt sa.sa_handler = handler;
303df930be7Sderaadt sigfillset(&mask_everything);
304df930be7Sderaadt
3054158ce8dSderaadt while ((sig = va_arg(ap, int))) {
306df930be7Sderaadt sa.sa_mask = mask_everything;
307df930be7Sderaadt /* XXX SA_RESTART? */
308df930be7Sderaadt sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
3097674422fSkstailey sigaction(sig, &sa, NULL);
310df930be7Sderaadt }
311df930be7Sderaadt va_end(ap);
312df930be7Sderaadt }
313df930be7Sderaadt
314df930be7Sderaadt /*
315df930be7Sderaadt * Delete a set of signals from a mask.
316df930be7Sderaadt */
317df930be7Sderaadt void
delset(sigset_t * maskp,...)318df930be7Sderaadt delset(sigset_t *maskp, ...)
319df930be7Sderaadt {
320df930be7Sderaadt int sig;
321df930be7Sderaadt va_list ap;
322df930be7Sderaadt
323df930be7Sderaadt va_start(ap, maskp);
3244158ce8dSderaadt while ((sig = va_arg(ap, int)))
325df930be7Sderaadt sigdelset(maskp, sig);
326df930be7Sderaadt va_end(ap);
327df930be7Sderaadt }
328df930be7Sderaadt
329df930be7Sderaadt /*
330df930be7Sderaadt * Log a message and sleep for a while (to give someone an opportunity
331df930be7Sderaadt * to read it and to save log or hardcopy output if the problem is chronic).
332df930be7Sderaadt * NB: should send a message to the session logger to avoid blocking.
333df930be7Sderaadt */
334df930be7Sderaadt void
stall(char * message,...)335df930be7Sderaadt stall(char *message, ...)
336df930be7Sderaadt {
337df930be7Sderaadt va_list ap;
338df930be7Sderaadt
339df930be7Sderaadt va_start(ap, message);
340df930be7Sderaadt vsyslog(LOG_ALERT, message, ap);
341df930be7Sderaadt va_end(ap);
3422898efc9Sderaadt closelog();
343df930be7Sderaadt sleep(STALL_TIMEOUT);
344df930be7Sderaadt }
345df930be7Sderaadt
346df930be7Sderaadt /*
347df930be7Sderaadt * Like stall(), but doesn't sleep.
348df930be7Sderaadt * If cpp had variadic macros, the two functions could be #defines for another.
349df930be7Sderaadt * NB: should send a message to the session logger to avoid blocking.
350df930be7Sderaadt */
351df930be7Sderaadt void
warning(char * message,...)352df930be7Sderaadt warning(char *message, ...)
353df930be7Sderaadt {
354df930be7Sderaadt va_list ap;
355df930be7Sderaadt
356df930be7Sderaadt va_start(ap, message);
357df930be7Sderaadt vsyslog(LOG_ALERT, message, ap);
358df930be7Sderaadt va_end(ap);
3592898efc9Sderaadt closelog();
360df930be7Sderaadt }
361df930be7Sderaadt
362df930be7Sderaadt /*
363df930be7Sderaadt * Log an emergency message.
364df930be7Sderaadt * NB: should send a message to the session logger to avoid blocking.
365df930be7Sderaadt */
366df930be7Sderaadt void
emergency(char * message,...)367df930be7Sderaadt emergency(char *message, ...)
368df930be7Sderaadt {
369bc52e260Sderaadt struct syslog_data sdata = SYSLOG_DATA_INIT;
370df930be7Sderaadt va_list ap;
371df930be7Sderaadt
372df930be7Sderaadt va_start(ap, message);
373bc52e260Sderaadt vsyslog_r(LOG_EMERG, &sdata, message, ap);
374df930be7Sderaadt va_end(ap);
375df930be7Sderaadt }
376df930be7Sderaadt
377df930be7Sderaadt /*
378df930be7Sderaadt * Catch an unexpected signal.
379df930be7Sderaadt */
380df930be7Sderaadt void
disaster(int sig)381bc52e260Sderaadt disaster(int sig)
382df930be7Sderaadt {
383df930be7Sderaadt emergency("fatal signal: %s", strsignal(sig));
384df930be7Sderaadt
385df930be7Sderaadt sleep(STALL_TIMEOUT);
386df930be7Sderaadt _exit(sig); /* reboot */
387df930be7Sderaadt }
388df930be7Sderaadt
389df930be7Sderaadt /*
390df930be7Sderaadt * Get the security level of the kernel.
391df930be7Sderaadt */
392df930be7Sderaadt int
getsecuritylevel(void)393bc52e260Sderaadt getsecuritylevel(void)
394df930be7Sderaadt {
395df930be7Sderaadt #ifdef KERN_SECURELVL
396df930be7Sderaadt int name[2], curlevel;
397df930be7Sderaadt size_t len;
398df930be7Sderaadt
399df930be7Sderaadt name[0] = CTL_KERN;
400df930be7Sderaadt name[1] = KERN_SECURELVL;
401df930be7Sderaadt len = sizeof curlevel;
402df930be7Sderaadt if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
403df930be7Sderaadt emergency("cannot get kernel security level: %s",
404df930be7Sderaadt strerror(errno));
405df930be7Sderaadt return (-1);
406df930be7Sderaadt }
407df930be7Sderaadt return (curlevel);
408df930be7Sderaadt #else
409df930be7Sderaadt return (-1);
410df930be7Sderaadt #endif
411df930be7Sderaadt }
412df930be7Sderaadt
413df930be7Sderaadt /*
414df930be7Sderaadt * Set the security level of the kernel.
415df930be7Sderaadt */
416df930be7Sderaadt void
setsecuritylevel(int newlevel)417bc52e260Sderaadt setsecuritylevel(int newlevel)
418df930be7Sderaadt {
419df930be7Sderaadt #ifdef KERN_SECURELVL
420df930be7Sderaadt int name[2], curlevel;
421df930be7Sderaadt
422df930be7Sderaadt curlevel = getsecuritylevel();
423df930be7Sderaadt if (newlevel == curlevel)
424df930be7Sderaadt return;
425df930be7Sderaadt name[0] = CTL_KERN;
426df930be7Sderaadt name[1] = KERN_SECURELVL;
427df930be7Sderaadt if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) {
428df930be7Sderaadt emergency(
429df930be7Sderaadt "cannot change kernel security level from %d to %d: %s",
430df930be7Sderaadt curlevel, newlevel, strerror(errno));
431df930be7Sderaadt return;
432df930be7Sderaadt }
433df930be7Sderaadt #ifdef SECURE
434df930be7Sderaadt warning("kernel security level changed from %d to %d",
435df930be7Sderaadt curlevel, newlevel);
436df930be7Sderaadt #endif
437df930be7Sderaadt #endif
438df930be7Sderaadt }
439df930be7Sderaadt
440df930be7Sderaadt /*
441df930be7Sderaadt * Change states in the finite state machine.
442df930be7Sderaadt * The initial state is passed as an argument.
443df930be7Sderaadt */
444df930be7Sderaadt void
transition(state_t s)445bc52e260Sderaadt transition(state_t s)
446df930be7Sderaadt {
447df930be7Sderaadt for (;;)
4485085bfb6Smillert s = (*state_funcs[s])();
449df930be7Sderaadt }
450df930be7Sderaadt
451df930be7Sderaadt /*
452df930be7Sderaadt * Close out the accounting files for a login session.
453df930be7Sderaadt * NB: should send a message to the session logger to avoid blocking.
454df930be7Sderaadt */
455df930be7Sderaadt void
clear_session_logs(session_t * sp)456bc52e260Sderaadt clear_session_logs(session_t *sp)
457df930be7Sderaadt {
458df930be7Sderaadt char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
459df930be7Sderaadt
460df930be7Sderaadt if (logout(line))
461df930be7Sderaadt logwtmp(line, "", "");
462df930be7Sderaadt }
463df930be7Sderaadt
464df930be7Sderaadt /*
465df930be7Sderaadt * Start a session and allocate a controlling terminal.
466df930be7Sderaadt * Only called by children of init after forking.
467df930be7Sderaadt */
468df930be7Sderaadt void
setctty(char * name)469bc52e260Sderaadt setctty(char *name)
470df930be7Sderaadt {
471df930be7Sderaadt int fd;
472df930be7Sderaadt
473df930be7Sderaadt (void) revoke(name);
474df930be7Sderaadt sleep(2); /* leave DTR low */
475df930be7Sderaadt if ((fd = open(name, O_RDWR)) == -1) {
476df930be7Sderaadt stall("can't open %s: %m", name);
477df930be7Sderaadt _exit(1);
478df930be7Sderaadt }
479df930be7Sderaadt if (login_tty(fd) == -1) {
480df930be7Sderaadt stall("can't get %s for controlling terminal: %m", name);
481df930be7Sderaadt _exit(1);
482df930be7Sderaadt }
483df930be7Sderaadt }
484df930be7Sderaadt
485df930be7Sderaadt /*
486df930be7Sderaadt * Bring the system up single user.
487df930be7Sderaadt */
4885085bfb6Smillert state_t
f_single_user(void)4895085bfb6Smillert f_single_user(void)
490df930be7Sderaadt {
491df930be7Sderaadt pid_t pid, wpid;
492df930be7Sderaadt int status;
493df930be7Sderaadt sigset_t mask;
494b9fc9a72Sderaadt char shell[PATH_MAX]; /* Allocate space here */
495b9fc9a72Sderaadt char name[PATH_MAX]; /* Name (argv[0]) of shell */
496df930be7Sderaadt char *argv[2];
497df930be7Sderaadt #ifdef SECURE
498df930be7Sderaadt struct ttyent *typ;
499df930be7Sderaadt struct passwd *pp;
500df930be7Sderaadt static const char banner[] =
501df930be7Sderaadt "Enter root password, or ^D to go multi-user\n";
5029044f8b1Sjca char *clear;
503c43387b9Sgsoares char pbuf[1024];
504df930be7Sderaadt #endif
505df930be7Sderaadt
5062ebac4d9Sweingart /* Init shell and name */
507dcab0d16Sderaadt strlcpy(shell, _PATH_BSHELL, sizeof shell);
508dcab0d16Sderaadt strlcpy(name, "-sh", sizeof name);
5092ebac4d9Sweingart
510df930be7Sderaadt /*
511df930be7Sderaadt * If the kernel is in secure mode, downgrade it to insecure mode.
512df930be7Sderaadt */
513df930be7Sderaadt if (getsecuritylevel() > 0)
514df930be7Sderaadt setsecuritylevel(0);
515df930be7Sderaadt
516df930be7Sderaadt if ((pid = fork()) == 0) {
517df930be7Sderaadt /*
518df930be7Sderaadt * Start the single user session.
519df930be7Sderaadt */
520df930be7Sderaadt setctty(_PATH_CONSOLE);
521df930be7Sderaadt
522df930be7Sderaadt #ifdef SECURE
523df930be7Sderaadt /*
524df930be7Sderaadt * Check the root password.
525df930be7Sderaadt * We don't care if the console is 'on' by default;
526df930be7Sderaadt * it's the only tty that can be 'off' and 'secure'.
527df930be7Sderaadt */
528df930be7Sderaadt typ = getttynam("console");
529fc334d60Stedu pp = getpwnam_shadow("root");
530c5ee85c1Sderaadt if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp &&
531c5ee85c1Sderaadt *pp->pw_passwd) {
5325392146dSmillert write(STDERR_FILENO, banner, sizeof banner - 1);
533df930be7Sderaadt for (;;) {
534fc334d60Stedu int ok = 0;
5353a7efd93Smestre clear = readpassphrase("Password:", pbuf,
5363a7efd93Smestre sizeof(pbuf), RPP_ECHO_OFF);
537fc334d60Stedu if (clear == NULL || *clear == '\0')
538df930be7Sderaadt _exit(0);
539fc334d60Stedu if (crypt_checkpass(clear, pp->pw_passwd) == 0)
540fc334d60Stedu ok = 1;
5413a7efd93Smestre explicit_bzero(pbuf, sizeof(pbuf));
542fc334d60Stedu if (ok)
543df930be7Sderaadt break;
544df930be7Sderaadt warning("single-user login failed\n");
545df930be7Sderaadt }
546df930be7Sderaadt }
547df930be7Sderaadt endttyent();
548df930be7Sderaadt endpwent();
549df930be7Sderaadt #endif /* SECURE */
550df930be7Sderaadt
551df930be7Sderaadt #ifdef DEBUGSHELL
552df930be7Sderaadt {
553df930be7Sderaadt char altshell[128], *cp = altshell;
554df930be7Sderaadt int num;
555df930be7Sderaadt
556df930be7Sderaadt #define SHREQUEST \
557df930be7Sderaadt "Enter pathname of shell or RETURN for sh: "
558dcab0d16Sderaadt
559df930be7Sderaadt (void)write(STDERR_FILENO,
560df930be7Sderaadt SHREQUEST, sizeof(SHREQUEST) - 1);
561df930be7Sderaadt while ((num = read(STDIN_FILENO, cp, 1)) != -1 &&
562df930be7Sderaadt num != 0 && *cp != '\n' && cp < &altshell[127])
563df930be7Sderaadt cp++;
564df930be7Sderaadt *cp = '\0';
5652ebac4d9Sweingart
5662ebac4d9Sweingart /* Copy in alternate shell */
5672ebac4d9Sweingart if (altshell[0] != '\0'){
5682ebac4d9Sweingart char *p;
5692ebac4d9Sweingart
5702ebac4d9Sweingart /* Binary to exec */
571dcab0d16Sderaadt strlcpy(shell, altshell, sizeof shell);
5722ebac4d9Sweingart
5732ebac4d9Sweingart /* argv[0] */
5742ebac4d9Sweingart p = strrchr(altshell, '/');
5752ebac4d9Sweingart if(p == NULL) p = altshell;
5762ebac4d9Sweingart else p++;
5772ebac4d9Sweingart
5782ebac4d9Sweingart name[0] = '-';
579dcab0d16Sderaadt strlcpy(&name[1], p, sizeof name -1);
5802ebac4d9Sweingart }
581df930be7Sderaadt }
582df930be7Sderaadt #endif /* DEBUGSHELL */
583df930be7Sderaadt
584df930be7Sderaadt /*
585df930be7Sderaadt * Unblock signals.
586df930be7Sderaadt * We catch all the interesting ones,
587df930be7Sderaadt * and those are reset to SIG_DFL on exec.
588df930be7Sderaadt */
589df930be7Sderaadt sigemptyset(&mask);
5907674422fSkstailey sigprocmask(SIG_SETMASK, &mask, NULL);
591df930be7Sderaadt
592df930be7Sderaadt /*
593df930be7Sderaadt * Fire off a shell.
594df930be7Sderaadt * If the default one doesn't work, try the Bourne shell.
595df930be7Sderaadt */
5962ebac4d9Sweingart argv[0] = name;
5972ebac4d9Sweingart argv[1] = NULL;
598df930be7Sderaadt setenv("PATH", _PATH_STDPATH, 1);
599df930be7Sderaadt execv(shell, argv);
600df930be7Sderaadt emergency("can't exec %s for single user: %m", shell);
6012ebac4d9Sweingart
6022ebac4d9Sweingart argv[0] = "-sh";
6032ebac4d9Sweingart argv[1] = NULL;
604df930be7Sderaadt execv(_PATH_BSHELL, argv);
605df930be7Sderaadt emergency("can't exec %s for single user: %m", _PATH_BSHELL);
606df930be7Sderaadt sleep(STALL_TIMEOUT);
607df930be7Sderaadt _exit(1);
608df930be7Sderaadt }
609df930be7Sderaadt
610df930be7Sderaadt if (pid == -1) {
611df930be7Sderaadt /*
612df930be7Sderaadt * We are seriously hosed. Do our best.
613df930be7Sderaadt */
614df930be7Sderaadt emergency("can't fork single-user shell, trying again");
6157674422fSkstailey while (waitpid(-1, NULL, WNOHANG) > 0)
616df930be7Sderaadt continue;
6175085bfb6Smillert return single_user;
618df930be7Sderaadt }
619df930be7Sderaadt
620df930be7Sderaadt requested_transition = 0;
621df930be7Sderaadt do {
622df930be7Sderaadt if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
623df930be7Sderaadt collect_child(wpid);
624df930be7Sderaadt if (wpid == -1) {
625df930be7Sderaadt if (errno == EINTR)
626df930be7Sderaadt continue;
627df930be7Sderaadt warning("wait for single-user shell failed: %m; restarting");
6285085bfb6Smillert return single_user;
629df930be7Sderaadt }
630df930be7Sderaadt if (wpid == pid && WIFSTOPPED(status)) {
631df930be7Sderaadt warning("init: shell stopped, restarting\n");
632df930be7Sderaadt kill(pid, SIGCONT);
633df930be7Sderaadt wpid = -1;
634df930be7Sderaadt }
635df930be7Sderaadt } while (wpid != pid && !requested_transition);
636df930be7Sderaadt
637df930be7Sderaadt if (requested_transition)
6385085bfb6Smillert return requested_transition;
639df930be7Sderaadt
640df930be7Sderaadt if (!WIFEXITED(status)) {
641df930be7Sderaadt if (WTERMSIG(status) == SIGKILL) {
642df930be7Sderaadt /*
643df930be7Sderaadt * reboot(8) killed shell?
644df930be7Sderaadt */
645df930be7Sderaadt warning("single user shell terminated.");
646df930be7Sderaadt sleep(STALL_TIMEOUT);
647df930be7Sderaadt _exit(0);
648df930be7Sderaadt } else {
649df930be7Sderaadt warning("single user shell terminated, restarting");
6505085bfb6Smillert return single_user;
651df930be7Sderaadt }
652df930be7Sderaadt }
653df930be7Sderaadt
654df930be7Sderaadt runcom_mode = FASTBOOT;
6555085bfb6Smillert return runcom;
656df930be7Sderaadt }
657df930be7Sderaadt
658df930be7Sderaadt /*
659df930be7Sderaadt * Run the system startup script.
660df930be7Sderaadt */
6615085bfb6Smillert state_t
f_runcom(void)6625085bfb6Smillert f_runcom(void)
663df930be7Sderaadt {
664df930be7Sderaadt pid_t pid, wpid;
665df930be7Sderaadt int status;
666df930be7Sderaadt char *argv[4];
667df930be7Sderaadt struct sigaction sa;
668df930be7Sderaadt
669df930be7Sderaadt if ((pid = fork()) == 0) {
67064fbf2d7Sderaadt memset(&sa, 0, sizeof sa);
671df930be7Sderaadt sigemptyset(&sa.sa_mask);
672df930be7Sderaadt sa.sa_flags = 0;
673df930be7Sderaadt sa.sa_handler = SIG_IGN;
6747674422fSkstailey (void) sigaction(SIGTSTP, &sa, NULL);
6757674422fSkstailey (void) sigaction(SIGHUP, &sa, NULL);
676df930be7Sderaadt
677df930be7Sderaadt setctty(_PATH_CONSOLE);
678df930be7Sderaadt
679df930be7Sderaadt argv[0] = "sh";
680df930be7Sderaadt argv[1] = _PATH_RUNCOM;
681f52a7f8cSmmcc argv[2] = runcom_mode == AUTOBOOT ? "autoboot" : NULL;
682f52a7f8cSmmcc argv[3] = NULL;
683df930be7Sderaadt
6847674422fSkstailey sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);
685df930be7Sderaadt
686fed231abSmillert setprocresources(RESOURCE_RC);
687fed231abSmillert
688df930be7Sderaadt execv(_PATH_BSHELL, argv);
689df930be7Sderaadt stall("can't exec %s for %s: %m", _PATH_BSHELL, _PATH_RUNCOM);
690df930be7Sderaadt _exit(1); /* force single user mode */
691df930be7Sderaadt }
692df930be7Sderaadt
693df930be7Sderaadt if (pid == -1) {
694df930be7Sderaadt emergency("can't fork for %s on %s: %m",
695df930be7Sderaadt _PATH_BSHELL, _PATH_RUNCOM);
6967674422fSkstailey while (waitpid(-1, NULL, WNOHANG) > 0)
697df930be7Sderaadt continue;
698df930be7Sderaadt sleep(STALL_TIMEOUT);
6995085bfb6Smillert return single_user;
700df930be7Sderaadt }
701df930be7Sderaadt
702df930be7Sderaadt /*
703df930be7Sderaadt * Copied from single_user(). This is a bit paranoid.
704df930be7Sderaadt */
705df930be7Sderaadt do {
706df930be7Sderaadt if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
707df930be7Sderaadt collect_child(wpid);
708df930be7Sderaadt if (wpid == -1) {
709df930be7Sderaadt if (errno == EINTR)
710df930be7Sderaadt continue;
711df930be7Sderaadt warning("wait for %s on %s failed: %m; going to single user mode",
712df930be7Sderaadt _PATH_BSHELL, _PATH_RUNCOM);
7135085bfb6Smillert return single_user;
714df930be7Sderaadt }
715df930be7Sderaadt if (wpid == pid && WIFSTOPPED(status)) {
716df930be7Sderaadt warning("init: %s on %s stopped, restarting\n",
717df930be7Sderaadt _PATH_BSHELL, _PATH_RUNCOM);
718df930be7Sderaadt kill(pid, SIGCONT);
719df930be7Sderaadt wpid = -1;
720df930be7Sderaadt }
721df930be7Sderaadt } while (wpid != pid);
722df930be7Sderaadt
723df930be7Sderaadt if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
724df930be7Sderaadt requested_transition == catatonia) {
725df930be7Sderaadt /* /etc/rc executed /sbin/reboot; wait for the end quietly */
726df930be7Sderaadt sigset_t s;
727df930be7Sderaadt
728df930be7Sderaadt sigfillset(&s);
729df930be7Sderaadt for (;;)
730df930be7Sderaadt sigsuspend(&s);
731df930be7Sderaadt }
732df930be7Sderaadt
733df930be7Sderaadt if (!WIFEXITED(status)) {
734df930be7Sderaadt warning("%s on %s terminated abnormally, going to single user mode",
735df930be7Sderaadt _PATH_BSHELL, _PATH_RUNCOM);
7365085bfb6Smillert return single_user;
737df930be7Sderaadt }
738df930be7Sderaadt
739df930be7Sderaadt if (WEXITSTATUS(status))
7405085bfb6Smillert return single_user;
741df930be7Sderaadt
742df930be7Sderaadt runcom_mode = AUTOBOOT; /* the default */
743df930be7Sderaadt /* NB: should send a message to the session logger to avoid blocking. */
744df930be7Sderaadt logwtmp("~", "reboot", "");
7455085bfb6Smillert return read_ttys;
746df930be7Sderaadt }
747df930be7Sderaadt
748df930be7Sderaadt /*
749ce842bbcSnicm * Compare session keys.
750df930be7Sderaadt */
751ce842bbcSnicm static int
cmp_sessions(session_t * sp1,session_t * sp2)752ce842bbcSnicm cmp_sessions(session_t *sp1, session_t *sp2)
753df930be7Sderaadt {
754ce842bbcSnicm if (sp1->se_process < sp2->se_process)
755ce842bbcSnicm return (-1);
756ce842bbcSnicm if (sp1->se_process > sp2->se_process)
757df930be7Sderaadt return (1);
758df930be7Sderaadt return (0);
759df930be7Sderaadt }
760df930be7Sderaadt
761df930be7Sderaadt /*
762df930be7Sderaadt * Add a new login session.
763df930be7Sderaadt */
764df930be7Sderaadt void
add_session(session_t * sp)765bc52e260Sderaadt add_session(session_t *sp)
766df930be7Sderaadt {
767ce842bbcSnicm if (RB_INSERT(session_tree, &session_tree, sp) != NULL)
768df930be7Sderaadt emergency("insert %d: %s", sp->se_process, strerror(errno));
769df930be7Sderaadt }
770df930be7Sderaadt
771df930be7Sderaadt /*
772df930be7Sderaadt * Delete an old login session.
773df930be7Sderaadt */
774df930be7Sderaadt void
del_session(session_t * sp)775bc52e260Sderaadt del_session(session_t *sp)
776df930be7Sderaadt {
777ce842bbcSnicm RB_REMOVE(session_tree, &session_tree, sp);
778df930be7Sderaadt }
779df930be7Sderaadt
780df930be7Sderaadt /*
781df930be7Sderaadt * Look up a login session by pid.
782df930be7Sderaadt */
783df930be7Sderaadt session_t *
find_session(pid_t pid)784df930be7Sderaadt find_session(pid_t pid)
785df930be7Sderaadt {
786ce842bbcSnicm struct init_session s;
787df930be7Sderaadt
788ce842bbcSnicm s.se_process = pid;
789ce842bbcSnicm return (RB_FIND(session_tree, &session_tree, &s));
790df930be7Sderaadt }
791df930be7Sderaadt
792df930be7Sderaadt /*
793df930be7Sderaadt * Construct an argument vector from a command line.
794df930be7Sderaadt */
795df930be7Sderaadt char **
construct_argv(char * command)796bc52e260Sderaadt construct_argv(char *command)
797df930be7Sderaadt {
798e073c79dSmpech int argc = 0;
7995ae94ef8Sderaadt char **argv = calloc((strlen(command) + 1) / 2 + 1, sizeof (char *));
800df930be7Sderaadt static const char separators[] = " \t";
801df930be7Sderaadt
80298b17e93Sotto if (argv == NULL)
8035392146dSmillert return (0);
80498b17e93Sotto
80598b17e93Sotto if ((argv[argc++] = strtok(command, separators)) == 0) {
80698b17e93Sotto free(argv);
80798b17e93Sotto return (0);
80898b17e93Sotto }
8094158ce8dSderaadt while ((argv[argc++] = strtok(NULL, separators)))
810df930be7Sderaadt continue;
8115392146dSmillert return (argv);
812df930be7Sderaadt }
813df930be7Sderaadt
814df930be7Sderaadt /*
815df930be7Sderaadt * Deallocate a session descriptor.
816df930be7Sderaadt */
817df930be7Sderaadt void
free_session(session_t * sp)818bc52e260Sderaadt free_session(session_t *sp)
819df930be7Sderaadt {
820df930be7Sderaadt free(sp->se_device);
821df930be7Sderaadt if (sp->se_getty) {
822df930be7Sderaadt free(sp->se_getty);
823df930be7Sderaadt free(sp->se_getty_argv);
824df930be7Sderaadt }
825df930be7Sderaadt if (sp->se_window) {
826df930be7Sderaadt free(sp->se_window);
827df930be7Sderaadt free(sp->se_window_argv);
828df930be7Sderaadt }
829df930be7Sderaadt free(sp);
830df930be7Sderaadt }
831df930be7Sderaadt
832df930be7Sderaadt /*
833df930be7Sderaadt * Allocate a new session descriptor.
834df930be7Sderaadt */
835df930be7Sderaadt session_t *
new_session(session_t * sprev,int session_index,struct ttyent * typ)836bc52e260Sderaadt new_session(session_t *sprev, int session_index, struct ttyent *typ)
837df930be7Sderaadt {
838e073c79dSmpech session_t *sp;
839df930be7Sderaadt
840df930be7Sderaadt if ((typ->ty_status & TTY_ON) == 0 ||
841df930be7Sderaadt typ->ty_name == 0 ||
842df930be7Sderaadt typ->ty_getty == 0)
8435392146dSmillert return (0);
844df930be7Sderaadt
845e7049ca9Stedu sp = calloc(1, sizeof (session_t));
846e7049ca9Stedu if (sp == NULL)
847e7049ca9Stedu err(1, "calloc");
848df930be7Sderaadt
849df930be7Sderaadt sp->se_flags = SE_PRESENT;
850df930be7Sderaadt sp->se_index = session_index;
851df930be7Sderaadt
852e19c6df5Sderaadt if (asprintf(&sp->se_device, "%s%s", _PATH_DEV, typ->ty_name) == -1)
853e19c6df5Sderaadt err(1, "asprintf");
854df930be7Sderaadt
855df930be7Sderaadt if (setupargv(sp, typ) == 0) {
856df930be7Sderaadt free_session(sp);
857df930be7Sderaadt return (0);
858df930be7Sderaadt }
859df930be7Sderaadt
860f52a7f8cSmmcc sp->se_next = NULL;
861f52a7f8cSmmcc if (sprev == NULL) {
862df930be7Sderaadt sessions = sp;
863f52a7f8cSmmcc sp->se_prev = NULL;
864df930be7Sderaadt } else {
865df930be7Sderaadt sprev->se_next = sp;
866df930be7Sderaadt sp->se_prev = sprev;
867df930be7Sderaadt }
868df930be7Sderaadt
8695392146dSmillert return (sp);
870df930be7Sderaadt }
871df930be7Sderaadt
872df930be7Sderaadt /*
873df930be7Sderaadt * Calculate getty and if useful window argv vectors.
874df930be7Sderaadt */
875df930be7Sderaadt int
setupargv(session_t * sp,struct ttyent * typ)876bc52e260Sderaadt setupargv(session_t *sp, struct ttyent *typ)
877df930be7Sderaadt {
878df930be7Sderaadt if (sp->se_getty) {
879df930be7Sderaadt free(sp->se_getty);
880df930be7Sderaadt free(sp->se_getty_argv);
881df930be7Sderaadt }
882e19c6df5Sderaadt if (asprintf(&sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name) == -1)
883e19c6df5Sderaadt err(1, "asprintf");
884df930be7Sderaadt sp->se_getty_argv = construct_argv(sp->se_getty);
885df930be7Sderaadt if (sp->se_getty_argv == 0) {
886df930be7Sderaadt warning("can't parse getty for port %s", sp->se_device);
887df930be7Sderaadt free(sp->se_getty);
888f52a7f8cSmmcc sp->se_getty = NULL;
889df930be7Sderaadt return (0);
890df930be7Sderaadt }
891df930be7Sderaadt if (typ->ty_window) {
892df930be7Sderaadt free(sp->se_window);
893df930be7Sderaadt sp->se_window = strdup(typ->ty_window);
894332a991fSderaadt if (sp->se_window == NULL) {
895332a991fSderaadt warning("can't allocate window");
896332a991fSderaadt return (0);
897332a991fSderaadt }
898df930be7Sderaadt sp->se_window_argv = construct_argv(sp->se_window);
899332a991fSderaadt if (sp->se_window_argv == NULL) {
900df930be7Sderaadt warning("can't parse window for port %s",
901df930be7Sderaadt sp->se_device);
902df930be7Sderaadt free(sp->se_window);
903332a991fSderaadt sp->se_window = NULL;
904df930be7Sderaadt return (0);
905df930be7Sderaadt }
906df930be7Sderaadt }
907df930be7Sderaadt return (1);
908df930be7Sderaadt }
909df930be7Sderaadt
910df930be7Sderaadt /*
911df930be7Sderaadt * Walk the list of ttys and create sessions for each active line.
912df930be7Sderaadt */
9135085bfb6Smillert state_t
f_read_ttys(void)9145085bfb6Smillert f_read_ttys(void)
915df930be7Sderaadt {
916df930be7Sderaadt int session_index = 0;
917e073c79dSmpech session_t *sp, *snext;
918e073c79dSmpech struct ttyent *typ;
919df930be7Sderaadt
920df930be7Sderaadt /*
921df930be7Sderaadt * Destroy any previous session state.
922df930be7Sderaadt * There shouldn't be any, but just in case...
923df930be7Sderaadt */
924df930be7Sderaadt for (sp = sessions; sp; sp = snext) {
925df930be7Sderaadt if (sp->se_process)
926df930be7Sderaadt clear_session_logs(sp);
927df930be7Sderaadt snext = sp->se_next;
928df930be7Sderaadt free_session(sp);
929df930be7Sderaadt }
930f52a7f8cSmmcc sessions = NULL;
931df930be7Sderaadt
932df930be7Sderaadt /*
933df930be7Sderaadt * Allocate a session entry for each active port.
934df930be7Sderaadt * Note that sp starts at 0.
935df930be7Sderaadt */
9364158ce8dSderaadt while ((typ = getttyent()))
9374158ce8dSderaadt if ((snext = new_session(sp, ++session_index, typ)))
938df930be7Sderaadt sp = snext;
939df930be7Sderaadt
940df930be7Sderaadt endttyent();
941df930be7Sderaadt
9425085bfb6Smillert return multi_user;
943df930be7Sderaadt }
944df930be7Sderaadt
945df930be7Sderaadt /*
946df930be7Sderaadt * Start a window system running.
947df930be7Sderaadt */
948df930be7Sderaadt void
start_window_system(session_t * sp)949bc52e260Sderaadt start_window_system(session_t *sp)
950df930be7Sderaadt {
951df930be7Sderaadt pid_t pid;
952df930be7Sderaadt sigset_t mask;
953df930be7Sderaadt
954df930be7Sderaadt if ((pid = fork()) == -1) {
955df930be7Sderaadt emergency("can't fork for window system on port %s: %m",
956df930be7Sderaadt sp->se_device);
957df930be7Sderaadt /* hope that getty fails and we can try again */
958df930be7Sderaadt return;
959df930be7Sderaadt }
960df930be7Sderaadt
961df930be7Sderaadt if (pid)
962df930be7Sderaadt return;
963df930be7Sderaadt
964df930be7Sderaadt sigemptyset(&mask);
9657674422fSkstailey sigprocmask(SIG_SETMASK, &mask, NULL);
966df930be7Sderaadt
967df69c215Sderaadt if (setsid() == -1)
968df930be7Sderaadt emergency("setsid failed (window) %m");
969df930be7Sderaadt
970fed231abSmillert setprocresources(RESOURCE_WINDOW);
971fed231abSmillert
972df930be7Sderaadt execv(sp->se_window_argv[0], sp->se_window_argv);
973df930be7Sderaadt stall("can't exec window system '%s' for port %s: %m",
974df930be7Sderaadt sp->se_window_argv[0], sp->se_device);
975df930be7Sderaadt _exit(1);
976df930be7Sderaadt }
977df930be7Sderaadt
978df930be7Sderaadt /*
979df930be7Sderaadt * Start a login session running.
9808bf92784Sderaadt * For first open, man-handle tty directly to determine if it
9818bf92784Sderaadt * really exists. It is not efficient to spawn gettys on devices
9828bf92784Sderaadt * that do not exist.
983df930be7Sderaadt */
984df930be7Sderaadt pid_t
start_getty(session_t * sp)985bc52e260Sderaadt start_getty(session_t *sp)
986df930be7Sderaadt {
987df930be7Sderaadt pid_t pid;
988df930be7Sderaadt sigset_t mask;
989eb10f49cScheloha struct timespec current_time, elapsed;
9908bf92784Sderaadt int p[2], new = 1;
9918bf92784Sderaadt
9928bf92784Sderaadt if (sp->se_flags & SE_DEVEXISTS)
9938bf92784Sderaadt new = 0;
9948bf92784Sderaadt
9958bf92784Sderaadt if (new) {
9968bf92784Sderaadt if (pipe(p) == -1)
9975392146dSmillert return (-1);
9988bf92784Sderaadt }
999df930be7Sderaadt
1000df930be7Sderaadt /*
1001df930be7Sderaadt * fork(), not vfork() -- we can't afford to block.
1002df930be7Sderaadt */
1003df930be7Sderaadt if ((pid = fork()) == -1) {
1004df930be7Sderaadt emergency("can't fork for getty on port %s: %m", sp->se_device);
10055392146dSmillert return (-1);
1006df930be7Sderaadt }
1007df930be7Sderaadt
10088bf92784Sderaadt if (pid) {
10098bf92784Sderaadt if (new) {
10108bf92784Sderaadt char c;
10118bf92784Sderaadt
10128bf92784Sderaadt close(p[1]);
10138bf92784Sderaadt if (read(p[0], &c, 1) != 1) {
10148bf92784Sderaadt close(p[0]);
10155392146dSmillert return (-1);
10168bf92784Sderaadt }
10178bf92784Sderaadt close(p[0]);
10188bf92784Sderaadt if (c == '1')
10198bf92784Sderaadt sp->se_flags |= SE_DEVEXISTS;
10208bf92784Sderaadt else
10218bf92784Sderaadt sp->se_flags |= SE_SHUTDOWN;
10228bf92784Sderaadt }
10235392146dSmillert return (pid);
10248bf92784Sderaadt }
10258bf92784Sderaadt if (new) {
10268bf92784Sderaadt int fd;
10278bf92784Sderaadt
10288bf92784Sderaadt close(p[0]);
1029b7041c07Sderaadt fd = open(sp->se_device, O_RDONLY | O_NONBLOCK);
10308bf92784Sderaadt if (fd == -1 && (errno == ENXIO || errno == ENOENT ||
10318bf92784Sderaadt errno == EISDIR)) {
10328bf92784Sderaadt (void)write(p[1], "0", 1);
10338bf92784Sderaadt close(p[1]);
10348bf92784Sderaadt _exit(1);
10358bf92784Sderaadt }
10368bf92784Sderaadt (void)write(p[1], "1", 1);
10378bf92784Sderaadt close(p[1]);
10388bf92784Sderaadt close(fd);
10398bf92784Sderaadt sleep(1);
10408bf92784Sderaadt }
1041df930be7Sderaadt
1042eb10f49cScheloha if (timespecisset(&sp->se_started)) {
1043eb10f49cScheloha clock_gettime(CLOCK_MONOTONIC, ¤t_time);
1044eb10f49cScheloha timespecsub(¤t_time, &sp->se_started, &elapsed);
1045eb10f49cScheloha if (elapsed.tv_sec < GETTY_SPACING) {
1046eb10f49cScheloha warning(
1047eb10f49cScheloha "getty repeating too quickly on port %s, sleeping",
1048df930be7Sderaadt sp->se_device);
10495d655d40Sderaadt sleep(GETTY_SLEEP);
1050df930be7Sderaadt }
1051eb10f49cScheloha }
1052df930be7Sderaadt
1053df930be7Sderaadt if (sp->se_window) {
1054df930be7Sderaadt start_window_system(sp);
1055df930be7Sderaadt sleep(WINDOW_WAIT);
1056df930be7Sderaadt }
1057df930be7Sderaadt
1058df930be7Sderaadt sigemptyset(&mask);
10597674422fSkstailey sigprocmask(SIG_SETMASK, &mask, NULL);
1060df930be7Sderaadt
1061fed231abSmillert setprocresources(RESOURCE_GETTY);
1062fed231abSmillert
1063df930be7Sderaadt execv(sp->se_getty_argv[0], sp->se_getty_argv);
1064df930be7Sderaadt stall("can't exec getty '%s' for port %s: %m",
1065df930be7Sderaadt sp->se_getty_argv[0], sp->se_device);
1066df930be7Sderaadt _exit(1);
1067df930be7Sderaadt }
1068df930be7Sderaadt
1069df930be7Sderaadt /*
1070df930be7Sderaadt * Collect exit status for a child.
1071df930be7Sderaadt * If an exiting login, start a new login running.
1072df930be7Sderaadt */
1073df930be7Sderaadt void
collect_child(pid_t pid)1074df930be7Sderaadt collect_child(pid_t pid)
1075df930be7Sderaadt {
1076e073c79dSmpech session_t *sp, *sprev, *snext;
1077df930be7Sderaadt
1078824827eeSmillert if (sessions == NULL)
1079df930be7Sderaadt return;
1080df930be7Sderaadt
1081824827eeSmillert if ((sp = find_session(pid)) == NULL)
1082df930be7Sderaadt return;
1083df930be7Sderaadt
1084df930be7Sderaadt clear_session_logs(sp);
108548397f5fSmillert login_fbtab(sp->se_device + sizeof(_PATH_DEV) - 1, 0, 0);
1086df930be7Sderaadt del_session(sp);
1087df930be7Sderaadt sp->se_process = 0;
1088df930be7Sderaadt
1089df930be7Sderaadt if (sp->se_flags & SE_SHUTDOWN) {
10904158ce8dSderaadt if ((sprev = sp->se_prev))
1091df930be7Sderaadt sprev->se_next = sp->se_next;
1092df930be7Sderaadt else
1093df930be7Sderaadt sessions = sp->se_next;
10944158ce8dSderaadt if ((snext = sp->se_next))
1095df930be7Sderaadt snext->se_prev = sp->se_prev;
1096df930be7Sderaadt free_session(sp);
1097df930be7Sderaadt return;
1098df930be7Sderaadt }
1099df930be7Sderaadt
1100df930be7Sderaadt if ((pid = start_getty(sp)) == -1) {
1101df930be7Sderaadt /* serious trouble */
1102df930be7Sderaadt requested_transition = clean_ttys;
1103df930be7Sderaadt return;
1104df930be7Sderaadt }
1105df930be7Sderaadt
1106df930be7Sderaadt sp->se_process = pid;
1107eb10f49cScheloha clock_gettime(CLOCK_MONOTONIC, &sp->se_started);
1108df930be7Sderaadt add_session(sp);
1109df930be7Sderaadt }
1110df930be7Sderaadt
1111df930be7Sderaadt /*
1112df930be7Sderaadt * Catch a signal and request a state transition.
1113df930be7Sderaadt */
1114df930be7Sderaadt void
transition_handler(int sig)1115bc52e260Sderaadt transition_handler(int sig)
1116df930be7Sderaadt {
1117df930be7Sderaadt
1118df930be7Sderaadt switch (sig) {
1119df930be7Sderaadt case SIGHUP:
1120df930be7Sderaadt requested_transition = clean_ttys;
1121df930be7Sderaadt break;
1122bff23b0cSdlg case SIGINT:
1123dee114d4Sdlg requested_transition = do_reboot;
1124dee114d4Sdlg break;
1125df930be7Sderaadt case SIGTERM:
1126df930be7Sderaadt requested_transition = death;
1127df930be7Sderaadt break;
1128ab091da3Sderaadt case SIGUSR1:
1129ab091da3Sderaadt requested_transition = nice_death;
1130ab091da3Sderaadt break;
1131bdbecee4Sderaadt case SIGUSR2:
1132bdbecee4Sderaadt requested_transition = hard_death;
1133bdbecee4Sderaadt break;
1134df930be7Sderaadt case SIGTSTP:
1135df930be7Sderaadt requested_transition = catatonia;
1136df930be7Sderaadt break;
1137df930be7Sderaadt default:
1138df930be7Sderaadt requested_transition = 0;
1139df930be7Sderaadt break;
1140df930be7Sderaadt }
1141df930be7Sderaadt }
1142df930be7Sderaadt
1143df930be7Sderaadt /*
1144df930be7Sderaadt * Take the system multiuser.
1145df930be7Sderaadt */
11465085bfb6Smillert state_t
f_multi_user(void)11475085bfb6Smillert f_multi_user(void)
1148df930be7Sderaadt {
1149df930be7Sderaadt pid_t pid;
1150e073c79dSmpech session_t *sp;
1151df930be7Sderaadt
1152df930be7Sderaadt /*
1153df930be7Sderaadt * If the administrator has not set the security level to -1
1154df930be7Sderaadt * to indicate that the kernel should not run multiuser in secure
1155df930be7Sderaadt * mode, and the run script has not set a higher level of security
1156df930be7Sderaadt * than level 1, then put the kernel into secure mode.
1157df930be7Sderaadt */
1158ec7f310bSmillert if (requested_transition != catatonia) {
1159df930be7Sderaadt if (getsecuritylevel() == 0)
1160df930be7Sderaadt setsecuritylevel(1);
1161ec7f310bSmillert }
1162ec7f310bSmillert
1163ec7f310bSmillert requested_transition = 0;
1164df930be7Sderaadt
1165df930be7Sderaadt for (sp = sessions; sp; sp = sp->se_next) {
1166df930be7Sderaadt if (sp->se_process)
1167df930be7Sderaadt continue;
1168df930be7Sderaadt if ((pid = start_getty(sp)) == -1) {
1169df930be7Sderaadt /* serious trouble */
1170df930be7Sderaadt requested_transition = clean_ttys;
1171df930be7Sderaadt break;
1172df930be7Sderaadt }
1173df930be7Sderaadt sp->se_process = pid;
1174eb10f49cScheloha clock_gettime(CLOCK_MONOTONIC, &sp->se_started);
1175df930be7Sderaadt add_session(sp);
1176df930be7Sderaadt }
1177df930be7Sderaadt
1178df930be7Sderaadt while (!requested_transition)
11797674422fSkstailey if ((pid = waitpid(-1, NULL, 0)) != -1)
1180df930be7Sderaadt collect_child(pid);
1181df930be7Sderaadt
11825085bfb6Smillert return requested_transition;
1183df930be7Sderaadt }
1184df930be7Sderaadt
1185df930be7Sderaadt /*
1186df930be7Sderaadt * This is an n-squared algorithm. We hope it isn't run often...
1187df930be7Sderaadt */
11885085bfb6Smillert state_t
f_clean_ttys(void)11895085bfb6Smillert f_clean_ttys(void)
1190df930be7Sderaadt {
1191e073c79dSmpech session_t *sp, *sprev;
1192e073c79dSmpech struct ttyent *typ;
1193e073c79dSmpech int session_index = 0;
1194e073c79dSmpech int devlen;
1195df930be7Sderaadt
1196df930be7Sderaadt for (sp = sessions; sp; sp = sp->se_next)
1197df930be7Sderaadt sp->se_flags &= ~SE_PRESENT;
1198df930be7Sderaadt
1199df930be7Sderaadt devlen = sizeof(_PATH_DEV) - 1;
12004158ce8dSderaadt while ((typ = getttyent())) {
1201df930be7Sderaadt ++session_index;
1202df930be7Sderaadt
1203f52a7f8cSmmcc for (sprev = NULL, sp = sessions; sp; sprev = sp, sp = sp->se_next)
1204df930be7Sderaadt if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)
1205df930be7Sderaadt break;
1206df930be7Sderaadt
1207df930be7Sderaadt if (sp) {
1208df930be7Sderaadt sp->se_flags |= SE_PRESENT;
1209df930be7Sderaadt if (sp->se_index != session_index) {
1210df930be7Sderaadt warning("port %s changed utmp index from %d to %d",
1211df930be7Sderaadt sp->se_device, sp->se_index,
1212df930be7Sderaadt session_index);
1213df930be7Sderaadt sp->se_index = session_index;
1214df930be7Sderaadt }
1215df930be7Sderaadt if ((typ->ty_status & TTY_ON) == 0 ||
1216df930be7Sderaadt typ->ty_getty == 0) {
1217df930be7Sderaadt sp->se_flags |= SE_SHUTDOWN;
1218df930be7Sderaadt kill(sp->se_process, SIGHUP);
1219df930be7Sderaadt continue;
1220df930be7Sderaadt }
1221df930be7Sderaadt sp->se_flags &= ~SE_SHUTDOWN;
1222df930be7Sderaadt if (setupargv(sp, typ) == 0) {
1223df930be7Sderaadt warning("can't parse getty for port %s",
1224df930be7Sderaadt sp->se_device);
1225df930be7Sderaadt sp->se_flags |= SE_SHUTDOWN;
1226df930be7Sderaadt kill(sp->se_process, SIGHUP);
1227df930be7Sderaadt }
1228df930be7Sderaadt continue;
1229df930be7Sderaadt }
1230df930be7Sderaadt
1231df930be7Sderaadt new_session(sprev, session_index, typ);
1232df930be7Sderaadt }
1233df930be7Sderaadt
1234df930be7Sderaadt endttyent();
1235df930be7Sderaadt
1236df930be7Sderaadt for (sp = sessions; sp; sp = sp->se_next)
1237df930be7Sderaadt if ((sp->se_flags & SE_PRESENT) == 0) {
1238df930be7Sderaadt sp->se_flags |= SE_SHUTDOWN;
1239df930be7Sderaadt kill(sp->se_process, SIGHUP);
1240df930be7Sderaadt }
1241df930be7Sderaadt
12425085bfb6Smillert return multi_user;
1243df930be7Sderaadt }
1244df930be7Sderaadt
1245df930be7Sderaadt /*
1246df930be7Sderaadt * Block further logins.
1247df930be7Sderaadt */
12485085bfb6Smillert state_t
f_catatonia(void)12495085bfb6Smillert f_catatonia(void)
1250df930be7Sderaadt {
1251e073c79dSmpech session_t *sp;
1252df930be7Sderaadt
1253df930be7Sderaadt for (sp = sessions; sp; sp = sp->se_next)
1254df930be7Sderaadt sp->se_flags |= SE_SHUTDOWN;
1255df930be7Sderaadt
12565085bfb6Smillert return multi_user;
1257df930be7Sderaadt }
1258df930be7Sderaadt
1259df930be7Sderaadt /*
1260df930be7Sderaadt * Note SIGALRM.
1261df930be7Sderaadt */
1262df930be7Sderaadt void
alrm_handler(int sig)1263bc52e260Sderaadt alrm_handler(int sig)
1264df930be7Sderaadt {
1265df930be7Sderaadt clang = 1;
1266df930be7Sderaadt }
1267df930be7Sderaadt
1268bdbecee4Sderaadt int death_howto = RB_HALT;
1269bdbecee4Sderaadt
1270bdbecee4Sderaadt /*
1271dee114d4Sdlg * Reboot the system.
1272dee114d4Sdlg */
12735085bfb6Smillert state_t
f_do_reboot(void)12745085bfb6Smillert f_do_reboot(void)
1275dee114d4Sdlg {
1276dee114d4Sdlg death_howto = RB_AUTOBOOT;
12775085bfb6Smillert return nice_death;
1278dee114d4Sdlg }
1279dee114d4Sdlg
1280dee114d4Sdlg /*
1281bdbecee4Sderaadt * Bring the system down nicely, then we must powerdown because something
1282bdbecee4Sderaadt * is very wrong.
1283bdbecee4Sderaadt */
12845085bfb6Smillert state_t
f_hard_death(void)12855085bfb6Smillert f_hard_death(void)
1286bdbecee4Sderaadt {
1287bdbecee4Sderaadt death_howto |= RB_POWERDOWN;
12885085bfb6Smillert return nice_death;
1289bdbecee4Sderaadt }
1290bdbecee4Sderaadt
1291ab091da3Sderaadt /*
1292ab091da3Sderaadt * Bring the system down to single user nicely, after run the shutdown script.
1293ab091da3Sderaadt */
12945085bfb6Smillert state_t
f_nice_death(void)12955085bfb6Smillert f_nice_death(void)
1296ab091da3Sderaadt {
1297e073c79dSmpech session_t *sp;
1298e073c79dSmpech int i;
1299ab091da3Sderaadt pid_t pid;
1300ab091da3Sderaadt static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL };
1301ab091da3Sderaadt int status;
1302ab091da3Sderaadt
130302638669Snatano #ifdef CPU_LIDACTION
13042d357aedSnatano int mib[] = {CTL_MACHDEP, CPU_LIDACTION};
13052d357aedSnatano int lidaction = 0;
1306d51453aaSphessler
1307d51453aaSphessler if ((death_howto & RB_POWERDOWN) &&
13082d357aedSnatano (sysctl(mib, 2, NULL, NULL, &lidaction,
13092d357aedSnatano sizeof(lidaction)) == -1) && (errno != EOPNOTSUPP))
13102d357aedSnatano warning("cannot disable lid action");
1311d51453aaSphessler #endif
1312d51453aaSphessler
1313ab091da3Sderaadt for (sp = sessions; sp; sp = sp->se_next) {
1314ab091da3Sderaadt sp->se_flags &= ~SE_PRESENT;
1315ab091da3Sderaadt sp->se_flags |= SE_SHUTDOWN;
1316ab091da3Sderaadt kill(sp->se_process, SIGHUP);
1317ab091da3Sderaadt }
1318ab091da3Sderaadt
1319ae1c47a4Smarkus /* terminate the accounting process */
1320ae1c47a4Smarkus acct(NULL);
1321ae1c47a4Smarkus
1322ab091da3Sderaadt /* NB: should send a message to the session logger to avoid blocking. */
1323ab091da3Sderaadt logwtmp("~", "shutdown", "");
1324ab091da3Sderaadt
132575a54d2eSderaadt if (access(_PATH_RUNCOM, R_OK) != -1) {
1326ab091da3Sderaadt struct sigaction sa;
1327ab091da3Sderaadt
1328ab091da3Sderaadt switch ((pid = fork())) {
1329ab091da3Sderaadt case -1:
1330ab091da3Sderaadt break;
1331ab091da3Sderaadt case 0:
1332ab091da3Sderaadt
1333ab091da3Sderaadt memset(&sa, 0, sizeof sa);
1334ab091da3Sderaadt sigemptyset(&sa.sa_mask);
1335ab091da3Sderaadt sa.sa_flags = 0;
1336ab091da3Sderaadt sa.sa_handler = SIG_IGN;
1337ab091da3Sderaadt (void) sigaction(SIGTSTP, &sa, NULL);
1338ab091da3Sderaadt (void) sigaction(SIGHUP, &sa, NULL);
1339ab091da3Sderaadt
1340ab091da3Sderaadt setctty(_PATH_CONSOLE);
1341ab091da3Sderaadt
1342ab091da3Sderaadt sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);
1343ab091da3Sderaadt
134475a54d2eSderaadt execl(_PATH_BSHELL, "sh", _PATH_RUNCOM, "shutdown",
1345c96f6a27Sderaadt (char *)NULL);
134675a54d2eSderaadt stall("can't exec %s for %s %s: %m", _PATH_BSHELL,
134775a54d2eSderaadt _PATH_RUNCOM, "shutdown");
1348ab091da3Sderaadt _exit(1);
1349ab091da3Sderaadt default:
1350ab091da3Sderaadt waitpid(pid, &status, 0);
1351ab091da3Sderaadt if (WIFEXITED(status) && WEXITSTATUS(status) == 2)
1352bdbecee4Sderaadt death_howto |= RB_POWERDOWN;
1353ab091da3Sderaadt }
1354ab091da3Sderaadt }
1355ab091da3Sderaadt
1356ab091da3Sderaadt for (i = 0; i < 3; ++i) {
1357ab091da3Sderaadt if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
1358ab091da3Sderaadt goto die;
1359ab091da3Sderaadt
1360ab091da3Sderaadt clang = 0;
1361ab091da3Sderaadt alarm(DEATH_WATCH);
1362b5e17218Sderaadt do {
1363ab091da3Sderaadt if ((pid = waitpid(-1, NULL, 0)) != -1)
1364ab091da3Sderaadt collect_child(pid);
1365b5e17218Sderaadt } while (clang == 0 && errno != ECHILD);
1366ab091da3Sderaadt
1367ab091da3Sderaadt if (errno == ECHILD)
1368ab091da3Sderaadt goto die;
1369ab091da3Sderaadt }
1370ab091da3Sderaadt
1371ab091da3Sderaadt warning("some processes would not die; ps axl advised");
1372ab091da3Sderaadt
1373ab091da3Sderaadt die:
1374bdbecee4Sderaadt reboot(death_howto);
1375ab091da3Sderaadt
1376ab091da3Sderaadt /* ... and if that fails.. oh well */
13775085bfb6Smillert return single_user;
1378ab091da3Sderaadt }
1379ab091da3Sderaadt
1380df930be7Sderaadt /*
1381df930be7Sderaadt * Bring the system down to single user.
1382df930be7Sderaadt */
13835085bfb6Smillert state_t
f_death(void)13845085bfb6Smillert f_death(void)
1385df930be7Sderaadt {
1386e073c79dSmpech session_t *sp;
1387e073c79dSmpech int i;
1388df930be7Sderaadt pid_t pid;
1389df930be7Sderaadt static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL };
1390df930be7Sderaadt
1391ae1c47a4Smarkus /* terminate the accounting process */
1392ae1c47a4Smarkus acct(NULL);
1393ae1c47a4Smarkus
1394df930be7Sderaadt for (sp = sessions; sp; sp = sp->se_next)
1395df930be7Sderaadt sp->se_flags |= SE_SHUTDOWN;
1396df930be7Sderaadt
1397df930be7Sderaadt /* NB: should send a message to the session logger to avoid blocking. */
1398df930be7Sderaadt logwtmp("~", "shutdown", "");
1399df930be7Sderaadt
1400df930be7Sderaadt for (i = 0; i < 3; ++i) {
1401df930be7Sderaadt if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
14025085bfb6Smillert return single_user;
1403df930be7Sderaadt
1404df930be7Sderaadt clang = 0;
1405df930be7Sderaadt alarm(DEATH_WATCH);
1406b5e17218Sderaadt do {
14077674422fSkstailey if ((pid = waitpid(-1, NULL, 0)) != -1)
1408df930be7Sderaadt collect_child(pid);
1409b5e17218Sderaadt } while (clang == 0 && errno != ECHILD);
1410df930be7Sderaadt
1411df930be7Sderaadt if (errno == ECHILD)
14125085bfb6Smillert return single_user;
1413df930be7Sderaadt }
1414df930be7Sderaadt
1415df930be7Sderaadt warning("some processes would not die; ps axl advised");
1416df930be7Sderaadt
14175085bfb6Smillert return single_user;
1418df930be7Sderaadt }
1419fed231abSmillert
1420fed231abSmillert void
setprocresources(char * class)1421bc52e260Sderaadt setprocresources(char *class)
1422fed231abSmillert {
1423fed231abSmillert login_cap_t *lc;
1424fed231abSmillert
1425fed231abSmillert if ((lc = login_getclass(class)) != NULL) {
1426fed231abSmillert setusercontext(lc, NULL, 0,
1427fed231abSmillert LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
1428fed231abSmillert login_close(lc);
1429fed231abSmillert }
1430fed231abSmillert }
1431