关键词:halt/poweroff/reboot、reboot()、SIGUSR1/SIGTERM/SIGUSR2等。

1. busybox下的halt/poweroff/reboot实现

通过applets.h下的halt/poweroff/reboot可知,实现都在halt_main()中。

  1. IF_HALT(APPLET(halt, BB_DIR_SBIN, BB_SUID_DROP))
  2. IF_POWEROFF(APPLET_ODDNAME(poweroff, halt, BB_DIR_SBIN, BB_SUID_DROP, poweroff))
  3. IF_REBOOT( APPLET_ODDNAME(reboot, halt, BB_DIR_SBIN, BB_SUID_DROP, reboot))

下面就看看halt_main(),-d表示延迟多久执行操作;-n表示在执行操作之前是否执行sync();-f表示强制整个系统直接系统调用reboot重启操作,不定义的情况下通过init。

  1. int halt_main(int argc UNUSED_PARAM, char **argv)
  2. {
  3. static const int magic[] = {
  4. RB_HALT_SYSTEM,
  5. RB_POWER_OFF,
  6. RB_AUTOBOOT
  7. };
  8. static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM };------------SIGUSR1表示halt操作;SIGUSR2表示poweroff操作;SIGTERM表示reboot操作。
  9.  
  10. int delay = ;
  11. int which, flags, rc;
  12.  
  13. /* Figure out which applet we're running */
  14. if (ENABLE_HALT && !ENABLE_POWEROFF && !ENABLE_REBOOT)
  15. which = ;
  16. else
  17. if (!ENABLE_HALT && ENABLE_POWEROFF && !ENABLE_REBOOT)
  18. which = ;
  19. else
  20. if (!ENABLE_HALT && !ENABLE_POWEROFF && ENABLE_REBOOT)
  21. which = ;
  22. else
  23. for (which = ; "hpr"[which] != applet_name[]; which++)
  24. continue;---------------------------------------------------------------根据applet_name[]来确定which的值,小技巧实现了下面kill()和reboot参数which
  25.  
  26. /* Parse and handle arguments */
  27. /* We support -w even if !ENABLE_FEATURE_WTMP,
  28. * in order to not break scripts.
  29. * -i (shut down network interfaces) is ignored.
  30. */
  31. flags = getopt32(argv, "d:+nfwi", &delay);
  32.  
  33. sleep(delay);------------------------------------------------延时多久执行操作。
  34. ...
  35. if (!(flags & )) /* no -n */
  36. sync();--------------------------------------------------sync()同步操作。
  37.  
  38. /* Perform action. */
  39. rc = ;
  40. if (!(flags & )) { /* no -f */------------------------------重要区别是-f是否定义,对reboot命令影响较大。
  41. ...
  42. if (rc) {
  43. /* talk to init */
  44. if (!ENABLE_FEATURE_CALL_TELINIT) {
  45. /* bbox init assumed */
  46. rc = kill(, signals[which]);--------------------对init进程发送信号,信号值是由which决定的。
  47. } else {
  48. ...
  49. }
  50. }
  51. } else {
  52. rc = reboot(magic[which]);------------------------------在定义-f的情况下,执行真正的内核reboot命令。具体的哪种reboot,也是通过which决定的。
  53. }
  54.  
  55. if (rc)
  56. bb_perror_nomsg_and_die();
  57. return rc;
  58. }

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系统调用。

  1. static int check_delayed_sigs(void)
  2. {
  3. int sigs_seen = ;
  4.  
  5. while () {
  6. ...
  7. if (( << sig) & (
  8. #ifdef SIGPWR
  9. + ( << SIGPWR)
  10. #endif
  11. + ( << SIGUSR1)
  12. + ( << SIGUSR2)
  13. + ( << SIGTERM)
  14. )) {
  15. halt_reboot_pwoff(sig);
  16. }
  17. }
  18. }

  19. static void halt_reboot_pwoff(int sig)
  20. {
  21. const char *m;
  22. unsigned rb;
  23.  
  24. reset_sighandlers_and_unblock_sigs();
  25.  
  26. run_shutdown_and_kill_processes();---------------执行inittab中的SHUTDOWN action
  27.  
  28. m = "halt";
  29. rb = RB_HALT_SYSTEM;-----------------------------默认是halt magic
  30. if (sig == SIGTERM) {----------------------------对应reboot magic
  31. m = "reboot";
  32. rb = RB_AUTOBOOT;
  33. } else if (sig == SIGUSR2) {---------------------对应poweroff magic
  34. m = "poweroff";
  35. rb = RB_POWER_OFF;
  36. }
  37. message(L_CONSOLE, "Requesting system %s", m);
  38. pause_and_low_level_reboot(rb);
  39. /* not reached */
  40. }

  41. static void pause_and_low_level_reboot(unsigned magic)
  42. {
  43. pid_t pid;
  44.  
  45. sleep();
  46.  
  47. pid = vfork();
  48. if (pid == ) { /* child */
  49. reboot(magic);-------------------------------在子进程中执行reboot()系统调用。
  50. _exit(EXIT_SUCCESS);
  51. }
  52. while ()
  53. sleep();------------------------------------init进程本身进入了while(1)。
  54. }

2. reboot系统调用

halt/poweroff/reboot三个busybox命令,分别对应RB_HALT_SYSTEM(0xcdef0123)/RB_POWER_OFF(0x4321fedc)/RB_AUTOBOOT(0x01234567)。

这三个命令的区,详细可以参考kernel_halt()、kernel_power_off()、kernel_restart()。

  1. /*
  2. * Reboot system call: for obvious reasons only root may call it,
  3. * and even root needs to set up some magic numbers in the registers
  4. * so that some mistake won't make this reboot the whole machine.
  5. * You can also set the meaning of the ctrl-alt-del-key here.
  6. *
  7. * reboot doesn't sync: do that yourself before calling this.
  8. */
  9. SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
  10. void __user *, arg)
  11. {
  12. ...
  13. if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
  14. cmd = LINUX_REBOOT_CMD_HALT;
  15.  
  16. mutex_lock(&reboot_mutex);
  17. switch (cmd) {
  18. case LINUX_REBOOT_CMD_RESTART:-----------------------对应busybox中的reboot命令。
  19. kernel_restart(NULL);
  20. break;
  21. ...
  22. case LINUX_REBOOT_CMD_HALT:--------------------------对应busybox中的halt命令。
  23. kernel_halt();
  24. do_exit();
  25. panic("cannot halt");
  26.  
  27. case LINUX_REBOOT_CMD_POWER_OFF:---------------------对应busybox中的poweroff命令。
  28. kernel_power_off();
  29. do_exit();
  30. break;
  31.  
  32. case LINUX_REBOOT_CMD_RESTART2:
  33. ret = strncpy_from_user(&buffer[], arg, sizeof(buffer) - );
  34. if (ret < ) {
  35. ret = -EFAULT;
  36. break;
  37. }
  38. buffer[sizeof(buffer) - ] = '\0';
  39.  
  40. kernel_restart(buffer);
  41. break;
  42. ...
  43. default:
  44. ret = -EINVAL;
  45. break;
  46. }
  47. mutex_unlock(&reboot_mutex);
  48. return ret;
  49. }

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. 一致性hash算法--负载均衡

    有没有好奇过redis.memcache等是怎么实现集群负载均衡的呢? 其实他们都是通过一致性hash算法实现节点调度的. 讲一致性hash算法前,先简述一下求余hash算法: hash(object ...

  2. IT兄弟连 HTML5教程 CSS3属性特效 动画-animation

    CSS3属性中有关于制作动画的三个属性:Transform,Transition,Animation.前面已经介绍过Transform和Transition了,这里我们来学习Animation动画.通 ...

  3. Spring中常见的设计模式——委派模式

    一.委派模式的定义及应用场景 委派模式(Delegate Pattern)的基本作用是负责任务的调用和分配,跟代理模式很像,可以看做特殊情况下的静态的全权代理,但是代理模式注重过程,而委派模式注重结果 ...

  4. MyBatis操作Oracle批量插入 ORA-00933: SQL 命令未正确结束

    最近在使用MyBatis操作Oracle数据库的时候,进行批量插入数据,思路是封装一个List集合通过Myabtis 的foreach标签进行循环插入,可是搬照Mysql的批量插入会产生 异常 ### ...

  5. C#DataTable转List<T>互转

    using System; using System.Collections.Generic; using System.Data; using System.Reflection; namespac ...

  6. [转]UiPath Invoke Code

    本文转自:https://dotnetbasic.com/2019/08/uipath-invoke-code.html We will learn step by step tutorial for ...

  7. 团队项目之Alpha阶段项目复审

    组的名字和链接 优点 缺点,bug报告 最终名次 六姑娘 https://www.cnblogs.com/liujiamei/p/11992659.html 团队的小程序功能齐全,这说明团队在需求分析 ...

  8. PHP Loser 说说做前端需要如何进一步学习

    PHP Loser 说说做前端需要如何进一步学习 做前端的,需要如何进一步学习?书籍这个事情贵精不在多,我这里推荐两本即可: <javascript教程 高级程序设计> <CSS权威 ...

  9. mongodb基本安装

    这次搞搞NOSQL, 但最简单的MONGODB安装,还是要作点配置的. 一,安装网址: https://www.mongodb.com/download-center/community?jmp=na ...

  10. 如何解决Sublime text3文件名称中文乱码问题

    在sublime text 3中,Preference, Settings-User,最后加上一行 "dpi_scale": 1.0 { "auto_complete_t ...