]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bootctl: split-out entry token related definitions into boot-entry.[ch]
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 26 Mar 2023 07:33:43 +0000 (16:33 +0900)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 27 Mar 2023 07:51:18 +0000 (09:51 +0200)
No functional change, just preparation for later commits.
These can be used in kernel-install later.

Note, unlike the our usual coding style, the arguments for
boot_entry_token_ensure() and parse_boot_entry_token_type() are
referenced, updated, and may freed, hence, always pass initialized
values. That's why they are not named as 'ret_xyz'.

src/boot/bootctl-install.c
src/boot/bootctl-util.c
src/boot/bootctl.c
src/boot/bootctl.h
src/shared/boot-entry.c [new file with mode: 0644]
src/shared/boot-entry.h [new file with mode: 0644]
src/shared/meson.build

index dc7ea8c5ca66d2bf193e881d256a1d5b92fb7f95..a50f984a23631a056c3d5a339a9b7fb28fbf689e 100644 (file)
@@ -133,7 +133,7 @@ static int settle_make_entry_directory(void) {
         bool layout_type1 = use_boot_loader_spec_type1();
         if (arg_make_entry_directory < 0) { /* Automatic mode */
                 if (layout_type1) {
-                        if (arg_entry_token_type == ARG_ENTRY_TOKEN_MACHINE_ID) {
+                        if (arg_entry_token_type == BOOT_ENTRY_TOKEN_MACHINE_ID) {
                                 r = path_is_temporary_fs("/etc/machine-id");
                                 if (r < 0)
                                         return log_debug_errno(r, "Couldn't determine whether /etc/machine-id is on a temporary file system: %m");
@@ -510,7 +510,7 @@ static int install_entry_token(void) {
         /* Let's save the used entry token in /etc/kernel/entry-token if we used it to create the entry
          * directory, or if anything else but the machine ID */
 
-        if (!arg_make_entry_directory && arg_entry_token_type == ARG_ENTRY_TOKEN_MACHINE_ID)
+        if (!arg_make_entry_directory && arg_entry_token_type == BOOT_ENTRY_TOKEN_MACHINE_ID)
                 return 0;
 
         p = path_join(arg_root, etc_kernel(), "entry-token");
index 62c0b64406d272622b58a7550ad78a88909e64d5..6cae9b4debc0184dc9478da712f662e9f5baab46 100644 (file)
@@ -5,11 +5,8 @@
 #include "bootctl.h"
 #include "bootctl-util.h"
 #include "fileio.h"
-#include "os-util.h"
-#include "path-util.h"
 #include "stat-util.h"
 #include "sync-util.h"
-#include "utf8.h"
 
 int sync_everything(void) {
         int ret = 0, k;
@@ -118,93 +115,14 @@ finish:
 int settle_entry_token(void) {
         int r;
 
-        switch (arg_entry_token_type) {
-
-        case ARG_ENTRY_TOKEN_AUTO: {
-                _cleanup_free_ char *buf = NULL, *p = NULL;
-                p = path_join(arg_root, etc_kernel(), "entry-token");
-                if (!p)
-                        return log_oom();
-                r = read_one_line_file(p, &buf);
-                if (r < 0 && r != -ENOENT)
-                        return log_error_errno(r, "Failed to read %s: %m", p);
-
-                if (!isempty(buf)) {
-                        free_and_replace(arg_entry_token, buf);
-                        arg_entry_token_type = ARG_ENTRY_TOKEN_LITERAL;
-                } else if (sd_id128_is_null(arg_machine_id)) {
-                        _cleanup_free_ char *id = NULL, *image_id = NULL;
-
-                        r = parse_os_release(arg_root,
-                                             "IMAGE_ID", &image_id,
-                                             "ID", &id);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to load /etc/os-release: %m");
-
-                        if (!isempty(image_id)) {
-                                free_and_replace(arg_entry_token, image_id);
-                                arg_entry_token_type = ARG_ENTRY_TOKEN_OS_IMAGE_ID;
-                        } else if (!isempty(id)) {
-                                free_and_replace(arg_entry_token, id);
-                                arg_entry_token_type = ARG_ENTRY_TOKEN_OS_ID;
-                        } else
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No machine ID set, and /etc/os-release carries no ID=/IMAGE_ID= fields.");
-                } else {
-                        r = free_and_strdup_warn(&arg_entry_token, SD_ID128_TO_STRING(arg_machine_id));
-                        if (r < 0)
-                                return r;
-
-                        arg_entry_token_type = ARG_ENTRY_TOKEN_MACHINE_ID;
-                }
-
-                break;
-        }
-
-        case ARG_ENTRY_TOKEN_MACHINE_ID:
-                if (sd_id128_is_null(arg_machine_id))
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No machine ID set.");
-
-                r = free_and_strdup_warn(&arg_entry_token, SD_ID128_TO_STRING(arg_machine_id));
-                if (r < 0)
-                        return r;
-
-                break;
-
-        case ARG_ENTRY_TOKEN_OS_IMAGE_ID: {
-                _cleanup_free_ char *buf = NULL;
-
-                r = parse_os_release(arg_root, "IMAGE_ID", &buf);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to load /etc/os-release: %m");
-
-                if (isempty(buf))
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "IMAGE_ID= field not set in /etc/os-release.");
-
-                free_and_replace(arg_entry_token, buf);
-                break;
-        }
-
-        case ARG_ENTRY_TOKEN_OS_ID: {
-                _cleanup_free_ char *buf = NULL;
-
-                r = parse_os_release(arg_root, "ID", &buf);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to load /etc/os-release: %m");
-
-                if (isempty(buf))
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "ID= field not set in /etc/os-release.");
-
-                free_and_replace(arg_entry_token, buf);
-                break;
-        }
-
-        case ARG_ENTRY_TOKEN_LITERAL:
-                assert(!isempty(arg_entry_token)); /* already filled in by command line parser */
-                break;
-        }
-
-        if (isempty(arg_entry_token) || !(utf8_is_valid(arg_entry_token) && string_is_safe(arg_entry_token)))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected entry token not valid: %s", arg_entry_token);
+        r = boot_entry_token_ensure(
+                        arg_root,
+                        etc_kernel(),
+                        arg_machine_id,
+                        &arg_entry_token_type,
+                        &arg_entry_token);
+        if (r < 0)
+                return r;
 
         log_debug("Using entry token: %s", arg_entry_token);
         return 0;
index 022e680255f12a26ea6ac3d79d1312b9151214ba..710cf8da65b832b4bc114f9f37d19d1b3ae63a7c 100644 (file)
@@ -43,7 +43,7 @@ bool arg_quiet = false;
 int arg_make_entry_directory = false; /* tri-state: < 0 for automatic logic */
 sd_id128_t arg_machine_id = SD_ID128_NULL;
 char *arg_install_layout = NULL;
-EntryTokenType arg_entry_token_type = ARG_ENTRY_TOKEN_AUTO;
+BootEntryTokenType arg_entry_token_type = BOOT_ENTRY_TOKEN_AUTO;
 char *arg_entry_token = NULL;
 JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
 bool arg_arch_all = false;
@@ -328,30 +328,11 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_quiet = true;
                         break;
 
-                case ARG_ENTRY_TOKEN: {
-                        const char *e;
-
-                        if (streq(optarg, "machine-id")) {
-                                arg_entry_token_type = ARG_ENTRY_TOKEN_MACHINE_ID;
-                                arg_entry_token = mfree(arg_entry_token);
-                        } else if (streq(optarg, "os-image-id")) {
-                                arg_entry_token_type = ARG_ENTRY_TOKEN_OS_IMAGE_ID;
-                                arg_entry_token = mfree(arg_entry_token);
-                        } else if (streq(optarg, "os-id")) {
-                                arg_entry_token_type = ARG_ENTRY_TOKEN_OS_ID;
-                                arg_entry_token = mfree(arg_entry_token);
-                        } else if ((e = startswith(optarg, "literal:"))) {
-                                arg_entry_token_type = ARG_ENTRY_TOKEN_LITERAL;
-
-                                r = free_and_strdup_warn(&arg_entry_token, e);
-                                if (r < 0)
-                                        return r;
-                        } else
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "Unexpected parameter for --entry-token=: %s", optarg);
-
+                case ARG_ENTRY_TOKEN:
+                        r = parse_boot_entry_token_type(optarg, &arg_entry_token_type, &arg_entry_token);
+                        if (r < 0)
+                                return r;
                         break;
-                }
 
                 case ARG_MAKE_ENTRY_DIRECTORY:
                         if (streq(optarg, "auto"))  /* retained for backwards compatibility */
index 9012bf932bbde6bb6295b6dcb96986127f86478c..c87d43694f809b1273de36a9a1309e25bbf02331 100644 (file)
@@ -3,17 +3,10 @@
 
 #include "sd-id128.h"
 
+#include "boot-entry.h"
 #include "json.h"
 #include "pager.h"
 
-typedef enum EntryTokenType {
-        ARG_ENTRY_TOKEN_MACHINE_ID,
-        ARG_ENTRY_TOKEN_OS_IMAGE_ID,
-        ARG_ENTRY_TOKEN_OS_ID,
-        ARG_ENTRY_TOKEN_LITERAL,
-        ARG_ENTRY_TOKEN_AUTO,
-} EntryTokenType;
-
 typedef enum InstallSource {
         ARG_INSTALL_SOURCE_IMAGE,
         ARG_INSTALL_SOURCE_HOST,
@@ -32,7 +25,7 @@ extern bool arg_quiet;
 extern int arg_make_entry_directory; /* tri-state: < 0 for automatic logic */
 extern sd_id128_t arg_machine_id;
 extern char *arg_install_layout;
-extern EntryTokenType arg_entry_token_type;
+extern BootEntryTokenType arg_entry_token_type;
 extern char *arg_entry_token;
 extern JsonFormatFlags arg_json_format_flags;
 extern bool arg_arch_all;
diff --git a/src/shared/boot-entry.c b/src/shared/boot-entry.c
new file mode 100644 (file)
index 0000000..90e72bd
--- /dev/null
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "boot-entry.h"
+#include "fileio.h"
+#include "id128-util.h"
+#include "os-util.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "utf8.h"
+
+bool boot_entry_token_valid(const char *p) {
+        return utf8_is_valid(p) && string_is_safe(p) && filename_is_valid(p);
+}
+
+static int entry_token_load(const char *root, const char *etc_kernel, BootEntryTokenType *type, char **token) {
+        _cleanup_free_ char *buf = NULL, *p = NULL;
+        int r;
+
+        assert(type);
+        assert(*type == BOOT_ENTRY_TOKEN_AUTO);
+        assert(token);
+
+        if (!etc_kernel)
+                return 0;
+
+        p = path_join(root, etc_kernel, "entry-token");
+        if (!p)
+                return log_oom();
+
+        r = read_one_line_file(p, &buf);
+        if (r == -ENOENT)
+                return 0;
+        if (r < 0)
+                return log_error_errno(r, "Failed to read %s: %m", p);
+
+        if (isempty(buf))
+                return 0;
+
+        if (!boot_entry_token_valid(buf)) {
+                log_debug("Invalid entry token specified in %s, ignoring.", p);
+                return 0;
+        }
+
+        *token = TAKE_PTR(buf);
+        *type = BOOT_ENTRY_TOKEN_LITERAL;
+        return 1;
+}
+
+static int entry_token_from_machine_id(sd_id128_t machine_id, BootEntryTokenType *type, char **token) {
+        char *p;
+
+        assert(type);
+        assert(IN_SET(*type, BOOT_ENTRY_TOKEN_AUTO, BOOT_ENTRY_TOKEN_MACHINE_ID));
+        assert(token);
+
+        if (sd_id128_is_null(machine_id))
+                return 0;
+
+        p = strdup(SD_ID128_TO_STRING(machine_id));
+        if (!p)
+                return log_oom();
+
+        *token = p;
+        *type = BOOT_ENTRY_TOKEN_MACHINE_ID;
+        return 1;
+}
+
+static int entry_token_from_os_release(const char *root, BootEntryTokenType *type, char **token) {
+        _cleanup_free_ char *id = NULL, *image_id = NULL;
+        int r;
+
+        assert(type);
+        assert(IN_SET(*type, BOOT_ENTRY_TOKEN_AUTO, BOOT_ENTRY_TOKEN_OS_IMAGE_ID, BOOT_ENTRY_TOKEN_OS_ID));
+        assert(token);
+
+        switch (*type) {
+        case BOOT_ENTRY_TOKEN_AUTO:
+                r = parse_os_release(root,
+                                     "IMAGE_ID", &image_id,
+                                     "ID",       &id);
+                break;
+
+        case BOOT_ENTRY_TOKEN_OS_IMAGE_ID:
+                r = parse_os_release(root, "IMAGE_ID", &image_id);
+                break;
+
+        case BOOT_ENTRY_TOKEN_OS_ID:
+                r = parse_os_release(root, "ID", &id);
+                break;
+
+        default:
+                assert_not_reached();
+        }
+        if (r == -ENOENT)
+                return 0;
+        if (r < 0)
+                return log_error_errno(r, "Failed to load %s/etc/os-release: %m", strempty(root));
+
+        if (!isempty(image_id) && boot_entry_token_valid(image_id)) {
+                *token = TAKE_PTR(image_id);
+                *type = BOOT_ENTRY_TOKEN_OS_IMAGE_ID;
+                return 1;
+        }
+
+        if (!isempty(id) && boot_entry_token_valid(id)) {
+                *token = TAKE_PTR(id);
+                *type = BOOT_ENTRY_TOKEN_OS_ID;
+                return 1;
+        }
+
+        return 0;
+}
+
+int boot_entry_token_ensure(
+                const char *root,
+                const char *etc_kernel,
+                sd_id128_t machine_id,
+                BootEntryTokenType *type,
+                char **token) {
+
+        int r;
+
+        assert(type);
+        assert(token);
+
+        if (*token)
+                return 0; /* Already set. */
+
+        switch (*type) {
+
+        case BOOT_ENTRY_TOKEN_AUTO:
+                r = entry_token_load(root, etc_kernel, type, token);
+                if (r != 0)
+                        return r;
+
+                r = entry_token_from_machine_id(machine_id, type, token);
+                if (r != 0)
+                        return r;
+
+                r = entry_token_from_os_release(root, type, token);
+                if (r != 0)
+                        return r;
+
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "No machine ID set, and %s/etc/os-release carries no ID=/IMAGE_ID= fields.",
+                                       strempty(root));
+
+        case BOOT_ENTRY_TOKEN_MACHINE_ID:
+                r = entry_token_from_machine_id(machine_id, type, token);
+                if (r != 0)
+                        return r;
+
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No machine ID set.");
+
+        case BOOT_ENTRY_TOKEN_OS_IMAGE_ID:
+                r = entry_token_from_os_release(root, type, token);
+                if (r != 0)
+                        return r;
+
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "IMAGE_ID= field not set in %s/etc/os-release.",
+                                       strempty(root));
+
+        case BOOT_ENTRY_TOKEN_OS_ID:
+                r = entry_token_from_os_release(root, type, token);
+                if (r != 0)
+                        return r;
+
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "ID= field not set in %s/etc/os-release.",
+                                       strempty(root));
+
+        case BOOT_ENTRY_TOKEN_LITERAL:
+                /* In this case, the token should be already set by the user input. */
+                return -EINVAL;
+
+        default:
+                assert_not_reached();
+        }
+}
+
+int parse_boot_entry_token_type(const char *s, BootEntryTokenType *type, char **token) {
+        assert(s);
+        assert(type);
+        assert(token);
+
+        /*
+         * This function is intended to be used in command line parsers, to handle token that are passed in.
+         *
+         * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON SUCCESS!
+         * Hence, do not pass in uninitialized pointers.
+         */
+
+        if (streq(s, "machine-id")) {
+                *type = BOOT_ENTRY_TOKEN_MACHINE_ID;
+                *token = mfree(*token);
+                return 0;
+        }
+
+        if (streq(s, "os-image-id")) {
+                *type = BOOT_ENTRY_TOKEN_OS_IMAGE_ID;
+                *token = mfree(*token);
+                return 0;
+        }
+
+        if (streq(s, "os-id")) {
+                *type = BOOT_ENTRY_TOKEN_OS_ID;
+                *token = mfree(*token);
+                return 0;
+        }
+
+        const char *e = startswith(s, "literal:");
+        if (e) {
+                if (!boot_entry_token_valid(e))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Invalid entry token literal is specified for --entry-token=.");
+
+                *type = BOOT_ENTRY_TOKEN_LITERAL;
+                return free_and_strdup_warn(token, e);
+        }
+
+        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                               "Unexpected parameter for --entry-token=: %s", s);
+}
diff --git a/src/shared/boot-entry.h b/src/shared/boot-entry.h
new file mode 100644 (file)
index 0000000..97b3070
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdbool.h>
+
+#include "sd-id128.h"
+
+typedef enum BootEntryTokenType {
+        BOOT_ENTRY_TOKEN_MACHINE_ID,
+        BOOT_ENTRY_TOKEN_OS_IMAGE_ID,
+        BOOT_ENTRY_TOKEN_OS_ID,
+        BOOT_ENTRY_TOKEN_LITERAL,
+        BOOT_ENTRY_TOKEN_AUTO,
+} BootEntryTokenType;
+
+bool boot_entry_token_valid(const char *p);
+
+int boot_entry_token_ensure(
+                const char *root,
+                const char *etc_kernel,   /* will be prefixed with root, typically /etc/kernel. */
+                sd_id128_t machine_id,
+                BootEntryTokenType *type, /* input and output */
+                char **token);            /* output, but do not pass uninitialized value. */
+
+int parse_boot_entry_token_type(const char *s, BootEntryTokenType *type, char **token);
index 9342d25273c407da424013e474ff3cefd8cd6acc..cb0697d1b9331f23f91f24539d311e6f95a7f58e 100644 (file)
@@ -10,6 +10,7 @@ shared_sources = files(
         'bitmap.c',
         'blockdev-util.c',
         'bond-util.c',
+        'boot-entry.c',
         'boot-timestamps.c',
         'bootspec.c',
         'bpf-dlopen.c',