busybox之reboot命令流程分析

3 篇文章 0 订阅

busybox初始化注册reboot处理信号

busybox启动的时候,会注册reboot的处理信号

init_main
		bb_signals(0
			+ (1 << SIGUSR1) /* halt */
			+ (1 << SIGTERM) /* reboot */
			+ (1 << SIGUSR2) /* poweroff */
			, halt_reboot_pwoff);
		signal(SIGQUIT, restart_handler); /* re-exec another init */  		

busybox 的命令对应入口查找流程

运行busybox对应的命令的时候,处理流程如下:
busybox对外提供了一个命令列表,支持非常多的命令
这个列表在代码里面的 include/applet_names.h
applet_names 定义了字符串和函数钩子的对应列表applet_main,顺序是一一对应的
入这里 reboot —> halt_main
其他命令的处理入口函数根据这个顺序去查找

lbb_main
    run_applet_and_exit
		int applet = find_applet_by_name(name);
		if (applet >= 0)
			run_applet_no_and_exit(applet, argv);
		if (!strncmp(name, "busybox", 7))
			exit(busybox_main(argv));

从这段代码可以看出来,运行busybox命令的时候,会根据name查找到
命令在 applet_main 的下表索引 applet_no ,最后直接调用
applet_main[applet_no](argc, argv)命令执行对应命令的处理函数

reboot命令处理函数 halt_main

该函数的主要处理流程如下:

	if (!(flags & 4)) { /* no -f */
//TODO: I tend to think that signalling linuxrc is wrong
// pity original author didn't comment on it...
		if (ENABLE_FEATURE_INITRD) {
			/* talk to linuxrc */
			/* bbox init/linuxrc assumed */
			pid_t *pidlist = find_pid_by_name("linuxrc");
			if (pidlist[0] > 0)
				rc = kill(pidlist[0], signals[which]);
			if (ENABLE_FEATURE_CLEAN_UP)
				free(pidlist);
		}
		if (rc) {
			/* talk to init */
			if (!ENABLE_FEATURE_CALL_TELINIT) {
				/* bbox init assumed */
				rc = kill(1, signals[which]);
			} else {
				/* SysV style init assumed */
				/* runlevels:
				 * 0 == shutdown
				 * 6 == reboot */
				rc = execlp(CONFIG_TELINIT_PATH,
						CONFIG_TELINIT_PATH,
						which == 2 ? "6" : "0",
						(char *)NULL
				);
			}
		}
	} else {
		rc = reboot(magic[which]);
	}

这里可以看出来,分为两个流程:

  1. 当reboot命令没有加 -f的时候,直接使用kill发送信号到busybox执行halt_reboot_pwoff函数
  2. 直接使用-f的话,直接使用reboot系统调用接口,通知内核,让内核执行重启操作,简单粗暴

halt_reboot_pwoff函数处理流程

我们大部分的重启命令都是直接使用reboot命令,最后走halt_reboot_pwoff流程,
当我们执行reboot的时候,一般都会有以下的打印:

The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes
Requesting system reboot

从上面可以看出来,分为三步:

  1. 发送SIGTERM给所有进程,让进程正常退出
  2. 发送SIGKILL给所有进程,将其杀掉
  3. 让系统重启

以上三步都是在halt_reboot_pwoff里面实现的

static void halt_reboot_pwoff(int sig)
{
	const char *m;
	unsigned rb;

	/* We may call run() and it unmasks signals,
	 * including the one masked inside this signal handler.
	 * Testcase which would start multiple reboot scripts:
	 *  while true; do reboot; done
	 * Preventing it:
	 */
	reset_sighandlers_and_unblock_sigs();

	run_shutdown_and_kill_processes();

	m = "halt";
	rb = RB_HALT_SYSTEM;
	if (sig == SIGTERM) {
		m = "reboot";
		rb = RB_AUTOBOOT;
	} else if (sig == SIGUSR2) {
		m = "poweroff";
		rb = RB_POWER_OFF;
	}
	message(L_CONSOLE, "Requesting system %s", m);
	pause_and_low_level_reboot(rb);
	/* not reached */
}

static void run_shutdown_and_kill_processes(void)
{
	/* Run everything to be run at "shutdown".  This is done _prior_
	 * to killing everything, in case people wish to use scripts to
	 * shut things down gracefully... */
	run_actions(SHUTDOWN);

	message(L_CONSOLE | L_LOG, "The system is going down NOW!");

	/* Send signals to every process _except_ pid 1 */
	kill(-1, SIGTERM);
	message(L_CONSOLE | L_LOG, "Sent SIG%s to all processes", "TERM");
	sync();
	sleep(1);

	kill(-1, SIGKILL);
	message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
	sync();
	/*sleep(1); - callers take care about making a pause */
}

上面的源码可以看出来,halt_reboot_pwoff直接调用run_shutdown_and_kill_processes去
完成第一第二步,中间sleep 一秒钟
第三步是直接使用vfork子进程出来下发系统调用reboot(magic)命令给内核,让内核完成重启,
这一步和我们直接用reboot -f基本一致,也就是说reboot和reboot -f之间相差了第一第二步而已。

内核处理reboot系统调用流程

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg)
	kernel_restart(NULL);
		kernel_restart_prepare(cmd);
		migrate_to_reboot_cpu();
		syscore_shutdown();
		if (!cmd)
			pr_emerg("Restarting system\n");
		else
			pr_emerg("Restarting system with command '%s'\n", cmd);
		kmsg_dump(KMSG_DUMP_RESTART);
		machine_restart(cmd);	

用户态运行reboot命令,除了用户态先kill所有用户态进程之外,还需要通过系统调用reboot接口
通知内核,让内核执行正常的cpu重启,这里涉及到不同架构cpu板子的重启,所以这里是分架构
来调用对应架构的重启cpu操作的.

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BusyBox 是一个精简的 Linux 工具集合,它包含了大量的常用命令,如 ls、cp、mv、rm 等,它可以运行在嵌入式系统和资源有限的环境中。虽然 BusyBox 已经包含了大部分常用的命令,但是有时候我们可能需要添加一些额外的命令。 要添加命令BusyBox,我们首先需要获取 BusyBox 的源代码。然后,在源代码中找到命令的配置文件,这通常是一个以 .config 结尾的文件。在这个配置文件中,我们可以找到已经包含的命令列表。要添加一个新命令,我们可以简单地在配置文件中添加该命令的选项,并将其设置为 "y" 或 "m",表示该命令是开启的。如果所需的命令相关的依赖也没有包含在 BusyBox 中,我们还需要将依赖的选项也设置为 "y" 或 "m"。 接下来,我们需要重新编译 BusyBox。在终端中进入 BusyBox 源代码目录,运行 make 命令以重新编译该工具集合。编译完成后,我们就可以在输出目录中找到新的 BusyBox 可执行文件。 最后,我们可以将新的 BusyBox 可执行文件拷贝到目标系统中,替换原有的 BusyBox 可执行文件即可。现在,我们就可以使用我们刚刚添加的新命令了。 总的来说,虽然 BusyBox 已经包含了大量的常用命令,但添加新命令也是相对简单的。只需获取源代码,修改配置文件,重新编译,替换原有的可执行文件,就可以轻松地扩展 BusyBox 的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值