Changeset View
Changeset View
Standalone View
Standalone View
head/sbin/init/init.c
Show All 40 Lines | |||||
static char sccsid[] = "@(#)init.c 8.1 (Berkeley) 7/15/93"; | static char sccsid[] = "@(#)init.c 8.1 (Berkeley) 7/15/93"; | ||||
#endif | #endif | ||||
static const char rcsid[] = | static const char rcsid[] = | ||||
"$FreeBSD$"; | "$FreeBSD$"; | ||||
#endif /* not lint */ | #endif /* not lint */ | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/ioctl.h> | #include <sys/ioctl.h> | ||||
#include <sys/mman.h> | |||||
#include <sys/mount.h> | #include <sys/mount.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/wait.h> | #include <sys/wait.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <sys/uio.h> | #include <sys/uio.h> | ||||
#include <db.h> | #include <db.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
Show All 17 Lines | |||||
#ifdef SECURE | #ifdef SECURE | ||||
#include <pwd.h> | #include <pwd.h> | ||||
#endif | #endif | ||||
#ifdef LOGIN_CAP | #ifdef LOGIN_CAP | ||||
#include <login_cap.h> | #include <login_cap.h> | ||||
#endif | #endif | ||||
#include "mntopts.h" | |||||
#include "pathnames.h" | #include "pathnames.h" | ||||
/* | /* | ||||
* Sleep times; used to prevent thrashing. | * Sleep times; used to prevent thrashing. | ||||
*/ | */ | ||||
#define GETTY_SPACING 5 /* N secs minimum getty spacing */ | #define GETTY_SPACING 5 /* N secs minimum getty spacing */ | ||||
#define GETTY_SLEEP 30 /* sleep N secs after spacing problem */ | #define GETTY_SLEEP 30 /* sleep N secs after spacing problem */ | ||||
#define GETTY_NSPACE 3 /* max. spacing count to bring reaction */ | #define GETTY_NSPACE 3 /* max. spacing count to bring reaction */ | ||||
#define WINDOW_WAIT 3 /* wait N secs after starting window */ | #define WINDOW_WAIT 3 /* wait N secs after starting window */ | ||||
#define STALL_TIMEOUT 30 /* wait N secs after warning */ | #define STALL_TIMEOUT 30 /* wait N secs after warning */ | ||||
#define DEATH_WATCH 10 /* wait N secs for procs to die */ | #define DEATH_WATCH 10 /* wait N secs for procs to die */ | ||||
#define DEATH_SCRIPT 120 /* wait for 2min for /etc/rc.shutdown */ | #define DEATH_SCRIPT 120 /* wait for 2min for /etc/rc.shutdown */ | ||||
#define RESOURCE_RC "daemon" | #define RESOURCE_RC "daemon" | ||||
#define RESOURCE_WINDOW "default" | #define RESOURCE_WINDOW "default" | ||||
#define RESOURCE_GETTY "default" | #define RESOURCE_GETTY "default" | ||||
static void handle(sig_t, ...); | static void handle(sig_t, ...); | ||||
static void delset(sigset_t *, ...); | static void delset(sigset_t *, ...); | ||||
static void stall(const char *, ...) __printflike(1, 2); | static void stall(const char *, ...) __printflike(1, 2); | ||||
static void warning(const char *, ...) __printflike(1, 2); | static void warning(const char *, ...) __printflike(1, 2); | ||||
static void emergency(const char *, ...) __printflike(1, 2); | static void emergency(const char *, ...) __printflike(1, 2); | ||||
static void disaster(int); | static void disaster(int); | ||||
static void badsys(int); | static void badsys(int); | ||||
static void revoke_ttys(void); | |||||
static int runshutdown(void); | static int runshutdown(void); | ||||
static char *strk(char *); | static char *strk(char *); | ||||
/* | /* | ||||
* We really need a recursive typedef... | * We really need a recursive typedef... | ||||
* The following at least guarantees that the return type of (*state_t)() | * The following at least guarantees that the return type of (*state_t)() | ||||
* is sufficiently wide to hold a function pointer. | * is sufficiently wide to hold a function pointer. | ||||
*/ | */ | ||||
typedef long (*state_func_t)(void); | typedef long (*state_func_t)(void); | ||||
typedef state_func_t (*state_t)(void); | typedef state_func_t (*state_t)(void); | ||||
static state_func_t single_user(void); | static state_func_t single_user(void); | ||||
static state_func_t runcom(void); | static state_func_t runcom(void); | ||||
static state_func_t read_ttys(void); | static state_func_t read_ttys(void); | ||||
static state_func_t multi_user(void); | static state_func_t multi_user(void); | ||||
static state_func_t clean_ttys(void); | static state_func_t clean_ttys(void); | ||||
static state_func_t catatonia(void); | static state_func_t catatonia(void); | ||||
static state_func_t death(void); | static state_func_t death(void); | ||||
static state_func_t death_single(void); | static state_func_t death_single(void); | ||||
static state_func_t reroot(void); | |||||
static state_func_t reroot_phase_two(void); | |||||
static state_func_t run_script(const char *); | static state_func_t run_script(const char *); | ||||
static enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT; | static enum { AUTOBOOT, FASTBOOT } runcom_mode = AUTOBOOT; | ||||
#define FALSE 0 | #define FALSE 0 | ||||
#define TRUE 1 | #define TRUE 1 | ||||
static int Reboot = FALSE; | static int Reboot = FALSE; | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* The mother of all processes. | * The mother of all processes. | ||||
*/ | */ | ||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
state_t initial_transition = runcom; | state_t initial_transition = runcom; | ||||
char kenv_value[PATH_MAX]; | char kenv_value[PATH_MAX]; | ||||
int c; | int c, error; | ||||
struct sigaction sa; | struct sigaction sa; | ||||
sigset_t mask; | sigset_t mask; | ||||
/* Dispose of random users. */ | /* Dispose of random users. */ | ||||
if (getuid() != 0) | if (getuid() != 0) | ||||
errx(1, "%s", strerror(EPERM)); | errx(1, "%s", strerror(EPERM)); | ||||
/* System V users like to reexec init. */ | /* System V users like to reexec init. */ | ||||
Show All 16 Lines | if (argc > 1) { | ||||
sig = SIGINT; | sig = SIGINT; | ||||
break; | break; | ||||
case 'c': /* block further logins */ | case 'c': /* block further logins */ | ||||
sig = SIGTSTP; | sig = SIGTSTP; | ||||
break; | break; | ||||
case 'q': /* rescan /etc/ttys */ | case 'q': /* rescan /etc/ttys */ | ||||
sig = SIGHUP; | sig = SIGHUP; | ||||
break; | break; | ||||
case 'r': /* remount root */ | |||||
sig = SIGEMT; | |||||
break; | |||||
default: | default: | ||||
goto invalid; | goto invalid; | ||||
} | } | ||||
kill(1, sig); | kill(1, sig); | ||||
_exit(0); | _exit(0); | ||||
} else | } else | ||||
invalid: | invalid: | ||||
errx(1, "invalid run-level ``%s''", argv[1]); | errx(1, "invalid run-level ``%s''", argv[1]); | ||||
} else | } else | ||||
#endif | #endif | ||||
errx(1, "already running"); | errx(1, "already running"); | ||||
} | } | ||||
/* | /* | ||||
* Note that this does NOT open a file... | * Note that this does NOT open a file... | ||||
* Does 'init' deserve its own facility number? | * Does 'init' deserve its own facility number? | ||||
*/ | */ | ||||
openlog("init", LOG_CONS, LOG_AUTH); | openlog("init", LOG_CONS, LOG_AUTH); | ||||
/* | /* | ||||
* Create an initial session. | * Create an initial session. | ||||
*/ | */ | ||||
if (setsid() < 0) | if (setsid() < 0 && (errno != EPERM || getsid(0) != 1)) | ||||
warning("initial setsid() failed: %m"); | warning("initial setsid() failed: %m"); | ||||
/* | /* | ||||
* Establish an initial user so that programs running | * Establish an initial user so that programs running | ||||
* single user do not freak out and die (like passwd). | * single user do not freak out and die (like passwd). | ||||
*/ | */ | ||||
if (setlogin("root") < 0) | if (setlogin("root") < 0) | ||||
warning("setlogin() failed: %m"); | warning("setlogin() failed: %m"); | ||||
/* | /* | ||||
* This code assumes that we always get arguments through flags, | * This code assumes that we always get arguments through flags, | ||||
* never through bits set in some random machine register. | * never through bits set in some random machine register. | ||||
*/ | */ | ||||
while ((c = getopt(argc, argv, "dsf")) != -1) | while ((c = getopt(argc, argv, "dsfr")) != -1) | ||||
switch (c) { | switch (c) { | ||||
case 'd': | case 'd': | ||||
devfs = 1; | devfs = 1; | ||||
break; | break; | ||||
case 's': | case 's': | ||||
initial_transition = single_user; | initial_transition = single_user; | ||||
break; | break; | ||||
case 'f': | case 'f': | ||||
runcom_mode = FASTBOOT; | runcom_mode = FASTBOOT; | ||||
break; | break; | ||||
case 'r': | |||||
initial_transition = reroot_phase_two; | |||||
break; | |||||
default: | default: | ||||
warning("unrecognized flag '-%c'", c); | warning("unrecognized flag '-%c'", c); | ||||
break; | break; | ||||
} | } | ||||
if (optind != argc) | if (optind != argc) | ||||
warning("ignoring excess arguments"); | warning("ignoring excess arguments"); | ||||
/* | /* | ||||
* We catch or block signals rather than ignore them, | * We catch or block signals rather than ignore them, | ||||
* so that they get reset on exec. | * so that they get reset on exec. | ||||
*/ | */ | ||||
handle(badsys, SIGSYS, 0); | handle(badsys, SIGSYS, 0); | ||||
handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGXCPU, | handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGXCPU, | ||||
SIGXFSZ, 0); | SIGXFSZ, 0); | ||||
handle(transition_handler, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGUSR1, | handle(transition_handler, SIGHUP, SIGINT, SIGEMT, SIGTERM, SIGTSTP, | ||||
SIGUSR2, 0); | SIGUSR1, SIGUSR2, 0); | ||||
handle(alrm_handler, SIGALRM, 0); | handle(alrm_handler, SIGALRM, 0); | ||||
sigfillset(&mask); | sigfillset(&mask); | ||||
delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS, | delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS, | ||||
SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGALRM, | SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGEMT, SIGTERM, SIGTSTP, | ||||
SIGUSR1, SIGUSR2, 0); | SIGALRM, SIGUSR1, SIGUSR2, 0); | ||||
sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); | sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); | ||||
sigemptyset(&sa.sa_mask); | sigemptyset(&sa.sa_mask); | ||||
sa.sa_flags = 0; | sa.sa_flags = 0; | ||||
sa.sa_handler = SIG_IGN; | sa.sa_handler = SIG_IGN; | ||||
sigaction(SIGTTIN, &sa, (struct sigaction *)0); | sigaction(SIGTTIN, &sa, (struct sigaction *)0); | ||||
sigaction(SIGTTOU, &sa, (struct sigaction *)0); | sigaction(SIGTTOU, &sa, (struct sigaction *)0); | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | if (s != NULL) { | ||||
iov[3].iov_base = _path_dev; | iov[3].iov_base = _path_dev; | ||||
iov[3].iov_len = sizeof(_path_dev); | iov[3].iov_len = sizeof(_path_dev); | ||||
} | } | ||||
nmount(iov, 4, 0); | nmount(iov, 4, 0); | ||||
if (s != NULL) | if (s != NULL) | ||||
free(s); | free(s); | ||||
} | } | ||||
if (initial_transition != reroot_phase_two) { | |||||
/* | /* | ||||
* Unmount reroot leftovers. This runs after init(8) | |||||
* gets reexecuted after reroot_phase_two() is done. | |||||
*/ | |||||
error = unmount(_PATH_REROOT, MNT_FORCE); | |||||
if (error != 0 && errno != EINVAL) | |||||
warning("Cannot unmount %s: %m", _PATH_REROOT); | |||||
} | |||||
/* | |||||
* Start the state machine. | * Start the state machine. | ||||
*/ | */ | ||||
transition(initial_transition); | transition(initial_transition); | ||||
/* | /* | ||||
* Should never reach here. | * Should never reach here. | ||||
*/ | */ | ||||
return 1; | return 1; | ||||
▲ Show 20 Lines • Show All 230 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
write_stderr(const char *message) | write_stderr(const char *message) | ||||
{ | { | ||||
write(STDERR_FILENO, message, strlen(message)); | write(STDERR_FILENO, message, strlen(message)); | ||||
} | } | ||||
static int | |||||
read_file(const char *path, void **bufp, size_t *bufsizep) | |||||
{ | |||||
struct stat sb; | |||||
size_t bufsize; | |||||
void *buf; | |||||
ssize_t nbytes; | |||||
int error, fd; | |||||
fd = open(path, O_RDONLY); | |||||
if (fd < 0) { | |||||
emergency("%s: %s", path, strerror(errno)); | |||||
return (-1); | |||||
} | |||||
error = fstat(fd, &sb); | |||||
if (error != 0) { | |||||
emergency("fstat: %s", strerror(errno)); | |||||
return (error); | |||||
} | |||||
bufsize = sb.st_size; | |||||
buf = malloc(bufsize); | |||||
if (buf == NULL) { | |||||
emergency("malloc: %s", strerror(errno)); | |||||
return (error); | |||||
} | |||||
nbytes = read(fd, buf, bufsize); | |||||
if (nbytes != (ssize_t)bufsize) { | |||||
emergency("read: %s", strerror(errno)); | |||||
free(buf); | |||||
return (error); | |||||
} | |||||
error = close(fd); | |||||
if (error != 0) { | |||||
emergency("close: %s", strerror(errno)); | |||||
free(buf); | |||||
return (error); | |||||
} | |||||
*bufp = buf; | |||||
*bufsizep = bufsize; | |||||
return (0); | |||||
} | |||||
static int | |||||
create_file(const char *path, void *buf, size_t bufsize) | |||||
{ | |||||
ssize_t nbytes; | |||||
int error, fd; | |||||
fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0700); | |||||
if (fd < 0) { | |||||
emergency("%s: %s", path, strerror(errno)); | |||||
return (-1); | |||||
} | |||||
nbytes = write(fd, buf, bufsize); | |||||
if (nbytes != (ssize_t)bufsize) { | |||||
emergency("write: %s", strerror(errno)); | |||||
return (-1); | |||||
} | |||||
error = close(fd); | |||||
if (error != 0) { | |||||
emergency("close: %s", strerror(errno)); | |||||
free(buf); | |||||
return (-1); | |||||
} | |||||
return (0); | |||||
} | |||||
static int | |||||
mount_tmpfs(const char *fspath) | |||||
{ | |||||
struct iovec *iov; | |||||
char errmsg[255]; | |||||
int error, iovlen; | |||||
iov = NULL; | |||||
iovlen = 0; | |||||
memset(errmsg, 0, sizeof(errmsg)); | |||||
build_iovec(&iov, &iovlen, "fstype", | |||||
__DECONST(void *, "tmpfs"), (size_t)-1); | |||||
build_iovec(&iov, &iovlen, "fspath", | |||||
__DECONST(void *, fspath), (size_t)-1); | |||||
build_iovec(&iov, &iovlen, "errmsg", | |||||
errmsg, sizeof(errmsg)); | |||||
error = nmount(iov, iovlen, 0); | |||||
if (error != 0) { | |||||
if (*errmsg != '\0') { | |||||
emergency("cannot mount tmpfs on %s: %s: %s", | |||||
fspath, errmsg, strerror(errno)); | |||||
} else { | |||||
emergency("cannot mount tmpfs on %s: %s", | |||||
fspath, strerror(errno)); | |||||
} | |||||
return (error); | |||||
} | |||||
return (0); | |||||
} | |||||
static state_func_t | |||||
reroot(void) | |||||
{ | |||||
void *buf; | |||||
char init_path[PATH_MAX]; | |||||
size_t bufsize, init_path_len; | |||||
int error, name[4]; | |||||
name[0] = CTL_KERN; | |||||
name[1] = KERN_PROC; | |||||
name[2] = KERN_PROC_PATHNAME; | |||||
name[3] = -1; | |||||
init_path_len = sizeof(init_path); | |||||
error = sysctl(name, 4, init_path, &init_path_len, NULL, 0); | |||||
if (error != 0) { | |||||
emergency("failed to get kern.proc.pathname: %s", | |||||
strerror(errno)); | |||||
goto out; | |||||
} | |||||
revoke_ttys(); | |||||
runshutdown(); | |||||
/* | /* | ||||
* Make sure nobody can interfere with our scheme. | |||||
*/ | |||||
error = kill(-1, SIGKILL); | |||||
if (error != 0) { | |||||
emergency("kill(2) failed: %s", strerror(errno)); | |||||
goto out; | |||||
} | |||||
/* | |||||
* Pacify GCC. | |||||
*/ | |||||
buf = NULL; | |||||
bufsize = 0; | |||||
/* | |||||
* Copy the init binary into tmpfs, so that we can unmount | |||||
* the old rootfs without committing suicide. | |||||
*/ | |||||
error = read_file(init_path, &buf, &bufsize); | |||||
if (error != 0) | |||||
goto out; | |||||
error = mount_tmpfs(_PATH_REROOT); | |||||
if (error != 0) | |||||
goto out; | |||||
error = create_file(_PATH_REROOT_INIT, buf, bufsize); | |||||
if (error != 0) | |||||
goto out; | |||||
/* | |||||
* Execute the temporary init. | |||||
*/ | |||||
execl(_PATH_REROOT_INIT, _PATH_REROOT_INIT, "-r", NULL); | |||||
emergency("cannot exec %s: %s", _PATH_REROOT_INIT, strerror(errno)); | |||||
out: | |||||
emergency("reroot failed; going to single user mode"); | |||||
return (state_func_t) single_user; | |||||
} | |||||
static state_func_t | |||||
reroot_phase_two(void) | |||||
{ | |||||
char init_path[PATH_MAX], *path, *path_component; | |||||
size_t init_path_len; | |||||
int nbytes, error; | |||||
/* | |||||
* Ask the kernel to mount the new rootfs. | |||||
*/ | |||||
error = reboot(RB_REROOT); | |||||
if (error != 0) { | |||||
emergency("RB_REBOOT failed: %s", strerror(errno)); | |||||
goto out; | |||||
} | |||||
/* | |||||
* Figure out where the destination init(8) binary is. Note that | |||||
* the path could be different than what we've started with. Use | |||||
* the value from kenv, if set, or the one from sysctl otherwise. | |||||
* The latter defaults to a hardcoded value, but can be overridden | |||||
* by a build time option. | |||||
*/ | |||||
nbytes = kenv(KENV_GET, "init_path", init_path, sizeof(init_path)); | |||||
if (nbytes <= 0) { | |||||
init_path_len = sizeof(init_path); | |||||
error = sysctlbyname("kern.init_path", | |||||
init_path, &init_path_len, NULL, 0); | |||||
if (error != 0) { | |||||
emergency("failed to retrieve kern.init_path: %s", | |||||
strerror(errno)); | |||||
goto out; | |||||
} | |||||
} | |||||
/* | |||||
* Repeat the init search logic from sys/kern/init_path.c | |||||
*/ | |||||
path_component = init_path; | |||||
while ((path = strsep(&path_component, ":")) != NULL) { | |||||
/* | |||||
* Execute init(8) from the new rootfs. | |||||
*/ | |||||
execl(path, path, NULL); | |||||
} | |||||
emergency("cannot exec init from %s: %s", init_path, strerror(errno)); | |||||
out: | |||||
emergency("reroot failed; going to single user mode"); | |||||
return (state_func_t) single_user; | |||||
} | |||||
/* | |||||
* Bring the system up single user. | * Bring the system up single user. | ||||
*/ | */ | ||||
static state_func_t | static state_func_t | ||||
single_user(void) | single_user(void) | ||||
{ | { | ||||
pid_t pid, wpid; | pid_t pid, wpid; | ||||
int status; | int status; | ||||
sigset_t mask; | sigset_t mask; | ||||
▲ Show 20 Lines • Show All 214 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* Copied from single_user(). This is a bit paranoid. | * Copied from single_user(). This is a bit paranoid. | ||||
*/ | */ | ||||
requested_transition = 0; | requested_transition = 0; | ||||
do { | do { | ||||
if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) | if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) | ||||
collect_child(wpid); | collect_child(wpid); | ||||
if (wpid == -1) { | if (wpid == -1) { | ||||
if (requested_transition == death_single) | if (requested_transition == death_single || | ||||
return (state_func_t) death_single; | requested_transition == reroot) | ||||
return (state_func_t) requested_transition; | |||||
if (errno == EINTR) | if (errno == EINTR) | ||||
continue; | continue; | ||||
warning("wait for %s on %s failed: %m; going to " | warning("wait for %s on %s failed: %m; going to " | ||||
"single user mode", shell, script); | "single user mode", shell, script); | ||||
return (state_func_t) single_user; | return (state_func_t) single_user; | ||||
} | } | ||||
if (wpid == pid && WIFSTOPPED(status)) { | if (wpid == pid && WIFSTOPPED(status)) { | ||||
warning("init: %s on %s stopped, restarting\n", | warning("init: %s on %s stopped, restarting\n", | ||||
▲ Show 20 Lines • Show All 454 Lines • ▼ Show 20 Lines | else | ||||
requested_transition = death_single; | requested_transition = death_single; | ||||
break; | break; | ||||
case SIGTSTP: | case SIGTSTP: | ||||
if (current_state == runcom || current_state == read_ttys || | if (current_state == runcom || current_state == read_ttys || | ||||
current_state == clean_ttys || | current_state == clean_ttys || | ||||
current_state == multi_user || current_state == catatonia) | current_state == multi_user || current_state == catatonia) | ||||
requested_transition = catatonia; | requested_transition = catatonia; | ||||
break; | break; | ||||
case SIGEMT: | |||||
requested_transition = reroot; | |||||
break; | |||||
default: | default: | ||||
requested_transition = 0; | requested_transition = 0; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Take the system multiuser. | * Take the system multiuser. | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Bring the system down to single user. | * Bring the system down to single user. | ||||
*/ | */ | ||||
static state_func_t | static state_func_t | ||||
death(void) | death(void) | ||||
{ | { | ||||
session_t *sp; | |||||
int block, blocked; | int block, blocked; | ||||
size_t len; | size_t len; | ||||
/* Temporarily block suspend. */ | /* Temporarily block suspend. */ | ||||
len = sizeof(blocked); | len = sizeof(blocked); | ||||
block = 1; | block = 1; | ||||
if (sysctlbyname("kern.suspend_blocked", &blocked, &len, | if (sysctlbyname("kern.suspend_blocked", &blocked, &len, | ||||
&block, sizeof(block)) == -1) | &block, sizeof(block)) == -1) | ||||
blocked = 0; | blocked = 0; | ||||
/* | /* | ||||
* Also revoke the TTY here. Because runshutdown() may reopen | * Also revoke the TTY here. Because runshutdown() may reopen | ||||
* the TTY whose getty we're killing here, there is no guarantee | * the TTY whose getty we're killing here, there is no guarantee | ||||
* runshutdown() will perform the initial open() call, causing | * runshutdown() will perform the initial open() call, causing | ||||
* the terminal attributes to be misconfigured. | * the terminal attributes to be misconfigured. | ||||
*/ | */ | ||||
for (sp = sessions; sp; sp = sp->se_next) { | revoke_ttys(); | ||||
sp->se_flags |= SE_SHUTDOWN; | |||||
kill(sp->se_process, SIGHUP); | |||||
revoke(sp->se_device); | |||||
} | |||||
/* Try to run the rc.shutdown script within a period of time */ | /* Try to run the rc.shutdown script within a period of time */ | ||||
runshutdown(); | runshutdown(); | ||||
/* Unblock suspend if we blocked it. */ | /* Unblock suspend if we blocked it. */ | ||||
if (!blocked) | if (!blocked) | ||||
sysctlbyname("kern.suspend_blocked", NULL, NULL, | sysctlbyname("kern.suspend_blocked", NULL, NULL, | ||||
&blocked, sizeof(blocked)); | &blocked, sizeof(blocked)); | ||||
Show All 27 Lines | for (i = 0; i < 2; ++i) { | ||||
if (errno == ECHILD) | if (errno == ECHILD) | ||||
return (state_func_t) single_user; | return (state_func_t) single_user; | ||||
} | } | ||||
warning("some processes would not die; ps axl advised"); | warning("some processes would not die; ps axl advised"); | ||||
return (state_func_t) single_user; | return (state_func_t) single_user; | ||||
} | |||||
static void | |||||
revoke_ttys(void) | |||||
{ | |||||
session_t *sp; | |||||
for (sp = sessions; sp; sp = sp->se_next) { | |||||
sp->se_flags |= SE_SHUTDOWN; | |||||
kill(sp->se_process, SIGHUP); | |||||
revoke(sp->se_device); | |||||
} | |||||
} | } | ||||
/* | /* | ||||
* Run the system shutdown script. | * Run the system shutdown script. | ||||
* | * | ||||
* Exit codes: XXX I should document more | * Exit codes: XXX I should document more | ||||
* -2 shutdown script terminated abnormally | * -2 shutdown script terminated abnormally | ||||
* -1 fatal error - can't run script | * -1 fatal error - can't run script | ||||
▲ Show 20 Lines • Show All 178 Lines • Show Last 20 Lines |