1*0a6a1f1dSLionel Sambuc /* $NetBSD: init.c,v 1.106 2015/06/16 23:18:55 christos Exp $ */
2a06e2ab3SBen Gras
3a06e2ab3SBen Gras /*-
4a06e2ab3SBen Gras * Copyright (c) 1991, 1993
5a06e2ab3SBen Gras * The Regents of the University of California. All rights reserved.
6a06e2ab3SBen Gras *
7a06e2ab3SBen Gras * This code is derived from software contributed to Berkeley by
8a06e2ab3SBen Gras * Donn Seeley at Berkeley Software Design, Inc.
9a06e2ab3SBen Gras *
10a06e2ab3SBen Gras * Redistribution and use in source and binary forms, with or without
11a06e2ab3SBen Gras * modification, are permitted provided that the following conditions
12a06e2ab3SBen Gras * are met:
13a06e2ab3SBen Gras * 1. Redistributions of source code must retain the above copyright
14a06e2ab3SBen Gras * notice, this list of conditions and the following disclaimer.
15a06e2ab3SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
16a06e2ab3SBen Gras * notice, this list of conditions and the following disclaimer in the
17a06e2ab3SBen Gras * documentation and/or other materials provided with the distribution.
18a06e2ab3SBen Gras * 3. Neither the name of the University nor the names of its contributors
19a06e2ab3SBen Gras * may be used to endorse or promote products derived from this software
20a06e2ab3SBen Gras * without specific prior written permission.
21a06e2ab3SBen Gras *
22a06e2ab3SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23a06e2ab3SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24a06e2ab3SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25a06e2ab3SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26a06e2ab3SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27a06e2ab3SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28a06e2ab3SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29a06e2ab3SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30a06e2ab3SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31a06e2ab3SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32a06e2ab3SBen Gras * SUCH DAMAGE.
33a06e2ab3SBen Gras */
34a06e2ab3SBen Gras
35a06e2ab3SBen Gras #include <sys/cdefs.h>
36a06e2ab3SBen Gras #ifndef lint
37a06e2ab3SBen Gras __COPYRIGHT("@(#) Copyright (c) 1991, 1993\
38a06e2ab3SBen Gras The Regents of the University of California. All rights reserved.");
39a06e2ab3SBen Gras #endif /* not lint */
40a06e2ab3SBen Gras
41a06e2ab3SBen Gras #ifndef lint
42a06e2ab3SBen Gras #if 0
43a06e2ab3SBen Gras static char sccsid[] = "@(#)init.c 8.2 (Berkeley) 4/28/95";
44a06e2ab3SBen Gras #else
45*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: init.c,v 1.106 2015/06/16 23:18:55 christos Exp $");
46a06e2ab3SBen Gras #endif
47a06e2ab3SBen Gras #endif /* not lint */
48a06e2ab3SBen Gras
49a06e2ab3SBen Gras #include <sys/param.h>
50a06e2ab3SBen Gras #include <sys/sysctl.h>
51a06e2ab3SBen Gras #include <sys/wait.h>
52a06e2ab3SBen Gras #include <sys/mman.h>
53a06e2ab3SBen Gras #include <sys/stat.h>
54a06e2ab3SBen Gras #include <sys/mount.h>
55a06e2ab3SBen Gras #include <machine/cpu.h>
56a06e2ab3SBen Gras
57a06e2ab3SBen Gras #include <db.h>
58a06e2ab3SBen Gras #include <errno.h>
59a06e2ab3SBen Gras #include <fcntl.h>
60a06e2ab3SBen Gras #include <signal.h>
61a06e2ab3SBen Gras #include <stdio.h>
62a06e2ab3SBen Gras #include <stdlib.h>
63a06e2ab3SBen Gras #include <string.h>
64a06e2ab3SBen Gras #include <syslog.h>
65a06e2ab3SBen Gras #include <time.h>
66a06e2ab3SBen Gras #include <ttyent.h>
67a06e2ab3SBen Gras #include <unistd.h>
68a06e2ab3SBen Gras #include <util.h>
69a06e2ab3SBen Gras #include <paths.h>
70a06e2ab3SBen Gras #include <err.h>
7184d9c625SLionel Sambuc #ifdef SUPPORT_UTMP
7284d9c625SLionel Sambuc #include <utmp.h>
7384d9c625SLionel Sambuc #endif
7484d9c625SLionel Sambuc #ifdef SUPPORT_UTMPX
7584d9c625SLionel Sambuc #include <utmpx.h>
7684d9c625SLionel Sambuc #endif
77a06e2ab3SBen Gras
78a06e2ab3SBen Gras #include <stdarg.h>
79a06e2ab3SBen Gras
80a06e2ab3SBen Gras #ifdef SECURE
81a06e2ab3SBen Gras #include <pwd.h>
82a06e2ab3SBen Gras #endif
83a06e2ab3SBen Gras
84a06e2ab3SBen Gras #include "pathnames.h"
85a06e2ab3SBen Gras
86a06e2ab3SBen Gras #define XSTR(x) #x
87a06e2ab3SBen Gras #define STR(x) XSTR(x)
88a06e2ab3SBen Gras
89a06e2ab3SBen Gras /*
90a06e2ab3SBen Gras * Sleep times; used to prevent thrashing.
91a06e2ab3SBen Gras */
92a06e2ab3SBen Gras #define GETTY_SPACING 5 /* N secs minimum getty spacing */
93a06e2ab3SBen Gras #define GETTY_SLEEP 30 /* sleep N secs after spacing problem */
94a06e2ab3SBen Gras #define WINDOW_WAIT 3 /* wait N secs after starting window */
95a06e2ab3SBen Gras #define STALL_TIMEOUT 30 /* wait N secs after warning */
96a06e2ab3SBen Gras #define DEATH_WATCH 10 /* wait N secs for procs to die */
97a06e2ab3SBen Gras
98a06e2ab3SBen Gras static const struct timespec dtrtime = {.tv_sec = 0, .tv_nsec = 250000};
99a06e2ab3SBen Gras
100a06e2ab3SBen Gras #if defined(RESCUEDIR)
101a06e2ab3SBen Gras #define INIT_BSHELL RESCUEDIR "/sh"
102a06e2ab3SBen Gras #define INIT_MOUNT_MFS RESCUEDIR "/mount_mfs"
103a06e2ab3SBen Gras #define INIT_PATH RESCUEDIR ":" _PATH_STDPATH
104a06e2ab3SBen Gras #else
105a06e2ab3SBen Gras #define INIT_BSHELL _PATH_BSHELL
106a06e2ab3SBen Gras #define INIT_MOUNT_MFS "/sbin/mount_mfs"
107a06e2ab3SBen Gras #define INIT_PATH _PATH_STDPATH
108a06e2ab3SBen Gras #endif
109a06e2ab3SBen Gras
110a06e2ab3SBen Gras static void handle(sig_t, ...);
111a06e2ab3SBen Gras static void delset(sigset_t *, ...);
112a06e2ab3SBen Gras
113a06e2ab3SBen Gras static void stall(const char *, ...) __printflike(1, 2);
114a06e2ab3SBen Gras static void warning(const char *, ...) __printflike(1, 2);
115a06e2ab3SBen Gras static void emergency(const char *, ...) __printflike(1, 2);
116a06e2ab3SBen Gras __dead static void disaster(int);
117a06e2ab3SBen Gras
11884d9c625SLionel Sambuc #if defined(__minix)
119a06e2ab3SBen Gras static void minixreboot(int);
120a06e2ab3SBen Gras static void minixpowerdown(int);
12184d9c625SLionel Sambuc #else
122a06e2ab3SBen Gras static void badsys(int);
12384d9c625SLionel Sambuc #endif /* defined(__minix) */
124a06e2ab3SBen Gras
125a06e2ab3SBen Gras /*
126a06e2ab3SBen Gras * We really need a recursive typedef...
127a06e2ab3SBen Gras * The following at least guarantees that the return type of (*state_t)()
128a06e2ab3SBen Gras * is sufficiently wide to hold a function pointer.
129a06e2ab3SBen Gras */
130a06e2ab3SBen Gras typedef long (*state_func_t)(void);
131a06e2ab3SBen Gras typedef state_func_t (*state_t)(void);
132a06e2ab3SBen Gras
133a06e2ab3SBen Gras #define DEATH 'd'
134a06e2ab3SBen Gras #define SINGLE_USER 's'
135a06e2ab3SBen Gras #define RUNCOM 'r'
136a06e2ab3SBen Gras #define READ_TTYS 't'
137a06e2ab3SBen Gras #define MULTI_USER 'm'
138a06e2ab3SBen Gras #define CLEAN_TTYS 'T'
139a06e2ab3SBen Gras #define CATATONIA 'c'
140a06e2ab3SBen Gras
141a06e2ab3SBen Gras static state_func_t single_user(void);
142a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
143a06e2ab3SBen Gras static state_func_t runcom(void);
144a06e2ab3SBen Gras static state_func_t read_ttys(void);
145a06e2ab3SBen Gras static state_func_t multi_user(void);
146a06e2ab3SBen Gras static state_func_t clean_ttys(void);
147a06e2ab3SBen Gras static state_func_t catatonia(void);
148a06e2ab3SBen Gras static state_func_t death(void);
149a06e2ab3SBen Gras #endif
150a06e2ab3SBen Gras
151a06e2ab3SBen Gras static enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT;
152a06e2ab3SBen Gras
153a06e2ab3SBen Gras static void transition(state_t);
154a06e2ab3SBen Gras static void setctty(const char *);
155a06e2ab3SBen Gras
156a06e2ab3SBen Gras typedef struct init_session {
157a06e2ab3SBen Gras int se_index; /* index of entry in ttys file */
158a06e2ab3SBen Gras pid_t se_process; /* controlling process */
159a06e2ab3SBen Gras struct timeval se_started; /* used to avoid thrashing */
160a06e2ab3SBen Gras int se_flags; /* status of session */
161a06e2ab3SBen Gras #define SE_SHUTDOWN 0x1 /* session won't be restarted */
162a06e2ab3SBen Gras #define SE_PRESENT 0x2 /* session is in /etc/ttys */
163a06e2ab3SBen Gras char *se_device; /* filename of port */
164a06e2ab3SBen Gras char *se_getty; /* what to run on that port */
165a06e2ab3SBen Gras char **se_getty_argv; /* pre-parsed argument array */
166a06e2ab3SBen Gras char *se_window; /* window system (started only once) */
167a06e2ab3SBen Gras char **se_window_argv; /* pre-parsed argument array */
168a06e2ab3SBen Gras struct init_session *se_prev;
169a06e2ab3SBen Gras struct init_session *se_next;
170a06e2ab3SBen Gras } session_t;
171a06e2ab3SBen Gras
172a06e2ab3SBen Gras static void collect_child(pid_t, int);
173a06e2ab3SBen Gras static int clang;
174a06e2ab3SBen Gras static void transition_handler(int);
175a06e2ab3SBen Gras static void alrm_handler(int);
176a06e2ab3SBen Gras static int has_securelevel(void);
177a06e2ab3SBen Gras static int securelevel_present;
178a06e2ab3SBen Gras
179a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
180a06e2ab3SBen Gras static int do_setttyent(void);
181a06e2ab3SBen Gras static void start_window_system(session_t *);
182a06e2ab3SBen Gras static char **construct_argv(char *);
183a06e2ab3SBen Gras static int setupargv(session_t *, struct ttyent *);
184a06e2ab3SBen Gras static pid_t start_getty(session_t *);
185a06e2ab3SBen Gras static void free_session(session_t *);
186a06e2ab3SBen Gras static session_t *new_session(session_t *, int, struct ttyent *);
187a06e2ab3SBen Gras static session_t *sessions;
188a06e2ab3SBen Gras static void setsecuritylevel(int);
189a06e2ab3SBen Gras static int getsecuritylevel(void);
190a06e2ab3SBen Gras static int start_session_db(void);
191a06e2ab3SBen Gras static void add_session(session_t *);
192a06e2ab3SBen Gras static void del_session(session_t *);
193a06e2ab3SBen Gras static session_t *find_session(pid_t);
194a06e2ab3SBen Gras static DB *session_db;
195a06e2ab3SBen Gras static state_t requested_transition = runcom;
196a06e2ab3SBen Gras
197a06e2ab3SBen Gras static void clear_session_logs(session_t *, int);
198a06e2ab3SBen Gras static state_func_t runetcrc(int);
199a06e2ab3SBen Gras #ifdef SUPPORT_UTMPX
200a06e2ab3SBen Gras static struct timeval boot_time;
201a06e2ab3SBen Gras static state_t current_state = death;
202a06e2ab3SBen Gras static void session_utmpx(const session_t *, int);
203a06e2ab3SBen Gras static void make_utmpx(const char *, const char *, int, pid_t,
204a06e2ab3SBen Gras const struct timeval *, int);
205a06e2ab3SBen Gras static char get_runlevel(const state_t);
206a06e2ab3SBen Gras static void utmpx_set_runlevel(char, char);
207a06e2ab3SBen Gras #endif
208a06e2ab3SBen Gras
209a06e2ab3SBen Gras #ifdef CHROOT
210a06e2ab3SBen Gras static int did_multiuser_chroot = 0;
211a06e2ab3SBen Gras static char rootdir[PATH_MAX];
212a06e2ab3SBen Gras static int shouldchroot(void);
213a06e2ab3SBen Gras static int createsysctlnode(void);
214a06e2ab3SBen Gras #endif /* CHROOT */
215a06e2ab3SBen Gras
216a06e2ab3SBen Gras #else /* LETS_GET_SMALL */
217a06e2ab3SBen Gras static state_t requested_transition = single_user;
218a06e2ab3SBen Gras #endif /* !LETS_GET_SMALL */
219a06e2ab3SBen Gras
220a06e2ab3SBen Gras #ifdef MFS_DEV_IF_NO_CONSOLE
221a06e2ab3SBen Gras
222a06e2ab3SBen Gras static int mfs_dev(void);
223a06e2ab3SBen Gras
224a06e2ab3SBen Gras #endif
225a06e2ab3SBen Gras
226a06e2ab3SBen Gras /*
227a06e2ab3SBen Gras * The mother of all processes.
228a06e2ab3SBen Gras */
229a06e2ab3SBen Gras int
main(int argc,char ** argv)230a06e2ab3SBen Gras main(int argc, char **argv)
231a06e2ab3SBen Gras {
232a06e2ab3SBen Gras struct sigaction sa;
233a06e2ab3SBen Gras sigset_t mask;
234a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
235a06e2ab3SBen Gras int c;
236a06e2ab3SBen Gras
237a06e2ab3SBen Gras #ifdef SUPPORT_UTMPX
238a06e2ab3SBen Gras (void)gettimeofday(&boot_time, NULL);
239a06e2ab3SBen Gras #endif /* SUPPORT_UTMPX */
240a06e2ab3SBen Gras
241a06e2ab3SBen Gras /* Dispose of random users. */
242a06e2ab3SBen Gras if (getuid() != 0) {
243a06e2ab3SBen Gras errno = EPERM;
244a06e2ab3SBen Gras err(1, NULL);
245a06e2ab3SBen Gras }
246a06e2ab3SBen Gras
247a06e2ab3SBen Gras /* System V users like to reexec init. */
248a06e2ab3SBen Gras if (getpid() != 1)
249a06e2ab3SBen Gras errx(1, "already running");
250a06e2ab3SBen Gras #endif
251a06e2ab3SBen Gras
252a06e2ab3SBen Gras /*
253a06e2ab3SBen Gras * Create an initial session.
254a06e2ab3SBen Gras */
255a06e2ab3SBen Gras if (setsid() < 0)
256a06e2ab3SBen Gras warn("initial setsid() failed");
257a06e2ab3SBen Gras
258a06e2ab3SBen Gras /*
259a06e2ab3SBen Gras * Establish an initial user so that programs running
260a06e2ab3SBen Gras * single user do not freak out and die (like passwd).
261a06e2ab3SBen Gras */
26284d9c625SLionel Sambuc #if !defined(__minix)
263a06e2ab3SBen Gras if (setlogin("root") < 0)
264a06e2ab3SBen Gras warn("setlogin() failed");
26584d9c625SLionel Sambuc #endif /* !defined(__minix) */
266a06e2ab3SBen Gras
267a06e2ab3SBen Gras
268a06e2ab3SBen Gras #ifdef MFS_DEV_IF_NO_CONSOLE
269a06e2ab3SBen Gras if (mfs_dev() == -1)
270a06e2ab3SBen Gras requested_transition = single_user;
271a06e2ab3SBen Gras #endif
272a06e2ab3SBen Gras
273a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
274a06e2ab3SBen Gras /*
275a06e2ab3SBen Gras * Note that this does NOT open a file...
276a06e2ab3SBen Gras * Does 'init' deserve its own facility number?
277a06e2ab3SBen Gras */
278a06e2ab3SBen Gras openlog("init", LOG_CONS, LOG_AUTH);
279a06e2ab3SBen Gras #endif /* LETS_GET_SMALL */
280a06e2ab3SBen Gras
281a06e2ab3SBen Gras
282a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
283a06e2ab3SBen Gras /*
284a06e2ab3SBen Gras * This code assumes that we always get arguments through flags,
285a06e2ab3SBen Gras * never through bits set in some random machine register.
286a06e2ab3SBen Gras */
287a06e2ab3SBen Gras while ((c = getopt(argc, argv, "sf")) != -1)
288a06e2ab3SBen Gras switch (c) {
289a06e2ab3SBen Gras case 's':
290a06e2ab3SBen Gras requested_transition = single_user;
291a06e2ab3SBen Gras break;
292a06e2ab3SBen Gras case 'f':
293a06e2ab3SBen Gras runcom_mode = FASTBOOT;
294a06e2ab3SBen Gras break;
295a06e2ab3SBen Gras default:
296a06e2ab3SBen Gras warning("unrecognized flag `%c'", c);
297a06e2ab3SBen Gras break;
298a06e2ab3SBen Gras }
299a06e2ab3SBen Gras
300a06e2ab3SBen Gras if (optind != argc)
301a06e2ab3SBen Gras warning("ignoring excess arguments");
302a06e2ab3SBen Gras #else /* LETS_GET_SMALL */
303a06e2ab3SBen Gras requested_transition = single_user;
304a06e2ab3SBen Gras #endif /* LETS_GET_SMALL */
305a06e2ab3SBen Gras
306a06e2ab3SBen Gras /*
307a06e2ab3SBen Gras * We catch or block signals rather than ignore them,
308a06e2ab3SBen Gras * so that they get reset on exec.
309a06e2ab3SBen Gras */
31084d9c625SLionel Sambuc #if !defined(__minix)
311a06e2ab3SBen Gras handle(badsys, SIGSYS, 0);
312a06e2ab3SBen Gras handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV,
313a06e2ab3SBen Gras SIGBUS, SIGXCPU, SIGXFSZ, 0);
314a06e2ab3SBen Gras #else
315a06e2ab3SBen Gras handle(minixreboot, SIGABRT, 0);
316a06e2ab3SBen Gras handle(minixpowerdown, SIGUSR1, 0);
317a06e2ab3SBen Gras handle(disaster, SIGFPE, SIGILL, SIGSEGV, SIGBUS, 0);
31884d9c625SLionel Sambuc #endif /* !defined(__minix) */
319a06e2ab3SBen Gras handle(transition_handler, SIGHUP, SIGTERM, SIGTSTP, 0);
320a06e2ab3SBen Gras handle(alrm_handler, SIGALRM, 0);
321a06e2ab3SBen Gras (void)sigfillset(&mask);
32284d9c625SLionel Sambuc #if !defined(__minix)
323a06e2ab3SBen Gras delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS,
324a06e2ab3SBen Gras SIGXCPU, SIGXFSZ, SIGHUP, SIGTERM, SIGTSTP, SIGALRM, 0);
325a06e2ab3SBen Gras #else
326a06e2ab3SBen Gras delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS,
327a06e2ab3SBen Gras SIGHUP, SIGTERM, SIGTSTP, SIGALRM, 0);
32884d9c625SLionel Sambuc #endif /* !defined(__minix) */
329a06e2ab3SBen Gras (void)sigprocmask(SIG_SETMASK, &mask, NULL);
330a06e2ab3SBen Gras (void)sigemptyset(&sa.sa_mask);
331a06e2ab3SBen Gras sa.sa_flags = 0;
332a06e2ab3SBen Gras sa.sa_handler = SIG_IGN;
333a06e2ab3SBen Gras (void)sigaction(SIGTTIN, &sa, NULL);
334a06e2ab3SBen Gras (void)sigaction(SIGTTOU, &sa, NULL);
335a06e2ab3SBen Gras
336a06e2ab3SBen Gras /*
337a06e2ab3SBen Gras * Paranoia.
338a06e2ab3SBen Gras */
339a06e2ab3SBen Gras (void)close(0);
340a06e2ab3SBen Gras (void)close(1);
341a06e2ab3SBen Gras (void)close(2);
342a06e2ab3SBen Gras
343a06e2ab3SBen Gras #if !defined(LETS_GET_SMALL) && defined(CHROOT)
344a06e2ab3SBen Gras /* Create "init.root" sysctl node. */
345a06e2ab3SBen Gras (void)createsysctlnode();
346a06e2ab3SBen Gras #endif /* !LETS_GET_SMALL && CHROOT*/
347a06e2ab3SBen Gras
348a06e2ab3SBen Gras /*
349a06e2ab3SBen Gras * Securelevel might not be supported by the kernel. Query for it, and
350a06e2ab3SBen Gras * set a variable indicating whether we should attempt anything with it
351a06e2ab3SBen Gras * or not.
352a06e2ab3SBen Gras */
353a06e2ab3SBen Gras securelevel_present = has_securelevel();
354a06e2ab3SBen Gras
355a06e2ab3SBen Gras /*
356a06e2ab3SBen Gras * Start the state machine.
357a06e2ab3SBen Gras */
358a06e2ab3SBen Gras transition(requested_transition);
359a06e2ab3SBen Gras
360a06e2ab3SBen Gras /*
361a06e2ab3SBen Gras * Should never reach here.
362a06e2ab3SBen Gras */
363a06e2ab3SBen Gras return 1;
364a06e2ab3SBen Gras }
365a06e2ab3SBen Gras
366a06e2ab3SBen Gras /*
367a06e2ab3SBen Gras * Associate a function with a signal handler.
368a06e2ab3SBen Gras */
369a06e2ab3SBen Gras static void
handle(sig_t handler,...)370a06e2ab3SBen Gras handle(sig_t handler, ...)
371a06e2ab3SBen Gras {
372a06e2ab3SBen Gras int sig;
373a06e2ab3SBen Gras struct sigaction sa;
374a06e2ab3SBen Gras sigset_t mask_everything;
375a06e2ab3SBen Gras va_list ap;
376a06e2ab3SBen Gras
377a06e2ab3SBen Gras va_start(ap, handler);
378a06e2ab3SBen Gras
379a06e2ab3SBen Gras sa.sa_handler = handler;
380a06e2ab3SBen Gras (void)sigfillset(&mask_everything);
381a06e2ab3SBen Gras
382a06e2ab3SBen Gras while ((sig = va_arg(ap, int)) != 0) {
383a06e2ab3SBen Gras sa.sa_mask = mask_everything;
384a06e2ab3SBen Gras /* XXX SA_RESTART? */
385a06e2ab3SBen Gras sa.sa_flags = sig == SIGCHLD ? SA_NOCLDSTOP : 0;
386a06e2ab3SBen Gras (void)sigaction(sig, &sa, NULL);
387a06e2ab3SBen Gras }
388a06e2ab3SBen Gras va_end(ap);
389a06e2ab3SBen Gras }
390a06e2ab3SBen Gras
391a06e2ab3SBen Gras /*
392a06e2ab3SBen Gras * Delete a set of signals from a mask.
393a06e2ab3SBen Gras */
394a06e2ab3SBen Gras static void
delset(sigset_t * maskp,...)395a06e2ab3SBen Gras delset(sigset_t *maskp, ...)
396a06e2ab3SBen Gras {
397a06e2ab3SBen Gras int sig;
398a06e2ab3SBen Gras va_list ap;
399a06e2ab3SBen Gras
400a06e2ab3SBen Gras va_start(ap, maskp);
401a06e2ab3SBen Gras
402a06e2ab3SBen Gras while ((sig = va_arg(ap, int)) != 0)
403a06e2ab3SBen Gras (void)sigdelset(maskp, sig);
404a06e2ab3SBen Gras va_end(ap);
405a06e2ab3SBen Gras }
406a06e2ab3SBen Gras
407a06e2ab3SBen Gras #if 0 /* Enable to get error messages from init ! */
408a06e2ab3SBen Gras #define vsyslog(level, fmt, ap) print_console(level, fmt, ap)
409a06e2ab3SBen Gras #define closelog()
410a06e2ab3SBen Gras
411a06e2ab3SBen Gras static void
412a06e2ab3SBen Gras print_console(int level, const char *message, va_list ap)
413a06e2ab3SBen Gras {
414a06e2ab3SBen Gras /*
415a06e2ab3SBen Gras * XXX: syslog seems to just plain not work in console-only
416a06e2ab3SBen Gras * XXX: situation... that should be fixed. Let's leave this
417a06e2ab3SBen Gras * XXX: note + code here in case someone gets in trouble and
418a06e2ab3SBen Gras * XXX: wants to debug. -- Jachym Holecek <freza@liberouter.org>
419a06e2ab3SBen Gras */
420a06e2ab3SBen Gras char errbuf[1024];
421a06e2ab3SBen Gras int fd, len;
422a06e2ab3SBen Gras
423a06e2ab3SBen Gras /* We can't do anything on errors, anyway... */
424a06e2ab3SBen Gras fd = open(_PATH_CONSOLE, O_WRONLY);
425a06e2ab3SBen Gras if (fd == -1)
426a06e2ab3SBen Gras return ;
427a06e2ab3SBen Gras
428a06e2ab3SBen Gras /* %m will get lost... */
429a06e2ab3SBen Gras len = vsnprintf(errbuf, sizeof(errbuf), message, ap);
430a06e2ab3SBen Gras (void)write(fd, (void *)errbuf, len);
431a06e2ab3SBen Gras (void)close(fd);
432a06e2ab3SBen Gras }
433a06e2ab3SBen Gras #endif
434a06e2ab3SBen Gras
435a06e2ab3SBen Gras /*
436a06e2ab3SBen Gras * Log a message and sleep for a while (to give someone an opportunity
437a06e2ab3SBen Gras * to read it and to save log or hardcopy output if the problem is chronic).
438a06e2ab3SBen Gras * NB: should send a message to the session logger to avoid blocking.
439a06e2ab3SBen Gras */
440a06e2ab3SBen Gras static void
stall(const char * message,...)441a06e2ab3SBen Gras stall(const char *message, ...)
442a06e2ab3SBen Gras {
443a06e2ab3SBen Gras va_list ap;
444a06e2ab3SBen Gras
445a06e2ab3SBen Gras va_start(ap, message);
446a06e2ab3SBen Gras vsyslog(LOG_ALERT, message, ap);
447a06e2ab3SBen Gras va_end(ap);
448a06e2ab3SBen Gras closelog();
449a06e2ab3SBen Gras (void)sleep(STALL_TIMEOUT);
450a06e2ab3SBen Gras }
451a06e2ab3SBen Gras
452a06e2ab3SBen Gras /*
453a06e2ab3SBen Gras * Like stall(), but doesn't sleep.
454a06e2ab3SBen Gras * If cpp had variadic macros, the two functions could be #defines for another.
455a06e2ab3SBen Gras * NB: should send a message to the session logger to avoid blocking.
456a06e2ab3SBen Gras */
457a06e2ab3SBen Gras static void
warning(const char * message,...)458a06e2ab3SBen Gras warning(const char *message, ...)
459a06e2ab3SBen Gras {
460a06e2ab3SBen Gras va_list ap;
461a06e2ab3SBen Gras
462a06e2ab3SBen Gras va_start(ap, message);
463a06e2ab3SBen Gras vsyslog(LOG_ALERT, message, ap);
464a06e2ab3SBen Gras va_end(ap);
465a06e2ab3SBen Gras closelog();
466a06e2ab3SBen Gras }
467a06e2ab3SBen Gras
468a06e2ab3SBen Gras /*
469a06e2ab3SBen Gras * Log an emergency message.
470a06e2ab3SBen Gras * NB: should send a message to the session logger to avoid blocking.
471a06e2ab3SBen Gras */
472a06e2ab3SBen Gras static void
emergency(const char * message,...)473a06e2ab3SBen Gras emergency(const char *message, ...)
474a06e2ab3SBen Gras {
475a06e2ab3SBen Gras va_list ap;
476a06e2ab3SBen Gras
477a06e2ab3SBen Gras va_start(ap, message);
478a06e2ab3SBen Gras vsyslog(LOG_EMERG, message, ap);
479a06e2ab3SBen Gras va_end(ap);
480a06e2ab3SBen Gras closelog();
481a06e2ab3SBen Gras }
482a06e2ab3SBen Gras
48384d9c625SLionel Sambuc #if !defined(__minix)
484a06e2ab3SBen Gras /*
485a06e2ab3SBen Gras * Catch a SIGSYS signal.
486a06e2ab3SBen Gras *
487a06e2ab3SBen Gras * These may arise if a system does not support sysctl.
488a06e2ab3SBen Gras * We tolerate up to 25 of these, then throw in the towel.
489a06e2ab3SBen Gras */
490a06e2ab3SBen Gras static void
badsys(int sig)491a06e2ab3SBen Gras badsys(int sig)
492a06e2ab3SBen Gras {
493a06e2ab3SBen Gras static int badcount = 0;
494a06e2ab3SBen Gras
495a06e2ab3SBen Gras if (badcount++ < 25)
496a06e2ab3SBen Gras return;
497a06e2ab3SBen Gras disaster(sig);
498a06e2ab3SBen Gras }
49984d9c625SLionel Sambuc #endif /* !defined(__minix) */
500a06e2ab3SBen Gras
501a06e2ab3SBen Gras /*
502a06e2ab3SBen Gras * Catch an unexpected signal.
503a06e2ab3SBen Gras */
504a06e2ab3SBen Gras static void
disaster(int sig)505a06e2ab3SBen Gras disaster(int sig)
506a06e2ab3SBen Gras {
507a06e2ab3SBen Gras
508a06e2ab3SBen Gras emergency("fatal signal: %s", strsignal(sig));
509a06e2ab3SBen Gras (void)sleep(STALL_TIMEOUT);
510a06e2ab3SBen Gras _exit(sig); /* reboot */
511a06e2ab3SBen Gras }
512a06e2ab3SBen Gras
51384d9c625SLionel Sambuc #if defined(__minix)
514a06e2ab3SBen Gras /*
515a06e2ab3SBen Gras * controlled reboot - minix tradition, SIGABRT by tty
516a06e2ab3SBen Gras */
517a06e2ab3SBen Gras static void
minixreboot(int sig)518a06e2ab3SBen Gras minixreboot(int sig)
519a06e2ab3SBen Gras {
520a06e2ab3SBen Gras if(fork() == 0) {
521a06e2ab3SBen Gras (void)execl("/sbin/shutdown",
522a06e2ab3SBen Gras "shutdown", "-r", "now", "CTRL-ALT_DEL", NULL);
523a06e2ab3SBen Gras _exit(1);
524a06e2ab3SBen Gras }
525a06e2ab3SBen Gras }
526a06e2ab3SBen Gras
527a06e2ab3SBen Gras /*
528a06e2ab3SBen Gras * controlled powerdown
529a06e2ab3SBen Gras */
530a06e2ab3SBen Gras static void
minixpowerdown(int sig)531a06e2ab3SBen Gras minixpowerdown(int sig)
532a06e2ab3SBen Gras {
533a06e2ab3SBen Gras if(fork() == 0) {
534a06e2ab3SBen Gras (void)execl("/sbin/shutdown",
535a06e2ab3SBen Gras "shutdown", "-p", "now", "CTRL-ALT_DEL", NULL);
536a06e2ab3SBen Gras _exit(1);
537a06e2ab3SBen Gras }
538a06e2ab3SBen Gras }
53984d9c625SLionel Sambuc #endif /* defined(__minix) */
540a06e2ab3SBen Gras
541a06e2ab3SBen Gras /*
542a06e2ab3SBen Gras * Check if securelevel is present.
543a06e2ab3SBen Gras */
544a06e2ab3SBen Gras static int
has_securelevel(void)545a06e2ab3SBen Gras has_securelevel(void)
546a06e2ab3SBen Gras {
547a06e2ab3SBen Gras #ifdef KERN_SECURELVL
548a06e2ab3SBen Gras int name[2], curlevel;
549a06e2ab3SBen Gras size_t len;
550a06e2ab3SBen Gras
551a06e2ab3SBen Gras name[0] = CTL_KERN;
552a06e2ab3SBen Gras name[1] = KERN_SECURELVL;
553a06e2ab3SBen Gras len = sizeof curlevel;
554a06e2ab3SBen Gras if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
555a06e2ab3SBen Gras /* If it doesn't exist, it's okay. */
556a06e2ab3SBen Gras if (errno == ENOENT)
557a06e2ab3SBen Gras return 0;
558a06e2ab3SBen Gras }
559a06e2ab3SBen Gras return 1;
560a06e2ab3SBen Gras #else
561a06e2ab3SBen Gras return 0;
562a06e2ab3SBen Gras #endif
563a06e2ab3SBen Gras }
564a06e2ab3SBen Gras
565a06e2ab3SBen Gras /*
566a06e2ab3SBen Gras * Get the security level of the kernel.
567a06e2ab3SBen Gras */
568a06e2ab3SBen Gras static int
getsecuritylevel(void)569a06e2ab3SBen Gras getsecuritylevel(void)
570a06e2ab3SBen Gras {
571a06e2ab3SBen Gras #ifdef KERN_SECURELVL
572a06e2ab3SBen Gras int name[2], curlevel;
573a06e2ab3SBen Gras size_t len;
574a06e2ab3SBen Gras
575a06e2ab3SBen Gras if (!securelevel_present)
576a06e2ab3SBen Gras return -1;
577a06e2ab3SBen Gras
578a06e2ab3SBen Gras name[0] = CTL_KERN;
579a06e2ab3SBen Gras name[1] = KERN_SECURELVL;
580a06e2ab3SBen Gras len = sizeof curlevel;
581a06e2ab3SBen Gras if (sysctl(name, 2, &curlevel, &len, NULL, 0) == -1) {
582a06e2ab3SBen Gras emergency("cannot get kernel security level: %m");
583a06e2ab3SBen Gras return -1;
584a06e2ab3SBen Gras }
585a06e2ab3SBen Gras return curlevel;
586a06e2ab3SBen Gras #else
587a06e2ab3SBen Gras return -1;
588a06e2ab3SBen Gras #endif
589a06e2ab3SBen Gras }
590a06e2ab3SBen Gras
591a06e2ab3SBen Gras /*
592a06e2ab3SBen Gras * Set the security level of the kernel.
593a06e2ab3SBen Gras */
594a06e2ab3SBen Gras static void
setsecuritylevel(int newlevel)595a06e2ab3SBen Gras setsecuritylevel(int newlevel)
596a06e2ab3SBen Gras {
597a06e2ab3SBen Gras #ifdef KERN_SECURELVL
598a06e2ab3SBen Gras int name[2], curlevel;
599a06e2ab3SBen Gras
600a06e2ab3SBen Gras if (!securelevel_present)
601a06e2ab3SBen Gras return;
602a06e2ab3SBen Gras
603a06e2ab3SBen Gras curlevel = getsecuritylevel();
604a06e2ab3SBen Gras if (newlevel == curlevel)
605a06e2ab3SBen Gras return;
606a06e2ab3SBen Gras name[0] = CTL_KERN;
607a06e2ab3SBen Gras name[1] = KERN_SECURELVL;
608a06e2ab3SBen Gras if (sysctl(name, 2, NULL, NULL, &newlevel, sizeof newlevel) == -1) {
609a06e2ab3SBen Gras emergency("cannot change kernel security level from"
610a06e2ab3SBen Gras " %d to %d: %m", curlevel, newlevel);
611a06e2ab3SBen Gras return;
612a06e2ab3SBen Gras }
613a06e2ab3SBen Gras #ifdef SECURE
614a06e2ab3SBen Gras warning("kernel security level changed from %d to %d",
615a06e2ab3SBen Gras curlevel, newlevel);
616a06e2ab3SBen Gras #endif
617a06e2ab3SBen Gras #endif
618a06e2ab3SBen Gras }
619a06e2ab3SBen Gras
620a06e2ab3SBen Gras /*
621a06e2ab3SBen Gras * Change states in the finite state machine.
622a06e2ab3SBen Gras * The initial state is passed as an argument.
623a06e2ab3SBen Gras */
624a06e2ab3SBen Gras static void
transition(state_t s)625a06e2ab3SBen Gras transition(state_t s)
626a06e2ab3SBen Gras {
627a06e2ab3SBen Gras
628a06e2ab3SBen Gras if (s == NULL)
629a06e2ab3SBen Gras return;
630a06e2ab3SBen Gras for (;;) {
631a06e2ab3SBen Gras #ifdef SUPPORT_UTMPX
632a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
633a06e2ab3SBen Gras utmpx_set_runlevel(get_runlevel(current_state),
634a06e2ab3SBen Gras get_runlevel(s));
635a06e2ab3SBen Gras current_state = s;
636a06e2ab3SBen Gras #endif
637a06e2ab3SBen Gras #endif
638a06e2ab3SBen Gras s = (state_t)(*s)();
639a06e2ab3SBen Gras }
640a06e2ab3SBen Gras }
641a06e2ab3SBen Gras
642a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
643a06e2ab3SBen Gras /*
644a06e2ab3SBen Gras * Close out the accounting files for a login session.
645a06e2ab3SBen Gras * NB: should send a message to the session logger to avoid blocking.
646a06e2ab3SBen Gras */
647a06e2ab3SBen Gras static void
clear_session_logs(session_t * sp,int status)648a06e2ab3SBen Gras clear_session_logs(session_t *sp, int status)
649a06e2ab3SBen Gras {
650a06e2ab3SBen Gras #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
651a06e2ab3SBen Gras char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
652a06e2ab3SBen Gras #endif
653a06e2ab3SBen Gras
654a06e2ab3SBen Gras #ifdef SUPPORT_UTMPX
655a06e2ab3SBen Gras if (logoutx(line, status, DEAD_PROCESS))
656a06e2ab3SBen Gras logwtmpx(line, "", "", status, DEAD_PROCESS);
657a06e2ab3SBen Gras #endif
658a06e2ab3SBen Gras #ifdef SUPPORT_UTMP
659a06e2ab3SBen Gras if (logout(line))
660a06e2ab3SBen Gras logwtmp(line, "", "");
661a06e2ab3SBen Gras #endif
662a06e2ab3SBen Gras }
663a06e2ab3SBen Gras #endif
664a06e2ab3SBen Gras
665a06e2ab3SBen Gras /*
666a06e2ab3SBen Gras * Start a session and allocate a controlling terminal.
667a06e2ab3SBen Gras * Only called by children of init after forking.
668a06e2ab3SBen Gras */
669a06e2ab3SBen Gras static void
setctty(const char * name)670a06e2ab3SBen Gras setctty(const char *name)
671a06e2ab3SBen Gras {
672a06e2ab3SBen Gras int fd;
673a06e2ab3SBen Gras
67484d9c625SLionel Sambuc #if !defined(__minix)
675a06e2ab3SBen Gras (void)revoke(name);
676a06e2ab3SBen Gras #else
677a06e2ab3SBen Gras if (setsid() < 0)
678a06e2ab3SBen Gras warn("child setsid() failed");
67984d9c625SLionel Sambuc #endif /* !defined(__minix) */
680a06e2ab3SBen Gras (void)nanosleep(&dtrtime, NULL); /* leave DTR low for a bit */
681a06e2ab3SBen Gras if ((fd = open(name, O_RDWR)) == -1) {
682a06e2ab3SBen Gras stall("can't open %s: %m", name);
683a06e2ab3SBen Gras _exit(1);
684a06e2ab3SBen Gras }
685a06e2ab3SBen Gras if (login_tty(fd) == -1) {
686a06e2ab3SBen Gras stall("can't get %s for controlling terminal: %m", name);
687a06e2ab3SBen Gras _exit(2);
688a06e2ab3SBen Gras }
689a06e2ab3SBen Gras }
690a06e2ab3SBen Gras
691a06e2ab3SBen Gras /*
692a06e2ab3SBen Gras * Bring the system up single user.
693a06e2ab3SBen Gras */
694a06e2ab3SBen Gras static state_func_t
single_user(void)695a06e2ab3SBen Gras single_user(void)
696a06e2ab3SBen Gras {
697a06e2ab3SBen Gras pid_t pid, wpid;
698a06e2ab3SBen Gras int status;
699a06e2ab3SBen Gras int from_securitylevel;
700a06e2ab3SBen Gras sigset_t mask;
701a06e2ab3SBen Gras struct sigaction sa, satstp, sahup;
702a06e2ab3SBen Gras #ifdef ALTSHELL
703a06e2ab3SBen Gras const char *shell = INIT_BSHELL;
704a06e2ab3SBen Gras #endif
705a06e2ab3SBen Gras const char *argv[2];
706a06e2ab3SBen Gras #ifdef SECURE
707a06e2ab3SBen Gras struct ttyent *typ;
708a06e2ab3SBen Gras struct passwd *pp;
709a06e2ab3SBen Gras char *clear, *password;
710a06e2ab3SBen Gras #endif
711a06e2ab3SBen Gras #ifdef ALTSHELL
712a06e2ab3SBen Gras char altshell[128];
713a06e2ab3SBen Gras #endif /* ALTSHELL */
714a06e2ab3SBen Gras
715a06e2ab3SBen Gras #if !defined(LETS_GET_SMALL) && defined(CHROOT)
716a06e2ab3SBen Gras /* Clear previous idea, just in case. */
717a06e2ab3SBen Gras did_multiuser_chroot = 0;
718a06e2ab3SBen Gras #endif /* !LETS_GET_SMALL && CHROOT */
719a06e2ab3SBen Gras
720a06e2ab3SBen Gras /*
721a06e2ab3SBen Gras * If the kernel is in secure mode, downgrade it to insecure mode.
722a06e2ab3SBen Gras */
723a06e2ab3SBen Gras from_securitylevel = getsecuritylevel();
724a06e2ab3SBen Gras if (from_securitylevel > 0)
725a06e2ab3SBen Gras setsecuritylevel(0);
726a06e2ab3SBen Gras
727a06e2ab3SBen Gras (void)sigemptyset(&sa.sa_mask);
728a06e2ab3SBen Gras sa.sa_flags = 0;
729a06e2ab3SBen Gras sa.sa_handler = SIG_IGN;
730a06e2ab3SBen Gras (void)sigaction(SIGTSTP, &sa, &satstp);
731a06e2ab3SBen Gras (void)sigaction(SIGHUP, &sa, &sahup);
732a06e2ab3SBen Gras if ((pid = fork()) == 0) {
733a06e2ab3SBen Gras /*
734a06e2ab3SBen Gras * Start the single user session.
735a06e2ab3SBen Gras */
736a06e2ab3SBen Gras if (access(_PATH_CONSTTY, F_OK) == 0)
737a06e2ab3SBen Gras setctty(_PATH_CONSTTY);
738a06e2ab3SBen Gras else
739a06e2ab3SBen Gras setctty(_PATH_CONSOLE);
740a06e2ab3SBen Gras
741a06e2ab3SBen Gras #ifdef SECURE
742a06e2ab3SBen Gras /*
743a06e2ab3SBen Gras * Check the root password.
744a06e2ab3SBen Gras * We don't care if the console is 'on' by default;
745a06e2ab3SBen Gras * it's the only tty that can be 'off' and 'secure'.
746a06e2ab3SBen Gras */
747a06e2ab3SBen Gras typ = getttynam("console");
748a06e2ab3SBen Gras pp = getpwnam("root");
749a06e2ab3SBen Gras if (typ && (from_securitylevel >=2 || (typ->ty_status
750a06e2ab3SBen Gras & TTY_SECURE) == 0) && pp && *pp->pw_passwd != '\0') {
751a06e2ab3SBen Gras (void)fprintf(stderr,
752a06e2ab3SBen Gras "Enter root password, or ^D to go multi-user\n");
753a06e2ab3SBen Gras for (;;) {
754a06e2ab3SBen Gras clear = getpass("Password:");
755a06e2ab3SBen Gras if (clear == 0 || *clear == '\0')
756a06e2ab3SBen Gras _exit(0);
757a06e2ab3SBen Gras password = crypt(clear, pp->pw_passwd);
758a06e2ab3SBen Gras (void)memset(clear, 0, _PASSWORD_LEN);
759a06e2ab3SBen Gras if (strcmp(password, pp->pw_passwd) == 0)
760a06e2ab3SBen Gras break;
761a06e2ab3SBen Gras warning("single-user login failed");
762a06e2ab3SBen Gras }
763a06e2ab3SBen Gras }
764a06e2ab3SBen Gras (void)endttyent();
765a06e2ab3SBen Gras endpwent();
766a06e2ab3SBen Gras #endif /* SECURE */
767a06e2ab3SBen Gras
768a06e2ab3SBen Gras #ifdef ALTSHELL
769a06e2ab3SBen Gras (void)fprintf(stderr,
770a06e2ab3SBen Gras "Enter pathname of shell or RETURN for %s: ", shell);
771a06e2ab3SBen Gras if (fgets(altshell, sizeof(altshell), stdin) == NULL) {
772a06e2ab3SBen Gras altshell[0] = '\0';
773a06e2ab3SBen Gras } else {
774a06e2ab3SBen Gras /* nuke \n */
775a06e2ab3SBen Gras char *p;
776a06e2ab3SBen Gras
777a06e2ab3SBen Gras if ((p = strchr(altshell, '\n')) != NULL)
778a06e2ab3SBen Gras *p = '\0';
779a06e2ab3SBen Gras }
780a06e2ab3SBen Gras
781a06e2ab3SBen Gras if (altshell[0])
782a06e2ab3SBen Gras shell = altshell;
783a06e2ab3SBen Gras #endif /* ALTSHELL */
784a06e2ab3SBen Gras
785a06e2ab3SBen Gras /*
786a06e2ab3SBen Gras * Unblock signals.
787a06e2ab3SBen Gras * We catch all the interesting ones,
788a06e2ab3SBen Gras * and those are reset to SIG_DFL on exec.
789a06e2ab3SBen Gras */
790a06e2ab3SBen Gras (void)sigemptyset(&mask);
791a06e2ab3SBen Gras (void)sigprocmask(SIG_SETMASK, &mask, NULL);
792a06e2ab3SBen Gras
793a06e2ab3SBen Gras /*
794a06e2ab3SBen Gras * Fire off a shell.
795a06e2ab3SBen Gras * If the default one doesn't work, try the Bourne shell.
796a06e2ab3SBen Gras */
797a06e2ab3SBen Gras argv[0] = "-sh";
798a06e2ab3SBen Gras argv[1] = 0;
799a06e2ab3SBen Gras (void)setenv("PATH", INIT_PATH, 1);
800a06e2ab3SBen Gras #ifdef ALTSHELL
801a06e2ab3SBen Gras if (altshell[0])
802a06e2ab3SBen Gras argv[0] = altshell;
803a06e2ab3SBen Gras (void)execv(shell, __UNCONST(argv));
804a06e2ab3SBen Gras emergency("can't exec `%s' for single user: %m", shell);
805a06e2ab3SBen Gras argv[0] = "-sh";
806a06e2ab3SBen Gras #endif /* ALTSHELL */
807a06e2ab3SBen Gras (void)execv(INIT_BSHELL, __UNCONST(argv));
808a06e2ab3SBen Gras emergency("can't exec `%s' for single user: %m", INIT_BSHELL);
809a06e2ab3SBen Gras (void)sleep(STALL_TIMEOUT);
810a06e2ab3SBen Gras _exit(3);
811a06e2ab3SBen Gras }
812a06e2ab3SBen Gras
813a06e2ab3SBen Gras if (pid == -1) {
814a06e2ab3SBen Gras /*
815a06e2ab3SBen Gras * We are seriously hosed. Do our best.
816a06e2ab3SBen Gras */
817a06e2ab3SBen Gras emergency("can't fork single-user shell: %m, trying again");
818a06e2ab3SBen Gras while (waitpid(-1, NULL, WNOHANG) > 0)
819a06e2ab3SBen Gras continue;
820a06e2ab3SBen Gras (void)sigaction(SIGTSTP, &satstp, NULL);
821a06e2ab3SBen Gras (void)sigaction(SIGHUP, &sahup, NULL);
822a06e2ab3SBen Gras return (state_func_t)single_user;
823a06e2ab3SBen Gras }
824a06e2ab3SBen Gras
825a06e2ab3SBen Gras requested_transition = 0;
826a06e2ab3SBen Gras do {
827a06e2ab3SBen Gras if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
828a06e2ab3SBen Gras collect_child(wpid, status);
829a06e2ab3SBen Gras if (wpid == -1) {
830a06e2ab3SBen Gras if (errno == EINTR)
831a06e2ab3SBen Gras continue;
832a06e2ab3SBen Gras warning("wait for single-user shell failed: %m; "
833a06e2ab3SBen Gras "restarting");
834a06e2ab3SBen Gras return (state_func_t)single_user;
835a06e2ab3SBen Gras }
836a06e2ab3SBen Gras if (wpid == pid && WIFSTOPPED(status)) {
837a06e2ab3SBen Gras warning("shell stopped, restarting");
838a06e2ab3SBen Gras (void)kill(pid, SIGCONT);
839a06e2ab3SBen Gras wpid = -1;
840a06e2ab3SBen Gras }
841a06e2ab3SBen Gras } while (wpid != pid && !requested_transition);
842a06e2ab3SBen Gras
843a06e2ab3SBen Gras if (requested_transition) {
844a06e2ab3SBen Gras (void)sigaction(SIGTSTP, &satstp, NULL);
845a06e2ab3SBen Gras (void)sigaction(SIGHUP, &sahup, NULL);
846a06e2ab3SBen Gras return (state_func_t)requested_transition;
847a06e2ab3SBen Gras }
848a06e2ab3SBen Gras
849a06e2ab3SBen Gras if (WIFSIGNALED(status)) {
850a06e2ab3SBen Gras if (WTERMSIG(status) == SIGKILL) {
851a06e2ab3SBen Gras /* executed /sbin/reboot; wait for the end quietly */
852a06e2ab3SBen Gras sigset_t s;
853a06e2ab3SBen Gras
854a06e2ab3SBen Gras (void)sigfillset(&s);
855a06e2ab3SBen Gras for (;;)
856a06e2ab3SBen Gras (void)sigsuspend(&s);
857a06e2ab3SBen Gras } else {
858a06e2ab3SBen Gras warning("single user shell terminated (%x), restarting",
859a06e2ab3SBen Gras status);
860a06e2ab3SBen Gras (void)sigaction(SIGTSTP, &satstp, NULL);
861a06e2ab3SBen Gras (void)sigaction(SIGHUP, &sahup, NULL);
862a06e2ab3SBen Gras return (state_func_t)single_user;
863a06e2ab3SBen Gras }
864a06e2ab3SBen Gras }
865a06e2ab3SBen Gras
866a06e2ab3SBen Gras runcom_mode = FASTBOOT;
867a06e2ab3SBen Gras (void)sigaction(SIGTSTP, &satstp, NULL);
868a06e2ab3SBen Gras (void)sigaction(SIGHUP, &sahup, NULL);
869a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
870a06e2ab3SBen Gras return (state_func_t)runcom;
871a06e2ab3SBen Gras #else /* LETS_GET_SMALL */
872a06e2ab3SBen Gras return (state_func_t)single_user;
873a06e2ab3SBen Gras #endif /* LETS_GET_SMALL */
874a06e2ab3SBen Gras }
875a06e2ab3SBen Gras
876a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
877a06e2ab3SBen Gras
878a06e2ab3SBen Gras /* ARGSUSED */
879a06e2ab3SBen Gras static state_func_t
runetcrc(int trychroot)880a06e2ab3SBen Gras runetcrc(int trychroot)
881a06e2ab3SBen Gras {
882a06e2ab3SBen Gras pid_t pid, wpid;
883a06e2ab3SBen Gras int status;
884a06e2ab3SBen Gras const char *argv[4];
885a06e2ab3SBen Gras struct sigaction sa;
886a06e2ab3SBen Gras
887a06e2ab3SBen Gras switch ((pid = fork())) {
888a06e2ab3SBen Gras case 0:
889a06e2ab3SBen Gras (void)sigemptyset(&sa.sa_mask);
890a06e2ab3SBen Gras sa.sa_flags = 0;
891a06e2ab3SBen Gras sa.sa_handler = SIG_IGN;
892a06e2ab3SBen Gras (void)sigaction(SIGTSTP, &sa, NULL);
893a06e2ab3SBen Gras (void)sigaction(SIGHUP, &sa, NULL);
894a06e2ab3SBen Gras
895a06e2ab3SBen Gras setctty(_PATH_CONSOLE);
896a06e2ab3SBen Gras
897a06e2ab3SBen Gras argv[0] = "sh";
898a06e2ab3SBen Gras argv[1] = _PATH_RUNCOM;
899a06e2ab3SBen Gras argv[2] = (runcom_mode == AUTOBOOT ? "autoboot" : 0);
900a06e2ab3SBen Gras argv[3] = 0;
901a06e2ab3SBen Gras
902a06e2ab3SBen Gras (void)sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);
903a06e2ab3SBen Gras
904a06e2ab3SBen Gras #ifdef CHROOT
905a06e2ab3SBen Gras if (trychroot)
906a06e2ab3SBen Gras if (chroot(rootdir) != 0) {
907a06e2ab3SBen Gras warning("failed to chroot to `%s': %m",
908a06e2ab3SBen Gras rootdir);
909a06e2ab3SBen Gras _exit(4); /* force single user mode */
910a06e2ab3SBen Gras }
911a06e2ab3SBen Gras #endif /* CHROOT */
912a06e2ab3SBen Gras
913a06e2ab3SBen Gras (void)execv(INIT_BSHELL, __UNCONST(argv));
914a06e2ab3SBen Gras stall("can't exec `%s' for `%s': %m", INIT_BSHELL, _PATH_RUNCOM);
915a06e2ab3SBen Gras _exit(5); /* force single user mode */
916a06e2ab3SBen Gras /*NOTREACHED*/
917a06e2ab3SBen Gras case -1:
918a06e2ab3SBen Gras emergency("can't fork for `%s' on `%s': %m", INIT_BSHELL,
919a06e2ab3SBen Gras _PATH_RUNCOM);
920a06e2ab3SBen Gras while (waitpid(-1, NULL, WNOHANG) > 0)
921a06e2ab3SBen Gras continue;
922a06e2ab3SBen Gras (void)sleep(STALL_TIMEOUT);
923a06e2ab3SBen Gras return (state_func_t)single_user;
924a06e2ab3SBen Gras default:
925a06e2ab3SBen Gras break;
926a06e2ab3SBen Gras }
927a06e2ab3SBen Gras
928a06e2ab3SBen Gras /*
929a06e2ab3SBen Gras * Copied from single_user(). This is a bit paranoid.
930a06e2ab3SBen Gras */
931a06e2ab3SBen Gras do {
932a06e2ab3SBen Gras if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
933a06e2ab3SBen Gras collect_child(wpid, status);
934a06e2ab3SBen Gras if (wpid == -1) {
935a06e2ab3SBen Gras if (errno == EINTR)
936a06e2ab3SBen Gras continue;
937a06e2ab3SBen Gras warning("wait for `%s' on `%s' failed: %m; going to "
938a06e2ab3SBen Gras "single user mode", INIT_BSHELL, _PATH_RUNCOM);
939a06e2ab3SBen Gras return (state_func_t)single_user;
940a06e2ab3SBen Gras }
941a06e2ab3SBen Gras if (wpid == pid && WIFSTOPPED(status)) {
942a06e2ab3SBen Gras warning("`%s' on `%s' stopped, restarting",
943a06e2ab3SBen Gras INIT_BSHELL, _PATH_RUNCOM);
944a06e2ab3SBen Gras (void)kill(pid, SIGCONT);
945a06e2ab3SBen Gras wpid = -1;
946a06e2ab3SBen Gras }
947a06e2ab3SBen Gras } while (wpid != pid);
948a06e2ab3SBen Gras
949a06e2ab3SBen Gras if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM &&
950a06e2ab3SBen Gras requested_transition == catatonia) {
951a06e2ab3SBen Gras /* /etc/rc executed /sbin/reboot; wait for the end quietly */
952a06e2ab3SBen Gras sigset_t s;
953a06e2ab3SBen Gras
954a06e2ab3SBen Gras (void)sigfillset(&s);
955a06e2ab3SBen Gras for (;;)
956a06e2ab3SBen Gras (void)sigsuspend(&s);
957a06e2ab3SBen Gras }
958a06e2ab3SBen Gras
959a06e2ab3SBen Gras if (!WIFEXITED(status)) {
960a06e2ab3SBen Gras warning("`%s' on `%s' terminated abnormally, going to "
961a06e2ab3SBen Gras "single user mode", INIT_BSHELL, _PATH_RUNCOM);
962a06e2ab3SBen Gras return (state_func_t)single_user;
963a06e2ab3SBen Gras }
964a06e2ab3SBen Gras
965a06e2ab3SBen Gras if (WEXITSTATUS(status))
966a06e2ab3SBen Gras return (state_func_t)single_user;
967a06e2ab3SBen Gras
968a06e2ab3SBen Gras return (state_func_t)read_ttys;
969a06e2ab3SBen Gras }
970a06e2ab3SBen Gras
971a06e2ab3SBen Gras /*
972a06e2ab3SBen Gras * Run the system startup script.
973a06e2ab3SBen Gras */
974a06e2ab3SBen Gras static state_func_t
runcom(void)975a06e2ab3SBen Gras runcom(void)
976a06e2ab3SBen Gras {
977a06e2ab3SBen Gras state_func_t next_step;
978a06e2ab3SBen Gras
979a06e2ab3SBen Gras /* Run /etc/rc and choose next state depending on the result. */
980a06e2ab3SBen Gras next_step = runetcrc(0);
981a06e2ab3SBen Gras if (next_step != (state_func_t)read_ttys)
982a06e2ab3SBen Gras return (state_func_t)next_step;
983a06e2ab3SBen Gras
984a06e2ab3SBen Gras #ifdef CHROOT
985a06e2ab3SBen Gras /*
986a06e2ab3SBen Gras * If init.root sysctl does not point to "/", we'll chroot and run
987a06e2ab3SBen Gras * The Real(tm) /etc/rc now. Global variable rootdir will tell us
988a06e2ab3SBen Gras * where to go.
989a06e2ab3SBen Gras */
990a06e2ab3SBen Gras if (shouldchroot()) {
991a06e2ab3SBen Gras next_step = runetcrc(1);
992a06e2ab3SBen Gras if (next_step != (state_func_t)read_ttys)
993a06e2ab3SBen Gras return (state_func_t)next_step;
994a06e2ab3SBen Gras
995a06e2ab3SBen Gras did_multiuser_chroot = 1;
996a06e2ab3SBen Gras } else {
997a06e2ab3SBen Gras did_multiuser_chroot = 0;
998a06e2ab3SBen Gras }
999a06e2ab3SBen Gras #endif /* CHROOT */
1000a06e2ab3SBen Gras
1001a06e2ab3SBen Gras /*
1002a06e2ab3SBen Gras * Regardless of whether in chroot or not, we booted successfuly.
1003a06e2ab3SBen Gras * It's time to spawn gettys (ie. next_step's value at this point).
1004a06e2ab3SBen Gras */
1005a06e2ab3SBen Gras runcom_mode = AUTOBOOT; /* the default */
1006a06e2ab3SBen Gras /* NB: should send a message to the session logger to avoid blocking. */
1007a06e2ab3SBen Gras #ifdef SUPPORT_UTMPX
1008a06e2ab3SBen Gras logwtmpx("~", "reboot", "", 0, INIT_PROCESS);
1009a06e2ab3SBen Gras #endif
1010a06e2ab3SBen Gras #ifdef SUPPORT_UTMP
1011a06e2ab3SBen Gras logwtmp("~", "reboot", "");
1012a06e2ab3SBen Gras #endif
1013a06e2ab3SBen Gras return (state_func_t)read_ttys;
1014a06e2ab3SBen Gras }
1015a06e2ab3SBen Gras
1016a06e2ab3SBen Gras /*
1017a06e2ab3SBen Gras * Open the session database.
1018a06e2ab3SBen Gras *
1019a06e2ab3SBen Gras * NB: We could pass in the size here; is it necessary?
1020a06e2ab3SBen Gras */
1021a06e2ab3SBen Gras static int
start_session_db(void)1022a06e2ab3SBen Gras start_session_db(void)
1023a06e2ab3SBen Gras {
1024a06e2ab3SBen Gras
1025a06e2ab3SBen Gras if (session_db && (*session_db->close)(session_db))
1026a06e2ab3SBen Gras emergency("session database close: %m");
1027a06e2ab3SBen Gras if ((session_db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == 0) {
1028a06e2ab3SBen Gras emergency("session database open: %m");
1029a06e2ab3SBen Gras return 1;
1030a06e2ab3SBen Gras }
1031a06e2ab3SBen Gras return 0;
1032a06e2ab3SBen Gras
1033a06e2ab3SBen Gras }
1034a06e2ab3SBen Gras
1035a06e2ab3SBen Gras /*
1036a06e2ab3SBen Gras * Add a new login session.
1037a06e2ab3SBen Gras */
1038a06e2ab3SBen Gras static void
add_session(session_t * sp)1039a06e2ab3SBen Gras add_session(session_t *sp)
1040a06e2ab3SBen Gras {
1041a06e2ab3SBen Gras DBT key;
1042a06e2ab3SBen Gras DBT data;
1043a06e2ab3SBen Gras
1044a06e2ab3SBen Gras if (session_db == NULL)
1045a06e2ab3SBen Gras return;
1046a06e2ab3SBen Gras
1047a06e2ab3SBen Gras key.data = &sp->se_process;
1048a06e2ab3SBen Gras key.size = sizeof sp->se_process;
1049a06e2ab3SBen Gras data.data = &sp;
1050a06e2ab3SBen Gras data.size = sizeof sp;
1051a06e2ab3SBen Gras
1052a06e2ab3SBen Gras if ((*session_db->put)(session_db, &key, &data, 0))
1053a06e2ab3SBen Gras emergency("insert %d: %m", sp->se_process);
1054a06e2ab3SBen Gras #ifdef SUPPORT_UTMPX
1055a06e2ab3SBen Gras session_utmpx(sp, 1);
1056a06e2ab3SBen Gras #endif
1057a06e2ab3SBen Gras }
1058a06e2ab3SBen Gras
1059a06e2ab3SBen Gras /*
1060a06e2ab3SBen Gras * Delete an old login session.
1061a06e2ab3SBen Gras */
1062a06e2ab3SBen Gras static void
del_session(session_t * sp)1063a06e2ab3SBen Gras del_session(session_t *sp)
1064a06e2ab3SBen Gras {
1065a06e2ab3SBen Gras DBT key;
1066a06e2ab3SBen Gras
1067a06e2ab3SBen Gras key.data = &sp->se_process;
1068a06e2ab3SBen Gras key.size = sizeof sp->se_process;
1069a06e2ab3SBen Gras
1070a06e2ab3SBen Gras if ((*session_db->del)(session_db, &key, 0))
1071a06e2ab3SBen Gras emergency("delete %d: %m", sp->se_process);
1072a06e2ab3SBen Gras #ifdef SUPPORT_UTMPX
1073a06e2ab3SBen Gras session_utmpx(sp, 0);
1074a06e2ab3SBen Gras #endif
1075a06e2ab3SBen Gras }
1076a06e2ab3SBen Gras
1077a06e2ab3SBen Gras /*
1078a06e2ab3SBen Gras * Look up a login session by pid.
1079a06e2ab3SBen Gras */
1080a06e2ab3SBen Gras static session_t *
find_session(pid_t pid)1081a06e2ab3SBen Gras find_session(pid_t pid)
1082a06e2ab3SBen Gras {
1083a06e2ab3SBen Gras DBT key;
1084a06e2ab3SBen Gras DBT data;
1085a06e2ab3SBen Gras session_t *ret;
1086a06e2ab3SBen Gras
1087a06e2ab3SBen Gras if (session_db == NULL)
1088a06e2ab3SBen Gras return NULL;
1089a06e2ab3SBen Gras
1090a06e2ab3SBen Gras key.data = &pid;
1091a06e2ab3SBen Gras key.size = sizeof pid;
1092a06e2ab3SBen Gras if ((*session_db->get)(session_db, &key, &data, 0) != 0)
1093a06e2ab3SBen Gras return 0;
1094a06e2ab3SBen Gras (void)memmove(&ret, data.data, sizeof(ret));
1095a06e2ab3SBen Gras return ret;
1096a06e2ab3SBen Gras }
1097a06e2ab3SBen Gras
1098a06e2ab3SBen Gras /*
1099a06e2ab3SBen Gras * Construct an argument vector from a command line.
1100a06e2ab3SBen Gras */
1101a06e2ab3SBen Gras static char **
construct_argv(char * command)1102a06e2ab3SBen Gras construct_argv(char *command)
1103a06e2ab3SBen Gras {
1104a06e2ab3SBen Gras int argc = 0;
1105a06e2ab3SBen Gras char **argv = malloc(((strlen(command) + 1) / 2 + 1) * sizeof (char *));
1106a06e2ab3SBen Gras static const char separators[] = " \t";
1107a06e2ab3SBen Gras
1108a06e2ab3SBen Gras if (argv == NULL)
1109a06e2ab3SBen Gras return NULL;
1110a06e2ab3SBen Gras
1111a06e2ab3SBen Gras if ((argv[argc++] = strtok(command, separators)) == 0) {
1112a06e2ab3SBen Gras free(argv);
1113a06e2ab3SBen Gras return NULL;
1114a06e2ab3SBen Gras }
1115a06e2ab3SBen Gras while ((argv[argc++] = strtok(NULL, separators)) != NULL)
1116a06e2ab3SBen Gras continue;
1117a06e2ab3SBen Gras return argv;
1118a06e2ab3SBen Gras }
1119a06e2ab3SBen Gras
1120a06e2ab3SBen Gras /*
1121a06e2ab3SBen Gras * Deallocate a session descriptor.
1122a06e2ab3SBen Gras */
1123a06e2ab3SBen Gras static void
free_session(session_t * sp)1124a06e2ab3SBen Gras free_session(session_t *sp)
1125a06e2ab3SBen Gras {
1126a06e2ab3SBen Gras
1127a06e2ab3SBen Gras free(sp->se_device);
1128a06e2ab3SBen Gras if (sp->se_getty) {
1129a06e2ab3SBen Gras free(sp->se_getty);
1130a06e2ab3SBen Gras free(sp->se_getty_argv);
1131a06e2ab3SBen Gras }
1132a06e2ab3SBen Gras if (sp->se_window) {
1133a06e2ab3SBen Gras free(sp->se_window);
1134a06e2ab3SBen Gras free(sp->se_window_argv);
1135a06e2ab3SBen Gras }
1136a06e2ab3SBen Gras free(sp);
1137a06e2ab3SBen Gras }
1138a06e2ab3SBen Gras
1139a06e2ab3SBen Gras /*
1140a06e2ab3SBen Gras * Allocate a new session descriptor.
1141a06e2ab3SBen Gras */
1142a06e2ab3SBen Gras static session_t *
new_session(session_t * sprev,int session_index,struct ttyent * typ)1143a06e2ab3SBen Gras new_session(session_t *sprev, int session_index, struct ttyent *typ)
1144a06e2ab3SBen Gras {
1145a06e2ab3SBen Gras session_t *sp;
1146a06e2ab3SBen Gras
1147a06e2ab3SBen Gras if ((typ->ty_status & TTY_ON) == 0 || typ->ty_name == NULL ||
1148a06e2ab3SBen Gras typ->ty_getty == NULL)
1149a06e2ab3SBen Gras return NULL;
1150a06e2ab3SBen Gras
1151a06e2ab3SBen Gras sp = malloc(sizeof (session_t));
1152a06e2ab3SBen Gras if (sp == NULL)
1153a06e2ab3SBen Gras return NULL;
1154a06e2ab3SBen Gras (void)memset(sp, 0, sizeof *sp);
1155a06e2ab3SBen Gras
1156a06e2ab3SBen Gras sp->se_flags = SE_PRESENT;
1157a06e2ab3SBen Gras sp->se_index = session_index;
1158a06e2ab3SBen Gras
1159a06e2ab3SBen Gras (void)asprintf(&sp->se_device, "%s%s", _PATH_DEV, typ->ty_name);
116084d9c625SLionel Sambuc if (!sp->se_device) {
116184d9c625SLionel Sambuc free(sp);
1162a06e2ab3SBen Gras return NULL;
116384d9c625SLionel Sambuc }
1164a06e2ab3SBen Gras
1165a06e2ab3SBen Gras if (setupargv(sp, typ) == 0) {
1166a06e2ab3SBen Gras free_session(sp);
1167a06e2ab3SBen Gras return NULL;
1168a06e2ab3SBen Gras }
1169a06e2ab3SBen Gras
1170a06e2ab3SBen Gras sp->se_next = NULL;
1171a06e2ab3SBen Gras if (sprev == NULL) {
1172a06e2ab3SBen Gras sessions = sp;
1173a06e2ab3SBen Gras sp->se_prev = NULL;
1174a06e2ab3SBen Gras } else {
1175a06e2ab3SBen Gras sprev->se_next = sp;
1176a06e2ab3SBen Gras sp->se_prev = sprev;
1177a06e2ab3SBen Gras }
1178a06e2ab3SBen Gras
1179a06e2ab3SBen Gras return sp;
1180a06e2ab3SBen Gras }
1181a06e2ab3SBen Gras
1182a06e2ab3SBen Gras /*
1183a06e2ab3SBen Gras * Calculate getty and if useful window argv vectors.
1184a06e2ab3SBen Gras */
1185a06e2ab3SBen Gras static int
setupargv(session_t * sp,struct ttyent * typ)1186a06e2ab3SBen Gras setupargv(session_t *sp, struct ttyent *typ)
1187a06e2ab3SBen Gras {
1188a06e2ab3SBen Gras
1189a06e2ab3SBen Gras if (sp->se_getty) {
1190a06e2ab3SBen Gras free(sp->se_getty);
1191a06e2ab3SBen Gras free(sp->se_getty_argv);
1192a06e2ab3SBen Gras }
1193a06e2ab3SBen Gras (void)asprintf(&sp->se_getty, "%s %s", typ->ty_getty, typ->ty_name);
1194a06e2ab3SBen Gras if (!sp->se_getty)
1195a06e2ab3SBen Gras return 0;
1196a06e2ab3SBen Gras sp->se_getty_argv = construct_argv(sp->se_getty);
1197a06e2ab3SBen Gras if (sp->se_getty_argv == NULL) {
1198a06e2ab3SBen Gras warning("can't parse getty for port `%s'", sp->se_device);
1199a06e2ab3SBen Gras free(sp->se_getty);
1200a06e2ab3SBen Gras sp->se_getty = NULL;
1201a06e2ab3SBen Gras return 0;
1202a06e2ab3SBen Gras }
1203a06e2ab3SBen Gras if (typ->ty_window) {
1204a06e2ab3SBen Gras if (sp->se_window)
1205a06e2ab3SBen Gras free(sp->se_window);
1206a06e2ab3SBen Gras sp->se_window = strdup(typ->ty_window);
1207a06e2ab3SBen Gras sp->se_window_argv = construct_argv(sp->se_window);
1208a06e2ab3SBen Gras if (sp->se_window_argv == NULL) {
1209a06e2ab3SBen Gras warning("can't parse window for port `%s'",
1210a06e2ab3SBen Gras sp->se_device);
1211a06e2ab3SBen Gras free(sp->se_window);
1212a06e2ab3SBen Gras sp->se_window = NULL;
1213a06e2ab3SBen Gras return 0;
1214a06e2ab3SBen Gras }
1215a06e2ab3SBen Gras }
1216a06e2ab3SBen Gras return 1;
1217a06e2ab3SBen Gras }
1218a06e2ab3SBen Gras
1219a06e2ab3SBen Gras /*
1220a06e2ab3SBen Gras * Walk the list of ttys and create sessions for each active line.
1221a06e2ab3SBen Gras */
1222a06e2ab3SBen Gras static state_func_t
read_ttys(void)1223a06e2ab3SBen Gras read_ttys(void)
1224a06e2ab3SBen Gras {
1225a06e2ab3SBen Gras int session_index = 0;
1226a06e2ab3SBen Gras session_t *sp, *snext;
1227a06e2ab3SBen Gras struct ttyent *typ;
1228a06e2ab3SBen Gras
1229a06e2ab3SBen Gras #ifdef SUPPORT_UTMPX
1230a06e2ab3SBen Gras if (sessions == NULL) {
1231a06e2ab3SBen Gras struct stat st;
1232a06e2ab3SBen Gras
1233a06e2ab3SBen Gras make_utmpx("", BOOT_MSG, BOOT_TIME, 0, &boot_time, 0);
1234a06e2ab3SBen Gras
1235a06e2ab3SBen Gras /*
1236a06e2ab3SBen Gras * If wtmpx is not empty, pick the down time from there
1237a06e2ab3SBen Gras */
1238a06e2ab3SBen Gras if (stat(_PATH_WTMPX, &st) != -1 && st.st_size != 0) {
1239a06e2ab3SBen Gras struct timeval down_time;
1240a06e2ab3SBen Gras
1241a06e2ab3SBen Gras TIMESPEC_TO_TIMEVAL(&down_time,
1242a06e2ab3SBen Gras st.st_atime > st.st_mtime ?
1243a06e2ab3SBen Gras &st.st_atimespec : &st.st_mtimespec);
1244a06e2ab3SBen Gras make_utmpx("", DOWN_MSG, DOWN_TIME, 0, &down_time, 0);
1245a06e2ab3SBen Gras }
1246a06e2ab3SBen Gras }
1247a06e2ab3SBen Gras #endif
1248a06e2ab3SBen Gras /*
1249a06e2ab3SBen Gras * Destroy any previous session state.
1250a06e2ab3SBen Gras * There shouldn't be any, but just in case...
1251a06e2ab3SBen Gras */
1252a06e2ab3SBen Gras for (sp = sessions; sp; sp = snext) {
1253a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
1254a06e2ab3SBen Gras if (sp->se_process)
1255a06e2ab3SBen Gras clear_session_logs(sp, 0);
1256a06e2ab3SBen Gras #endif
1257a06e2ab3SBen Gras snext = sp->se_next;
1258a06e2ab3SBen Gras free_session(sp);
1259a06e2ab3SBen Gras }
1260a06e2ab3SBen Gras sessions = NULL;
1261a06e2ab3SBen Gras
1262a06e2ab3SBen Gras if (start_session_db()) {
1263a06e2ab3SBen Gras warning("start_session_db failed, death");
1264a06e2ab3SBen Gras #ifdef CHROOT
1265a06e2ab3SBen Gras /* If /etc/rc ran in chroot, we want to kill any survivors. */
1266a06e2ab3SBen Gras if (did_multiuser_chroot)
1267a06e2ab3SBen Gras return (state_func_t)death;
1268a06e2ab3SBen Gras else
1269a06e2ab3SBen Gras #endif /* CHROOT */
1270a06e2ab3SBen Gras return (state_func_t)single_user;
1271a06e2ab3SBen Gras }
1272a06e2ab3SBen Gras
1273a06e2ab3SBen Gras (void)do_setttyent();
1274a06e2ab3SBen Gras
1275a06e2ab3SBen Gras /*
1276a06e2ab3SBen Gras * Allocate a session entry for each active port.
1277a06e2ab3SBen Gras * Note that sp starts at 0.
1278a06e2ab3SBen Gras */
1279a06e2ab3SBen Gras while ((typ = getttyent()) != NULL)
1280a06e2ab3SBen Gras if ((snext = new_session(sp, ++session_index, typ)) != NULL)
1281a06e2ab3SBen Gras sp = snext;
1282a06e2ab3SBen Gras (void)endttyent();
1283a06e2ab3SBen Gras
1284a06e2ab3SBen Gras return (state_func_t)multi_user;
1285a06e2ab3SBen Gras }
1286a06e2ab3SBen Gras
1287a06e2ab3SBen Gras /*
1288a06e2ab3SBen Gras * Start a window system running.
1289a06e2ab3SBen Gras */
1290a06e2ab3SBen Gras static void
start_window_system(session_t * sp)1291a06e2ab3SBen Gras start_window_system(session_t *sp)
1292a06e2ab3SBen Gras {
1293a06e2ab3SBen Gras pid_t pid;
1294a06e2ab3SBen Gras sigset_t mask;
1295a06e2ab3SBen Gras
1296a06e2ab3SBen Gras if ((pid = fork()) == -1) {
1297a06e2ab3SBen Gras emergency("can't fork for window system on port `%s': %m",
1298a06e2ab3SBen Gras sp->se_device);
1299a06e2ab3SBen Gras /* hope that getty fails and we can try again */
1300a06e2ab3SBen Gras return;
1301a06e2ab3SBen Gras }
1302a06e2ab3SBen Gras
1303a06e2ab3SBen Gras if (pid)
1304a06e2ab3SBen Gras return;
1305a06e2ab3SBen Gras
1306a06e2ab3SBen Gras (void)sigemptyset(&mask);
1307a06e2ab3SBen Gras (void)sigprocmask(SIG_SETMASK, &mask, NULL);
1308a06e2ab3SBen Gras
1309a06e2ab3SBen Gras if (setsid() < 0)
1310a06e2ab3SBen Gras emergency("setsid failed (window): %m");
1311a06e2ab3SBen Gras
1312a06e2ab3SBen Gras (void)execv(sp->se_window_argv[0], sp->se_window_argv);
1313a06e2ab3SBen Gras stall("can't exec window system `%s' for port `%s': %m",
1314a06e2ab3SBen Gras sp->se_window_argv[0], sp->se_device);
1315a06e2ab3SBen Gras _exit(6);
1316a06e2ab3SBen Gras }
1317a06e2ab3SBen Gras
1318a06e2ab3SBen Gras /*
1319a06e2ab3SBen Gras * Start a login session running.
1320a06e2ab3SBen Gras */
1321a06e2ab3SBen Gras static pid_t
start_getty(session_t * sp)1322a06e2ab3SBen Gras start_getty(session_t *sp)
1323a06e2ab3SBen Gras {
1324a06e2ab3SBen Gras pid_t pid;
1325a06e2ab3SBen Gras sigset_t mask;
1326a06e2ab3SBen Gras time_t current_time = time(NULL);
1327a06e2ab3SBen Gras
1328a06e2ab3SBen Gras /*
1329a06e2ab3SBen Gras * fork(), not vfork() -- we can't afford to block.
1330a06e2ab3SBen Gras */
1331a06e2ab3SBen Gras if ((pid = fork()) == -1) {
1332a06e2ab3SBen Gras emergency("can't fork for getty on port `%s': %m",
1333a06e2ab3SBen Gras sp->se_device);
1334a06e2ab3SBen Gras return -1;
1335a06e2ab3SBen Gras }
1336a06e2ab3SBen Gras
1337a06e2ab3SBen Gras if (pid)
1338a06e2ab3SBen Gras return pid;
1339a06e2ab3SBen Gras
1340a06e2ab3SBen Gras #ifdef CHROOT
1341a06e2ab3SBen Gras /* If /etc/rc did proceed inside chroot, we have to try as well. */
1342a06e2ab3SBen Gras if (did_multiuser_chroot)
1343a06e2ab3SBen Gras if (chroot(rootdir) != 0) {
1344a06e2ab3SBen Gras stall("can't chroot getty `%s' inside `%s': %m",
1345a06e2ab3SBen Gras sp->se_getty_argv[0], rootdir);
1346a06e2ab3SBen Gras _exit(7);
1347a06e2ab3SBen Gras }
1348a06e2ab3SBen Gras #endif /* CHROOT */
1349a06e2ab3SBen Gras
1350a06e2ab3SBen Gras if (current_time > sp->se_started.tv_sec &&
1351a06e2ab3SBen Gras current_time - sp->se_started.tv_sec < GETTY_SPACING) {
1352a06e2ab3SBen Gras warning("getty repeating too quickly on port `%s', sleeping",
1353a06e2ab3SBen Gras sp->se_device);
1354a06e2ab3SBen Gras (void)sleep(GETTY_SLEEP);
1355a06e2ab3SBen Gras }
1356a06e2ab3SBen Gras
1357a06e2ab3SBen Gras if (sp->se_window) {
1358a06e2ab3SBen Gras start_window_system(sp);
1359a06e2ab3SBen Gras (void)sleep(WINDOW_WAIT);
1360a06e2ab3SBen Gras }
1361a06e2ab3SBen Gras
1362a06e2ab3SBen Gras (void)sigemptyset(&mask);
1363a06e2ab3SBen Gras (void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
1364a06e2ab3SBen Gras
1365a06e2ab3SBen Gras (void)execv(sp->se_getty_argv[0], sp->se_getty_argv);
1366a06e2ab3SBen Gras stall("can't exec getty `%s' for port `%s': %m",
1367a06e2ab3SBen Gras sp->se_getty_argv[0], sp->se_device);
1368a06e2ab3SBen Gras _exit(8);
1369a06e2ab3SBen Gras /*NOTREACHED*/
1370a06e2ab3SBen Gras }
1371a06e2ab3SBen Gras #ifdef SUPPORT_UTMPX
1372a06e2ab3SBen Gras static void
session_utmpx(const session_t * sp,int add)1373a06e2ab3SBen Gras session_utmpx(const session_t *sp, int add)
1374a06e2ab3SBen Gras {
1375a06e2ab3SBen Gras const char *name = sp->se_getty ? sp->se_getty :
1376a06e2ab3SBen Gras (sp->se_window ? sp->se_window : "");
1377a06e2ab3SBen Gras const char *line = sp->se_device + sizeof(_PATH_DEV) - 1;
1378a06e2ab3SBen Gras
1379a06e2ab3SBen Gras make_utmpx(name, line, add ? LOGIN_PROCESS : DEAD_PROCESS,
1380a06e2ab3SBen Gras sp->se_process, &sp->se_started, sp->se_index);
1381a06e2ab3SBen Gras }
1382a06e2ab3SBen Gras
1383a06e2ab3SBen Gras static void
make_utmpx(const char * name,const char * line,int type,pid_t pid,const struct timeval * tv,int session)1384a06e2ab3SBen Gras make_utmpx(const char *name, const char *line, int type, pid_t pid,
1385a06e2ab3SBen Gras const struct timeval *tv, int session)
1386a06e2ab3SBen Gras {
1387a06e2ab3SBen Gras struct utmpx ut;
1388a06e2ab3SBen Gras const char *eline;
1389a06e2ab3SBen Gras
1390a06e2ab3SBen Gras (void)memset(&ut, 0, sizeof(ut));
1391a06e2ab3SBen Gras (void)strlcpy(ut.ut_name, name, sizeof(ut.ut_name));
1392a06e2ab3SBen Gras ut.ut_type = type;
1393a06e2ab3SBen Gras (void)strlcpy(ut.ut_line, line, sizeof(ut.ut_line));
1394a06e2ab3SBen Gras ut.ut_pid = pid;
1395a06e2ab3SBen Gras if (tv)
1396a06e2ab3SBen Gras ut.ut_tv = *tv;
1397a06e2ab3SBen Gras else
1398a06e2ab3SBen Gras (void)gettimeofday(&ut.ut_tv, NULL);
1399a06e2ab3SBen Gras ut.ut_session = session;
1400a06e2ab3SBen Gras
1401a06e2ab3SBen Gras eline = line + strlen(line);
1402a06e2ab3SBen Gras if ((size_t)(eline - line) >= sizeof(ut.ut_id))
1403a06e2ab3SBen Gras line = eline - sizeof(ut.ut_id);
1404a06e2ab3SBen Gras (void)strncpy(ut.ut_id, line, sizeof(ut.ut_id));
1405a06e2ab3SBen Gras
1406a06e2ab3SBen Gras if (pututxline(&ut) == NULL)
1407a06e2ab3SBen Gras warning("can't add utmpx record for `%s': %m", ut.ut_line);
1408a06e2ab3SBen Gras endutxent();
1409a06e2ab3SBen Gras }
1410a06e2ab3SBen Gras
1411a06e2ab3SBen Gras static char
get_runlevel(const state_t s)1412a06e2ab3SBen Gras get_runlevel(const state_t s)
1413a06e2ab3SBen Gras {
1414a06e2ab3SBen Gras if (s == (state_t)single_user)
1415a06e2ab3SBen Gras return SINGLE_USER;
1416a06e2ab3SBen Gras if (s == (state_t)runcom)
1417a06e2ab3SBen Gras return RUNCOM;
1418a06e2ab3SBen Gras if (s == (state_t)read_ttys)
1419a06e2ab3SBen Gras return READ_TTYS;
1420a06e2ab3SBen Gras if (s == (state_t)multi_user)
1421a06e2ab3SBen Gras return MULTI_USER;
1422a06e2ab3SBen Gras if (s == (state_t)clean_ttys)
1423a06e2ab3SBen Gras return CLEAN_TTYS;
1424a06e2ab3SBen Gras if (s == (state_t)catatonia)
1425a06e2ab3SBen Gras return CATATONIA;
1426a06e2ab3SBen Gras return DEATH;
1427a06e2ab3SBen Gras }
1428a06e2ab3SBen Gras
1429a06e2ab3SBen Gras static void
utmpx_set_runlevel(char old,char new)1430a06e2ab3SBen Gras utmpx_set_runlevel(char old, char new)
1431a06e2ab3SBen Gras {
1432a06e2ab3SBen Gras struct utmpx ut;
1433a06e2ab3SBen Gras
1434a06e2ab3SBen Gras /*
1435a06e2ab3SBen Gras * Don't record any transitions until we did the first transition
1436a06e2ab3SBen Gras * to read ttys, which is when we are guaranteed to have a read-write
1437a06e2ab3SBen Gras * /var. Perhaps use a different variable for this?
1438a06e2ab3SBen Gras */
1439a06e2ab3SBen Gras if (sessions == NULL)
1440a06e2ab3SBen Gras return;
1441a06e2ab3SBen Gras
1442a06e2ab3SBen Gras (void)memset(&ut, 0, sizeof(ut));
1443a06e2ab3SBen Gras (void)snprintf(ut.ut_line, sizeof(ut.ut_line), RUNLVL_MSG, new);
1444a06e2ab3SBen Gras ut.ut_type = RUN_LVL;
1445a06e2ab3SBen Gras (void)gettimeofday(&ut.ut_tv, NULL);
1446a06e2ab3SBen Gras ut.ut_exit.e_exit = old;
1447a06e2ab3SBen Gras ut.ut_exit.e_termination = new;
1448a06e2ab3SBen Gras if (pututxline(&ut) == NULL)
1449a06e2ab3SBen Gras warning("can't add utmpx record for `runlevel': %m");
1450a06e2ab3SBen Gras endutxent();
1451a06e2ab3SBen Gras }
1452a06e2ab3SBen Gras #endif /* SUPPORT_UTMPX */
1453a06e2ab3SBen Gras
1454a06e2ab3SBen Gras #endif /* LETS_GET_SMALL */
1455a06e2ab3SBen Gras
1456a06e2ab3SBen Gras /*
1457a06e2ab3SBen Gras * Collect exit status for a child.
1458a06e2ab3SBen Gras * If an exiting login, start a new login running.
1459a06e2ab3SBen Gras */
1460a06e2ab3SBen Gras static void
collect_child(pid_t pid,int status)1461a06e2ab3SBen Gras collect_child(pid_t pid, int status)
1462a06e2ab3SBen Gras {
1463a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
1464a06e2ab3SBen Gras session_t *sp, *sprev, *snext;
1465a06e2ab3SBen Gras
1466a06e2ab3SBen Gras if (! sessions)
1467a06e2ab3SBen Gras return;
1468a06e2ab3SBen Gras
1469a06e2ab3SBen Gras if ((sp = find_session(pid)) == NULL)
1470a06e2ab3SBen Gras return;
1471a06e2ab3SBen Gras
1472a06e2ab3SBen Gras clear_session_logs(sp, status);
1473a06e2ab3SBen Gras del_session(sp);
1474a06e2ab3SBen Gras sp->se_process = 0;
1475a06e2ab3SBen Gras
1476a06e2ab3SBen Gras if (sp->se_flags & SE_SHUTDOWN) {
1477a06e2ab3SBen Gras if ((sprev = sp->se_prev) != NULL)
1478a06e2ab3SBen Gras sprev->se_next = sp->se_next;
1479a06e2ab3SBen Gras else
1480a06e2ab3SBen Gras sessions = sp->se_next;
1481a06e2ab3SBen Gras if ((snext = sp->se_next) != NULL)
1482a06e2ab3SBen Gras snext->se_prev = sp->se_prev;
1483a06e2ab3SBen Gras free_session(sp);
1484a06e2ab3SBen Gras return;
1485a06e2ab3SBen Gras }
1486a06e2ab3SBen Gras
1487a06e2ab3SBen Gras if ((pid = start_getty(sp)) == -1) {
1488a06e2ab3SBen Gras /* serious trouble */
1489a06e2ab3SBen Gras requested_transition = clean_ttys;
1490a06e2ab3SBen Gras return;
1491a06e2ab3SBen Gras }
1492a06e2ab3SBen Gras
1493a06e2ab3SBen Gras sp->se_process = pid;
1494a06e2ab3SBen Gras (void)gettimeofday(&sp->se_started, NULL);
1495a06e2ab3SBen Gras add_session(sp);
1496a06e2ab3SBen Gras #endif /* LETS_GET_SMALL */
1497a06e2ab3SBen Gras }
1498a06e2ab3SBen Gras
1499a06e2ab3SBen Gras /*
1500a06e2ab3SBen Gras * Catch a signal and request a state transition.
1501a06e2ab3SBen Gras */
1502a06e2ab3SBen Gras static void
transition_handler(int sig)1503a06e2ab3SBen Gras transition_handler(int sig)
1504a06e2ab3SBen Gras {
1505a06e2ab3SBen Gras
1506a06e2ab3SBen Gras switch (sig) {
1507a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
1508a06e2ab3SBen Gras case SIGHUP:
1509a06e2ab3SBen Gras requested_transition = clean_ttys;
1510a06e2ab3SBen Gras break;
1511a06e2ab3SBen Gras case SIGTERM:
1512a06e2ab3SBen Gras requested_transition = death;
1513a06e2ab3SBen Gras break;
1514a06e2ab3SBen Gras case SIGTSTP:
1515a06e2ab3SBen Gras requested_transition = catatonia;
1516a06e2ab3SBen Gras break;
1517a06e2ab3SBen Gras #endif /* LETS_GET_SMALL */
1518a06e2ab3SBen Gras default:
1519a06e2ab3SBen Gras requested_transition = 0;
1520a06e2ab3SBen Gras break;
1521a06e2ab3SBen Gras }
1522a06e2ab3SBen Gras }
1523a06e2ab3SBen Gras
1524a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
1525a06e2ab3SBen Gras /*
1526a06e2ab3SBen Gras * Take the system multiuser.
1527a06e2ab3SBen Gras */
1528a06e2ab3SBen Gras static state_func_t
multi_user(void)1529a06e2ab3SBen Gras multi_user(void)
1530a06e2ab3SBen Gras {
1531a06e2ab3SBen Gras pid_t pid;
1532a06e2ab3SBen Gras int status;
1533a06e2ab3SBen Gras session_t *sp;
1534a06e2ab3SBen Gras
1535a06e2ab3SBen Gras requested_transition = 0;
1536a06e2ab3SBen Gras
1537a06e2ab3SBen Gras /*
1538a06e2ab3SBen Gras * If the administrator has not set the security level to -1
1539a06e2ab3SBen Gras * to indicate that the kernel should not run multiuser in secure
1540a06e2ab3SBen Gras * mode, and the run script has not set a higher level of security
1541a06e2ab3SBen Gras * than level 1, then put the kernel into secure mode.
1542a06e2ab3SBen Gras */
1543a06e2ab3SBen Gras if (getsecuritylevel() == 0)
1544a06e2ab3SBen Gras setsecuritylevel(1);
1545a06e2ab3SBen Gras
1546a06e2ab3SBen Gras for (sp = sessions; sp; sp = sp->se_next) {
1547a06e2ab3SBen Gras if (sp->se_process)
1548a06e2ab3SBen Gras continue;
1549a06e2ab3SBen Gras if ((pid = start_getty(sp)) == -1) {
1550a06e2ab3SBen Gras /* serious trouble */
1551a06e2ab3SBen Gras requested_transition = clean_ttys;
1552a06e2ab3SBen Gras break;
1553a06e2ab3SBen Gras }
1554a06e2ab3SBen Gras sp->se_process = pid;
1555a06e2ab3SBen Gras (void)gettimeofday(&sp->se_started, NULL);
1556a06e2ab3SBen Gras add_session(sp);
1557a06e2ab3SBen Gras }
1558a06e2ab3SBen Gras
1559a06e2ab3SBen Gras while (!requested_transition)
1560a06e2ab3SBen Gras if ((pid = waitpid(-1, &status, 0)) != -1)
1561a06e2ab3SBen Gras collect_child(pid, status);
1562a06e2ab3SBen Gras
1563a06e2ab3SBen Gras return (state_func_t)requested_transition;
1564a06e2ab3SBen Gras }
1565a06e2ab3SBen Gras
1566a06e2ab3SBen Gras /*
1567a06e2ab3SBen Gras * This is an n-squared algorithm. We hope it isn't run often...
1568a06e2ab3SBen Gras */
1569a06e2ab3SBen Gras static state_func_t
clean_ttys(void)1570a06e2ab3SBen Gras clean_ttys(void)
1571a06e2ab3SBen Gras {
1572a06e2ab3SBen Gras session_t *sp, *sprev;
1573a06e2ab3SBen Gras struct ttyent *typ;
1574a06e2ab3SBen Gras int session_index = 0;
1575a06e2ab3SBen Gras int devlen;
1576a06e2ab3SBen Gras
1577a06e2ab3SBen Gras for (sp = sessions; sp; sp = sp->se_next)
1578a06e2ab3SBen Gras sp->se_flags &= ~SE_PRESENT;
1579a06e2ab3SBen Gras
1580a06e2ab3SBen Gras (void)do_setttyent();
1581a06e2ab3SBen Gras
1582a06e2ab3SBen Gras devlen = sizeof(_PATH_DEV) - 1;
1583a06e2ab3SBen Gras while ((typ = getttyent()) != NULL) {
1584a06e2ab3SBen Gras ++session_index;
1585a06e2ab3SBen Gras
1586a06e2ab3SBen Gras for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
1587a06e2ab3SBen Gras if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)
1588a06e2ab3SBen Gras break;
1589a06e2ab3SBen Gras
1590a06e2ab3SBen Gras if (sp) {
1591a06e2ab3SBen Gras sp->se_flags |= SE_PRESENT;
1592a06e2ab3SBen Gras if (sp->se_index != session_index) {
1593a06e2ab3SBen Gras warning("port `%s' changed utmp index from "
1594a06e2ab3SBen Gras "%d to %d", sp->se_device, sp->se_index,
1595a06e2ab3SBen Gras session_index);
1596a06e2ab3SBen Gras sp->se_index = session_index;
1597a06e2ab3SBen Gras }
1598a06e2ab3SBen Gras if ((typ->ty_status & TTY_ON) == 0 ||
1599a06e2ab3SBen Gras typ->ty_getty == 0) {
1600a06e2ab3SBen Gras sp->se_flags |= SE_SHUTDOWN;
1601a06e2ab3SBen Gras if (sp->se_process != 0)
1602a06e2ab3SBen Gras (void)kill(sp->se_process, SIGHUP);
1603a06e2ab3SBen Gras continue;
1604a06e2ab3SBen Gras }
1605a06e2ab3SBen Gras sp->se_flags &= ~SE_SHUTDOWN;
1606a06e2ab3SBen Gras if (setupargv(sp, typ) == 0) {
1607a06e2ab3SBen Gras warning("can't parse getty for port `%s'",
1608a06e2ab3SBen Gras sp->se_device);
1609a06e2ab3SBen Gras sp->se_flags |= SE_SHUTDOWN;
1610a06e2ab3SBen Gras if (sp->se_process != 0)
1611a06e2ab3SBen Gras (void)kill(sp->se_process, SIGHUP);
1612a06e2ab3SBen Gras }
1613a06e2ab3SBen Gras continue;
1614a06e2ab3SBen Gras }
1615a06e2ab3SBen Gras
1616a06e2ab3SBen Gras (void)new_session(sprev, session_index, typ);
1617a06e2ab3SBen Gras }
1618a06e2ab3SBen Gras
1619a06e2ab3SBen Gras (void)endttyent();
1620a06e2ab3SBen Gras
1621a06e2ab3SBen Gras for (sp = sessions; sp; sp = sp->se_next)
1622a06e2ab3SBen Gras if ((sp->se_flags & SE_PRESENT) == 0) {
1623a06e2ab3SBen Gras sp->se_flags |= SE_SHUTDOWN;
1624a06e2ab3SBen Gras if (sp->se_process != 0)
1625a06e2ab3SBen Gras (void)kill(sp->se_process, SIGHUP);
1626a06e2ab3SBen Gras }
1627a06e2ab3SBen Gras
1628a06e2ab3SBen Gras return (state_func_t)multi_user;
1629a06e2ab3SBen Gras }
1630a06e2ab3SBen Gras
1631a06e2ab3SBen Gras /*
1632a06e2ab3SBen Gras * Block further logins.
1633a06e2ab3SBen Gras */
1634a06e2ab3SBen Gras static state_func_t
catatonia(void)1635a06e2ab3SBen Gras catatonia(void)
1636a06e2ab3SBen Gras {
1637a06e2ab3SBen Gras session_t *sp;
1638a06e2ab3SBen Gras
1639a06e2ab3SBen Gras for (sp = sessions; sp; sp = sp->se_next)
1640a06e2ab3SBen Gras sp->se_flags |= SE_SHUTDOWN;
1641a06e2ab3SBen Gras
1642a06e2ab3SBen Gras return (state_func_t)multi_user;
1643a06e2ab3SBen Gras }
1644a06e2ab3SBen Gras #endif /* LETS_GET_SMALL */
1645a06e2ab3SBen Gras
1646a06e2ab3SBen Gras /*
1647a06e2ab3SBen Gras * Note SIGALRM.
1648a06e2ab3SBen Gras */
1649a06e2ab3SBen Gras static void
1650a06e2ab3SBen Gras /*ARGSUSED*/
alrm_handler(int sig)1651a06e2ab3SBen Gras alrm_handler(int sig)
1652a06e2ab3SBen Gras {
1653a06e2ab3SBen Gras
1654a06e2ab3SBen Gras clang = 1;
1655a06e2ab3SBen Gras }
1656a06e2ab3SBen Gras
1657a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
1658a06e2ab3SBen Gras /*
1659a06e2ab3SBen Gras * Bring the system down to single user.
1660a06e2ab3SBen Gras */
1661a06e2ab3SBen Gras static state_func_t
death(void)1662a06e2ab3SBen Gras death(void)
1663a06e2ab3SBen Gras {
1664a06e2ab3SBen Gras session_t *sp;
1665a06e2ab3SBen Gras int i, status;
1666a06e2ab3SBen Gras pid_t pid;
1667a06e2ab3SBen Gras static const int death_sigs[3] = { SIGHUP, SIGTERM, SIGKILL };
1668a06e2ab3SBen Gras
1669a06e2ab3SBen Gras for (sp = sessions; sp; sp = sp->se_next)
1670a06e2ab3SBen Gras sp->se_flags |= SE_SHUTDOWN;
1671a06e2ab3SBen Gras
1672a06e2ab3SBen Gras /* NB: should send a message to the session logger to avoid blocking. */
1673a06e2ab3SBen Gras #ifdef SUPPORT_UTMPX
1674a06e2ab3SBen Gras logwtmpx("~", "shutdown", "", 0, INIT_PROCESS);
1675a06e2ab3SBen Gras #endif
1676a06e2ab3SBen Gras #ifdef SUPPORT_UTMP
1677a06e2ab3SBen Gras logwtmp("~", "shutdown", "");
1678a06e2ab3SBen Gras #endif
1679a06e2ab3SBen Gras
1680a06e2ab3SBen Gras for (i = 0; i < 3; ++i) {
1681a06e2ab3SBen Gras if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
1682a06e2ab3SBen Gras return (state_func_t)single_user;
1683a06e2ab3SBen Gras
1684a06e2ab3SBen Gras clang = 0;
1685a06e2ab3SBen Gras (void)alarm(DEATH_WATCH);
1686a06e2ab3SBen Gras do
1687a06e2ab3SBen Gras if ((pid = waitpid(-1, &status, 0)) != -1)
1688a06e2ab3SBen Gras collect_child(pid, status);
1689a06e2ab3SBen Gras while (clang == 0 && errno != ECHILD);
1690a06e2ab3SBen Gras
1691a06e2ab3SBen Gras if (errno == ECHILD)
1692a06e2ab3SBen Gras return (state_func_t)single_user;
1693a06e2ab3SBen Gras }
1694a06e2ab3SBen Gras
1695a06e2ab3SBen Gras warning("some processes would not die; ps axl advised");
1696a06e2ab3SBen Gras
1697a06e2ab3SBen Gras return (state_func_t)single_user;
1698a06e2ab3SBen Gras }
1699a06e2ab3SBen Gras #endif /* LETS_GET_SMALL */
1700a06e2ab3SBen Gras
1701a06e2ab3SBen Gras #ifdef MFS_DEV_IF_NO_CONSOLE
1702a06e2ab3SBen Gras
1703a06e2ab3SBen Gras static int
mfs_dev(void)1704a06e2ab3SBen Gras mfs_dev(void)
1705a06e2ab3SBen Gras {
1706a06e2ab3SBen Gras /*
1707a06e2ab3SBen Gras * We cannot print errors so we bail out silently...
1708a06e2ab3SBen Gras */
1709a06e2ab3SBen Gras pid_t pid;
1710a06e2ab3SBen Gras int status;
1711a06e2ab3SBen Gras
1712a06e2ab3SBen Gras /* If we have /dev/console, assume all is OK */
1713a06e2ab3SBen Gras if (access(_PATH_CONSOLE, F_OK) == 0)
1714a06e2ab3SBen Gras return 0;
1715a06e2ab3SBen Gras
1716a06e2ab3SBen Gras #if 0 /* Useful for testing MAKEDEV */
1717a06e2ab3SBen Gras /* Mount an mfs over /mnt so we can create a console entry */
1718a06e2ab3SBen Gras switch ((pid = fork())) {
1719a06e2ab3SBen Gras case 0:
1720a06e2ab3SBen Gras (void)execl(INIT_MOUNT_MFS, "mount_mfs",
1721a06e2ab3SBen Gras "-b", "4096", "-f", "512",
1722a06e2ab3SBen Gras "-s", 64, "-n", 10,
1723a06e2ab3SBen Gras "-p", "0755",
1724a06e2ab3SBen Gras "swap", "/mnt", NULL);
1725a06e2ab3SBen Gras _exit(9);
1726a06e2ab3SBen Gras /*NOTREACHED*/
1727a06e2ab3SBen Gras
1728a06e2ab3SBen Gras case -1:
1729a06e2ab3SBen Gras return(-1);
1730a06e2ab3SBen Gras
1731a06e2ab3SBen Gras default:
1732a06e2ab3SBen Gras if (waitpid(pid, &status, 0) == -1)
1733a06e2ab3SBen Gras return(-1);
1734a06e2ab3SBen Gras if (status != 0)
1735a06e2ab3SBen Gras return(-1);
1736a06e2ab3SBen Gras break;
1737a06e2ab3SBen Gras }
1738a06e2ab3SBen Gras
1739a06e2ab3SBen Gras {
1740a06e2ab3SBen Gras dev_t dev;
1741a06e2ab3SBen Gras #ifdef CPU_CONSDEV
1742a06e2ab3SBen Gras static int name[2] = { CTL_MACHDEP, CPU_CONSDEV };
1743a06e2ab3SBen Gras size_t olen;
1744a06e2ab3SBen Gras olen = sizeof(dev);
1745a06e2ab3SBen Gras if (sysctl(name, sizeof(name) / sizeof(name[0]), &dev, &olen,
1746a06e2ab3SBen Gras NULL, 0) == -1)
1747a06e2ab3SBen Gras #endif
1748a06e2ab3SBen Gras dev = makedev(0, 0);
1749a06e2ab3SBen Gras
1750a06e2ab3SBen Gras /* Make a console for us, so we can see things happening */
1751a06e2ab3SBen Gras if (mknod("/mnt/console", 0666 | S_IFCHR, dev) == -1)
1752a06e2ab3SBen Gras return(-1);
1753a06e2ab3SBen Gras (void)freopen("/mnt/console", "a", stderr);
1754a06e2ab3SBen Gras }
1755a06e2ab3SBen Gras
1756a06e2ab3SBen Gras #endif
1757a06e2ab3SBen Gras
1758a06e2ab3SBen Gras /* Run the makedev script to create devices */
1759a06e2ab3SBen Gras switch ((pid = fork())) {
1760a06e2ab3SBen Gras case 0:
1761a06e2ab3SBen Gras (void)dup2(2, 1); /* Give the script stdout */
1762a06e2ab3SBen Gras if (chdir("/dev") == 0)
1763a06e2ab3SBen Gras (void)execl(INIT_BSHELL, "sh",
1764a06e2ab3SBen Gras access("./MAKEDEV", X_OK) == 0
1765a06e2ab3SBen Gras ? "./MAKEDEV" : "/etc/MAKEDEV",
1766a06e2ab3SBen Gras "-MM", "init", NULL);
1767a06e2ab3SBen Gras _exit(10);
1768a06e2ab3SBen Gras /* NOTREACHED */
1769a06e2ab3SBen Gras
1770a06e2ab3SBen Gras case -1:
1771a06e2ab3SBen Gras break;
1772a06e2ab3SBen Gras
1773a06e2ab3SBen Gras default:
1774a06e2ab3SBen Gras if (waitpid(pid, &status, 0) == -1)
1775a06e2ab3SBen Gras break;
1776a06e2ab3SBen Gras if (status != 0)
1777*0a6a1f1dSLionel Sambuc warn("MAKEDEV exit status %d", status);
1778a06e2ab3SBen Gras /*
1779a06e2ab3SBen Gras * If /dev/console got created, then return 0
1780a06e2ab3SBen Gras * regardless of MAKEDEV exit status.
1781a06e2ab3SBen Gras */
1782a06e2ab3SBen Gras if (access(_PATH_CONSOLE, F_OK) == 0)
1783a06e2ab3SBen Gras return 0;
1784a06e2ab3SBen Gras _exit(11);
1785a06e2ab3SBen Gras }
1786a06e2ab3SBen Gras warn("Unable to run MAKEDEV");
1787a06e2ab3SBen Gras _exit(12);
1788a06e2ab3SBen Gras }
1789a06e2ab3SBen Gras #endif
1790a06e2ab3SBen Gras
1791a06e2ab3SBen Gras #ifndef LETS_GET_SMALL
1792a06e2ab3SBen Gras static int
do_setttyent(void)1793a06e2ab3SBen Gras do_setttyent(void)
1794a06e2ab3SBen Gras {
1795a06e2ab3SBen Gras (void)endttyent();
1796a06e2ab3SBen Gras #ifdef CHROOT
1797a06e2ab3SBen Gras if (did_multiuser_chroot) {
1798a06e2ab3SBen Gras char path[PATH_MAX];
1799a06e2ab3SBen Gras
1800a06e2ab3SBen Gras (void)snprintf(path, sizeof(path), "%s/%s", rootdir, _PATH_TTYS);
1801a06e2ab3SBen Gras
1802a06e2ab3SBen Gras return setttyentpath(path);
1803a06e2ab3SBen Gras } else
1804a06e2ab3SBen Gras #endif /* CHROOT */
1805a06e2ab3SBen Gras return setttyent();
1806a06e2ab3SBen Gras }
1807a06e2ab3SBen Gras #endif
1808a06e2ab3SBen Gras
1809a06e2ab3SBen Gras #if !defined(LETS_GET_SMALL) && defined(CHROOT)
1810a06e2ab3SBen Gras
1811a06e2ab3SBen Gras static int
createsysctlnode(void)1812a06e2ab3SBen Gras createsysctlnode(void)
1813a06e2ab3SBen Gras {
1814a06e2ab3SBen Gras struct sysctlnode node;
1815a06e2ab3SBen Gras int mib[2];
1816a06e2ab3SBen Gras size_t len;
1817a06e2ab3SBen Gras
1818a06e2ab3SBen Gras /*
1819a06e2ab3SBen Gras * Create top-level dynamic sysctl node. Its child nodes will only
1820a06e2ab3SBen Gras * be readable by the superuser, since regular mortals should not
1821a06e2ab3SBen Gras * care ("Sssh, it's a secret!").
1822a06e2ab3SBen Gras */
1823a06e2ab3SBen Gras len = sizeof(struct sysctlnode);
1824a06e2ab3SBen Gras mib[0] = CTL_CREATE;
1825a06e2ab3SBen Gras
1826a06e2ab3SBen Gras (void)memset(&node, 0, len);
1827a06e2ab3SBen Gras node.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE |
1828a06e2ab3SBen Gras CTLFLAG_PRIVATE | CTLTYPE_NODE;
1829a06e2ab3SBen Gras node.sysctl_num = CTL_CREATE;
1830a06e2ab3SBen Gras (void)snprintf(node.sysctl_name, SYSCTL_NAMELEN, "init");
1831a06e2ab3SBen Gras if (sysctl(&mib[0], 1, &node, &len, &node, len) == -1) {
1832a06e2ab3SBen Gras warning("could not create init node: %m");
1833a06e2ab3SBen Gras return -1;
1834a06e2ab3SBen Gras }
1835a06e2ab3SBen Gras
1836a06e2ab3SBen Gras /*
1837a06e2ab3SBen Gras * Create second level dynamic node capable of holding pathname.
1838a06e2ab3SBen Gras * Provide "/" as the default value.
1839a06e2ab3SBen Gras */
1840a06e2ab3SBen Gras len = sizeof(struct sysctlnode);
1841a06e2ab3SBen Gras mib[0] = node.sysctl_num;
1842a06e2ab3SBen Gras mib[1] = CTL_CREATE;
1843a06e2ab3SBen Gras
1844a06e2ab3SBen Gras (void)memset(&node, 0, len);
1845a06e2ab3SBen Gras node.sysctl_flags = SYSCTL_VERSION | CTLFLAG_READWRITE |
1846a06e2ab3SBen Gras CTLTYPE_STRING | CTLFLAG_OWNDATA;
1847a06e2ab3SBen Gras node.sysctl_size = _POSIX_PATH_MAX;
1848a06e2ab3SBen Gras node.sysctl_data = __UNCONST("/");
1849a06e2ab3SBen Gras node.sysctl_num = CTL_CREATE;
1850a06e2ab3SBen Gras (void)snprintf(node.sysctl_name, SYSCTL_NAMELEN, "root");
1851a06e2ab3SBen Gras if (sysctl(&mib[0], 2, NULL, NULL, &node, len) == -1) {
1852a06e2ab3SBen Gras warning("could not create init.root node: %m");
1853a06e2ab3SBen Gras return -1;
1854a06e2ab3SBen Gras }
1855a06e2ab3SBen Gras
1856a06e2ab3SBen Gras return 0;
1857a06e2ab3SBen Gras }
1858a06e2ab3SBen Gras
1859a06e2ab3SBen Gras static int
shouldchroot(void)1860a06e2ab3SBen Gras shouldchroot(void)
1861a06e2ab3SBen Gras {
1862a06e2ab3SBen Gras struct sysctlnode node;
1863a06e2ab3SBen Gras size_t len, cnt;
1864a06e2ab3SBen Gras int mib;
1865a06e2ab3SBen Gras
1866a06e2ab3SBen Gras len = sizeof(struct sysctlnode);
1867a06e2ab3SBen Gras
1868a06e2ab3SBen Gras if (sysctlbyname("init.root", rootdir, &len, NULL, 0) == -1) {
1869a06e2ab3SBen Gras warning("could not read init.root: %m");
1870a06e2ab3SBen Gras
1871a06e2ab3SBen Gras /* Child killed our node. Recreate it. */
1872a06e2ab3SBen Gras if (errno == ENOENT) {
1873a06e2ab3SBen Gras /* Destroy whatever is left, recreate from scratch. */
1874a06e2ab3SBen Gras if (sysctlnametomib("init", &mib, &cnt) != -1) {
1875a06e2ab3SBen Gras (void)memset(&node, 0, sizeof(node));
1876a06e2ab3SBen Gras node.sysctl_flags = SYSCTL_VERSION;
1877a06e2ab3SBen Gras node.sysctl_num = mib;
1878a06e2ab3SBen Gras mib = CTL_DESTROY;
1879a06e2ab3SBen Gras
1880a06e2ab3SBen Gras (void)sysctl(&mib, 1, NULL, NULL, &node,
1881a06e2ab3SBen Gras sizeof(node));
1882a06e2ab3SBen Gras }
1883a06e2ab3SBen Gras
1884a06e2ab3SBen Gras (void)createsysctlnode();
1885a06e2ab3SBen Gras }
1886a06e2ab3SBen Gras
1887a06e2ab3SBen Gras /* We certainly won't chroot. */
1888a06e2ab3SBen Gras return 0;
1889a06e2ab3SBen Gras }
1890a06e2ab3SBen Gras
1891a06e2ab3SBen Gras if (rootdir[len] != '\0' || strlen(rootdir) != len - 1) {
1892a06e2ab3SBen Gras warning("init.root is not a string");
1893a06e2ab3SBen Gras return 0;
1894a06e2ab3SBen Gras }
1895a06e2ab3SBen Gras
1896a06e2ab3SBen Gras if (strcmp(rootdir, "/") == 0)
1897a06e2ab3SBen Gras return 0;
189884d9c625SLionel Sambuc
1899a06e2ab3SBen Gras return 1;
1900a06e2ab3SBen Gras }
1901a06e2ab3SBen Gras
1902a06e2ab3SBen Gras #endif /* !LETS_GET_SMALL && CHROOT */
1903