diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index 74a71bba93..8eb2b9b9e2 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -52,9 +52,13 @@ All tools: * `$SYSTEMD_EFI_OPTIONS` — if set, used instead of the string in the SystemdOptions EFI variable. Analogous to `$SYSTEMD_PROC_CMDLINE`. -* `$SYSTEMD_IN_INITRD` — takes a boolean. If set, overrides initrd detection. - This is useful for debugging and testing initrd-only programs in the main - system. +* `$SYSTEMD_IN_INITRD=[auto|lenient|0|1]` — if set, specifies initrd detection + method. Defaults to `auto`. Behavior is defined as follows: + `auto`: Checks if `/etc/initrd-release` exists, and a temporary fs is mounted + on `/`. If both conditions meet, then it's in initrd. + `lenient`: Similiar to `auto`, but the rootfs check is skipped. + `0|1`: Simply overrides initrd detection. This is useful for debugging and + testing initrd-only programs in the main system. * `$SYSTEMD_BUS_TIMEOUT=SECS` — specifies the maximum time to wait for method call completion. If no time unit is specified, assumes seconds. The usual other units diff --git a/src/basic/util.c b/src/basic/util.c index 7c708eb3be..d24d52190c 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -52,13 +52,14 @@ int prot_from_flags(int flags) { } bool in_initrd(void) { - struct statfs s; int r; + const char *e; + bool lenient = false; if (saved_in_initrd >= 0) return saved_in_initrd; - /* We make two checks here: + /* We have two checks here: * * 1. the flag file /etc/initrd-release must exist * 2. the root file system must be a memory file system @@ -66,18 +67,46 @@ bool in_initrd(void) { * The second check is extra paranoia, since misdetecting an * initrd can have bad consequences due the initrd * emptying when transititioning to the main systemd. + * + * If env var $SYSTEMD_IN_INITRD is not set or set to "auto", + * both checks are used. If it's set to "lenient", only check + * 1 is used. If set to a booleen value, then the boolean + * value is returned. */ - r = getenv_bool_secure("SYSTEMD_IN_INITRD"); - if (r < 0 && r != -ENXIO) - log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m"); + e = secure_getenv("SYSTEMD_IN_INITRD"); + if (e) { + if (streq(e, "lenient")) + lenient = true; + else if (!streq(e, "auto")) { + r = parse_boolean(e); + if (r >= 0) { + saved_in_initrd = r > 0; + return saved_in_initrd; + } + log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m"); + } + } + + if (!lenient) { + r = path_is_temporary_fs("/"); + if (r < 0) + log_debug_errno(r, "Couldn't determine if / is a temporary file system: %m"); - if (r >= 0) saved_in_initrd = r > 0; - else - saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 && - statfs("/", &s) >= 0 && - is_temporary_fs(&s); + } + + r = access("/etc/initrd-release", F_OK); + if (r >= 0) { + if (saved_in_initrd == 0) + log_debug("/etc/initrd-release exists, but it's not an initrd."); + else + saved_in_initrd = 1; + } else { + if (errno != ENOENT) + log_debug_errno(errno, "Failed to test if /etc/initrd-release exists: %m"); + saved_in_initrd = 0; + } return saved_in_initrd; }