zoukankan      html  css  js  c++  java
  • 基于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 */

        }

    }

  • 相关阅读:
    springboot之静态资源放行的方法(记录)
    FastDFS之图片上传
    FastDFS安装部署
    Docker安装MySQL5.7.25
    123qwe
    Spring3 MVC 注解(一)---注解基本配置及@controller和 @RequestMapping 常用解释
    jQuery可见性过滤选择器
    jQuery属性过滤选择器
    jQuery内容过滤选择器
    jQuery子元素过滤选择器
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/5774516.html
Copyright © 2011-2022 走看看