1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "bus-locator.h"
9 #include "parse-util.h"
10 #include "path-util.h"
11 #include "process-util.h"
12 #include "reboot-util.h"
13 #include "systemctl-logind.h"
14 #include "systemctl-start-special.h"
15 #include "systemctl-start-unit.h"
16 #include "systemctl-trivial-method.h"
17 #include "systemctl-util.h"
18 #include "systemctl.h"
20 static int load_kexec_kernel(void) {
21 _cleanup_(boot_config_free
) BootConfig config
= BOOT_CONFIG_NULL
;
22 _cleanup_free_
char *kernel
= NULL
, *initrd
= NULL
, *options
= NULL
;
28 log_debug("Kexec kernel already loaded.");
32 if (access(KEXEC
, X_OK
) < 0)
33 return log_error_errno(errno
, KEXEC
" is not available: %m");
35 r
= boot_config_load_auto(&config
, NULL
, NULL
);
37 /* The call doesn't log about ENOKEY, let's do so here. */
38 return log_error_errno(r
,
39 "No kexec kernel loaded and autodetection failed.\n%s",
41 ? "Cannot automatically load kernel: ESP mount point not found."
42 : "Automatic loading works only on systems booted with EFI.");
46 r
= boot_config_select_special_entries(&config
, /* skip_efivars= */ false);
50 e
= boot_config_default_entry(&config
);
52 return log_error_errno(SYNTHETIC_ERRNO(ENOENT
),
53 "No boot loader entry suitable as default, refusing to guess.");
55 log_debug("Found default boot loader entry in file \"%s\"", e
->path
);
58 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
59 "Boot entry does not refer to Linux kernel, which is not supported currently.");
60 if (strv_length(e
->initrd
) > 1)
61 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
62 "Boot entry specifies multiple initrds, which is not supported currently.");
64 kernel
= path_join(e
->root
, e
->kernel
);
68 if (!strv_isempty(e
->initrd
)) {
69 initrd
= path_join(e
->root
, e
->initrd
[0]);
74 options
= strv_join(e
->options
, " ");
78 log_full(arg_quiet
? LOG_DEBUG
: LOG_INFO
,
79 "%s "KEXEC
" --load \"%s\" --append \"%s\"%s%s%s",
80 arg_dry_run
? "Would run" : "Running",
83 initrd
? " --initrd \"" : NULL
, strempty(initrd
), initrd
? "\"" : "");
87 r
= safe_fork("(kexec)", FORK_WAIT
|FORK_RESET_SIGNALS
|FORK_DEATHSIG_SIGTERM
|FORK_RLIMIT_NOFILE_SAFE
|FORK_LOG
, &pid
);
91 const char* const args
[] = {
95 initrd
? "--initrd" : NULL
, initrd
,
100 execv(args
[0], (char * const *) args
);
107 static int set_exit_code(uint8_t code
) {
108 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
112 r
= acquire_bus(BUS_MANAGER
, &bus
);
116 r
= bus_call_method(bus
, bus_systemd_mgr
, "SetExitCode", &error
, NULL
, "y", code
);
118 return log_error_errno(r
, "Failed to set exit code: %s", bus_error_message(&error
, r
));
123 int verb_start_special(int argc
, char *argv
[], void *userdata
) {
124 bool termination_action
; /* An action that terminates the system, can be performed also by signal. */
130 a
= verb_to_action(argv
[0]);
132 r
= logind_check_inhibitors(a
);
136 if (arg_force
>= 2) {
142 termination_action
= IN_SET(a
, ACTION_HALT
, ACTION_POWEROFF
, ACTION_REBOOT
);
144 if (termination_action
) {
145 r
= prepare_firmware_setup();
149 r
= prepare_boot_loader_menu();
153 r
= prepare_boot_loader_entry();
158 if (a
== ACTION_REBOOT
) {
159 if (arg_reboot_argument
) {
160 r
= update_reboot_parameter_and_warn(arg_reboot_argument
, false);
165 } else if (a
== ACTION_KEXEC
) {
166 r
= load_kexec_kernel();
167 if (r
< 0 && arg_force
>= 1)
168 log_notice("Failed to load kexec kernel, continuing without.");
172 } else if (a
== ACTION_EXIT
&& argc
> 1) {
175 /* If the exit code is not given on the command line, don't reset it to zero: just keep it as
176 * it might have been set previously. */
178 r
= safe_atou8(argv
[1], &code
);
180 return log_error_errno(r
, "Invalid exit code.");
182 r
= set_exit_code(code
);
187 if (termination_action
&& arg_force
>= 2)
190 if (arg_force
>= 1 &&
191 (termination_action
|| IN_SET(a
, ACTION_KEXEC
, ACTION_EXIT
)))
192 r
= verb_trivial_method(argc
, argv
, userdata
);
194 /* First try logind, to allow authentication with polkit */
197 case ACTION_POWEROFF
:
201 case ACTION_SOFT_REBOOT
:
203 r
= logind_reboot(a
);
204 else if (arg_when
!= USEC_INFINITY
)
205 r
= logind_schedule_shutdown(a
);
206 else /* arg_when == USEC_INFINITY */
207 r
= logind_cancel_shutdown();
208 if (r
>= 0 || IN_SET(r
, -EACCES
, -EOPNOTSUPP
, -EINPROGRESS
))
209 /* The latter indicates that the requested operation requires auth,
210 * is not supported or already in progress, in which cases we ignore the error. */
213 /* On all other errors, try low-level operation. In order to minimize the difference
214 * between operation with and without logind, we explicitly enable non-blocking mode
215 * for this, as logind's shutdown operations are always non-blocking. */
220 case ACTION_HIBERNATE
:
221 case ACTION_HYBRID_SLEEP
:
222 case ACTION_SUSPEND_THEN_HIBERNATE
:
224 r
= logind_reboot(a
);
225 if (r
>= 0 || IN_SET(r
, -EACCES
, -EOPNOTSUPP
, -EINPROGRESS
))
232 return logind_reboot(a
);
235 /* Since exit is so close in behaviour to power-off/reboot, let's also make
236 * it asynchronous, in order to not confuse the user needlessly with unexpected
245 r
= verb_start(argc
, argv
, userdata
);
248 if (termination_action
&& arg_force
< 2 &&
249 IN_SET(r
, -ENOENT
, -ETIMEDOUT
))
250 log_notice("It is possible to perform action directly, see discussion of --force --force in man:systemctl(1).");
255 int verb_start_system_special(int argc
, char *argv
[], void *userdata
) {
256 /* Like start_special above, but raises an error when running in user mode */
258 if (arg_runtime_scope
!= RUNTIME_SCOPE_SYSTEM
)
259 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
260 "Bad action for %s mode.",
261 runtime_scope_cmdline_option_to_string(arg_runtime_scope
));
263 return verb_start_special(argc
, argv
, userdata
);