基于linux与busybox的reboot命令流程分析
http://www.xuebuyuan.com/736763.html
基于Linux与Busybox的Reboot命令流程分析
***************************************************************************************************************************
作者:EasyWave
时间:2013.01.26
类别:Linux 内核系统源码分析 声明:转载,请保留链接
注意:如有错误,欢迎指正。这些是我学习的日志文章......
***************************************************************************************************************************
一:Busyobx层的分析
这段时间,在忙到一个项目时,需要在busybox中用到reboot命令,开始在busybox中的shell中输入reboot命令,始终如下的信息,然后就停止在那里了,无法重启...为了彻底的弄明白这个问题,我在网络上找了很久,终于有个人写的一个reboot流程分析,我就借花献佛.在这里重新分析下busybox是如何运行这个命令,同时又是如何调用到Linux内核中的mach_reset中的arch_reset,当针对不同的ARM芯片时,作为Linux内核开发和驱动开发的朋友,对于这个流程还是一定要了解的。要不,出现问题,又如何找出问题呢。忘记了reboot的打印信息了,如下:
The system is going down NOW !!
Sending SIGTERM to all processes.
Sending SIGKILL to all processes.
Please stand by while rebooting the system.
Restarting system.
.
通过分析busybox1.20.0的代码可以看出在init.c中有这样一行的代码,如下:
int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int init_main(int argc UNUSED_PARAM, char **argv)
{
static const int magic[] = {
RB_HALT_SYSTEM,
RB_POWER_OFF,
RB_AUTOBOOT
};
static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM };
......
/* struct sysinfo is linux-specific */
#ifdef __linux__
/* Make sure there is enough memory to do something useful. */
if (ENABLE_SWAPONOFF) { //是否配置了swapoff命令
struct sysinfo info;
if (sysinfo(&info) == 0
&& (info.mem_unit ? info.mem_unit : 1) * (long long)info.totalram < 1024*1024
) {
message(L_CONSOLE, "Low memory, forcing swapon");
/* swapon -a requires /proc typically */
new_init_action(SYSINIT, "mount -t proc proc /proc", "");
/* Try to turn on swap */
new_init_action(SYSINIT, "swapon -a", "");
run_actions(SYSINIT); /* wait and removing */
}
}
#endif
......
/* Make the command line just say "init" - thats all, nothing else */
strncpy(argv[0], "init", strlen(argv[0]));
/* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
while (*++argv)
memset(*argv, 0, strlen(*argv));
/* Set up signal handlers */
/* Set up signal handlers */
if (!DEBUG_INIT) {
struct sigaction sa;
bb_signals(0
+ (1 << SIGUSR1) /* halt */
+ (1 << SIGTERM) /* reboot */
+ (1 << SIGUSR2) /* poweroff */
, halt_reboot_pwoff);//看到这个halt_reboot_pwoff
signal(SIGQUIT, restart_handler); /* re-exec another init */ //看到这个restart_handler函数,这是我们需要分析的
/* 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 */
/* SIGINT (Ctrl-Alt-Del) must interrupt wait(),
* setting handler without SA_RESTART flag.
*/
bb_signals_recursive_norestart((1 << SIGINT), record_signo);
}
......
}
单独拿出halt_reboot_pwoff和restart_handler这个函数来看看
/* The SIGUSR[12]/SIGTERM handler */
static void halt_reboot_pwoff(int sig) NORETURN;
static void halt_reboot_pwoff(int sig)
{
const char *m;
unsigned rb;
/* We may call run() and it unmasks signals,
* including the one masked inside this signal handler.
* Testcase which would start multiple reboot scripts:
* while true; do reboot; done
* Preventing it:
*/
reset_sighandlers_and_unblock_sigs();
run_shutdown_and_kill_processes();
m = "halt";
rb = RB_HALT_SYSTEM;
if (sig == SIGTERM) {
m = "reboot";
rb = RB_AUTOBOOT;
} else if (sig == SIGUSR2) {
m = "poweroff";
rb = RB_POWER_OFF;
}
message(L_CONSOLE, "Requesting system %s", m);
pause_and_low_level_reboot(rb);
/* not reached */
}
restart_handler函数如下:
/* Handler for QUIT - exec "restart" action,
* else (no such action defined) do nothing */
static void restart_handler(int sig UNUSED_PARAM)
{
struct init_action *a;
for (a = init_action_list; a; a = a->next) {
if (!(a->action_type & RESTART))
continue;
/* Starting from here, we won't return.
* Thus don't need to worry about preserving errno
* and such.
*/
reset_sighandlers_and_unblock_sigs();
run_shutdown_and_kill_processes();
#ifdef RB_ENABLE_CAD
/* Allow Ctrl-Alt-Del to reboot the system.
* This is how kernel sets it up for init, we follow suit.
*/
reboot(RB_ENABLE_CAD); /* misnomer */
#endif
if (open_stdio_to_tty(a->terminal)) {
dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command);
/* Theoretically should be safe.
* But in practice, kernel bugs may leave
* unkillable processes, and wait() may block forever.
* Oh well. Hoping "new" init won't be too surprised
* by having children it didn't create.
*/
//while (wait(NULL) > 0)
// continue;
init_exec(a->command);
}
/* Open or exec failed */
pause_and_low_level_reboot(RB_HALT_SYSTEM);
/* not reached */
}
}
通过分析,我们看到他们都会有调用这两个函数:reset_sighandlers_and_unblock_sigs();以及 run_shutdown_and_kill_processes();,我们重点关注如下这个函数:
static void run_shutdown_and_kill_processes(void)
{
/* Run everything to be run at "shutdown". This is done _prior_
* to killing everything, in case people wish to use scripts to
* shut things down gracefully... */
run_actions(SHUTDOWN);
message(L_CONSOLE | L_LOG, "The system is going down NOW!");
/* Send signals to every process _except_ pid 1 */
kill(-1, SIGTERM);
message(L_CONSOLE | L_LOG, "Sent SIG%s to all processes", "TERM");
sync();
sleep(1);
kill(-1, SIGKILL);
message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
sync();
/*sleep(1); - callers take care about making a pause */
}
嘿嘿,终于看到了上面的打印信息:The
system is going down NOW !! 以及Sending SIGTERM to all
processes. 同时在上面的halt_reboot_pwoff和restart_handler中都会调用这样一个函数,如下:
static void pause_and_low_level_reboot(unsigned magic) NORETURN;
static void pause_and_low_level_reboot(unsigned magic)
{
pid_t pid;
/* Allow time for last message to reach serial console, etc */
sleep(1);
/* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS)
* in linux/kernel/sys.c, which can cause the machine to panic when
* the init process exits... */
pid = vfork();
if (pid == 0) { /* child */
reboot(magic);
_exit(EXIT_SUCCESS);
}
while (1)
sleep(1);
}
看到了吗?有一个reboot(magic)函数,对于vfork函数,请参考fork函数。这里不多说了.... 我们现在来看看reboot.h文件,如下:
/*
* Definitions related to the reboot() system call,
* shared between init.c and halt.c.
*/
#include <sys/reboot.h>
#ifndef RB_HALT_SYSTEM
# if defined(__linux__)
# define RB_HALT_SYSTEM 0xcdef0123
# define RB_ENABLE_CAD 0x89abcdef
# define RB_DISABLE_CAD 0
# define RB_POWER_OFF 0x4321fedc
# define RB_AUTOBOOT 0x01234567
# elif defined(RB_HALT)
# define RB_HALT_SYSTEM RB_HALT
# endif
#endif
/* Stop system and switch power off if possible. */
#ifndef RB_POWER_OFF
# if defined(RB_POWERDOWN)
# define RB_POWER_OFF RB_POWERDOWN
# elif defined(__linux__)
# define RB_POWER_OFF 0x4321fedc
# else
# warning "poweroff unsupported, using halt as fallback"
# define RB_POWER_OFF RB_HALT_SYSTEM
# endif
#endif
而在linux的内核中的定义如下:
busybox和linux内核中的REBOOT的定义值是一样的。看到了没有了。这个很重要的哦,否则busybox是无法调用linux内核的reboot函数。
二:Linux内核层的分析
Linux内核是如何衔接busybox的reboot函数的呢,如下代码:
/*
* Reboot system call: for obvious reasons only root may call it,
* and even root needs to set up some magic numbers in the registers
* so that some mistake won't make this reboot the whole machine.
* You can also set the meaning of the ctrl-alt-del-key here.
*
* reboot doesn't sync: do that yourself before calling this.
*/
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
{
char buffer[256];
int ret = 0;
/* We only trust the superuser with rebooting the system. */
if (!capable(CAP_SYS_BOOT))
return -EPERM;
/* For safety, we require "magic" arguments. */
if (magic1 != LINUX_REBOOT_MAGIC1 ||
(magic2 != LINUX_REBOOT_MAGIC2 &&
magic2 != LINUX_REBOOT_MAGIC2A &&
magic2 != LINUX_REBOOT_MAGIC2B &&
magic2 != LINUX_REBOOT_MAGIC2C))
return -EINVAL;
/* Instead of trying to make the power_off code look like
* halt when pm_power_off is not set do it the easy way.
*/
if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
cmd = LINUX_REBOOT_CMD_HALT;
lock_kernel();
switch (cmd) {
case LINUX_REBOOT_CMD_RESTART:
kernel_restart(NULL); //这个就是重新启动Linx的命令
break;
case LINUX_REBOOT_CMD_CAD_ON:
C_A_D = 1;
break;
case LINUX_REBOOT_CMD_CAD_OFF:
C_A_D = 0;
break;
case LINUX_REBOOT_CMD_HALT:
kernel_halt();
unlock_kernel();
do_exit(0);
panic("cannot halt");
case LINUX_REBOOT_CMD_POWER_OFF:
kernel_power_off();
unlock_kernel();
do_exit(0);
break;
case LINUX_REBOOT_CMD_RESTART2:
if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
unlock_kernel();
return -EFAULT;
}
buffer[sizeof(buffer) - 1] = '\0';
kernel_restart(buffer);
break;
#ifdef CONFIG_KEXEC
case LINUX_REBOOT_CMD_KEXEC:
ret = kernel_kexec();
break;
#endif
#ifdef CONFIG_HIBERNATION
case LINUX_REBOOT_CMD_SW_SUSPEND:
ret = hibernate();
break;
#endif
default:
ret = -EINVAL;
break;
}
unlock_kernel();
return ret;
}
继续跟踪kernel_restart()函数,如下:
最终会调用一个machine_restart(cmd)函数,这个是跟具体的芯片有很大的关系的,我们进一步的分析如下:
看到了吗,最终是调用arch_reset来复位整个系统的。同时我们也看到了S3C2440的reset的函数如下:
在arm_pm_restart = s3c24xx_pm_restart()函数,最终也是调用arm_machine_restart(mod, cmd)来实现的。而在arm_machine_restart()函数中,最终也是调用arch_reset()函数来实现,而这个函数是在哪里呢。在S3C2440没有看到arch_reset函数的实现,因此从S3C2410中找到了如下的代码,请继续看下面的代码:
终于看到了arch_reset函数,最终是采用S3C2410或者S3C2440的WatchDog来实现reboot的命令的。大家可以想想,busybox的poweroff命令,是如何实现通过Linux系统关闭整个系统的电源呢,其实很简单,只需要实现下面的函数中的pm_power_off的回调函数即可。
我们可以通过一个GPIO来控制整个系统的电源,而通过上面的pm_power_off的回调函数来实现,只需要在pm_power_off函数对GPIO进行操作就可以了。你看不是很简单吗?
====================================================================
at91sam9g10复位过程:
1) at91_arch_reset() = at91sam9261_reset();
kernel/arch/arm/mach-at91/at91sam9261.c
/* --------------------------------------------------------------------
* AT91SAM9261 processor initialization
* -------------------------------------------------------------------- */
void __init at91sam9261_initialize(unsigned long main_clock)
{
/* Map peripherals */
iotable_init(at91sam9261_io_desc, ARRAY_SIZE(at91sam9261_io_desc));
if (cpu_is_at91sam9g10())
iotable_init(at91sam9g10_sram_desc, ARRAY_SIZE(at91sam9g10_sram_desc));
else
iotable_init(at91sam9261_sram_desc, ARRAY_SIZE(at91sam9261_sram_desc));
at91_arch_reset = at91sam9261_reset;
pm_power_off = at91sam9261_poweroff;
at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
| (1 << AT91SAM9261_ID_IRQ2);
/* Init clock subsystem */
at91_clock_init(main_clock);
/* Register the processor-specific clocks */
at91sam9261_register_clocks();
/* Register GPIO subsystem */
at91_gpio_init(at91sam9261_gpio, 3);
}
static void at91sam9261_reset(void)
{
#ifdef CONFIG_ARCH_AT91SAM9G10
at91_lcdc_write(ATMEL_LCDC_PWRCON, 1 << ATMEL_LCDC_GUARDT_OFFSET);
while (at91_lcdc_read(ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
msleep(10);
at91_lcdc_write(ATMEL_LCDC_DMACON, 0);
while (at91_lcdc_read(ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
msleep(10);
local_irq_disable();
#endif
printk(KERN_ERR "software rest!!!\n") ;
// at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
at91_sys_write(AT91_RSTC_MR, AT91_RSTC_KEY | AT91_RSTC_ERSTL); at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST |AT91_RSTC_EXTRST );
}
static void at91sam9261_poweroff(void)
{
at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
}
2) arch_reset();
kernel/arch/arm/mach-at91/include/mach/system.h
static inline void arch_reset(char mode, const char *cmd)
{
/* call the CPU-specific reset function */
if (at91_arch_reset)
(at91_arch_reset)();
}
3) arm_machine_restart();
arch/arm/kernel/process.c
void arm_machine_restart(char mode, const char *cmd)
{
printk("in: %s:%s !\n",__FILE__,__FUNCTION__);
/*
* Clean and disable cache, and turn off interrupts
*/
cpu_proc_fin();
/*
* Tell the mm system that we are going to reboot -
* we may need it to insert some 1:1 mappings so that
* soft boot works.
*/
setup_mm_for_reboot(mode);
/*
* Now call the architecture specific reboot code.
*/
arch_reset(mode, cmd);
/*
* Whoops - the architecture was unable to reboot.
* Tell the user!
*/
mdelay(1000);
printk("Reboot failed -- System halted\n");
while (1);
}
4) machine_restart()
kernel/arch/arm/kernel/process.c
void machine_power_off(void)
{
if (pm_power_off)
pm_power_off();
}
void machine_restart(char *cmd)
{
printk("in:%s:%s\n",__FILE__,__FUNCTION__);
arm_pm_restart(reboot_mode, cmd);
}
void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart;
EXPORT_SYMBOL_GPL(arm_pm_restart);
5) kernel_restart()
kernel/kernel/sys.c
void kernel_restart_prepare(char *cmd)
{
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
system_state = SYSTEM_RESTART;
device_shutdown();
sysdev_shutdown();
}
/**
* kernel_restart - reboot the system
* @cmd: pointer to buffer containing command to execute for restart
* or %NULL
*
* Shutdown everything and perform a clean reboot.
* This is not safe to call in interrupt context.
*/
void kernel_restart(char *cmd)
{
kernel_restart_prepare(cmd);
if (!cmd)
printk(KERN_EMERG "Restarting system.\n");
else
printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
machine_restart(cmd);
}
EXPORT_SYMBOL_GPL(kernel_restart);
6) SYSCALL_DEFINE4()
kernel/kernel/sys.c
/*
* Reboot system call: for obvious reasons only root may call it,
* and even root needs to set up some magic numbers in the registers
* so that some mistake won't make this reboot the whole machine.
* You can also set the meaning of the ctrl-alt-del-key here.
*
* reboot doesn't sync: do that yourself before calling this.
*/
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
{
char buffer[256];
int ret = 0;
/* We only trust the superuser with rebooting the system. */
if (!capable(CAP_SYS_BOOT))
return -EPERM;
/* For safety, we require "magic" arguments. */
if (magic1 != LINUX_REBOOT_MAGIC1 ||
(magic2 != LINUX_REBOOT_MAGIC2 &&
magic2 != LINUX_REBOOT_MAGIC2A &&
magic2 != LINUX_REBOOT_MAGIC2B &&
magic2 != LINUX_REBOOT_MAGIC2C))
return -EINVAL;
/* Instead of trying to make the power_off code look like
* halt when pm_power_off is not set do it the easy way.
*/
if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
cmd = LINUX_REBOOT_CMD_HALT;
lock_kernel();
switch (cmd) {
case LINUX_REBOOT_CMD_RESTART:
printk("in %s:%s:%d\n",__FILE__,__FUNCTION__,__LINE__) ;
kernel_restart(NULL);
break;
case LINUX_REBOOT_CMD_CAD_ON:
C_A_D = 1;
break;
case LINUX_REBOOT_CMD_CAD_OFF:
C_A_D = 0;
break;
case LINUX_REBOOT_CMD_HALT:
kernel_halt();
unlock_kernel();
do_exit(0);
panic("cannot halt");
case LINUX_REBOOT_CMD_POWER_OFF:
kernel_power_off();
unlock_kernel();
do_exit(0);
break;
case LINUX_REBOOT_CMD_RESTART2:
if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
unlock_kernel();
return -EFAULT;
}
buffer[sizeof(buffer) - 1] = '\0';
printk("in %s:%s:%d\n",__FILE__,__FUNCTION__,__LINE__) ;
kernel_restart(buffer);
break;
#ifdef CONFIG_KEXEC
case LINUX_REBOOT_CMD_KEXEC:
ret = kernel_kexec();
break;
#endif
#ifdef CONFIG_HIBERNATION
case LINUX_REBOOT_CMD_SW_SUSPEND:
ret = hibernate();
break;
#endif
default:
ret = -EINVAL;
break;
}
unlock_kernel();
return ret;
}
7) kernel/include/linux/reboot.h
/*
* Magic values required to use _reboot() system call.
*/
#define LINUX_REBOOT_MAGIC1 0xfee1dead
#define LINUX_REBOOT_MAGIC2 672274793
#define LINUX_REBOOT_MAGIC2A 85072278
#define LINUX_REBOOT_MAGIC2B 369367448
#define LINUX_REBOOT_MAGIC2C 537993216
/*
* Commands accepted by the _reboot() system call.
*
* RESTART Restart system using default command and mode.
* HALT Stop OS and give system control to ROM monitor, if any.
* CAD_ON Ctrl-Alt-Del sequence causes RESTART command.
* CAD_OFF Ctrl-Alt-Del sequence sends SIGINT to init task.
* POWER_OFF Stop OS and remove all power from system, if possible.
* RESTART2 Restart system using given command string.
* SW_SUSPEND Suspend system using software suspend if compiled in.
* KEXEC Restart system using a previously loaded Linux kernel
*/
#define LINUX_REBOOT_CMD_RESTART 0x01234567
#define LINUX_REBOOT_CMD_HALT 0xCDEF0123
#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF
#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000
#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC
#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4
#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2
#define LINUX_REBOOT_CMD_KEXEC 0x45584543
8) busybox/init/reboot.h
#include <sys/reboot.h>
#ifndef RB_HALT_SYSTEM
# if defined(__linux__)
# define RB_HALT_SYSTEM 0xcdef0123
# define RB_ENABLE_CAD 0x89abcdef
# define RB_DISABLE_CAD 0
# define RB_POWER_OFF 0x4321fedc
# define RB_AUTOBOOT 0x01234567
# elif defined(RB_HALT)
# define RB_HALT_SYSTEM RB_HALT
# endif
#endif
/* Stop system and switch power off if possible. */
#ifndef RB_POWER_OFF
# if defined(RB_POWERDOWN)
# define RB_POWER_OFF RB_POWERDOWN
# elif defined(__linux__)
# define RB_POWER_OFF 0x4321fedc
# else
# warning "poweroff unsupported, using halt as fallback"
# define RB_POWER_OFF RB_HALT_SYSTEM
# endif
#endif
9) pause_and_low_level_reboot()
busybox/init/init.c
static void pause_and_low_level_reboot(unsigned magic) NORETURN;
static void pause_and_low_level_reboot(unsigned magic)
{
pid_t pid;
/* Allow time for last message to reach serial console, etc */
sleep(1);
/* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS)
* in linux/kernel/sys.c, which can cause the machine to panic when
* the init process exits... */
pid = vfork();
if (pid == 0) { /* child */
reboot(magic);
_exit(EXIT_SUCCESS);
}
while (1)
sleep(1);
}
static void run_shutdown_and_kill_processes(void)
{
/* Run everything to be run at "shutdown". This is done _prior_
* to killing everything, in case people wish to use scripts to
* shut things down gracefully... */
run_actions(SHUTDOWN);
message(L_CONSOLE | L_LOG, "The system is going down NOW!");
/* Send signals to every process _except_ pid 1 */
kill(-1, SIGTERM);
message(L_CONSOLE | L_LOG, "Sent SIG%s to all processes", "TERM");
sync();
sleep(1);
kill(-1, SIGKILL);
message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
sync();
/*sleep(1); - callers take care about making a pause */
}
/* The SIGPWR/SIGUSR[12]/SIGTERM handler */
static void halt_reboot_pwoff(int sig) NORETURN;
static void halt_reboot_pwoff(int sig)
{
const char *m;
unsigned rb;
/* We may call run() and it unmasks signals,
* including the one masked inside this signal handler.
* Testcase which would start multiple reboot scripts:
* while true; do reboot; done
* Preventing it:
*/
reset_sighandlers_and_unblock_sigs();
run_shutdown_and_kill_processes();
m = "halt";
rb = RB_HALT_SYSTEM;
if (sig == SIGTERM) {
m = "reboot";
rb = RB_AUTOBOOT;
} else if (sig == SIGUSR2) {
m = "poweroff";
rb = RB_POWER_OFF;
}
message(L_CONSOLE, "Requesting system %s", m);
pause_and_low_level_reboot(rb);
/* not reached */
}
/* Handler for QUIT - exec "restart" action,
* else (no such action defined) do nothing */
static void exec_restart_action(void)
{
struct init_action *a;
for (a = init_action_list; a; a = a->next) {
if (!(a->action_type & RESTART))
continue;
/* Starting from here, we won't return.
* Thus don't need to worry about preserving errno
* and such.
*/
reset_sighandlers_and_unblock_sigs();
run_shutdown_and_kill_processes();
#ifdef RB_ENABLE_CAD
/* Allow Ctrl-Alt-Del to reboot the system.
* This is how kernel sets it up for init, we follow suit.
*/
reboot(RB_ENABLE_CAD); /* misnomer */
#endif
if (open_stdio_to_tty(a->terminal)) {
dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command);
/* Theoretically should be safe.
* But in practice, kernel bugs may leave
* unkillable processes, and wait() may block forever.
* Oh well. Hoping "new" init won't be too surprised
* by having children it didn't create.
*/
//while (wait(NULL) > 0)
// continue;
init_exec(a->command);
}
/* Open or exec failed */
pause_and_low_level_reboot(RB_HALT_SYSTEM);
/* not reached */
}
}