[systemd-devel] [PATCH 1/2] systemctl: Add reboot to firmware support
Jan Janssen
medhefgo at web.de
Sun Mar 15 03:56:54 PDT 2015
---
man/systemctl.xml | 10 ++++++++
shell-completion/bash/systemctl.in | 2 +-
shell-completion/zsh/_systemctl.in | 1 +
src/shared/efivars.h | 7 +++---
src/systemctl/systemctl.c | 48 ++++++++++++++++++++++++++++++++++----
5 files changed, 60 insertions(+), 8 deletions(-)
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 50e6bc9..3e2bcde 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -456,6 +456,16 @@
</varlistentry>
<varlistentry>
+ <term><option>--firmware</option></term>
+
+ <listitem>
+ <para>Indicate to the firmware to boot into EFI setup on machines
+ that support it if <command>reboot</command> is used. Note that
+ this is only supported if the machine was booted in EFI mode.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--root=</option></term>
<listitem>
diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in
index 8063316..f14fe7a 100644
--- a/shell-completion/bash/systemctl.in
+++ b/shell-completion/bash/systemctl.in
@@ -92,7 +92,7 @@ _systemctl () {
local -A OPTS=(
[STANDALONE]='--all -a --reverse --after --before --defaults --fail --ignore-dependencies --failed --force -f --full -l --global
--help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall
- --quiet -q --privileged -P --system --user --version --runtime --recursive -r'
+ --quiet -q --privileged -P --system --user --version --runtime --recursive -r --firmware'
[ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --root'
)
diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in
index 7f2d5ac..1caf9a4 100644
--- a/shell-completion/zsh/_systemctl.in
+++ b/shell-completion/zsh/_systemctl.in
@@ -375,6 +375,7 @@ _arguments -s \
'--global[Enable/disable unit files globally]' \
"--no-reload[When enabling/disabling unit files, don't reload daemon configuration]" \
'--no-ask-password[Do not ask for system passwords]' \
+ '--firmware[Reboot to EFI setup on machines that support it]' \
'--kill-who=[Who to send signal to]:killwho:(main control all)' \
{-s+,--signal=}'[Which signal to send]:signal:_signals' \
{-f,--force}'[When enabling unit files, override existing symlinks. When shutting down, execute action immediately]' \
diff --git a/src/shared/efivars.h b/src/shared/efivars.h
index 2492893..7bdfb74 100644
--- a/src/shared/efivars.h
+++ b/src/shared/efivars.h
@@ -28,9 +28,10 @@
#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
#define EFI_VENDOR_GLOBAL SD_ID128_MAKE(8b,e4,df,61,93,ca,11,d2,aa,0d,00,e0,98,03,2b,8c)
-#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001
-#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
-#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004
+#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004
+#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
bool is_efi_boot(void);
int is_efi_secure_boot(void);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 3158a38..8aee3c4 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -68,6 +68,8 @@
#include "bus-common-errors.h"
#include "mkdir.h"
#include "dropin.h"
+#include "virt.h"
+#include "efivars.h"
static char **arg_types = NULL;
static char **arg_states = NULL;
@@ -132,7 +134,7 @@ static char *arg_host = NULL;
static unsigned arg_lines = 10;
static OutputMode arg_output = OUTPUT_SHORT;
static bool arg_plain = false;
-
+static bool arg_firmware = false;
static bool original_stdout_is_tty;
static int daemon_reload(sd_bus *bus, char **args);
@@ -2923,9 +2925,40 @@ static int start_special(sd_bus *bus, char **args) {
if (r < 0)
return r;
- if (arg_force >= 2 && geteuid() != 0) {
- log_error("Must be root.");
- return -EPERM;
+ if ((arg_firmware || arg_force >= 2) && geteuid() != 0)
+ return log_error_errno(EPERM, "Must be root.");
+
+ if (arg_firmware) {
+ size_t s;
+ uint64_t b;
+ _cleanup_free_ void *v = NULL;
+
+ if (a != ACTION_REBOOT)
+ return log_error_errno(EINVAL, "Must use reboot command to reboot to firmware.");
+ else if (detect_container(NULL) > 0)
+ return log_error_errno(ENOTSUP, "Cannot reboot to firmware from within a container.");
+ else if (!is_efi_boot())
+ return log_error_errno(ENOTSUP, "Reboot to firmware requires the system to be booted in EFI mode.");
+
+ r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndicationsSupported", NULL, &v, &s);
+ if (r < 0 || s != sizeof(uint64_t))
+ return log_error_errno(r, "Error reading OsIndicationsSupported EFI variable.");
+
+ b = *(uint64_t *)v;
+ if (!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
+ return log_error_errno(ENOTSUP, "Reboot to firmware not supported.");
+
+ free(v);
+ v = NULL;
+ r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", NULL, &v, &s);
+ if (r < 0 || s != sizeof(uint64_t))
+ return log_error_errno(r, "Error reading OsIndications EFI variable.");
+
+ b = *(uint64_t *)v;
+ b |= EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
+ r = efi_set_variable(EFI_VENDOR_GLOBAL, "OsIndications", &b, s);
+ if (r < 0)
+ return log_error_errno(r, "Error writing OsIndications EFI variable.");
}
if (a == ACTION_REBOOT && args[1]) {
@@ -5965,6 +5998,7 @@ static void systemctl_help(void) {
" --runtime Enable unit files only temporarily until next reboot\n"
" -f --force When enabling unit files, override existing symlinks\n"
" When shutting down, execute action immediately\n"
+ " --firmware Reboot to EFI setup on machines that support it\n"
" --preset-mode= Apply only enable, only disable, or all presets\n"
" --root=PATH Enable unit files in the specified root directory\n"
" -n --lines=INTEGER Number of journal entries to show\n"
@@ -6150,6 +6184,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
ARG_STATE,
ARG_JOB_MODE,
ARG_PRESET_MODE,
+ ARG_FIRMWARE,
};
static const struct option options[] = {
@@ -6192,6 +6227,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "state", required_argument, NULL, ARG_STATE },
{ "recursive", no_argument, NULL, 'r' },
{ "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
+ { "firmware", no_argument, NULL, ARG_FIRMWARE },
{}
};
@@ -6468,6 +6504,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
+ case ARG_FIRMWARE:
+ arg_firmware = true;
+ break;
+
case '?':
return -EINVAL;
--
2.3.2
More information about the systemd-devel
mailing list