]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bootspec: add bootspec_extract_osrelease() helper
authorLennart Poettering <lennart@amutable.com>
Fri, 20 Mar 2026 09:21:11 +0000 (10:21 +0100)
committerLennart Poettering <lennart@amutable.com>
Fri, 1 May 2026 05:10:31 +0000 (07:10 +0200)
src/shared/bootspec.c
src/shared/bootspec.h

index ebd63788c0ad1ba59da2d83a279e17437a08ee69..c0111d1f9c433762929b2e98c6e8aa1ae97b218d 100644 (file)
@@ -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);
index 01abe05e72dd9621ca1ad0df69b7c4f206a99e0e..d5f6930be99d13683ffd0794bfa751331c481194 100644 (file)
@@ -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);