关键词: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 = ;
int which, flags, rc; /* Figure out which applet we're running */
if (ENABLE_HALT && !ENABLE_POWEROFF && !ENABLE_REBOOT)
which = ;
else
if (!ENABLE_HALT && ENABLE_POWEROFF && !ENABLE_REBOOT)
which = ;
else
if (!ENABLE_HALT && !ENABLE_POWEROFF && ENABLE_REBOOT)
which = ;
else
for (which = ; "hpr"[which] != applet_name[]; 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 & )) /* no -n */
sync();--------------------------------------------------sync()同步操作。 /* Perform action. */
rc = ;
if (!(flags & )) { /* no -f */------------------------------重要区别是-f是否定义,对reboot命令影响较大。
...
if (rc) {
/* talk to init */
if (!ENABLE_FEATURE_CALL_TELINIT) {
/* bbox init assumed */
rc = kill(, 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 = ; while () {
...
if (( << sig) & (
#ifdef SIGPWR
+ ( << SIGPWR)
#endif
+ ( << SIGUSR1)
+ ( << SIGUSR2)
+ ( << 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(); pid = vfork();
if (pid == ) { /* child */
reboot(magic);-------------------------------在子进程中执行reboot()系统调用。
_exit(EXIT_SUCCESS);
}
while ()
sleep();------------------------------------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();
panic("cannot halt"); case LINUX_REBOOT_CMD_POWER_OFF:---------------------对应busybox中的poweroff命令。
kernel_power_off();
do_exit();
break; case LINUX_REBOOT_CMD_RESTART2:
ret = strncpy_from_user(&buffer[], arg, sizeof(buffer) - );
if (ret < ) {
ret = -EFAULT;
break;
}
buffer[sizeof(buffer) - ] = '\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()。

简单理解Busybox下halt/poweroff/reboot实现及区别的更多相关文章

  1. 简单理解Struts2中拦截器与过滤器的区别及执行顺序

    简单理解Struts2中拦截器与过滤器的区别及执行顺序 当接收到一个httprequest , a) 当外部的httpservletrequest到来时 b) 初始到了servlet容器 传递给一个标 ...

  2. Linux下关机命令的区别 (halt,poweroff,reboot,shutdown,init)

    1.shutdown shutdown命令安全地将系统关机.    而在系统关机前使用shutdown命令﹐系统管理员会通知所有登录的用户系统将要关闭.并且login指令会被冻结﹐即新的用户不能再登录 ...

  3. 理解Linux中的shutdown、poweroff、halt和reboot命令

    原文  http://os.51cto.com/art/201706/541525.htm   在本篇中,我们会向你解释 shutdown.poweroff.halt 以及 reboot 命令.我们会 ...

  4. 正确的关机方法: sync, shutdown, reboot, halt, poweroff, init

    正常情况下,要关机时需要注意底下几件事: 观察系统的使用状态: 如果要看目前有谁在在线,可以下达『who』这个命令,而如果要看网络的联机状态,可以下达 『 netstat -a 』这个命令, 而要看背 ...

  5. 从Docker在Linux和Windows下的区别简单理解Docker的层次结构

    上篇文章我们成功在Windows下安装了Docker,输出了一个简单的Hello World程序.本文中我们将利用Docker已有的云端镜像training/webapp来发布一个简单Python的W ...

  6. git的简单理解及基础操作命令

    前端小白一枚,最近开始使用git,于是花了2天看了廖雪峰的git教程(偏实践,对于学习git的基础操作很有帮助哦),也在看<git版本控制管理>这本书(偏理论,内容完善,很不错),针对所学 ...

  7. [转]简单理解Socket

    简单理解Socket 转自 http://www.cnblogs.com/dolphinX/p/3460545.html  题外话 前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公 ...

  8. Busybox下tftp命令使用详解

    http://blog.chinaunix.net/uid-375398-id-1991686.html Busybox下的tftp命令可以用来进行单文件传输.使用的时候,是把电脑作为服务器Serve ...

  9. 机器学习&数据挖掘笔记_12(对Conjugate Gradient 优化的简单理解)

    数学优化方法在机器学习算法中至关重要,本篇博客主要来简单介绍下Conjugate Gradient(共轭梯度法,以下简称CG)算法,内容是参考的文献为:An Introduction to the C ...

随机推荐

  1. 基于MbedTLS的AES加密实现,含STM32H7和STM32F4的实现例程

    说明: 1.mbedTLS的前身是PolarSSL,开源免费. 主要提供了的SSL/TLS支持(在传输层对网络进行加密),各种加密算法,各种哈希算法,随机数生成以及X.509(密码学里公钥证书的格式标 ...

  2. 求连通块的面积 - BFS、DFS实现

    本文以Leetcode中695.岛屿的最大面积题目为基础进行展开(题目

  3. C# Monitor and transfer or copy the changed or created file to a new location

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Tex ...

  4. python中time.strftime不支持中文,报错UnicodeEncodeError: 'locale' codec can't encode character '\u5e74' in position 2: encoding error

    使用time.strftime将 "2020-10-10 10:10:10" 转化为  2020年10月10日10时10分10 报错: import time timestr=&q ...

  5. ELK日志分析系统(1)-基本环境搭建

    1. 概述 ELK = Elasticsearch + Logstash + Kibana Elasticsearch是实时全文搜索和分析引擎,提供搜集.分析.存储数据三大功能:是一套开放REST和J ...

  6. MySQL数据库~~~~~锁和事务

    一 锁 innodb存储引擎默认是行级锁 行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的.由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予 ...

  7. [转载]MGR变量group_replication_primary_member

    组复制的状态变量只有一个,目前在8.0.17这个版本上还是存在的,未来会被废弃掉,我们在单主的模式下,可以用来查看哪个节点是读写节点. mysql: [Warning] Using a passwor ...

  8. python 基础学习笔记(8)--装饰器

    **装饰器** - [ ] 装饰器和闭包有很大的联系.有时你需要在不改变源代码的情况下修改已经存在的函数.装饰器的运用可以提高效率,减少重复的代码. - [ ] 装饰器的实质是一个函数.它把一个函数作 ...

  9. Unity3D 截取6面图 做全景图脚本

    using System.Collections;using System.Collections.Generic;using UnityEditor;using UnityEngine; publi ...

  10. unittest---unittest中verbosity参数设置

    我们在做自动化测试的时候,有时候想要很清楚的看到每条用例执行的详细信息,我们可以通过unittest中verbosity参数进行设置 verbosity参数设置 verbosity表示在只执行用例的过 ...