[systemd-devel] [PATCH 2/2] fsck: Add support for EFI variable based fsck indication
Jan Janssen
medhefgo at web.de
Sun Mar 15 03:56:55 PDT 2015
---
man/systemctl.xml | 26 ++++++++++++++++
shell-completion/bash/systemctl.in | 8 ++++-
shell-completion/zsh/_systemctl.in | 2 ++
src/fsck/fsck.c | 63 +++++++++++++++++++++++++++++++++++++
src/shared/efivars.h | 21 +++++++++++--
src/systemctl/systemctl.c | 64 +++++++++++++++++++++++++++++++++-----
6 files changed, 173 insertions(+), 11 deletions(-)
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 3e2bcde..8449d83 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -466,6 +466,32 @@
</varlistentry>
<varlistentry>
+ <term><option>--fsck-mode=</option></term>
+
+ <listitem>
+ <para>Control file system check behavior for next boot on EFI systems.</para>
+
+ <para>One of <literal>auto</literal>, <literal>force</literal> and
+ <literal>skip</literal>. See <citerefentry><refentrytitle>systemd-fsck</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ for details. Note that this requires the system to be booted in EFI mode and
+ that kernel command line parameters take precedence.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--fsck-repair=</option></term>
+
+ <listitem>
+ <para>Control file system check repair behavior for next boot on EFI systems.</para>
+
+ <para>One of <literal>preen</literal>, <literal>yes</literal> and
+ <literal>no</literal>. See <citerefentry><refentrytitle>systemd-fsck</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ for details. Note that this requires the system to be booted in EFI mode and
+ that kernel command line parameters take precedence.</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 f14fe7a..cea28cd 100644
--- a/shell-completion/bash/systemctl.in
+++ b/shell-completion/bash/systemctl.in
@@ -93,7 +93,7 @@ _systemctl () {
[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 --firmware'
- [ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --root'
+ [ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --root --fsck-mode --fsck-repair'
)
if __contains_word "--user" ${COMP_WORDS[*]}; then
@@ -118,6 +118,12 @@ _systemctl () {
--kill-who)
comps='all control main'
;;
+ --fsck-mode)
+ comps='auto force skip'
+ ;;
+ --fsck-repair)
+ comps='preen yes no'
+ ;;
--root)
comps=$(compgen -A directory -- "$cur" )
compopt -o filenames
diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in
index 1caf9a4..b8c82cc 100644
--- a/shell-completion/zsh/_systemctl.in
+++ b/shell-completion/zsh/_systemctl.in
@@ -377,6 +377,8 @@ _arguments -s \
'--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)' \
+ '--fsck-mode=[Control filesystem check mode next boot on EFI systems]:fsckmode:(auto force skip)' \
+ '--fsck-repair=[Mode of operation to use with filesystem check]:fsckrepair:(preen yes no)' \
{-s+,--signal=}'[Which signal to send]:signal:_signals' \
{-f,--force}'[When enabling unit files, override existing symlinks. When shutting down, execute action immediately]' \
'--root=[Enable unit files in the specified root directory]:directory:_directories' \
diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c
index 6e46633..ef56bb0 100644
--- a/src/fsck/fsck.c
+++ b/src/fsck/fsck.c
@@ -40,6 +40,7 @@
#include "path-util.h"
#include "socket-util.h"
#include "fsckd/fsckd.h"
+#include "efivars.h"
static bool arg_skip = false;
static bool arg_force = false;
@@ -130,6 +131,67 @@ static void test_files(void) {
}
+static void parse_efi_vars(void) {
+ int r;
+ size_t s;
+ _cleanup_free_ void *v = NULL;
+
+ if (!is_efi_boot())
+ return;
+
+ r = efi_get_variable(EFI_VENDOR_SYSTEMD, "FsckModeOneShot", NULL, &v, &s);
+ if (r < 0 || s != sizeof(EfiSystemdFsckMode))
+ log_warning("Failed to read FsckModeOneShot EFI variable.");
+ else {
+ EfiSystemdFsckMode value = *(EfiSystemdFsckMode *)v;
+
+ switch (value) {
+ case EFI_SYSTEMD_FSCK_MODE_AUTO:
+ arg_force = arg_skip = false;
+ break;
+ case EFI_SYSTEMD_FSCK_MODE_FORCE:
+ arg_force = true;
+ break;
+ case EFI_SYSTEMD_FSCK_MODE_SKIP:
+ arg_skip = true;
+ break;
+ default:
+ log_warning("Invalid value for FsckModeOneShot EFI variable. Ignoring.");
+ }
+
+ r = efi_set_variable(EFI_VENDOR_SYSTEMD, "FsckModeOneShot", NULL, 0);
+ if (r < 0)
+ log_warning_errno(r, "Error while deleting FsckModeOneShot EFI variable: %m");
+ }
+
+ free(v);
+ v = NULL;
+ r = efi_get_variable(EFI_VENDOR_SYSTEMD, "FsckRepairOneShot", NULL, &v, &s);
+ if (r < 0 || s != sizeof(EfiSystemdFsckRepair))
+ log_warning("Failed to read FsckRepairOneShot EFI variable.");
+ else {
+ EfiSystemdFsckRepair value = *(EfiSystemdFsckRepair *)v;
+
+ switch (value) {
+ case EFI_SYSTEMD_FSCK_REPAIR_PREEN:
+ arg_repair = "-a";
+ break;
+ case EFI_SYSTEMD_FSCK_REPAIR_YES:
+ arg_repair = "-y";
+ break;
+ case EFI_SYSTEMD_FSCK_REPAIR_NO:
+ arg_repair = "-n";
+ break;
+ default:
+ log_warning("Invalid value for FsckRepairOneShot EFI variable. Ignoring.");
+ }
+
+ r = efi_set_variable(EFI_VENDOR_SYSTEMD, "FsckRepairOneShot", NULL, 0);
+ if (r < 0)
+ log_warning_errno(r, "Error while deleting FsckRepairOneShot EFI variable: %m");
+ }
+}
+
static int process_progress(int fd, pid_t fsck_pid, dev_t device_num) {
_cleanup_fclose_ FILE *f = NULL;
usec_t last = 0;
@@ -218,6 +280,7 @@ int main(int argc, char *argv[]) {
umask(0022);
+ parse_efi_vars();
q = parse_proc_cmdline(parse_proc_cmdline_item);
if (q < 0)
log_warning_errno(q, "Failed to parse kernel command line, ignoring: %m");
diff --git a/src/shared/efivars.h b/src/shared/efivars.h
index 7bdfb74..3b7a314 100644
--- a/src/shared/efivars.h
+++ b/src/shared/efivars.h
@@ -26,13 +26,30 @@
#include "sd-id128.h"
#include "time-util.h"
-#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_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_VENDOR_SYSTEMD SD_ID128_MAKE(45,0e,ad,32,7c,d1,47,81,8b,25,da,83,30,cc,1e,22)
#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
+typedef enum EfiSystemdFsckMode {
+ EFI_SYSTEMD_FSCK_MODE_AUTO,
+ EFI_SYSTEMD_FSCK_MODE_FORCE,
+ EFI_SYSTEMD_FSCK_MODE_SKIP,
+ _EFI_SYSTEMD_FSCK_MODE_MAX,
+ _EFI_SYSTEMD_FSCK_MODE_INVALID = -1,
+} EfiSystemdFsckMode;
+
+typedef enum EfiSystemdFsckRepair {
+ EFI_SYSTEMD_FSCK_REPAIR_PREEN,
+ EFI_SYSTEMD_FSCK_REPAIR_YES,
+ EFI_SYSTEMD_FSCK_REPAIR_NO,
+ _EFI_SYSTEMD_FSCK_REPAIR_MAX,
+ _EFI_SYSTEMD_FSCK_REPAIR_INVALID = -1,
+} EfiSystemdFsckRepair;
+
bool is_efi_boot(void);
int is_efi_secure_boot(void);
int is_efi_secure_boot_setup_mode(void);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 8aee3c4..bddbd8d 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -135,6 +135,8 @@ static unsigned arg_lines = 10;
static OutputMode arg_output = OUTPUT_SHORT;
static bool arg_plain = false;
static bool arg_firmware = false;
+static EfiSystemdFsckMode arg_fsck_mode = _EFI_SYSTEMD_FSCK_MODE_INVALID;
+static EfiSystemdFsckRepair arg_fsck_repair = _EFI_SYSTEMD_FSCK_REPAIR_INVALID;
static bool original_stdout_is_tty;
static int daemon_reload(sd_bus *bus, char **args);
@@ -2916,6 +2918,7 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
static int start_special(sd_bus *bus, char **args) {
enum action a;
int r;
+ bool need_efi = false;
assert(args);
@@ -2925,21 +2928,35 @@ static int start_special(sd_bus *bus, char **args) {
if (r < 0)
return r;
- if ((arg_firmware || arg_force >= 2) && geteuid() != 0)
+ need_efi = arg_firmware
+ || arg_fsck_mode != _EFI_SYSTEMD_FSCK_MODE_INVALID
+ || arg_fsck_repair != _EFI_SYSTEMD_FSCK_REPAIR_INVALID;
+ if ((need_efi || arg_force >= 2) && geteuid() != 0)
return log_error_errno(EPERM, "Must be root.");
+ else if (need_efi && detect_container(NULL) > 0)
+ return log_error_errno(ENOTSUP, "Cannot perform operation from within a container.");
+ else if (need_efi && !is_efi_boot())
+ return log_error_errno(ENOTSUP, "Operation requires the system to be booted in EFI mode.");
+ else if (arg_firmware && a != ACTION_REBOOT)
+ return log_error_errno(EINVAL, "Must use reboot command to reboot to firmware.");
+
+ if (arg_fsck_mode != _EFI_SYSTEMD_FSCK_MODE_INVALID) {
+ r = efi_set_variable(EFI_VENDOR_SYSTEMD, "FsckModeOneShot", &arg_fsck_mode, sizeof(arg_fsck_mode));
+ if (r < 0)
+ return log_error_errno(r, "Error writing FsckModeOneShot EFI variable.");
+ }
+
+ if (arg_fsck_repair != _EFI_SYSTEMD_FSCK_REPAIR_INVALID) {
+ r = efi_set_variable(EFI_VENDOR_SYSTEMD, "FsckRepairOneShot", &arg_fsck_repair, sizeof(arg_fsck_repair));
+ if (r < 0)
+ return log_error_errno(r, "Error writing FsckRepairOneShot EFI variable.");
+ }
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.");
@@ -5999,6 +6016,9 @@ static void systemctl_help(void) {
" -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"
+ " --fsck-mode=MODE Control filesystem check mode next boot on EFI systems\n"
+ " --fsck-repair=MODE\n"
+ " Mode of operation to use with filesystem check\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"
@@ -6185,6 +6205,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
ARG_JOB_MODE,
ARG_PRESET_MODE,
ARG_FIRMWARE,
+ ARG_FSCK_MODE,
+ ARG_FSCK_REPAIR,
};
static const struct option options[] = {
@@ -6228,6 +6250,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "recursive", no_argument, NULL, 'r' },
{ "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
{ "firmware", no_argument, NULL, ARG_FIRMWARE },
+ { "fsck-mode", required_argument, NULL, ARG_FSCK_MODE },
+ { "fsck-repair", required_argument, NULL, ARG_FSCK_REPAIR },
{}
};
@@ -6504,6 +6528,30 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
+ case ARG_FSCK_MODE:
+
+ if (streq(optarg, "auto"))
+ arg_fsck_mode = EFI_SYSTEMD_FSCK_MODE_AUTO;
+ else if (streq(optarg, "force"))
+ arg_fsck_mode = EFI_SYSTEMD_FSCK_MODE_FORCE;
+ else if (streq(optarg, "skip"))
+ arg_fsck_mode = EFI_SYSTEMD_FSCK_MODE_SKIP;
+ else
+ return log_error_errno(EINVAL, "Failed to parse fsck-mode: %s.", optarg);
+ break;
+
+ case ARG_FSCK_REPAIR:
+
+ if (streq(optarg, "preen"))
+ arg_fsck_repair = EFI_SYSTEMD_FSCK_REPAIR_PREEN;
+ else if (streq(optarg, "yes"))
+ arg_fsck_repair = EFI_SYSTEMD_FSCK_REPAIR_YES;
+ else if (streq(optarg, "no"))
+ arg_fsck_repair = EFI_SYSTEMD_FSCK_REPAIR_NO;
+ else
+ return log_error_errno(EINVAL, "Failed to parse fsck-repair: %s.", optarg);
+ break;
+
case ARG_FIRMWARE:
arg_firmware = true;
break;
--
2.3.2
More information about the systemd-devel
mailing list