init: improve handling of signals racing with each other
Before this change, a request to reboot could be "overwritten" by e.g. SIGHUP. function old new delta init_main 709 793 +84 packed_usage 33273 33337 +64 run_actions 109 117 +8 stop_handler 87 88 +1 check_delayed_sigs 340 335 -5 run 214 198 -16 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/2 up/down: 157/-21) Total: 136 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
113c776f4d
commit
356f23de20
280
init/init.c
280
init/init.c
@ -210,6 +210,8 @@ struct globals {
|
|||||||
#if !ENABLE_FEATURE_INIT_SYSLOG
|
#if !ENABLE_FEATURE_INIT_SYSLOG
|
||||||
const char *log_console;
|
const char *log_console;
|
||||||
#endif
|
#endif
|
||||||
|
sigset_t delayed_sigset;
|
||||||
|
struct timespec zero_ts;
|
||||||
} FIX_ALIASING;
|
} FIX_ALIASING;
|
||||||
#define G (*(struct globals*)bb_common_bufsiz1)
|
#define G (*(struct globals*)bb_common_bufsiz1)
|
||||||
#define INIT_G() do { \
|
#define INIT_G() do { \
|
||||||
@ -411,14 +413,8 @@ static int open_stdio_to_tty(const char* tty_name)
|
|||||||
static void reset_sighandlers_and_unblock_sigs(void)
|
static void reset_sighandlers_and_unblock_sigs(void)
|
||||||
{
|
{
|
||||||
bb_signals(0
|
bb_signals(0
|
||||||
+ (1 << SIGUSR1)
|
| (1 << SIGTSTP)
|
||||||
+ (1 << SIGUSR2)
|
| (1 << SIGSTOP)
|
||||||
+ (1 << SIGTERM)
|
|
||||||
+ (1 << SIGQUIT)
|
|
||||||
+ (1 << SIGINT)
|
|
||||||
+ (1 << SIGHUP)
|
|
||||||
+ (1 << SIGTSTP)
|
|
||||||
+ (1 << SIGSTOP)
|
|
||||||
, SIG_DFL);
|
, SIG_DFL);
|
||||||
sigprocmask_allsigs(SIG_UNBLOCK);
|
sigprocmask_allsigs(SIG_UNBLOCK);
|
||||||
}
|
}
|
||||||
@ -484,16 +480,13 @@ static pid_t run(const struct init_action *a)
|
|||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
/* Careful: don't be affected by a signal in vforked child */
|
|
||||||
sigprocmask_allsigs(SIG_BLOCK);
|
|
||||||
if (BB_MMU && (a->action_type & ASKFIRST))
|
if (BB_MMU && (a->action_type & ASKFIRST))
|
||||||
pid = fork();
|
pid = fork();
|
||||||
else
|
else
|
||||||
pid = vfork();
|
pid = vfork();
|
||||||
if (pid < 0)
|
|
||||||
message(L_LOG | L_CONSOLE, "can't fork");
|
|
||||||
if (pid) {
|
if (pid) {
|
||||||
sigprocmask_allsigs(SIG_UNBLOCK);
|
if (pid < 0)
|
||||||
|
message(L_LOG | L_CONSOLE, "can't fork");
|
||||||
return pid; /* Parent or error */
|
return pid; /* Parent or error */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,9 +580,11 @@ static void waitfor(pid_t pid)
|
|||||||
while (1) {
|
while (1) {
|
||||||
pid_t wpid = wait(NULL);
|
pid_t wpid = wait(NULL);
|
||||||
mark_terminated(wpid);
|
mark_terminated(wpid);
|
||||||
/* Unsafe. SIGTSTP handler might have wait'ed it already */
|
if (wpid == pid) /* this was the process we waited for */
|
||||||
/*if (wpid == pid) break;*/
|
break;
|
||||||
/* More reliable: */
|
/* The above is not reliable enough: SIGTSTP handler might have
|
||||||
|
* wait'ed it already. Double check, exit if process is gone:
|
||||||
|
*/
|
||||||
if (kill(pid, 0))
|
if (kill(pid, 0))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -798,23 +793,17 @@ static void run_shutdown_and_kill_processes(void)
|
|||||||
* Delayed handlers just set a flag variable. The variable is checked
|
* Delayed handlers just set a flag variable. The variable is checked
|
||||||
* in the main loop and acted upon.
|
* in the main loop and acted upon.
|
||||||
*
|
*
|
||||||
* halt/poweroff/reboot and restart have immediate handlers.
|
|
||||||
* They only traverse linked list of struct action's, never modify it,
|
|
||||||
* this should be safe to do even in signal handler. Also they
|
|
||||||
* never return.
|
|
||||||
*
|
|
||||||
* SIGSTOP and SIGTSTP have immediate handlers. They just wait
|
* SIGSTOP and SIGTSTP have immediate handlers. They just wait
|
||||||
* for SIGCONT to happen.
|
* for SIGCONT to happen.
|
||||||
*
|
*
|
||||||
|
* halt/poweroff/reboot and restart have delayed handlers.
|
||||||
|
*
|
||||||
* SIGHUP has a delayed handler, because modifying linked list
|
* SIGHUP has a delayed handler, because modifying linked list
|
||||||
* of struct action's from a signal handler while it is manipulated
|
* of struct action's from a signal handler while it is manipulated
|
||||||
* by the program may be disastrous.
|
* by the program may be disastrous.
|
||||||
*
|
*
|
||||||
* Ctrl-Alt-Del has a delayed handler. Not a must, but allowing
|
* Ctrl-Alt-Del has a delayed handler. Not a must, but allowing
|
||||||
* it to happen even somewhere inside "sysinit" would be a bit awkward.
|
* it to happen even somewhere inside "sysinit" would be a bit awkward.
|
||||||
*
|
|
||||||
* There is a tiny probability that SIGHUP and Ctrl-Alt-Del will collide
|
|
||||||
* and only one will be remembered and acted upon.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* The SIGPWR/SIGUSR[12]/SIGTERM handler */
|
/* The SIGPWR/SIGUSR[12]/SIGTERM handler */
|
||||||
@ -898,11 +887,9 @@ static void exec_restart_action(void)
|
|||||||
*/
|
*/
|
||||||
static void stop_handler(int sig UNUSED_PARAM)
|
static void stop_handler(int sig UNUSED_PARAM)
|
||||||
{
|
{
|
||||||
smallint saved_bb_got_signal;
|
int saved_errno = errno;
|
||||||
int saved_errno;
|
|
||||||
|
|
||||||
saved_bb_got_signal = bb_got_signal;
|
bb_got_signal = 0;
|
||||||
saved_errno = errno;
|
|
||||||
signal(SIGCONT, record_signo);
|
signal(SIGCONT, record_signo);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -916,12 +903,12 @@ static void stop_handler(int sig UNUSED_PARAM)
|
|||||||
*/
|
*/
|
||||||
wpid = wait_any_nohang(NULL);
|
wpid = wait_any_nohang(NULL);
|
||||||
mark_terminated(wpid);
|
mark_terminated(wpid);
|
||||||
sleep(1);
|
if (wpid <= 0) /* no processes exited? sleep a bit */
|
||||||
|
sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
signal(SIGCONT, SIG_DFL);
|
signal(SIGCONT, SIG_DFL);
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
bb_got_signal = saved_bb_got_signal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_FEATURE_USE_INITTAB
|
#if ENABLE_FEATURE_USE_INITTAB
|
||||||
@ -986,43 +973,39 @@ static void reload_inittab(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int check_delayed_sigs(void)
|
static void check_delayed_sigs(struct timespec *ts)
|
||||||
{
|
{
|
||||||
int sigs_seen = 0;
|
int sig = sigtimedwait(&G.delayed_sigset, /* siginfo_t */ NULL, ts);
|
||||||
|
if (sig <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
while (1) {
|
/* The signal "sig" was caught */
|
||||||
smallint sig = bb_got_signal;
|
|
||||||
|
|
||||||
if (!sig)
|
|
||||||
return sigs_seen;
|
|
||||||
bb_got_signal = 0;
|
|
||||||
sigs_seen = 1;
|
|
||||||
#if ENABLE_FEATURE_USE_INITTAB
|
#if ENABLE_FEATURE_USE_INITTAB
|
||||||
if (sig == SIGHUP)
|
if (sig == SIGHUP)
|
||||||
reload_inittab();
|
reload_inittab();
|
||||||
#endif
|
#endif
|
||||||
if (sig == SIGINT)
|
if (sig == SIGINT)
|
||||||
run_actions(CTRLALTDEL);
|
run_actions(CTRLALTDEL);
|
||||||
if (sig == SIGQUIT) {
|
if (sig == SIGQUIT) {
|
||||||
exec_restart_action();
|
exec_restart_action();
|
||||||
/* returns only if no restart action defined */
|
/* returns only if no restart action defined */
|
||||||
}
|
|
||||||
if ((1 << sig) & (0
|
|
||||||
#ifdef SIGPWR
|
|
||||||
+ (1 << SIGPWR)
|
|
||||||
#endif
|
|
||||||
+ (1 << SIGUSR1)
|
|
||||||
+ (1 << SIGUSR2)
|
|
||||||
+ (1 << SIGTERM)
|
|
||||||
)) {
|
|
||||||
halt_reboot_pwoff(sig);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if ((1 << sig) & (0
|
||||||
|
#ifdef SIGPWR
|
||||||
|
| (1 << SIGPWR)
|
||||||
|
#endif
|
||||||
|
| (1 << SIGUSR1)
|
||||||
|
| (1 << SIGUSR2)
|
||||||
|
| (1 << SIGTERM)
|
||||||
|
)) {
|
||||||
|
halt_reboot_pwoff(sig);
|
||||||
|
}
|
||||||
|
/* if (sig == SIGCHLD) do nothing */
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_SEGV_HANDLER
|
#if DEBUG_SEGV_HANDLER
|
||||||
static
|
static void handle_sigsegv(int sig, siginfo_t *info, void *ucontext)
|
||||||
void handle_sigsegv(int sig, siginfo_t *info, void *ucontext)
|
|
||||||
{
|
{
|
||||||
long ip;
|
long ip;
|
||||||
ucontext_t *uc;
|
ucontext_t *uc;
|
||||||
@ -1049,50 +1032,62 @@ void handle_sigsegv(int sig, siginfo_t *info, void *ucontext)
|
|||||||
|
|
||||||
static void sleep_much(void)
|
static void sleep_much(void)
|
||||||
{
|
{
|
||||||
sleep(30 * 24*60*60);
|
sleep(30 * 24*60*60);
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||||
int init_main(int argc UNUSED_PARAM, char **argv)
|
int init_main(int argc UNUSED_PARAM, char **argv)
|
||||||
{
|
{
|
||||||
|
struct sigaction sa;
|
||||||
|
|
||||||
INIT_G();
|
INIT_G();
|
||||||
|
|
||||||
|
/* Some users send poweroff signals to init VERY early.
|
||||||
|
* To handle this, mask signals early.
|
||||||
|
*/
|
||||||
|
/* sigemptyset(&G.delayed_sigset); - done by INIT_G() */
|
||||||
|
sigaddset(&G.delayed_sigset, SIGINT); /* Ctrl-Alt-Del */
|
||||||
|
sigaddset(&G.delayed_sigset, SIGQUIT); /* re-exec another init */
|
||||||
|
#ifdef SIGPWR
|
||||||
|
sigaddset(&G.delayed_sigset, SIGPWR); /* halt */
|
||||||
|
#endif
|
||||||
|
sigaddset(&G.delayed_sigset, SIGUSR1); /* halt */
|
||||||
|
sigaddset(&G.delayed_sigset, SIGTERM); /* reboot */
|
||||||
|
sigaddset(&G.delayed_sigset, SIGUSR2); /* poweroff */
|
||||||
|
#if ENABLE_FEATURE_USE_INITTAB
|
||||||
|
sigaddset(&G.delayed_sigset, SIGHUP); /* reread /etc/inittab */
|
||||||
|
#endif
|
||||||
|
sigaddset(&G.delayed_sigset, SIGCHLD); /* make sigtimedwait() exit on SIGCHLD */
|
||||||
|
sigprocmask(SIG_BLOCK, &G.delayed_sigset, NULL);
|
||||||
|
|
||||||
|
#if DEBUG_SEGV_HANDLER
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sa.sa_sigaction = handle_sigsegv;
|
||||||
|
sa.sa_flags = SA_SIGINFO;
|
||||||
|
sigaction_set(SIGSEGV, &sa);
|
||||||
|
sigaction_set(SIGILL, &sa);
|
||||||
|
sigaction_set(SIGFPE, &sa);
|
||||||
|
sigaction_set(SIGBUS, &sa);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (argv[1] && strcmp(argv[1], "-q") == 0) {
|
if (argv[1] && strcmp(argv[1], "-q") == 0) {
|
||||||
return kill(1, SIGHUP);
|
return kill(1, SIGHUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_SEGV_HANDLER
|
#if !DEBUG_INIT
|
||||||
{
|
/* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
|
||||||
struct sigaction sa;
|
if (getpid() != 1
|
||||||
memset(&sa, 0, sizeof(sa));
|
&& (!ENABLE_LINUXRC || applet_name[0] != 'l') /* not linuxrc? */
|
||||||
sa.sa_sigaction = handle_sigsegv;
|
) {
|
||||||
sa.sa_flags = SA_SIGINFO;
|
bb_simple_error_msg_and_die("must be run as PID 1");
|
||||||
sigaction(SIGSEGV, &sa, NULL);
|
|
||||||
sigaction(SIGILL, &sa, NULL);
|
|
||||||
sigaction(SIGFPE, &sa, NULL);
|
|
||||||
sigaction(SIGBUS, &sa, NULL);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!DEBUG_INIT) {
|
# ifdef RB_DISABLE_CAD
|
||||||
/* Some users send poweroff signals to init VERY early.
|
/* Turn off rebooting via CTL-ALT-DEL - we get a
|
||||||
* To handle this, mask signals early,
|
* SIGINT on CAD so we can shut things down gracefully... */
|
||||||
* and unmask them only after signal handlers are installed.
|
reboot(RB_DISABLE_CAD); /* misnomer */
|
||||||
*/
|
# endif
|
||||||
sigprocmask_allsigs(SIG_BLOCK);
|
|
||||||
|
|
||||||
/* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
|
|
||||||
if (getpid() != 1
|
|
||||||
&& (!ENABLE_LINUXRC || applet_name[0] != 'l') /* not linuxrc? */
|
|
||||||
) {
|
|
||||||
bb_simple_error_msg_and_die("must be run as PID 1");
|
|
||||||
}
|
|
||||||
#ifdef RB_DISABLE_CAD
|
|
||||||
/* Turn off rebooting via CTL-ALT-DEL - we get a
|
|
||||||
* SIGINT on CAD so we can shut things down gracefully... */
|
|
||||||
reboot(RB_DISABLE_CAD); /* misnomer */
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
/* If, say, xmalloc would ever die, we don't want to oops kernel
|
/* If, say, xmalloc would ever die, we don't want to oops kernel
|
||||||
* by exiting.
|
* by exiting.
|
||||||
@ -1156,106 +1151,65 @@ int init_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ENABLE_FEATURE_INIT_MODIFY_CMDLINE) {
|
#if ENABLE_FEATURE_INIT_MODIFY_CMDLINE
|
||||||
/* Make the command line just say "init" - that's all, nothing else */
|
/* Make the command line just say "init" - that's all, nothing else */
|
||||||
strncpy(argv[0], "init", strlen(argv[0]));
|
strncpy(argv[0], "init", strlen(argv[0]));
|
||||||
/* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
|
/* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
|
||||||
while (*++argv)
|
while (*++argv)
|
||||||
nuke_str(*argv);
|
nuke_str(*argv);
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up signal handlers */
|
|
||||||
if (!DEBUG_INIT) {
|
|
||||||
struct sigaction sa;
|
|
||||||
|
|
||||||
/* Stop handler must allow only SIGCONT inside itself */
|
|
||||||
memset(&sa, 0, sizeof(sa));
|
|
||||||
sigfillset(&sa.sa_mask);
|
|
||||||
sigdelset(&sa.sa_mask, SIGCONT);
|
|
||||||
sa.sa_handler = stop_handler;
|
|
||||||
/* NB: sa_flags doesn't have SA_RESTART.
|
|
||||||
* It must be able to interrupt wait().
|
|
||||||
*/
|
|
||||||
sigaction_set(SIGTSTP, &sa); /* pause */
|
|
||||||
/* Does not work as intended, at least in 2.6.20.
|
|
||||||
* SIGSTOP is simply ignored by init:
|
|
||||||
*/
|
|
||||||
sigaction_set(SIGSTOP, &sa); /* pause */
|
|
||||||
|
|
||||||
/* These signals must interrupt wait(),
|
|
||||||
* setting handler without SA_RESTART flag.
|
|
||||||
*/
|
|
||||||
bb_signals_recursive_norestart(0
|
|
||||||
+ (1 << SIGINT) /* Ctrl-Alt-Del */
|
|
||||||
+ (1 << SIGQUIT) /* re-exec another init */
|
|
||||||
#ifdef SIGPWR
|
|
||||||
+ (1 << SIGPWR) /* halt */
|
|
||||||
#endif
|
#endif
|
||||||
+ (1 << SIGUSR1) /* halt */
|
|
||||||
+ (1 << SIGTERM) /* reboot */
|
|
||||||
+ (1 << SIGUSR2) /* poweroff */
|
|
||||||
#if ENABLE_FEATURE_USE_INITTAB
|
|
||||||
+ (1 << SIGHUP) /* reread /etc/inittab */
|
|
||||||
#endif
|
|
||||||
, record_signo);
|
|
||||||
|
|
||||||
sigprocmask_allsigs(SIG_UNBLOCK);
|
/* Set up STOP signal handlers */
|
||||||
}
|
/* Stop handler must allow only SIGCONT inside itself */
|
||||||
|
memset(&sa, 0, sizeof(sa));
|
||||||
|
sigfillset(&sa.sa_mask);
|
||||||
|
sigdelset(&sa.sa_mask, SIGCONT);
|
||||||
|
sa.sa_handler = stop_handler;
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
|
sigaction_set(SIGTSTP, &sa); /* pause */
|
||||||
|
/* Does not work as intended, at least in 2.6.20.
|
||||||
|
* SIGSTOP is simply ignored by init
|
||||||
|
* (NB: behavior might differ under strace):
|
||||||
|
*/
|
||||||
|
sigaction_set(SIGSTOP, &sa); /* pause */
|
||||||
|
|
||||||
/* Now run everything that needs to be run */
|
/* Now run everything that needs to be run */
|
||||||
/* First run the sysinit command */
|
/* First run the sysinit command */
|
||||||
run_actions(SYSINIT);
|
run_actions(SYSINIT);
|
||||||
check_delayed_sigs();
|
check_delayed_sigs(&G.zero_ts);
|
||||||
/* Next run anything that wants to block */
|
/* Next run anything that wants to block */
|
||||||
run_actions(WAIT);
|
run_actions(WAIT);
|
||||||
check_delayed_sigs();
|
check_delayed_sigs(&G.zero_ts);
|
||||||
/* Next run anything to be run only once */
|
/* Next run anything to be run only once */
|
||||||
run_actions(ONCE);
|
run_actions(ONCE);
|
||||||
|
|
||||||
/* Now run the looping stuff for the rest of forever.
|
/* Now run the looping stuff for the rest of forever */
|
||||||
*/
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int maybe_WNOHANG;
|
|
||||||
|
|
||||||
maybe_WNOHANG = check_delayed_sigs();
|
|
||||||
|
|
||||||
/* (Re)run the respawn/askfirst stuff */
|
/* (Re)run the respawn/askfirst stuff */
|
||||||
run_actions(RESPAWN | ASKFIRST);
|
run_actions(RESPAWN | ASKFIRST);
|
||||||
maybe_WNOHANG |= check_delayed_sigs();
|
|
||||||
|
|
||||||
/* Don't consume all CPU time - sleep a bit */
|
/* Wait for any signal (typically it's SIGCHLD) */
|
||||||
sleep(1);
|
check_delayed_sigs(NULL); /* NULL timespec makes it wait */
|
||||||
maybe_WNOHANG |= check_delayed_sigs();
|
|
||||||
|
|
||||||
/* Wait for any child process(es) to exit.
|
/* Wait for any child process(es) to exit */
|
||||||
*
|
|
||||||
* If check_delayed_sigs above reported that a signal
|
|
||||||
* was caught, wait will be nonblocking. This ensures
|
|
||||||
* that if SIGHUP has reloaded inittab, respawn and askfirst
|
|
||||||
* actions will not be delayed until next child death.
|
|
||||||
*/
|
|
||||||
if (maybe_WNOHANG)
|
|
||||||
maybe_WNOHANG = WNOHANG;
|
|
||||||
while (1) {
|
while (1) {
|
||||||
pid_t wpid;
|
pid_t wpid;
|
||||||
struct init_action *a;
|
struct init_action *a;
|
||||||
|
|
||||||
/* If signals happen _in_ the wait, they interrupt it,
|
wpid = waitpid(-1, NULL, WNOHANG);
|
||||||
* bb_signals_recursive_norestart set them up that way
|
|
||||||
*/
|
|
||||||
wpid = waitpid(-1, NULL, maybe_WNOHANG);
|
|
||||||
if (wpid <= 0)
|
if (wpid <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
a = mark_terminated(wpid);
|
a = mark_terminated(wpid);
|
||||||
if (a) {
|
if (a) {
|
||||||
message(L_LOG, "process '%s' (pid %d) exited. "
|
message(L_LOG, "process '%s' (pid %u) exited. "
|
||||||
"Scheduling for restart.",
|
"Scheduling for restart.",
|
||||||
a->command, wpid);
|
a->command, (unsigned)wpid);
|
||||||
}
|
}
|
||||||
/* See if anyone else is waiting to be reaped */
|
|
||||||
maybe_WNOHANG = WNOHANG;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Don't consume all CPU time - sleep a bit */
|
||||||
|
sleep(1);
|
||||||
} /* while (1) */
|
} /* while (1) */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1268,11 +1222,17 @@ int init_main(int argc UNUSED_PARAM, char **argv)
|
|||||||
//usage: "Init is the first process started during boot. It never exits."
|
//usage: "Init is the first process started during boot. It never exits."
|
||||||
//usage: IF_FEATURE_USE_INITTAB(
|
//usage: IF_FEATURE_USE_INITTAB(
|
||||||
//usage: "\n""It (re)spawns children according to /etc/inittab."
|
//usage: "\n""It (re)spawns children according to /etc/inittab."
|
||||||
|
//usage: "\n""Signals:"
|
||||||
|
//usage: "\n""HUP: reload /etc/inittab"
|
||||||
//usage: )
|
//usage: )
|
||||||
//usage: IF_NOT_FEATURE_USE_INITTAB(
|
//usage: IF_NOT_FEATURE_USE_INITTAB(
|
||||||
//usage: "\n""This version of init doesn't use /etc/inittab,"
|
//usage: "\n""This version of init doesn't use /etc/inittab,"
|
||||||
//usage: "\n""has fixed set of processed to run."
|
//usage: "\n""has fixed set of processed to run."
|
||||||
|
//usage: "\n""Signals:"
|
||||||
//usage: )
|
//usage: )
|
||||||
|
//usage: "\n""TSTP: stop respawning until CONT"
|
||||||
|
//usage: "\n""QUIT: re-exec another init"
|
||||||
|
//usage: "\n""USR1/TERM/USR2/INT: run halt/reboot/poweroff/Ctrl-Alt-Del script"
|
||||||
//usage:
|
//usage:
|
||||||
//usage:#define init_notes_usage
|
//usage:#define init_notes_usage
|
||||||
//usage: "This version of init is designed to be run only by the kernel.\n"
|
//usage: "This version of init is designed to be run only by the kernel.\n"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user