基于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] = '';

 

                    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!!! ") ;

    // 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 ! ",__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 ");

    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 ",__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. ");

    else

        printk(KERN_EMERG "Restarting system with command '%s'. ", 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 ",__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] = '';

        printk("in %s:%s:%d ",__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 */

    }

}

原文地址:https://www.cnblogs.com/embedded-linux/p/5774516.html