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()。

  • 相关阅读:
    Educational Codeforces Round 83 --- F. AND Segments
    Educational Codeforces Round 83 --- G. Autocompletion
    SEERC 2019 A.Max or Min
    2019-2020 ICPC Southwestern European Regional Programming Contest(Gym 102501)
    Educational Codeforces Round 78 --- F. Cards
    今天我学习了一门全新的语言
    codeforces 1323D 题解(数学)
    Educational Codeforces Round 80 (Div. 2) 题解 1288A 1288B 1288C 1288D 1288E
    Educational Codeforces Round 81 (Div. 2) 题解 1295A 1295B 1295C 1295D 1295E 1295F
    Codeforces Round #617 (Div. 3) 题解 1296C 1296D 1296E 1296F
  • 原文地址:https://www.cnblogs.com/arnoldlu/p/11121893.html
Copyright © 2011-2022 走看看