Skip to content

Commit

Permalink
Merge pull request #4 from getsolus/multiple-initrds
Browse files Browse the repository at this point in the history
systemd: Extend support for multiple kernel-dependent initrds
  • Loading branch information
silkeh authored Jun 16, 2024
2 parents 8c3d96b + 863a3ae commit d1f882a
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 4 deletions.
25 changes: 25 additions & 0 deletions src/bootloaders/systemd-class.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <glob.h>

#include "bootloader.h"
#include "bootman.h"
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)) {
Expand Down
88 changes: 84 additions & 4 deletions src/bootman/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <fcntl.h>
#include <limits.h>
#include <unistd.h>
#include <glob.h>

#include "bootman.h"
#include "bootman_private.h"
Expand Down Expand Up @@ -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
*/
Expand All @@ -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);
Expand Down Expand Up @@ -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)) {
Expand All @@ -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.
Expand All @@ -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
*/
Expand Down Expand Up @@ -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",
Expand Down

0 comments on commit d1f882a

Please sign in to comment.