From: Lennart Poettering Date: Fri, 20 Mar 2026 09:21:11 +0000 (+0100) Subject: bootspec: add bootspec_extract_osrelease() helper X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d292874bf6845605b733ad8e6926a5bee23ef5d3;p=thirdparty%2Fsystemd.git bootspec: add bootspec_extract_osrelease() helper --- diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index ebd63788c0a..c0111d1f9c4 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -31,6 +31,7 @@ #include "string-util.h" #include "strv.h" #include "uki.h" +#include "utf8.h" static const char* const boot_entry_type_description_table[_BOOT_ENTRY_TYPE_MAX] = { [BOOT_ENTRY_TYPE1] = "Boot Loader Specification Type #1 (.conf)", @@ -711,56 +712,143 @@ static int boot_entries_find_type1( return 0; } -static int boot_entry_load_unified( - const char *root, - const BootEntrySource source, - const char *path, - unsigned profile, - const char *osrelease_text, - const char *profile_text, - const char *cmdline_text, - BootEntry *ret) { +static void mangle_osrelease_string(char **s, const char *field) { + assert(s); + assert(field); - _cleanup_free_ char *fname = NULL, *os_pretty_name = NULL, *os_image_id = NULL, *os_name = NULL, *os_id = NULL, - *os_image_version = NULL, *os_version = NULL, *os_version_id = NULL, *os_build_id = NULL; - const char *k, *good_name, *good_version, *good_sort_key; - int r; + if (!isempty(*s) && !string_has_cc(*s, /* ok= */ NULL) && utf8_is_valid(*s)) + return; - assert(root); - assert(path); - assert(osrelease_text); - assert(ret); + if (*s) { + log_debug("OS release field '%s' is not clean, suppressing.", field); + *s = mfree(*s); + } +} - k = path_startswith(path, root); - if (!k) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Path is not below root: %s", path); +int bootspec_extract_osrelease( + const char *text, + char **ret_good_name, + char **ret_good_version, + char **ret_good_sort_key, + char **ret_os_id, + char **ret_os_version_id, + char **ret_image_id, + char **ret_image_version) { + + int r; + + assert(text); - r = parse_env_data(osrelease_text, /* size= */ SIZE_MAX, - ".osrel", + _cleanup_free_ char *os_pretty_name = NULL, *image_id = NULL, *os_name = NULL, *os_id = NULL, + *image_version = NULL, *os_version = NULL, *os_version_id = NULL, *os_build_id = NULL; + r = parse_env_data(text, /* size= */ SIZE_MAX, + "os-release", "PRETTY_NAME", &os_pretty_name, - "IMAGE_ID", &os_image_id, + "IMAGE_ID", &image_id, "NAME", &os_name, "ID", &os_id, - "IMAGE_VERSION", &os_image_version, + "IMAGE_VERSION", &image_version, "VERSION", &os_version, "VERSION_ID", &os_version_id, "BUILD_ID", &os_build_id); if (r < 0) - return log_error_errno(r, "Failed to parse os-release data from unified kernel image %s: %m", path); + return r; + + mangle_osrelease_string(&os_pretty_name, "PRETTY_NAME"); + mangle_osrelease_string(&image_id, "IMAGE_ID"); + mangle_osrelease_string(&os_name, "NAME"); + mangle_osrelease_string(&os_id, "ID"); + mangle_osrelease_string(&image_version, "IMAGE_VERSION"); + mangle_osrelease_string(&os_version, "VERSION"); + mangle_osrelease_string(&os_version_id, "VERSION_ID"); + mangle_osrelease_string(&os_build_id, "BUILD_ID"); + const char *good_name, *good_version, *good_sort_key; if (!bootspec_pick_name_version_sort_key( os_pretty_name, - os_image_id, + image_id, os_name, os_id, - os_image_version, + image_version, os_version, os_version_id, os_build_id, &good_name, &good_version, &good_sort_key)) - return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Missing fields in os-release data from unified kernel image %s, refusing.", path); + return -EBADMSG; + + _cleanup_free_ char *copy_good_name = NULL, *copy_good_version = NULL, *copy_good_sort_key = NULL; + if (ret_good_name) { + copy_good_name = strdup(good_name); + if (!copy_good_name) + return -ENOMEM; + } + + if (ret_good_version && good_version) { + copy_good_version = strdup(good_version); + if (!copy_good_version) + return -ENOMEM; + } + + if (ret_good_sort_key && good_sort_key) { + copy_good_sort_key = strdup(good_sort_key); + if (!copy_good_sort_key) + return -ENOMEM; + } + + if (ret_good_name) + *ret_good_name = TAKE_PTR(copy_good_name); + if (ret_good_version) + *ret_good_version = TAKE_PTR(copy_good_version); + if (ret_good_sort_key) + *ret_good_sort_key = TAKE_PTR(copy_good_sort_key); + + if (ret_os_id) + *ret_os_id = TAKE_PTR(os_id); + if (ret_os_version_id) + *ret_os_version_id = TAKE_PTR(os_version_id); + if (ret_image_id) + *ret_image_id = TAKE_PTR(image_id); + if (ret_image_version) + *ret_image_version = TAKE_PTR(image_version); + + return 0; +} + +static int boot_entry_load_unified( + const char *root, + const BootEntrySource source, + const char *path, + unsigned profile, + const char *osrelease_text, + const char *profile_text, + const char *cmdline_text, + BootEntry *ret) { + + int r; + + assert(root); + assert(path); + assert(osrelease_text); + assert(ret); + + const char *k = path_startswith(path, root); + if (!k) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Path is not below root: %s", path); + + _cleanup_free_ char *good_name = NULL, *good_version = NULL, *good_sort_key = NULL, *os_id = NULL, *os_version_id = NULL; + r = bootspec_extract_osrelease( + osrelease_text, + &good_name, + &good_version, + &good_sort_key, + &os_id, + &os_version_id, + /* ret_image_id= */ NULL, + /* ret_image_version= */ NULL); + if (r < 0) + return log_error_errno(r, "Failed to extract name/version/sort-key from os-release data from unified kernel image %s, refusing: %m", path); _cleanup_free_ char *profile_id = NULL, *profile_title = NULL; if (profile_text) { @@ -773,6 +861,7 @@ static int boot_entry_load_unified( return log_error_errno(r, "Failed to parse profile data from unified kernel image '%s': %m", path); } + _cleanup_free_ char *fname = NULL; r = path_extract_filename(path, &fname); if (r < 0) return log_error_errno(r, "Failed to extract file name from '%s': %m", path); diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h index 01abe05e72d..d5f6930be99 100644 --- a/src/shared/bootspec.h +++ b/src/shared/bootspec.h @@ -164,3 +164,5 @@ int boot_filename_extract_tries(const char *fname, char **ret_stripped, unsigned int boot_entry_to_json(const BootConfig *c, size_t i, sd_json_variant **ret); int pe_find_uki_sections(int fd, const char *path, unsigned profile, char **ret_osrelease, char **ret_profile, char **ret_cmdline); + +int bootspec_extract_osrelease(const char *text, char **ret_good_name, char **ret_good_version, char **ret_good_sort_key, char **ret_os_id, char **ret_os_version_id, char **ret_image_id, char **ret_image_version);