简单理解Busybox下halt/poweroff/reboot实现及区别
關鍵詞: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] = '';
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实现及区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jdbcmysql
- 下一篇: ethereal抓包工具