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