Linuxにおけるreboot
reboot
man(2)のrebootを読んで初めて知ったんですが、reboot(2)
はCtrl-Alt-Delete
の有効化/無効化もできるらしいです。
それはさておき、クリスマスなのでkernel/reboot.c
を読んだら面白かったです。
コードは1300行程で概観はわかりやすいです。
が、まぁ深堀するとキリが無いのはいつもどおりです。
SYSCALL_DEFINE4
システムコールの実装を読む時のEntry Pointとして、まずはSYSCALL_DEFINE
系のマクロから探します。
/*
* 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)
{
struct pid_namespace *pid_ns = task_active_pid_ns(current);
char buffer[256];
int ret = 0;
/* We only trust the superuser with rebooting the system. */
if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))
return -EPERM;
/* For safety, we require "magic" arguments. */
if (magic1 != LINUX_REBOOT_MAGIC1 ||
(magic2 != LINUX_REBOOT_MAGIC2 &&
magic2 != LINUX_REBOOT_MAGIC2A &&
magic2 != LINUX_REBOOT_MAGIC2B &&
magic2 != LINUX_REBOOT_MAGIC2C))
return -EINVAL;
/*
* If pid namespaces are enabled and the current task is in a child
* pid_namespace, the command is handled by reboot_pid_ns() which will
* call do_exit().
*/
ret = reboot_pid_ns(pid_ns, cmd);
if (ret)
return ret;
/* Instead of trying to make the power_off code look like
* halt when pm_power_off is not set do it the easy way.
*/
if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !kernel_can_power_off())
cmd = LINUX_REBOOT_CMD_HALT;
mutex_lock(&system_transition_mutex);
switch (cmd) {
case LINUX_REBOOT_CMD_RESTART:
kernel_restart(NULL);
break;
case LINUX_REBOOT_CMD_CAD_ON:
C_A_D = 1;
break;
case LINUX_REBOOT_CMD_CAD_OFF:
C_A_D = 0;
break;
case LINUX_REBOOT_CMD_HALT:
kernel_halt();
do_exit(0);
case LINUX_REBOOT_CMD_POWER_OFF:
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] = '\0';
kernel_restart(buffer);
break;
#ifdef CONFIG_KEXEC_CORE
case LINUX_REBOOT_CMD_KEXEC:
ret = kernel_kexec();
break;
#endif
#ifdef CONFIG_HIBERNATION
case LINUX_REBOOT_CMD_SW_SUSPEND:
ret = hibernate();
break;
#endif
default:
ret = -EINVAL;
break;
}
mutex_unlock(&system_transition_mutex);
return ret;
}
ありました。
これ読めば大体わかりますね。
面白いのがMagic Numberを受け取っている点です。
Magic Number
magic1
のLINUX_REBOOT_MAGIC1
はreboot.h
で0xfee1dead
として定義されている。おもしろ
magic2
についても同じくreboot.h
にあるが、
#define LINUX_REBOOT_MAGIC2 672274793
#define LINUX_REBOOT_MAGIC2A 85072278
#define LINUX_REBOOT_MAGIC2B 369367448
#define LINUX_REBOOT_MAGIC2C 537993216
なんだかわからんのでHexにしてみると
0x28121969
0x5121996
0x16041998
0x20112000
下4桁から見てdd/mm/yyyyでしょう
調べてみると
最初のMAGIC2、28/12/1969
はLinus Torvaldsの誕生日で、他3つは娘の誕生日らしい。いい父親かも。
要はLinusかその娘の誕生日を渡せばいいらしい。0xfee1dead
と一緒に。なんか縁起悪いな。
おわりに
この記事はn01e0 Advent Calendar 2023の25日目の記事です。
やっと終わりました。疲れた上に生活リズムが崩壊しただけで特に何も良い事はなかったです。
一人アドベントカレンダー、もしやるならちゃんとネタと時間を確保してからやることをおすすめします。
Comments