]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bootctl: split out "set-efivar" verbs, too
authorLennart Poettering <lennart@poettering.net>
Fri, 16 Dec 2022 17:51:10 +0000 (18:51 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 19 Dec 2022 11:06:33 +0000 (12:06 +0100)
meson.build
src/boot/bootctl-set-efivar.c [new file with mode: 0644]
src/boot/bootctl-set-efivar.h [new file with mode: 0644]
src/boot/bootctl.c

index d30331e72a98895ffe9d7f8e0ebdd5c19461bfeb..9155ec4f7891889832707bf61ec3e6bdb1275046 100644 (file)
@@ -2611,6 +2611,8 @@ if conf.get('HAVE_BLKID') == 1 and conf.get('HAVE_GNU_EFI') == 1
                  'src/boot/bootctl-random-seed.h',
                  'src/boot/bootctl-reboot-to-firmware.c',
                  'src/boot/bootctl-reboot-to-firmware.h',
+                 'src/boot/bootctl-set-efivar.c',
+                 'src/boot/bootctl-set-efivar.h',
                  'src/boot/bootctl-systemd-efi-options.c',
                  'src/boot/bootctl-systemd-efi-options.h',
                  'src/boot/bootctl-util.c',
diff --git a/src/boot/bootctl-set-efivar.c b/src/boot/bootctl-set-efivar.c
new file mode 100644 (file)
index 0000000..cbf92ca
--- /dev/null
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <uchar.h>
+#include <unistd.h>
+
+#include "bootctl.h"
+#include "bootctl-set-efivar.h"
+#include "efivars.h"
+#include "stdio-util.h"
+#include "utf8.h"
+#include "virt.h"
+
+static int parse_timeout(const char *arg1, char16_t **ret_timeout, size_t *ret_timeout_size) {
+        char utf8[DECIMAL_STR_MAX(usec_t)];
+        char16_t *encoded;
+        usec_t timeout;
+        int r;
+
+        assert(arg1);
+        assert(ret_timeout);
+        assert(ret_timeout_size);
+
+        if (streq(arg1, "menu-force"))
+                timeout = USEC_INFINITY;
+        else if (streq(arg1, "menu-hidden"))
+                timeout = 0;
+        else {
+                r = parse_time(arg1, &timeout, USEC_PER_SEC);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse timeout '%s': %m", arg1);
+                if (timeout != USEC_INFINITY && timeout > UINT32_MAX * USEC_PER_SEC)
+                        log_warning("Timeout is too long and will be treated as 'menu-force' instead.");
+        }
+
+        xsprintf(utf8, USEC_FMT, MIN(timeout / USEC_PER_SEC, UINT32_MAX));
+
+        encoded = utf8_to_utf16(utf8, strlen(utf8));
+        if (!encoded)
+                return log_oom();
+
+        *ret_timeout = encoded;
+        *ret_timeout_size = char16_strlen(encoded) * 2 + 2;
+        return 0;
+}
+
+static int parse_loader_entry_target_arg(const char *arg1, char16_t **ret_target, size_t *ret_target_size) {
+        char16_t *encoded = NULL;
+        int r;
+
+        assert(arg1);
+        assert(ret_target);
+        assert(ret_target_size);
+
+        if (streq(arg1, "@current")) {
+                r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntrySelected), NULL, (void *) ret_target, ret_target_size);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntrySelected': %m");
+
+        } else if (streq(arg1, "@oneshot")) {
+                r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntryOneShot), NULL, (void *) ret_target, ret_target_size);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryOneShot': %m");
+
+        } else if (streq(arg1, "@default")) {
+                r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntryDefault), NULL, (void *) ret_target, ret_target_size);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryDefault': %m");
+
+        } else if (arg1[0] == '@' && !streq(arg1, "@saved"))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unsupported special entry identifier: %s", arg1);
+        else {
+                encoded = utf8_to_utf16(arg1, strlen(arg1));
+                if (!encoded)
+                        return log_oom();
+
+                *ret_target = encoded;
+                *ret_target_size = char16_strlen(encoded) * 2 + 2;
+        }
+
+        return 0;
+}
+
+int verb_set_efivar(int argc, char *argv[], void *userdata) {
+        int r;
+
+        if (arg_root)
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "Acting on %s, skipping EFI variable setup.",
+                                       arg_image ? "image" : "root directory");
+
+        if (!is_efi_boot())
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "Not booted with UEFI.");
+
+        if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderInfo)), F_OK) < 0) {
+                if (errno == ENOENT) {
+                        log_error_errno(errno, "Not booted with a supported boot loader.");
+                        return -EOPNOTSUPP;
+                }
+
+                return log_error_errno(errno, "Failed to detect whether boot loader supports '%s' operation: %m", argv[0]);
+        }
+
+        if (detect_container() > 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "'%s' operation not supported in a container.",
+                                       argv[0]);
+
+        if (!arg_touch_variables)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "'%s' operation cannot be combined with --no-variables.",
+                                       argv[0]);
+
+        const char *variable;
+        int (* arg_parser)(const char *, char16_t **, size_t *);
+
+        if (streq(argv[0], "set-default")) {
+                variable = EFI_LOADER_VARIABLE(LoaderEntryDefault);
+                arg_parser = parse_loader_entry_target_arg;
+        } else if (streq(argv[0], "set-oneshot")) {
+                variable = EFI_LOADER_VARIABLE(LoaderEntryOneShot);
+                arg_parser = parse_loader_entry_target_arg;
+        } else if (streq(argv[0], "set-timeout")) {
+                variable = EFI_LOADER_VARIABLE(LoaderConfigTimeout);
+                arg_parser = parse_timeout;
+        } else if (streq(argv[0], "set-timeout-oneshot")) {
+                variable = EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot);
+                arg_parser = parse_timeout;
+        } else
+                assert_not_reached();
+
+        if (isempty(argv[1])) {
+                r = efi_set_variable(variable, NULL, 0);
+                if (r < 0 && r != -ENOENT)
+                        return log_error_errno(r, "Failed to remove EFI variable '%s': %m", variable);
+        } else {
+                _cleanup_free_ char16_t *value = NULL;
+                size_t value_size = 0;
+
+                r = arg_parser(argv[1], &value, &value_size);
+                if (r < 0)
+                        return r;
+                r = efi_set_variable(variable, value, value_size);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to update EFI variable '%s': %m", variable);
+        }
+
+        return 0;
+}
diff --git a/src/boot/bootctl-set-efivar.h b/src/boot/bootctl-set-efivar.h
new file mode 100644 (file)
index 0000000..6441681
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+int verb_set_efivar(int argc, char *argv[], void *userdata);
index 52f4200e3878f24458f40da044774c44e5eacb3a..f1e05067073c8d2e955dc5ffea64db189975a10a 100644 (file)
@@ -18,6 +18,7 @@
 #include "bootctl-random-seed.h"
 #include "bootctl-reboot-to-firmware.h"
 #include "bootctl-systemd-efi-options.h"
+#include "bootctl-set-efivar.h"
 #include "bootctl-util.h"
 #include "bootspec.h"
 #include "build.h"
@@ -2181,144 +2182,6 @@ static int verb_is_installed(int argc, char *argv[], void *userdata) {
         }
 }
 
-static int parse_timeout(const char *arg1, char16_t **ret_timeout, size_t *ret_timeout_size) {
-        char utf8[DECIMAL_STR_MAX(usec_t)];
-        char16_t *encoded;
-        usec_t timeout;
-        int r;
-
-        assert(arg1);
-        assert(ret_timeout);
-        assert(ret_timeout_size);
-
-        if (streq(arg1, "menu-force"))
-                timeout = USEC_INFINITY;
-        else if (streq(arg1, "menu-hidden"))
-                timeout = 0;
-        else {
-                r = parse_time(arg1, &timeout, USEC_PER_SEC);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to parse timeout '%s': %m", arg1);
-                if (timeout != USEC_INFINITY && timeout > UINT32_MAX * USEC_PER_SEC)
-                        log_warning("Timeout is too long and will be treated as 'menu-force' instead.");
-        }
-
-        xsprintf(utf8, USEC_FMT, MIN(timeout / USEC_PER_SEC, UINT32_MAX));
-
-        encoded = utf8_to_utf16(utf8, strlen(utf8));
-        if (!encoded)
-                return log_oom();
-
-        *ret_timeout = encoded;
-        *ret_timeout_size = char16_strlen(encoded) * 2 + 2;
-        return 0;
-}
-
-static int parse_loader_entry_target_arg(const char *arg1, char16_t **ret_target, size_t *ret_target_size) {
-        char16_t *encoded = NULL;
-        int r;
-
-        assert(arg1);
-        assert(ret_target);
-        assert(ret_target_size);
-
-        if (streq(arg1, "@current")) {
-                r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntrySelected), NULL, (void *) ret_target, ret_target_size);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntrySelected': %m");
-
-        } else if (streq(arg1, "@oneshot")) {
-                r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntryOneShot), NULL, (void *) ret_target, ret_target_size);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryOneShot': %m");
-
-        } else if (streq(arg1, "@default")) {
-                r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderEntryDefault), NULL, (void *) ret_target, ret_target_size);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryDefault': %m");
-
-        } else if (arg1[0] == '@' && !streq(arg1, "@saved"))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unsupported special entry identifier: %s", arg1);
-        else {
-                encoded = utf8_to_utf16(arg1, strlen(arg1));
-                if (!encoded)
-                        return log_oom();
-
-                *ret_target = encoded;
-                *ret_target_size = char16_strlen(encoded) * 2 + 2;
-        }
-
-        return 0;
-}
-
-static int verb_set_efivar(int argc, char *argv[], void *userdata) {
-        int r;
-
-        if (arg_root)
-                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                       "Acting on %s, skipping EFI variable setup.",
-                                       arg_image ? "image" : "root directory");
-
-        if (!is_efi_boot())
-                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                       "Not booted with UEFI.");
-
-        if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderInfo)), F_OK) < 0) {
-                if (errno == ENOENT) {
-                        log_error_errno(errno, "Not booted with a supported boot loader.");
-                        return -EOPNOTSUPP;
-                }
-
-                return log_error_errno(errno, "Failed to detect whether boot loader supports '%s' operation: %m", argv[0]);
-        }
-
-        if (detect_container() > 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                       "'%s' operation not supported in a container.",
-                                       argv[0]);
-
-        if (!arg_touch_variables)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "'%s' operation cannot be combined with --no-variables.",
-                                       argv[0]);
-
-        const char *variable;
-        int (* arg_parser)(const char *, char16_t **, size_t *);
-
-        if (streq(argv[0], "set-default")) {
-                variable = EFI_LOADER_VARIABLE(LoaderEntryDefault);
-                arg_parser = parse_loader_entry_target_arg;
-        } else if (streq(argv[0], "set-oneshot")) {
-                variable = EFI_LOADER_VARIABLE(LoaderEntryOneShot);
-                arg_parser = parse_loader_entry_target_arg;
-        } else if (streq(argv[0], "set-timeout")) {
-                variable = EFI_LOADER_VARIABLE(LoaderConfigTimeout);
-                arg_parser = parse_timeout;
-        } else if (streq(argv[0], "set-timeout-oneshot")) {
-                variable = EFI_LOADER_VARIABLE(LoaderConfigTimeoutOneShot);
-                arg_parser = parse_timeout;
-        } else
-                assert_not_reached();
-
-        if (isempty(argv[1])) {
-                r = efi_set_variable(variable, NULL, 0);
-                if (r < 0 && r != -ENOENT)
-                        return log_error_errno(r, "Failed to remove EFI variable '%s': %m", variable);
-        } else {
-                _cleanup_free_ char16_t *value = NULL;
-                size_t value_size = 0;
-
-                r = arg_parser(argv[1], &value, &value_size);
-                if (r < 0)
-                        return r;
-                r = efi_set_variable(variable, value, value_size);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to update EFI variable '%s': %m", variable);
-        }
-
-        return 0;
-}
-
 static int bootctl_main(int argc, char *argv[]) {
         static const Verb verbs[] = {
                 { "help",                VERB_ANY, VERB_ANY, 0,            help                     },