[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