/* * VAS_EBOOT -- GRand Unified Bootloader * Copyright (C) 2022 Free Software Foundation, Inc. * * VAS_EBOOT is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VAS_EBOOT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VAS_EBOOT. If not, see . */ #include #include #include #include #include #include #include VAS_EBOOT_MOD_LICENSE ("GPLv3+"); static VasEBoot_dl_t my_mod; static char *kernel_path; static char *initrd_path; static char *boot_cmdline; static VasEBoot_err_t VasEBoot_linux_boot (void) { VasEBoot_err_t rc = VAS_EBOOT_ERR_NONE; char *initrd_param; const char *kexec[] = {"kexec", "-la", kernel_path, boot_cmdline, NULL, NULL}; const char *systemctl[] = {"systemctl", "kexec", NULL}; int kexecute = VasEBoot_util_get_kexecute (); if (initrd_path) { initrd_param = VasEBoot_xasprintf ("--initrd=%s", initrd_path); kexec[3] = initrd_param; kexec[4] = boot_cmdline; } else initrd_param = VasEBoot_xasprintf ("%s", ""); VasEBoot_dprintf ("linux", "%serforming 'kexec -la %s %s %s'\n", (kexecute) ? "P" : "Not p", kernel_path, initrd_param, boot_cmdline); if (kexecute) rc = VasEBoot_util_exec (kexec); VasEBoot_free (initrd_param); if (rc != VAS_EBOOT_ERR_NONE) { VasEBoot_error (rc, N_("error trying to perform kexec load operation")); VasEBoot_sleep (3); return rc; } if (kexecute < 1) VasEBoot_fatal (N_("use '%s %s' to force a system restart"), program_name, "--kexec"); VasEBoot_dprintf ("linux", "Performing 'systemctl kexec' (%s) ", (kexecute==1) ? "do-or-die" : "just-in-case"); rc = VasEBoot_util_exec (systemctl); /* `systemctl kexec` is "asynchronous" and will return even on success. */ if (rc == 0) VasEBoot_sleep (10); if (kexecute == 1) VasEBoot_fatal (N_("error trying to perform 'systemctl kexec': %d"), rc); /* * WARNING: forcible reset should only be used in read-only environments. * VasEBoot-emu cannot check for these - users beware. */ VasEBoot_dprintf ("linux", "Performing 'kexec -ex'"); kexec[1] = "-ex"; kexec[2] = NULL; rc = VasEBoot_util_exec (kexec); if (rc != VAS_EBOOT_ERR_NONE) VasEBoot_fatal (N_("error trying to directly perform 'kexec -ex': %d"), rc); return rc; } static VasEBoot_err_t VasEBoot_linux_unload (void) { /* Unloading: we're no longer in use. */ VasEBoot_dl_unref (my_mod); VasEBoot_free (boot_cmdline); boot_cmdline = NULL; return VAS_EBOOT_ERR_NONE; } static VasEBoot_err_t VasEBoot_cmd_linux (VasEBoot_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { int i; char *tempstr; /* Mark ourselves as in-use. */ VasEBoot_dl_ref (my_mod); if (argc == 0) return VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT, N_("filename expected")); if (!VasEBoot_util_is_regular (argv[0])) return VasEBoot_error (VAS_EBOOT_ERR_FILE_NOT_FOUND, N_("cannot find kernel file %s"), argv[0]); VasEBoot_free (kernel_path); kernel_path = VasEBoot_xasprintf ("%s", argv[0]); VasEBoot_free (boot_cmdline); boot_cmdline = NULL; if (argc > 1) { boot_cmdline = VasEBoot_xasprintf ("--command-line=%s", argv[1]); for (i = 2; i < argc; i++) { tempstr = VasEBoot_xasprintf ("%s %s", boot_cmdline, argv[i]); VasEBoot_free (boot_cmdline); boot_cmdline = tempstr; } } VasEBoot_loader_set (VasEBoot_linux_boot, VasEBoot_linux_unload, 0); return VAS_EBOOT_ERR_NONE; } static VasEBoot_err_t VasEBoot_cmd_initrd (VasEBoot_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { if (argc == 0) return VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT, N_("filename expected")); if (!VasEBoot_util_is_regular (argv[0])) return VasEBoot_error (VAS_EBOOT_ERR_FILE_NOT_FOUND, N_("Cannot find initrd file %s"), argv[0]); VasEBoot_free (initrd_path); initrd_path = VasEBoot_xasprintf ("%s", argv[0]); /* We are done - mark ourselves as on longer in use. */ VasEBoot_dl_unref (my_mod); return VAS_EBOOT_ERR_NONE; } static VasEBoot_command_t cmd_linux, cmd_initrd; VAS_EBOOT_MOD_INIT (linux) { cmd_linux = VasEBoot_register_command ("linux", VasEBoot_cmd_linux, 0, N_("Load Linux.")); cmd_initrd = VasEBoot_register_command ("initrd", VasEBoot_cmd_initrd, 0, N_("Load initrd.")); my_mod = mod; } VAS_EBOOT_MOD_FINI (linux) { VasEBoot_unregister_command (cmd_linux); VasEBoot_unregister_command (cmd_initrd); }