簡單理解Busybox下halt/poweroff/reboot實現及區別

 關鍵詞:halt/poweroff/reboot、reboot()、SIGUSR1/SIGTERM/SIGUSR2等。app

1. busybox下的halt/poweroff/reboot實現

經過applets.h下的halt/poweroff/reboot可知,實現都在halt_main()中。this

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。spa

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。rest

check_delayed_sigs()接收SIGUSR[12]/SIGTERM信號,調用halt_reboot_pwoff()進行處理。code

halt_reboot_pwoff()執行inittab中SHUTDOWN操做,kill全部非init進程以後,調用reboot系統調用。orm

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

這三個命令的區,詳細能夠參考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] = '\0';

        kernel_restart(buffer);
        break;
...
    default:
        ret = -EINVAL;
        break;
    }
    mutex_unlock(&reboot_mutex);
    return ret;
}

3. 小結

halt/poweroff/reboot三個命令最終都經過內核reboot()系統調用實現,可是-f選項多了一些操做。ip

reboot相對於reboot -f區別是,能夠經過init對halt/poweroff/reboot附加一些操做,好比作一些備份操做、同步操做。get

不一樣reboot() magic區別是,調用不一樣kernel_restart()/kernel_halt()/kernel_power_off()。

相關文章
相關標籤/搜索