]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
gpt-auto-generator: if root=gpt-auto-force is specified ignore factory reset state
authorLennart Poettering <lennart@poettering.net>
Fri, 21 Feb 2025 16:23:22 +0000 (17:23 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 5 Mar 2025 11:38:28 +0000 (12:38 +0100)
man/systemd-gpt-auto-generator.xml
src/fstab-generator/fstab-generator.c
src/gpt-auto-generator/gpt-auto-generator.c

index 69788baab454734ac2d9dabba74b3549f79e1d26..d3724e7e9dd620a114fb983443f5c9589dc47ec7 100644 (file)
         <term><varname>rootflags=</varname></term>
 
         <listitem><para>When <varname>root=</varname> is used with the special value
-        <literal>gpt-auto</literal>, full automatic discovery of the root
-        partition based on the GPT partition type is enabled. Any other value disables this
-        logic.</para>
+        <literal>gpt-auto</literal>, full automatic discovery of the root partition based on the GPT
+        partition type is enabled. Use of the root partition is delayed until factory reset mode is left, in
+        case it is enabled during the current boot. See <ulink url="https://systemd.io/FACTORY_RESET">Factory
+        Reset</ulink> for more information on that. If <literal>gpt-auto-force</literal> is specified
+        automatic discovery of the root partition is enabled, ignoring any factory reset mode. Any other
+        value disables this logic.</para>
 
         <para>If <varname>root=</varname> is not specified at all on the kernel command line automatic
-        discovery of the root partition via the boot loader reported ESP is also enabled, however in this
-        case discovery based on the loopback block device <literal>.lo_name</literal> field is not enabled.</para>
+        discovery of the root partition via the ESP reported by the boot loader is also enabled (taking
+        factory reset state into account), however in this case discovery based on the loopback block device
+        <literal>.lo_name</literal> field is not enabled.</para>
 
-        <para>The <varname>rootfstype=</varname> and <varname>rootflags=</varname> are used to select the
-        file system type and options when the root file system is automatically discovered.</para>
+        <para>The <varname>rootfstype=</varname> and <varname>rootflags=</varname> options are used to select
+        the file system type and options when the root file system is automatically discovered.</para>
 
         <xi:include href="version-info.xml" xpointer="v242"/></listitem>
       </varlistentry>
index 6693333c4b18999529eec88cd8b184ba0709f1c2..7e85d476e4dd3de322c5ddb9e9c8d9854914f279 100644 (file)
@@ -1119,7 +1119,7 @@ static bool validate_root_or_usr_mount_source(const char *what, const char *swit
                 return false;
         }
 
-        if (streq(what, "gpt-auto")) {
+        if (STR_IN_SET(what, "gpt-auto", "gpt-auto-force")) {
                 /* This is handled by gpt-auto-generator */
                 log_debug("Skipping %s directory handling, as gpt-auto was requested.", switch_name);
                 return false;
index 1b59fecf9e82340222a6c6303fb448bcbde3e58d..6c2fbe178155a68bf6fe154306489fefeb17d9c0 100644 (file)
@@ -17,6 +17,7 @@
 #include "dissect-image.h"
 #include "dropin.h"
 #include "efi-loader.h"
+#include "factory-reset.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
 #include "unit-name.h"
 #include "virt.h"
 
+typedef enum GptAutoRoot {
+        GPT_AUTO_ROOT_UNSPECIFIED,  /* no root= specified */
+        GPT_AUTO_ROOT_OFF,          /* root= set to something else */
+        GPT_AUTO_ROOT_ON,           /* root= set explicitly to "gpt-auto" */
+        GPT_AUTO_ROOT_FORCE,        /* root= set explicitly to "gpt-auto-force" → ignores factory reset mode */
+} GptAutoRoot;
+
 static const char *arg_dest = NULL;
 static bool arg_enabled = true;
-static int arg_root_enabled = -1; /* tristate */
+static GptAutoRoot arg_auto_root = GPT_AUTO_ROOT_UNSPECIFIED;
 static bool arg_swap_enabled = true;
 static char *arg_root_fstype = NULL;
 static char *arg_root_options = NULL;
@@ -47,7 +55,6 @@ static int arg_root_rw = -1;
 static ImagePolicy *arg_image_policy = NULL;
 
 STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
-
 STATIC_DESTRUCTOR_REGISTER(arg_root_fstype, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep);
 
@@ -661,7 +668,19 @@ static int add_root_cryptsetup(void) {
         /* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
          * sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
 
-        return add_cryptsetup("root", "/dev/gpt-auto-root-luks", arg_root_options, /* rw= */ true, /* require= */ false, /* measure= */ true, NULL);
+        const char *bdev = "/dev/gpt-auto-root-luks";
+
+        if (arg_auto_root == GPT_AUTO_ROOT_FORCE) {
+                /* Similar logic as in add_root_mount(), see below */
+                FactoryResetMode f = factory_reset_mode();
+                if (f < 0)
+                        log_warning_errno(f, "Failed to determine whether we are in factory reset mode, assuming not: %m");
+
+                if (IN_SET(f, FACTORY_RESET_ON, FACTORY_RESET_COMPLETE))
+                        bdev = "/dev/gpt-auto-root-luks-ignore-factory-reset";
+        }
+
+        return add_cryptsetup("root", bdev, arg_root_options, /* rw= */ true, /* require= */ false, /* measure= */ true, NULL);
 #else
         return 0;
 #endif
@@ -674,11 +693,11 @@ static int add_root_mount(void) {
         int r;
 
         /* Explicitly disabled? Then exit immediately */
-        if (arg_root_enabled == 0)
+        if (arg_auto_root == GPT_AUTO_ROOT_OFF)
                 return 0;
 
         /* Neither explicitly enabled nor disabled? Then decide based on the EFI partition variables to be set */
-        if (arg_root_enabled < 0) {
+        if (arg_auto_root == GPT_AUTO_ROOT_UNSPECIFIED) {
                 if (!is_efi_boot()) {
                         log_debug("Not an EFI boot, not creating root mount.");
                         return 0;
@@ -695,10 +714,27 @@ static int add_root_mount(void) {
         }
 
         /* OK, we shall look for a root device, so let's wait for a root device to show up.  A udev rule will
-         * create the link for us under the right name. */
+         * create the link for us under the right name.
+         *
+         * There are two distinct names: the /dev/gpt-auto-root-ignore-factory-reset symlink is created for
+         * the root partition if factory reset mode is enabled or complete, and the /dev/gpt-auto-root
+         * symlink is only created if factory reset mode is off or already complete (thus taking factory
+         * reset state into account). In scenarios where the root disk is partially reformatted during
+         * factory reset the latter is the link to use, otherwise the former (so that we don't accidentally
+         * mount a root partition too early that is about to be wiped and replaced by another one). */
+
+        const char *bdev = "/dev/gpt-auto-root";
+        if (arg_auto_root == GPT_AUTO_ROOT_FORCE) {
+                FactoryResetMode f = factory_reset_mode();
+                if (f < 0)
+                        log_warning_errno(f, "Failed to determine whether we are in factory reset mode, assuming not: %m");
+
+                if (IN_SET(f, FACTORY_RESET_ON, FACTORY_RESET_COMPLETE))
+                        bdev = "/dev/gpt-auto-root-ignore-factory-reset";
+        }
 
         if (in_initrd()) {
-                r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root");
+                r = generator_write_initrd_root_device_deps(arg_dest, bdev);
                 if (r < 0)
                         return 0;
 
@@ -727,7 +763,7 @@ static int add_root_mount(void) {
 
         return add_mount(
                         "root",
-                        "/dev/gpt-auto-root",
+                        bdev,
                         in_initrd() ? "/sysroot" : "/",
                         arg_root_fstype,
                         /* rw= */ arg_root_rw > 0,
@@ -909,15 +945,18 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 if (proc_cmdline_value_missing(key, value))
                         return 0;
 
-                /* Disable root disk logic if there's a root= value
-                 * specified (unless it happens to be "gpt-auto") */
+                /* Disable root disk logic if there's a root= value specified (unless it happens to be
+                 * "gpt-auto" or "gpt-auto-force") */
 
                 if (streq(value, "gpt-auto")) {
-                        arg_root_enabled = true;
-                        log_debug("Enabling root partition auto-detection, root= is explicitly set to 'gpt_auto'.");
+                        arg_auto_root = GPT_AUTO_ROOT_ON;
+                        log_debug("Enabling root partition auto-detection (respecting factory reset mode), root= is explicitly set to 'gpt-auto'.");
+                } else if (streq(value, "gpt-auto-force")) {
+                        arg_auto_root = GPT_AUTO_ROOT_FORCE;
+                        log_debug("Enabling root partition auto-detection (ignoring factory reset mode), root= is explicitly set to 'gpt-auto-force'.");
                 } else {
-                        arg_root_enabled = false;
-                        log_debug("Disabling root partition auto-detection, root= is neither unset, nor set to 'gpt-auto'.");
+                        arg_auto_root = GPT_AUTO_ROOT_OFF;
+                        log_debug("Disabling root partition auto-detection, root= is neither unset, nor set to 'gpt-auto' or 'gpt-auto-force'.");
                 }
 
         } else if (streq(key, "roothash")) {
@@ -927,7 +966,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
 
                 /* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
 
-                arg_root_enabled = false;
+                arg_auto_root = GPT_AUTO_ROOT_OFF;
                 log_debug("Disabling root partition auto-detection, roothash= is set.");
 
         } else if (streq(key, "rootfstype")) {