]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/systemctl/systemctl-switch-root.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "bus-locator.h"
5 #include "parse-util.h"
7 #include "proc-cmdline.h"
8 #include "signal-util.h"
10 #include "systemctl-switch-root.h"
11 #include "systemctl-util.h"
12 #include "systemctl.h"
14 int switch_root(int argc
, char *argv
[], void *userdata
) {
15 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
16 _cleanup_free_
char *cmdline_init
= NULL
;
17 const char *root
, *init
;
21 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
22 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Cannot switch root remotely.");
24 if (argc
< 2 || argc
> 3)
25 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Wrong number of arguments.");
32 r
= proc_cmdline_get_key("init", 0, &cmdline_init
);
34 log_debug_errno(r
, "Failed to parse /proc/cmdline: %m");
39 init
= empty_to_null(init
);
41 const char *root_systemd_path
= NULL
, *root_init_path
= NULL
;
43 root_systemd_path
= prefix_roota(root
, "/" SYSTEMD_BINARY_PATH
);
44 root_init_path
= prefix_roota(root
, init
);
46 /* If the passed init is actually the same as the systemd binary, then let's suppress it. */
47 if (files_same(root_init_path
, root_systemd_path
, 0) > 0)
51 /* Instruct PID1 to exclude us from its killing spree applied during the transition. Otherwise we
52 * would exit with a failure status even though the switch to the new root has succeed. */
54 assert(saved_argv
[0]);
55 saved_argv
[0][0] = '@';
57 r
= acquire_bus(BUS_MANAGER
, &bus
);
61 /* If we are slow to exit after the root switch, the new systemd instance will send us a signal to
62 * terminate. Just ignore it and exit normally. This way the unit does not end up as failed. */
63 r
= ignore_signals(SIGTERM
, -1);
65 log_warning_errno(r
, "Failed to change disposition of SIGTERM to ignore: %m");
67 log_debug("Switching root - root: %s; init: %s", root
, strna(init
));
69 r
= bus_call_method(bus
, bus_systemd_mgr
, "SwitchRoot", &error
, NULL
, "ss", root
, init
);
71 (void) default_signals(SIGTERM
, -1);
73 return log_error_errno(r
, "Failed to switch root: %s", bus_error_message(&error
, r
));