summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2023-04-28 16:56:39 +0200
committerLuca Boccassi <luca.boccassi@gmail.com>2023-04-28 23:26:20 +0100
commit5ae89ef34774a777c5af7af48b1ad431d10a425e (patch)
tree54c2755ddf182ea784e38633b2cc5340a84f1bde
parent77b7026668cd376744a99881777dce8c2f5da835 (diff)
downloadsystemd-5ae89ef34774a777c5af7af48b1ad431d10a425e.tar.gz
core/systemctl: when switching root default to /sysroot/
We hardcode the path the initrd uses to prepare the final mount point at so many places, let's also imply it in "systemctl switch-root" if not specified. This adds the fallback both to systemctl and to PID 1 (this is because both to — different – checks on the path).
-rw-r--r--man/systemctl.xml19
-rw-r--r--src/core/dbus-manager.c24
-rw-r--r--src/systemctl/systemctl-switch-root.c21
-rw-r--r--src/systemctl/systemctl.c4
-rw-r--r--units/initrd-switch-root.service2
5 files changed, 41 insertions, 29 deletions
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 639c888110..009aabacb9 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -1561,19 +1561,20 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</varlistentry>
<varlistentry>
- <term><command>switch-root</command> <replaceable>ROOT</replaceable> <optional><replaceable>INIT</replaceable></optional></term>
+ <term><command>switch-root</command> <optional><replaceable>ROOT</replaceable> <optional><replaceable>INIT</replaceable></optional></optional></term>
<listitem>
<para>Switches to a different root directory and executes a new system manager process below it.
This is intended for use in the initrd, and will transition from the initrd's system manager
- process (a.k.a. "init" process) to the main system manager process which is loaded from the
- actual host root files system. This call takes two arguments: the directory that is to become the
- new root directory, and the path to the new system manager binary below it to execute as PID 1.
- If the latter is omitted or the empty string, a systemd binary will automatically be searched for
- and used as init. If the system manager path is omitted, equal to the empty string or identical
- to the path to the systemd binary, the state of the initrd's system manager process is passed to
- the main system manager, which allows later introspection of the state of the services involved
- in the initrd boot phase.</para>
+ process (a.k.a. "init" process, PID 1) to the main system manager process which is loaded from
+ the actual host root files system. This call takes two arguments: the directory that is to become
+ the new root directory, and the path to the new system manager binary below it to execute as PID
+ 1. If both are omitted or the former is an empty string it defaults to
+ <filename>/sysroot/</filename>. If the latter is omitted or is an empty string, a systemd binary
+ will automatically be searched for and used as service manager. If the system manager path is
+ omitted, equal to the empty string or identical to the path to the systemd binary, the state of
+ the initrd's system manager process is passed to the main system manager, which allows later
+ introspection of the state of the services involved in the initrd boot phase.</para>
</listitem>
</varlistentry>
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 2feec0bd7d..f6c9ae6940 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -1738,15 +1738,21 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
if (r < 0)
return r;
- if (!path_is_valid(root))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
- "New root directory must be a valid path.");
- if (!path_is_absolute(root))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
- "New root path '%s' is not absolute.", root);
- if (path_equal(root, "/"))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
- "New root directory cannot be the old root directory.");
+ if (isempty(root))
+ /* If path is not specified, default to "/sysroot" which is what we generally expect initrds
+ * to use */
+ root = "/sysroot";
+ else {
+ if (!path_is_valid(root))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "New root directory must be a valid path.");
+ if (!path_is_absolute(root))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "New root path '%s' is not absolute.", root);
+ if (path_equal(root, "/"))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "New root directory cannot be the old root directory.");
+ }
/* Safety check */
if (isempty(init)) {
diff --git a/src/systemctl/systemctl-switch-root.c b/src/systemctl/systemctl-switch-root.c
index 8cfcaf8935..b59ea701c9 100644
--- a/src/systemctl/systemctl-switch-root.c
+++ b/src/systemctl/systemctl-switch-root.c
@@ -42,14 +42,19 @@ int verb_switch_root(int argc, char *argv[], void *userdata) {
if (arg_transport != BUS_TRANSPORT_LOCAL)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot switch root remotely.");
- if (argc < 2 || argc > 3)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Wrong number of arguments.");
-
- root = argv[1];
- if (!path_is_valid(root))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid root path: %s", root);
- if (!path_is_absolute(root))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Root path is not absolute: %s", root);
+ if (argc > 3)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many arguments.");
+
+ if (argc >= 2) {
+ root = argv[1];
+ if (!path_is_valid(root))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid root path: %s", root);
+ if (!path_is_absolute(root))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Root path is not absolute: %s", root);
+ if (path_equal(root, "/"))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot switch to current root directory: %s", root);
+ } else
+ root = "/sysroot";
if (argc >= 3)
init = argv[2];
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 201d64a1f9..71c068b09e 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -243,7 +243,7 @@ static int systemctl_help(void) {
" reboot Shut down and reboot the system\n"
" kexec Shut down and reboot the system with kexec\n"
" exit [EXIT_CODE] Request user instance or container exit\n"
- " switch-root ROOT [INIT] Change to a different root file system\n"
+ " switch-root [ROOT [INIT]] Change to a different root file system\n"
" suspend Suspend the system\n"
" hibernate Hibernate the system\n"
" hybrid-sleep Hibernate and suspend the system\n"
@@ -1199,7 +1199,7 @@ static int systemctl_main(int argc, char *argv[]) {
{ "unmask", 2, VERB_ANY, 0, verb_enable },
{ "link", 2, VERB_ANY, 0, verb_enable },
{ "revert", 2, VERB_ANY, 0, verb_enable },
- { "switch-root", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_switch_root },
+ { "switch-root", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_switch_root },
{ "list-dependencies", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_list_dependencies },
{ "set-default", 2, 2, 0, verb_set_default },
{ "get-default", VERB_ANY, 1, 0, verb_get_default },
diff --git a/units/initrd-switch-root.service b/units/initrd-switch-root.service
index b19b7bbc21..f81b47871e 100644
--- a/units/initrd-switch-root.service
+++ b/units/initrd-switch-root.service
@@ -20,4 +20,4 @@ OnFailureJobMode=replace-irreversibly
[Service]
Type=oneshot
-ExecStart=systemctl --no-block switch-root /sysroot
+ExecStart=systemctl --no-block switch-root