简单理解Busybox下halt/poweroff/reboot实现及区别

本文深入探讨了BusyBox中halt/poweroff/reboot命令的实现原理,解析了它们如何通过不同的magic值调用内核reboot系统调用来实现系统停机、重启和关闭。特别关注了-f选项对reboot命令的影响,以及reboot与reboot-f的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 关键词: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] = '\0';

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

转载于:https://www.cnblogs.com/arnoldlu/p/11121893.html

### 武汉大学土地利用分类的相关信息 武汉大学提供了1985年至2022年间中国逐年的30米分辨率土地利用数据[^4]。这些数据基于多源卫星影像处理生成,其土地分类体系涵盖了九种主要类别:农田、森林、灌木、草地、水体、冰雪、荒地、建设用地以及湿地。每一种分类都经过严格的定义和验证过程,以确保数据的可靠性和一致性。 #### 数据特点 - **时间跨度**:数据覆盖了从1985年开始到2022年的逐年变化情况。 - **空间分辨率**:分辨率达到30米,能够提供较为精细的地表特征描述。 - **分类体系**:采用国际通用的土地利用分类标准,具体包括上述九大类目。 以下是这九种类别的简单说明: - **农田**:指用于耕作的土地,通常种植粮食作物或其他经济作物。 - **森林**:由乔木组成的植被群落,具有较高的树冠覆盖率。 - **灌木**:以低矮灌丛为主的植被类型,常见于干旱或半干旱地区。 - **草地**:主要用于放牧或自然生长草本植物的区域。 - **水体**:湖泊、河流及其他水域类型的总称。 - **冰雪**:永久积雪或冰川覆盖区。 - **荒地**:未被开发或难以利用的土地资源。 - **建设用地**:人类活动密集的地方,如城市、工业区等。 - **湿地**:介于陆地与水域之间的过渡地带,生态功能显著。 #### 获取方式 武汉大学已经将这部分数据整理完毕并通过网络共享给研究者使用。可以通过提供的链接访问下载页面,但需要注意的是可能涉及一定的费用补偿作为技术支持的认可。 ```python import requests from bs4 import BeautifulSoup def fetch_data_link(url): response = requests.get(url) soup = BeautifulSoup(response.text, 'html.parser') download_links = [] for link in soup.find_all('a', href=True): if 'download' in link['href']: download_links.append(link['href']) return download_links url = "http://generatelink.xam.ink/change/makeurl/changeurl/8277" print(fetch_data_link(url)) ``` 以上代码片段可以用来抓取指定网页中的下载地址列表(仅做演示用途,请合法合规操作)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值