1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 ProFUSION embedded systems
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <linux/reboot.h>
28 #include <sys/mount.h>
29 #include <sys/reboot.h>
33 #include "alloc-util.h"
34 #include "cgroup-util.h"
36 #include "exec-util.h"
41 #include "parse-util.h"
42 #include "process-util.h"
43 #include "string-util.h"
44 #include "switch-root.h"
45 #include "terminal-util.h"
51 #define FINALIZE_ATTEMPTS 50
53 static char* arg_verb
;
54 static uint8_t arg_exit_code
;
56 static int parse_argv(int argc
, char *argv
[]) {
58 ARG_LOG_LEVEL
= 0x100,
65 static const struct option options
[] = {
66 { "log-level", required_argument
, NULL
, ARG_LOG_LEVEL
},
67 { "log-target", required_argument
, NULL
, ARG_LOG_TARGET
},
68 { "log-color", optional_argument
, NULL
, ARG_LOG_COLOR
},
69 { "log-location", optional_argument
, NULL
, ARG_LOG_LOCATION
},
70 { "exit-code", required_argument
, NULL
, ARG_EXIT_CODE
},
79 /* "-" prevents getopt from permuting argv[] and moving the verb away
80 * from argv[1]. Our interface to initrd promises it'll be there. */
81 while ((c
= getopt_long(argc
, argv
, "-", options
, NULL
)) >= 0)
85 r
= log_set_max_level_from_string(optarg
);
87 log_error("Failed to parse log level %s, ignoring.", optarg
);
92 r
= log_set_target_from_string(optarg
);
94 log_error("Failed to parse log target %s, ignoring", optarg
);
101 r
= log_show_color_from_string(optarg
);
103 log_error("Failed to parse log color setting %s, ignoring", optarg
);
105 log_show_color(true);
109 case ARG_LOG_LOCATION
:
111 r
= log_show_location_from_string(optarg
);
113 log_error("Failed to parse log location setting %s, ignoring", optarg
);
115 log_show_location(true);
120 r
= safe_atou8(optarg
, &arg_exit_code
);
122 log_error("Failed to parse exit code %s, ignoring", optarg
);
130 log_error("Excess arguments, ignoring");
137 assert_not_reached("Unhandled option code.");
141 log_error("Verb argument missing.");
148 static int switch_root_initramfs(void) {
149 if (mount("/run/initramfs", "/run/initramfs", NULL
, MS_BIND
, NULL
) < 0)
150 return log_error_errno(errno
, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
152 if (mount(NULL
, "/run/initramfs", NULL
, MS_PRIVATE
, NULL
) < 0)
153 return log_error_errno(errno
, "Failed to make /run/initramfs private mount: %m");
155 /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file descriptors.
156 * /run/initramfs/shutdown will take care of these.
157 * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
159 return switch_root("/run/initramfs", "/oldroot", false, MS_BIND
);
162 int main(int argc
, char *argv
[]) {
163 bool need_umount
, need_swapoff
, need_loop_detach
, need_dm_detach
;
164 bool in_container
, use_watchdog
= false;
165 _cleanup_free_
char *cgroup
= NULL
;
169 static const char* const dirs
[] = {SYSTEM_SHUTDOWN_PATH
, NULL
};
171 log_parse_environment();
172 r
= parse_argv(argc
, argv
);
176 /* journald will die if not gone yet. The log target defaults
177 * to console, but may have been changed by command line options. */
179 log_close_console(); /* force reopen of /dev/console */
184 if (getpid_cached() != 1) {
185 log_error("Not executed by init (PID 1).");
190 if (streq(arg_verb
, "reboot"))
192 else if (streq(arg_verb
, "poweroff"))
194 else if (streq(arg_verb
, "halt"))
195 cmd
= RB_HALT_SYSTEM
;
196 else if (streq(arg_verb
, "kexec"))
197 cmd
= LINUX_REBOOT_CMD_KEXEC
;
198 else if (streq(arg_verb
, "exit"))
199 cmd
= 0; /* ignored, just checking that arg_verb is valid */
202 log_error("Unknown action '%s'.", arg_verb
);
206 (void) cg_get_root_path(&cgroup
);
207 in_container
= detect_container() > 0;
209 use_watchdog
= !!getenv("WATCHDOG_USEC");
211 /* Lock us into memory */
212 mlockall(MCL_CURRENT
|MCL_FUTURE
);
214 /* Synchronize everything that is not written to disk yet at this point already. This is a good idea so that
215 * slow IO is processed here already and the final process killing spree is not impacted by processes
216 * desperately trying to sync IO to disk within their timeout. */
220 log_info("Sending SIGTERM to remaining processes...");
221 broadcast_signal(SIGTERM
, true, true);
223 log_info("Sending SIGKILL to remaining processes...");
224 broadcast_signal(SIGKILL
, true, false);
226 need_umount
= !in_container
;
227 need_swapoff
= !in_container
;
228 need_loop_detach
= !in_container
;
229 need_dm_detach
= !in_container
;
231 /* Unmount all mountpoints, swaps, and loopback devices */
232 for (retries
= 0; retries
< FINALIZE_ATTEMPTS
; retries
++) {
233 bool changed
= false;
238 /* Let's trim the cgroup tree on each iteration so
239 that we leave an empty cgroup tree around, so that
240 container managers get a nice notify event when we
243 cg_trim(SYSTEMD_CGROUP_CONTROLLER
, cgroup
, false);
246 log_info("Unmounting file systems.");
247 r
= umount_all(&changed
);
250 log_info("All filesystems unmounted.");
252 log_info("Not all file systems unmounted, %d left.", r
);
254 log_error_errno(r
, "Failed to unmount file systems: %m");
258 log_info("Deactivating swaps.");
259 r
= swapoff_all(&changed
);
261 need_swapoff
= false;
262 log_info("All swaps deactivated.");
264 log_info("Not all swaps deactivated, %d left.", r
);
266 log_error_errno(r
, "Failed to deactivate swaps: %m");
269 if (need_loop_detach
) {
270 log_info("Detaching loop devices.");
271 r
= loopback_detach_all(&changed
);
273 need_loop_detach
= false;
274 log_info("All loop devices detached.");
276 log_info("Not all loop devices detached, %d left.", r
);
278 log_error_errno(r
, "Failed to detach loop devices: %m");
281 if (need_dm_detach
) {
282 log_info("Detaching DM devices.");
283 r
= dm_detach_all(&changed
);
285 need_dm_detach
= false;
286 log_info("All DM devices detached.");
288 log_info("Not all DM devices detached, %d left.", r
);
290 log_error_errno(r
, "Failed to detach DM devices: %m");
293 if (!need_umount
&& !need_swapoff
&& !need_loop_detach
&& !need_dm_detach
) {
295 log_info("All filesystems, swaps, loop devices, DM devices detached.");
300 /* If in this iteration we didn't manage to
301 * unmount/deactivate anything, we simply give up */
303 log_info("Cannot finalize remaining%s%s%s%s continuing.",
304 need_umount
? " file systems," : "",
305 need_swapoff
? " swap devices," : "",
306 need_loop_detach
? " loop devices," : "",
307 need_dm_detach
? " DM devices," : "");
311 log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
313 need_umount
? " file systems," : "",
314 need_swapoff
? " swap devices," : "",
315 need_loop_detach
? " loop devices," : "",
316 need_dm_detach
? " DM devices," : "");
319 log_error("Too many iterations, giving up.");
324 arguments
[1] = arg_verb
;
326 execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, NULL
, NULL
, arguments
);
328 if (!in_container
&& !in_initrd() &&
329 access("/run/initramfs/shutdown", X_OK
) == 0) {
330 r
= switch_root_initramfs();
332 argv
[0] = (char*) "/shutdown";
335 make_console_stdio();
337 log_info("Successfully changed into root pivot.\n"
338 "Returning to initrd...");
340 execv("/shutdown", argv
);
341 log_error_errno(errno
, "Failed to execute shutdown binary: %m");
343 log_error_errno(r
, "Failed to switch root to \"/run/initramfs\": %m");
347 if (need_umount
|| need_swapoff
|| need_loop_detach
|| need_dm_detach
)
348 log_error("Failed to finalize %s%s%s%s ignoring",
349 need_umount
? " file systems," : "",
350 need_swapoff
? " swap devices," : "",
351 need_loop_detach
? " loop devices," : "",
352 need_dm_detach
? " DM devices," : "");
354 /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be
355 * sync'ed explicitly in advance. So let's do this here, but not needlessly slow down containers. Note that we
356 * sync'ed things already once above, but we did some more work since then which might have caused IO, hence
357 * let's doit once more. */
361 if (streq(arg_verb
, "exit")) {
365 /* We cannot exit() on the host, fallback on another
373 case LINUX_REBOOT_CMD_KEXEC
:
376 /* We cheat and exec kexec to avoid doing all its work */
379 log_info("Rebooting with kexec.");
383 log_error_errno(errno
, "Failed to fork: %m");
386 const char * const args
[] = {
392 execv(args
[0], (char * const *) args
);
395 wait_for_terminate_and_warn("kexec", pid
, true);
404 _cleanup_free_
char *param
= NULL
;
406 r
= read_one_line_file("/run/systemd/reboot-param", ¶m
);
407 if (r
< 0 && r
!= -ENOENT
)
408 log_warning_errno(r
, "Failed to read reboot parameter file: %m");
410 if (!isempty(param
)) {
411 log_info("Rebooting with argument '%s'.", param
);
412 syscall(SYS_reboot
, LINUX_REBOOT_MAGIC1
, LINUX_REBOOT_MAGIC2
, LINUX_REBOOT_CMD_RESTART2
, param
);
413 log_warning_errno(errno
, "Failed to reboot with parameter, retrying without: %m");
417 log_info("Rebooting.");
421 log_info("Powering off.");
425 log_info("Halting system.");
429 assert_not_reached("Unknown magic");
433 if (errno
== EPERM
&& in_container
) {
434 /* If we are in a container, and we lacked
435 * CAP_SYS_BOOT just exit, this will kill our
436 * container for good. */
437 log_info("Exiting container.");
441 r
= log_error_errno(errno
, "Failed to invoke reboot(): %m");
444 log_emergency_errno(r
, "Critical error while doing system shutdown: %m");