关键词: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. CRC校验算法的实例解析

    概念   CRC校验算法,说白了,就是把需要校验的数据与多项式进行循环异或(XOR), 进行XOR的方式与实际中数据传输时,是高位先传.还是低位先传有关.对于数据 高位先传的方式,XOR从数据的高位开 ...

  2. 算法设计与分析——n后问题(回溯法+位运算)

    一.问题描述 在n×n格的国际象棋上摆放n个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. 二.算法设计 解n后问题的回溯算法描述如下: #include ...

  3. vs2017 C# ActiveX浏览器插件 创建 发布 C# windows窗体控件库(.NET Framework)注意事项

    vs2017需要安装插 插件下载地址:https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.Micro ...

  4. C# 结合 PInvoke 对接 IP 摄像头的笔记

    最近做项目的时候,需要对接厂商提供的 IP 摄像头.但是他们只提供了 C++ 的 SDK,没办法,只能开始撸 C# 的 SDK Helper 类.本篇文章主要记录了对接 C++ DLL 需要注意的几个 ...

  5. Docker容器镜像打成tar包

    简述需求: 在现在容器上保存镜像进行打包,在另一台服务上使用 首先查看下现有要打tar包的容器 docker ps -a 接下来用commit参数进行保存镜像, -a 提交人的姓名  -m “提交内容 ...

  6. 一些webpack常见编译报错的解决方案

    重新安装依赖可以解决80%的webpack编译报错问题. rm -rf node_modules rm package-lock.json npm cache clear --force npm in ...

  7. java之数据结构

    数据结构有什么用? 现实世界的存储,我们使用的工具和建模.每种数据结构有自己的优点和缺点,想想如果Google的数据用的是数组的存储,我们还能方便地查询到所需要的数据吗?而算法,在这么多的数据中如何做 ...

  8. [译]Vulkan教程(20)重建交换链

    [译]Vulkan教程(20)重建交换链 Swap chain recreation 重建交换链 Introduction 入门 The application we have now success ...

  9. 蓝牙spp协议分析

    基本概念 蓝牙串口是基于 SPP 协议(Serial Port Profile),能在蓝牙设备之间创建串口进行数据传输的一种设备. 蓝牙串口的目的是针对如何在两个不同设备(通信的两端)上的应用之间保证 ...

  10. 《Netty Redis Zookeeper 高并发实战》声明

    疯狂创客圈 Java 高并发[ 亿级流量聊天室实战]实战系列 [博客园总入口 ] 这里, 对疯狂创客圈 <Netty Redis Zookeeper 高并发实战> 一书,进行一些必要说明. ...