summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/boot/bootctl-install.c4
-rw-r--r--src/boot/bootctl-util.c98
-rw-r--r--src/boot/bootctl.c29
-rw-r--r--src/boot/bootctl.h11
-rw-r--r--src/shared/boot-entry.c224
-rw-r--r--src/shared/boot-entry.h25
-rw-r--r--src/shared/meson.build1
7 files changed, 267 insertions, 125 deletions
diff --git a/src/boot/bootctl-install.c b/src/boot/bootctl-install.c
index dc7ea8c5ca..a50f984a23 100644
--- a/src/boot/bootctl-install.c
+++ b/src/boot/bootctl-install.c
@@ -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");
diff --git a/src/boot/bootctl-util.c b/src/boot/bootctl-util.c
index 62c0b64406..6cae9b4deb 100644
--- a/src/boot/bootctl-util.c
+++ b/src/boot/bootctl-util.c
@@ -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;
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 022e680255..710cf8da65 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -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 */
diff --git a/src/boot/bootctl.h b/src/boot/bootctl.h
index 9012bf932b..c87d43694f 100644
--- a/src/boot/bootctl.h
+++ b/src/boot/bootctl.h
@@ -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
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',