df98bb
From 99ca5b681fceedd010b2616b1248a483f4bfbd97 Mon Sep 17 00:00:00 2001
df98bb
From: Kairui Song <kasong@redhat.com>
df98bb
Date: Wed, 13 Jan 2021 00:04:53 +0800
df98bb
Subject: [PATCH] initrd: extend SYSTEMD_IN_INITRD to accept non-ramfs rootfs
df98bb
df98bb
Sometimes, non-ramfs initrd root are useful. Eg, for kdump, because
df98bb
initramfs is memory consuming, so mount a compressed image in earlier
df98bb
initrd, chroot into it then let systemd do the rest of job is a good
df98bb
solution.
df98bb
df98bb
But systemd doesn't recognize the initrd environment if rootfs is not a
df98bb
temporary fs. This is a reasonable check, because switch-root in initrd
df98bb
will wipe the whole rootfs, will be a disaster if there are any
df98bb
misdetect.
df98bb
df98bb
So extend SYSTEMD_IN_INITRD environment variable, now it accepts boolean
df98bb
value and two extra keyword, "auto" and "lenient". "auto" is same as
df98bb
before, and it's the default value. "lenient" will let systemd bypass
df98bb
the rootfs check.
df98bb
df98bb
(cherry picked from commit db4c45cf4f10ca094b9e9570b758abd445d65381)
df98bb
df98bb
Related: #1959339
df98bb
---
df98bb
 doc/ENVIRONMENT.md |  8 ++++++++
df98bb
 src/basic/util.c   | 28 +++++++++++++++++++++++++---
df98bb
 2 files changed, 33 insertions(+), 3 deletions(-)
df98bb
df98bb
diff --git a/doc/ENVIRONMENT.md b/doc/ENVIRONMENT.md
df98bb
index 36b649afe1..8d7ce6ae2c 100644
df98bb
--- a/doc/ENVIRONMENT.md
df98bb
+++ b/doc/ENVIRONMENT.md
df98bb
@@ -37,6 +37,14 @@ All tools:
df98bb
   useful for debugging, in order to test generators and other code against
df98bb
   specific kernel command lines.
df98bb
 
df98bb
+* `$SYSTEMD_IN_INITRD=[auto|lenient|0|1]` — if set, specifies initrd detection
df98bb
+  method. Defaults to `auto`. Behavior is defined as follows:
df98bb
+  `auto`: Checks if `/etc/initrd-release` exists, and a temporary fs is mounted
df98bb
+          on `/`. If both conditions meet, then it's in initrd.
df98bb
+  `lenient`: Similiar to `auto`, but the rootfs check is skipped.
df98bb
+  `0|1`: Simply overrides initrd detection. This is useful for debugging and
df98bb
+         testing initrd-only programs in the main system.
df98bb
+
df98bb
 * `$SYSTEMD_EMOJI=0` — if set, tools such as "systemd-analyze security" will
df98bb
   not output graphical smiley emojis, but ASCII alternatives instead. Note that
df98bb
   this only controls use of Unicode emoji glyphs, and has no effect on other
df98bb
diff --git a/src/basic/util.c b/src/basic/util.c
df98bb
index b443e639f3..59bcf7b00c 100644
df98bb
--- a/src/basic/util.c
df98bb
+++ b/src/basic/util.c
df98bb
@@ -130,11 +130,14 @@ int prot_from_flags(int flags) {
df98bb
 }
df98bb
 
df98bb
 bool in_initrd(void) {
df98bb
+        int r;
df98bb
+        const char *e;
df98bb
+        bool lenient = false;
df98bb
 
df98bb
         if (saved_in_initrd >= 0)
df98bb
                 return saved_in_initrd;
df98bb
 
df98bb
-        /* We make two checks here:
df98bb
+        /* We have two checks here:
df98bb
          *
df98bb
          * 1. the flag file /etc/initrd-release must exist
df98bb
          * 2. the root file system must be a memory file system
df98bb
@@ -142,10 +145,29 @@ bool in_initrd(void) {
df98bb
          * The second check is extra paranoia, since misdetecting an
df98bb
          * initrd can have bad consequences due the initrd
df98bb
          * emptying when transititioning to the main systemd.
df98bb
+         *
df98bb
+         * If env var $SYSTEMD_IN_INITRD is not set or set to "auto",
df98bb
+         * both checks are used. If it's set to "lenient", only check
df98bb
+         * 1 is used. If set to a booleen value, then the boolean
df98bb
+         * value is returned.
df98bb
          */
df98bb
 
df98bb
-        saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
df98bb
-                          path_is_temporary_fs("/") > 0;
df98bb
+        e = secure_getenv("SYSTEMD_IN_INITRD");
df98bb
+        if (e) {
df98bb
+                if (streq(e, "lenient"))
df98bb
+                        lenient = true;
df98bb
+                else if (!streq(e, "auto")) {
df98bb
+                        r = parse_boolean(e);
df98bb
+                        if (r >= 0) {
df98bb
+                                saved_in_initrd = r > 0;
df98bb
+                                return saved_in_initrd;
df98bb
+                        }
df98bb
+                        log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m");
df98bb
+                }
df98bb
+        }
df98bb
+
df98bb
+        saved_in_initrd = (lenient || path_is_temporary_fs("/") > 0) &&
df98bb
+                          access("/etc/initrd-release", F_OK) >= 0;
df98bb
 
df98bb
         return saved_in_initrd;
df98bb
 }