diff --git a/src/bootloaders/systemd-class.c b/src/bootloaders/systemd-class.c index 9abbf8e..63ca8fe 100644 --- a/src/bootloaders/systemd-class.c +++ b/src/bootloaders/systemd-class.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "bootloader.h" #include "bootman.h" @@ -207,6 +208,27 @@ static bool sd_class_ensure_dirs(void) return true; } +bool _append_extra_initrds(const BootManager *manager, CbmWriter *writer, const char *initrd_target) { + autofree(char) *initrd_glob = string_printf("%s.*", initrd_target); + glob_t files; + + int res = glob(initrd_glob, 0, NULL, &files); + bool ret = (res == GLOB_NOMATCH); + if (res == 0) { + for(size_t i = 0; i < files.gl_pathc; i++) { + LOG_DEBUG("adding extra initrd to bootloader: %s", basename(files.gl_pathv[i])); + + cbm_writer_append_printf(writer, + "initrd %s/%s\n", + get_kernel_destination_impl(manager), + basename(files.gl_pathv[i])); + } + } + + globfree(&files); + return ret; +} + bool sd_class_install_kernel(const BootManager *manager, const Kernel *kernel) { if (!manager || !kernel) { @@ -261,6 +283,9 @@ bool sd_class_install_kernel(const BootManager *manager, const Kernel *kernel) kernel->target.initrd_path); } + /* Extra initrds */ + _append_extra_initrds(manager, writer, kernel->source.initrd_file); + boot_manager_initrd_iterator_init(manager, &iter); while (boot_manager_initrd_iterator_next(&iter, &initrd_name)) { if (streq(initrd_name, ucode_initrd)) { diff --git a/src/bootman/kernel.c b/src/bootman/kernel.c index 1a1f421..e8eda3d 100644 --- a/src/bootman/kernel.c +++ b/src/bootman/kernel.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "bootman.h" #include "bootman_private.h" @@ -608,6 +609,37 @@ static bool boot_manager_remove_legacy_uefi_kernel(const BootManager *manager, c return ret; } +bool _copy_glob_result(const glob_t files, const char *target_dir) { + for(size_t i = 0; i < files.gl_pathc; i++) { + char *initrd_source = files.gl_pathv[i]; + autofree(char) *initrd_target = string_printf("%s/%s", target_dir, basename(files.gl_pathv[i])); + + LOG_DEBUG("installing extra initrd: %s", files.gl_pathv[i]); + + if (!cbm_files_match(initrd_source, initrd_target)) { + if (!copy_file_atomic(initrd_source, initrd_target, 00644)) { + return false; + } + } + } + + return true; +} + +bool _copy_extra_initrds(const char *initrd_base, const char *target_dir) { + autofree(char) *initrd_glob = string_printf("%s.*", initrd_base); + glob_t files; + + int res = glob(initrd_glob, 0, NULL, &files); + bool ret = (res == GLOB_NOMATCH); + if (res == 0) { + ret = _copy_glob_result(files, target_dir); + } + + globfree(&files); + return ret; +} + /** * Internal function to install the kernel blob itself */ @@ -616,6 +648,7 @@ bool boot_manager_install_kernel_internal(const BootManager *manager, const Kern autofree(char) *kfile_target = NULL; autofree(char) *base_path = NULL; autofree(char) *initrd_target = NULL; + autofree(char) *initrd_target_dir = NULL; const char *initrd_source = NULL; bool is_uefi = ((manager->bootloader->get_capabilities(manager) & BOOTLOADER_CAP_UEFI) == BOOTLOADER_CAP_UEFI); @@ -658,10 +691,8 @@ bool boot_manager_install_kernel_internal(const BootManager *manager, const Kern return true; } - initrd_target = string_printf("%s%s/%s", - base_path, - (is_uefi ? efi_boot_dir : ""), - kernel->target.initrd_path); + initrd_target_dir = string_printf("%s%s", base_path, (is_uefi ? efi_boot_dir : "")); + initrd_target = string_printf("%s/%s", initrd_target_dir, kernel->target.initrd_path); if (!cbm_files_match(initrd_source, initrd_target)) { if (!copy_file_atomic(initrd_source, initrd_target, 00644)) { @@ -672,6 +703,13 @@ bool boot_manager_install_kernel_internal(const BootManager *manager, const Kern } } + if (!_copy_extra_initrds(initrd_source, initrd_target_dir)) { + LOG_FATAL("Failed to install extra initrds %s: %s", + initrd_source, + strerror(errno)); + return false; + } + /* Our portion is complete, remove any legacy uefi bits we might have * from previous runs, and then continue and let the bootloader configure * as appropriate. @@ -684,6 +722,34 @@ bool boot_manager_install_kernel_internal(const BootManager *manager, const Kern return true; } +bool _remove_glob_result(const glob_t files) { + bool ret = true; + + for(size_t i = 0; i < files.gl_pathc; i++) { + LOG_DEBUG("removing extra initrd: %s", files.gl_pathv[i]); + + if (unlink(files.gl_pathv[i]) < 0) { + ret = false; + } + } + + return ret; +} + +bool _remove_extra_initrds(const char *initrd_base) { + autofree(char) *initrd_glob = string_printf("%s.*", initrd_base); + glob_t files; + + int res = glob(initrd_glob, 0, NULL, &files); + bool ret = (res == GLOB_NOMATCH); + if (res == 0) { + ret = _remove_glob_result(files); + } + + globfree(&files); + return ret; +} + /** * Internal function to remove the kernel blob itself */ @@ -801,6 +867,20 @@ bool boot_manager_remove_kernel_internal(const BootManager *manager, const Kerne } } + /* Remove additional initrds */ + if (!_remove_extra_initrds(kernel->source.initrd_file)) { + LOG_ERROR("Failed to remove extra initrds %s.*: %s", + kernel->source.initrd_file, + strerror(errno)); + return false; + } + if (!_remove_extra_initrds(initrd_target)) { + LOG_ERROR("Failed to remove extra initrds %s.*: %s", + initrd_target, + strerror(errno)); + return false; + } + /* Lastly, remove the source */ if (unlink(kernel->source.path) < 0) { LOG_ERROR("Failed to remove kernel blob %s: %s",