zoukankan      html  css  js  c++  java
  • 简单理解Busybox下halt/poweroff/reboot实现及区别

     关键词:halt/poweroff/reboot、reboot()、SIGUSR1/SIGTERM/SIGUSR2等。

    1. busybox下的halt/poweroff/reboot实现

    通过applets.h下的halt/poweroff/reboot可知,实现都在halt_main()中。

    IF_HALT(APPLET(halt, BB_DIR_SBIN, BB_SUID_DROP))
    IF_POWEROFF(APPLET_ODDNAME(poweroff, halt, BB_DIR_SBIN, BB_SUID_DROP, poweroff))
    IF_REBOOT(  APPLET_ODDNAME(reboot,   halt, BB_DIR_SBIN, BB_SUID_DROP, reboot))

    下面就看看halt_main(),-d表示延迟多久执行操作;-n表示在执行操作之前是否执行sync();-f表示强制整个系统直接系统调用reboot重启操作,不定义的情况下通过init。

    int halt_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 };------------SIGUSR1表示halt操作;SIGUSR2表示poweroff操作;SIGTERM表示reboot操作。
    
        int delay = 0;
        int which, flags, rc;
    
        /* Figure out which applet we're running */
        if (ENABLE_HALT && !ENABLE_POWEROFF && !ENABLE_REBOOT)
            which = 0;
        else
        if (!ENABLE_HALT && ENABLE_POWEROFF && !ENABLE_REBOOT)
            which = 1;
        else
        if (!ENABLE_HALT && !ENABLE_POWEROFF && ENABLE_REBOOT)
            which = 2;
        else
        for (which = 0; "hpr"[which] != applet_name[0]; which++)
            continue;---------------------------------------------------------------根据applet_name[]来确定which的值,小技巧实现了下面kill()和reboot参数which。
    
        /* Parse and handle arguments */
        /* We support -w even if !ENABLE_FEATURE_WTMP,
         * in order to not break scripts.
         * -i (shut down network interfaces) is ignored.
         */
        flags = getopt32(argv, "d:+nfwi", &delay);
    
        sleep(delay);------------------------------------------------延时多久执行操作。
    ...
    if (!(flags & 2)) /* no -n */
            sync();--------------------------------------------------sync()同步操作。
    
        /* Perform action. */
        rc = 1;
        if (!(flags & 4)) { /* no -f */------------------------------重要区别是-f是否定义,对reboot命令影响较大。
    ...
            if (rc) {
                /* talk to init */
                if (!ENABLE_FEATURE_CALL_TELINIT) {
                    /* bbox init assumed */
                    rc = kill(1, signals[which]);--------------------对init进程发送信号,信号值是由which决定的。
                } else {
    ...
                }
            }
        } else {
            rc = reboot(magic[which]);------------------------------在定义-f的情况下,执行真正的内核reboot命令。具体的哪种reboot,也是通过which决定的。
        }
    
        if (rc)
            bb_perror_nomsg_and_die();
        return rc;
    }

    1.1 reboot -f和reboot的区别

    在没有-f选项情况下,直接调用reboot系统调用;反之,则向init进程发送SIGUSR1/SIGTERM/SIGUSR2信号,经由init处理这几个信号来实现halt/poweroff/reboot。

    check_delayed_sigs()接收SIGUSR[12]/SIGTERM信号,调用halt_reboot_pwoff()进行处理。

    halt_reboot_pwoff()执行inittab中SHUTDOWN操作,kill所有非init进程之后,调用reboot系统调用。

    static int check_delayed_sigs(void)
    {
        int sigs_seen = 0;
    
        while (1) {
    ...
            if ((1 << sig) & (0
    #ifdef SIGPWR
                + (1 << SIGPWR)
    #endif
                + (1 << SIGUSR1)
                + (1 << SIGUSR2)
                + (1 << SIGTERM)
            )) {
                halt_reboot_pwoff(sig);
            }
        }
    }
    
    static void halt_reboot_pwoff(int sig) { const char *m; unsigned rb; reset_sighandlers_and_unblock_sigs(); run_shutdown_and_kill_processes();---------------执行inittab中的SHUTDOWN action。 m = "halt"; rb = RB_HALT_SYSTEM;-----------------------------默认是halt magic。 if (sig == SIGTERM) {----------------------------对应reboot magic。 m = "reboot"; rb = RB_AUTOBOOT; } else if (sig == SIGUSR2) {---------------------对应poweroff magic。 m = "poweroff"; rb = RB_POWER_OFF; } message(L_CONSOLE, "Requesting system %s", m); pause_and_low_level_reboot(rb); /* not reached */ }
    static void pause_and_low_level_reboot(unsigned magic) { pid_t pid; sleep(1); pid = vfork(); if (pid == 0) { /* child */ reboot(magic);-------------------------------在子进程中执行reboot()系统调用。 _exit(EXIT_SUCCESS); } while (1) sleep(1);------------------------------------init进程本身进入了while(1)。 }

    2. reboot系统调用

    halt/poweroff/reboot三个busybox命令,分别对应RB_HALT_SYSTEM(0xcdef0123)/RB_POWER_OFF(0x4321fedc)/RB_AUTOBOOT(0x01234567)。

    这三个命令的区,详细可以参考kernel_halt()、kernel_power_off()、kernel_restart()。

    /*
     * 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)
    {
    ...
        if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
            cmd = LINUX_REBOOT_CMD_HALT;
    
        mutex_lock(&reboot_mutex);
        switch (cmd) {
        case LINUX_REBOOT_CMD_RESTART:-----------------------对应busybox中的reboot命令。
            kernel_restart(NULL);
            break;
    ...
        case LINUX_REBOOT_CMD_HALT:--------------------------对应busybox中的halt命令。
            kernel_halt();
            do_exit(0);
            panic("cannot halt");
    
        case LINUX_REBOOT_CMD_POWER_OFF:---------------------对应busybox中的poweroff命令。
            kernel_power_off();
            do_exit(0);
            break;
    
        case LINUX_REBOOT_CMD_RESTART2:
            ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);
            if (ret < 0) {
                ret = -EFAULT;
                break;
            }
            buffer[sizeof(buffer) - 1] = '';
    
            kernel_restart(buffer);
            break;
    ...
        default:
            ret = -EINVAL;
            break;
        }
        mutex_unlock(&reboot_mutex);
        return ret;
    }

    3. 小结

    halt/poweroff/reboot三个命令最终都通过内核reboot()系统调用实现,但是-f选项多了一些操作。

    reboot相对于reboot -f区别是,可以通过init对halt/poweroff/reboot附加一些操作,比如做一些备份操作、同步操作。

    不同reboot() magic区别是,调用不同kernel_restart()/kernel_halt()/kernel_power_off()。

  • 相关阅读:
    第五周学习总结-20175218
    第一周测试总结分析
    第四周学习总结-20175218
    第三周学习总结-20175218
    第二周学习任务-20175218
    第一周学习总结-20175218
    20175213 2018-2019-2 《Java程序设计》第11周学习总结
    数据结构-排序(选做)
    20175213 2018-2019-2 《Java程序设计》第10周学习总结
    2018-2019-2 20175213实验三《敏捷开发与XP实践》实验报告
  • 原文地址:https://www.cnblogs.com/arnoldlu/p/11121893.html
Copyright © 2011-2022 走看看