diff --git a/src/modules/bootloader/bootloader.conf b/src/modules/bootloader/bootloader.conf index f471c2ee0..60235e5d2 100644 --- a/src/modules/bootloader/bootloader.conf +++ b/src/modules/bootloader/bootloader.conf @@ -9,19 +9,21 @@ # Possible options are 'grub', 'sb-shim' and 'systemd-boot'. efiBootLoader: "grub" -# systemd-boot configuration files settings, set kernel and initramfs file names +# systemd-boot configuration files settings, set kernel search path, kernel name # and amount of time before default selection boots -kernel: "/vmlinuz-linux" -img: "/initramfs-linux.img" -fallback: "/initramfs-linux-fallback.img" +kernelSearchPath: "/usr/lib/modules" +kernelName: "vmlinuz" timeout: "10" -# Optionally set the menu entry name and kernel name to use in systemd-boot. +# additionalInitrdFiles is a comma seperated list of file names +additionalInitrdFiles: + - "/boot/amd-ucode" + - "/boot/intel-ucode" + +# Optionally set the menu entry name to use in systemd-boot. # If not specified here, these settings will be taken from branding.desc. # # bootloaderEntryName: "Generic GNU/Linux" -# kernelLine: ", with Stable-Kernel" -# fallbackKernelLine: ", with Stable-Kernel (fallback initramfs)" # GRUB 2 binary names and boot directory # Some distributions (e.g. Fedora) use grub2-* (resp. /boot/grub2/) names. diff --git a/src/modules/bootloader/bootloader.schema.yaml b/src/modules/bootloader/bootloader.schema.yaml index 152d3ab72..0849f6865 100644 --- a/src/modules/bootloader/bootloader.schema.yaml +++ b/src/modules/bootloader/bootloader.schema.yaml @@ -7,10 +7,13 @@ additionalProperties: false type: object properties: efiBootLoader: { type: string } - kernel: { type: string } - img: { type: string } - fallback: { type: string } + kernelSearchPath: { type: string } + kernelName: { type: string } timeout: { type: string } # Inserted verbatim + additionalInitrdFiles: + type: array + items: + type: string bootloaderEntryName: { type: string } kernelLine: { type: string } fallbackKernelLine: { type: string } @@ -27,9 +30,10 @@ properties: required: - efiBootLoader - - kernel - - img + - kernelSearchPath + - kernelName - grubInstall - grubMkconfig - grubCfg - grubProbe + - machineid diff --git a/src/modules/bootloader/main.py b/src/modules/bootloader/main.py index 68cbddd0e..bcb7f230a 100644 --- a/src/modules/bootloader/main.py +++ b/src/modules/bootloader/main.py @@ -73,37 +73,18 @@ def get_bootloader_entry_name(): return branding["bootloaderEntryName"] -def get_kernel_line(kernel_type): - """ - Passes 'kernel_line' to other routine based on configuration file. - - :param kernel_type: - :return: - """ - if kernel_type == "fallback": - if "fallbackKernelLine" in libcalamares.job.configuration: - return libcalamares.job.configuration["fallbackKernelLine"] - else: - return " (fallback)" - else: - if "kernelLine" in libcalamares.job.configuration: - return libcalamares.job.configuration["kernelLine"] - else: - return "" - - -def create_systemd_boot_conf(install_path, efi_dir, uuid, entry, entry_name, kernel_type): +def create_systemd_boot_conf(installation_root_path, efi_dir, uuid, entry, kernel, kernel_type, kernel_version): """ Creates systemd-boot configuration files based on given parameters. - :param install_path: - :param efi_dir: - :param uuid: - :param entry: - :param entry_name: - :param kernel_type: + :param installation_root_path: A string containing the absolute path to the root of the installation + :param efi_dir: A string containing the path to the efi dir relative to the root of the installation + :param uuid: A string containing the UUID of the root volume + :param entry: A string containing the name of the entry as it will be displayed on boot + :param kernel: A string containing the path to the kernel relative to the root of the installation + :param kernel_type: A string which should be set if there is a special version of the entry, for example "fallback" + :param kernel_version: The kernel version string """ - kernel = libcalamares.job.configuration["kernel"] kernel_params = ["quiet"] partitions = libcalamares.globalstorage.value("partitions") @@ -151,43 +132,60 @@ def create_systemd_boot_conf(install_path, efi_dir, uuid, entry, entry_name, ker kernel_params.append("resume=/dev/mapper/{!s}".format( swap_outer_mappername)) - kernel_line = get_kernel_line(kernel_type) - libcalamares.utils.debug("Configure: \"{!s}\"".format(kernel_line)) + libcalamares.utils.debug("Configure: \"{!s}\"".format(f"{entry} {kernel_version}")) if kernel_type == "fallback": - img = libcalamares.job.configuration["fallback"] - entry_name = entry_name + "-fallback" + version_string = kernel_version + "-fallback" + initrd = "initrd-fallback" else: - img = libcalamares.job.configuration["img"] + version_string = kernel_version + initrd = "initrd" - conf_path = os.path.join(install_path + efi_dir, - "loader", - "entries", - entry_name + ".conf") + # get the machine-id + with open(os.path.join(installation_root_path, "etc", "machine-id"), 'r') as machineid_file: + machine_id = machineid_file.read().rstrip('\n') - # Copy kernel and initramfs to a subdirectory of /efi partition - files_dir = os.path.join(install_path + efi_dir, entry_name) - os.mkdir(files_dir) + # Copy kernel to a subdirectory of /efi partition + machine_dir = os.path.join(installation_root_path + efi_dir, machine_id) + os.makedirs(machine_dir, exist_ok=True) - kernel_path = install_path + kernel + target_efi_files_dir = os.path.join(machine_dir, kernel_version) + os.makedirs(target_efi_files_dir, exist_ok=True) + + kernel_path = os.path.join(installation_root_path, kernel) kernel_name = os.path.basename(kernel_path) - shutil.copyfile(kernel_path, os.path.join(files_dir, kernel_name)) - - img_path = install_path + img - img_name = os.path.basename(img_path) - shutil.copyfile(img_path, os.path.join(files_dir, img_name)) + shutil.copyfile(kernel_path, os.path.join(target_efi_files_dir, "linux")) + # write the entry lines = [ - '## This is just an example config file.\n', - '## Please edit the paths and kernel parameters according\n', - '## to your system.\n', + '## Generated by Calamares\n', '\n', - "title {!s}{!s}\n".format(entry, kernel_line), - "linux {!s}\n".format(os.path.join("/", entry_name, kernel_name)), - "initrd {!s}\n".format(os.path.join("/", entry_name, img_name)), - "options {!s} rw\n".format(" ".join(kernel_params)), + "title {!s}\n".format(entry), + "version {!s}\n".format(version_string), + "machine-id {!s}\n".format(machine_id), + "linux {!s}\n".format(os.path.join("/", machine_id, kernel_version, "linux")), ] + try: + additional_initrd_files = libcalamares.job.configuration["additionalInitrdFiles"] + for initrd_file in additional_initrd_files: + libcalamares.utils.debug("Attempting to handle initrd image " + initrd_file) + if os.path.isfile(os.path.join(installation_root_path, initrd_file.lstrip('/'))): + libcalamares.utils.debug("Found image " + initrd_file) + shutil.copyfile(os.path.join(installation_root_path, initrd_file.lstrip('/')), os.path.join(target_efi_files_dir, os.path.basename(initrd_file))) + lines.append("initrd {!s}\n".format(os.path.join("/", machine_id, kernel_version, os.path.basename(initrd_file)))) + except KeyError: # If the configuration option isn't set, we can just move on + libcalamares.utils.debug("Failed to find key additionalInitrdFiles") + pass + + lines.append("initrd {!s}\n".format(os.path.join("/", machine_id, kernel_version, initrd))) + lines.append("options {!s} rw\n".format(" ".join(kernel_params))) + + conf_path = os.path.join(installation_root_path + efi_dir, + "loader", + "entries", + machine_id + "-" + version_string + ".conf") + with open(conf_path, 'w') as conf_file: for line in lines: conf_file.write(line) @@ -252,6 +250,30 @@ def efi_boot_next(): if boot_entry: subprocess.call([boot_mgr, "-n", boot_entry]) +def get_kernels(installation_root_path): + """ + Gets a list of kernels and associated values for each kernel. This will work as is for many distros. + If not, it should be safe to modify it to better support your distro + + :param installation_root_path: A string with the absolute path to the root of the installation + + Returns a list of 3-tuples + + Each 3-tuple contains the kernel, kernel_type and kernel_version + """ + kernel_search_path = libcalamares.job.configuration["kernelSearchPath"] + source_kernel_name = libcalamares.job.configuration["kernelName"] + kernel_list = [] + + # find all the installed kernels and generate default and fallback entries for each + for root, dirs, files in os.walk(os.path.join(installation_root_path, kernel_search_path.lstrip('/'))): + for file in files: + if file == source_kernel_name: + rel_root = os.path.relpath(root, installation_root_path) + kernel_list.append((os.path.join(rel_root, file),"default",os.path.basename(root))) + kernel_list.append((os.path.join(rel_root, file),"fallback",os.path.basename(root))) + + return kernel_list def install_systemd_boot(efi_directory): """ @@ -260,8 +282,8 @@ def install_systemd_boot(efi_directory): :param efi_directory: """ libcalamares.utils.debug("Bootloader: systemd-boot") - install_path = libcalamares.globalstorage.value("rootMountPoint") - install_efi_directory = install_path + efi_directory + installation_root_path = libcalamares.globalstorage.value("rootMountPoint") + install_efi_directory = installation_root_path + efi_directory uuid = get_uuid() distribution = get_bootloader_entry_name() distribution_translated = distribution.translate(file_name_sanitizer) @@ -271,21 +293,17 @@ def install_systemd_boot(efi_directory): subprocess.call(["bootctl", "--path={!s}".format(install_efi_directory), "install"]) - create_systemd_boot_conf(install_path, - efi_directory, - uuid, - distribution, - distribution_translated, - "default") - if "fallback" in libcalamares.job.configuration: - create_systemd_boot_conf(install_path, - efi_directory, - uuid, - distribution, - distribution_translated, - "fallback") - create_loader(loader_path, distribution_translated) + for (kernel, kernel_type, kernel_version) in get_kernels(installation_root_path): + create_systemd_boot_conf(installation_root_path, + efi_directory, + uuid, + distribution, + kernel, + kernel_type, + kernel_version) + + create_loader(loader_path, distribution_translated) def get_grub_efi_parameters(): """ @@ -323,8 +341,8 @@ def install_grub(efi_directory, fw_type): """ if fw_type == "efi": libcalamares.utils.debug("Bootloader: grub (efi)") - install_path = libcalamares.globalstorage.value("rootMountPoint") - install_efi_directory = install_path + efi_directory + installation_root_path = libcalamares.globalstorage.value("rootMountPoint") + install_efi_directory = installation_root_path + efi_directory if not os.path.isdir(install_efi_directory): os.makedirs(install_efi_directory) @@ -394,8 +412,8 @@ def install_secureboot(efi_directory): """ efi_bootloader_id = efi_label() - install_path = libcalamares.globalstorage.value("rootMountPoint") - install_efi_directory = install_path + efi_directory + installation_root_path = libcalamares.globalstorage.value("rootMountPoint") + install_efi_directory = installation_root_path + efi_directory if efi_word_size() == "64": install_efi_bin = "shimx64.efi"