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

magic1LINUX_REBOOT_MAGIC1reboot.h0xfee1deadとして定義されている。おもしろ

magic2についても同じくreboot.hにあるが、

#define	LINUX_REBOOT_MAGIC2	672274793
#define	LINUX_REBOOT_MAGIC2A	85072278
#define	LINUX_REBOOT_MAGIC2B	369367448
#define	LINUX_REBOOT_MAGIC2C	537993216

なんだかわからんのでHexにしてみると

下4桁から見てdd/mm/yyyyでしょう

調べてみると

最初のMAGIC2、28/12/1969はLinus Torvaldsの誕生日で、他3つは娘の誕生日らしい。いい父親かも。

要はLinusかその娘の誕生日を渡せばいいらしい。0xfee1deadと一緒に。なんか縁起悪いな。

おわりに

この記事はn01e0 Advent Calendar 2023の25日目の記事です。

やっと終わりました。疲れた上に生活リズムが崩壊しただけで特に何も良い事はなかったです。

一人アドベントカレンダー、もしやるならちゃんとネタと時間を確保してからやることをおすすめします。