summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2023-03-26 16:33:43 +0900
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2023-03-27 09:51:18 +0200
commit9e43296fd2c4959f045859d248a4e78fcfcceae6 (patch)
tree6eec450ebe932e55056b64ac7a6c4965c1c48ad1 /src/shared
parent600362aa11af5af90125aacc8ad7612a5cb80a68 (diff)
downloadsystemd-9e43296fd2c4959f045859d248a4e78fcfcceae6.tar.gz
bootctl: split-out entry token related definitions into boot-entry.[ch]
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'.
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/boot-entry.c224
-rw-r--r--src/shared/boot-entry.h25
-rw-r--r--src/shared/meson.build1
3 files changed, 250 insertions, 0 deletions
diff --git a/src/shared/boot-entry.c b/src/shared/boot-entry.c
new file mode 100644
index 0000000000..90e72bd754
--- /dev/null
+++ b/src/shared/boot-entry.c
@@ -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
index 0000000000..97b30702bc
--- /dev/null
+++ b/src/shared/boot-entry.h
@@ -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);
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 9342d25273..cb0697d1b9 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -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',