]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shutdown/shutdown.c
shutdown: Make all mounts private
[thirdparty/systemd.git] / src / shutdown / shutdown.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
b1b2a107 2/***
96b2fb93 3 Copyright © 2010 ProFUSION embedded systems
b1b2a107
FF
4***/
5
b1b2a107 6#include <errno.h>
07630cea 7#include <getopt.h>
c01dcddf 8#include <linux/reboot.h>
b1b2a107
FF
9#include <stdbool.h>
10#include <stdlib.h>
07630cea
LP
11#include <sys/mman.h>
12#include <sys/mount.h>
13#include <sys/reboot.h>
14#include <sys/stat.h>
15#include <unistd.h>
b1b2a107 16
b5efdb8a 17#include "alloc-util.h"
d00c2631 18#include "async.h"
0282c028 19#include "binfmt-util.h"
fdb3deca 20#include "cgroup-setup.h"
07630cea 21#include "cgroup-util.h"
c8715007 22#include "coredump-util.h"
28db6fbf 23#include "constants.h"
731e5cda 24#include "errno-util.h"
89711996 25#include "exec-util.h"
d00c2631 26#include "fd-util.h"
ec26be51 27#include "fileio.h"
baa6a42d 28#include "initrd-util.h"
07630cea
LP
29#include "killall.h"
30#include "log.h"
6bedfcbb 31#include "parse-util.h"
07630cea 32#include "process-util.h"
c01dcddf 33#include "reboot-util.h"
595225af 34#include "rlimit-util.h"
73ad712f 35#include "signal-util.h"
07630cea
LP
36#include "string-util.h"
37#include "switch-root.h"
827156b3 38#include "sysctl-util.h"
07630cea 39#include "terminal-util.h"
b1b2a107 40#include "umount.h"
b52aae1d 41#include "virt.h"
e96d6be7 42#include "watchdog.h"
b1b2a107 43
73ad712f
KW
44#define SYNC_PROGRESS_ATTEMPTS 3
45#define SYNC_TIMEOUT_USEC (10*USEC_PER_SEC)
46
b1e90ec5 47static char* arg_verb;
287419c1 48static uint8_t arg_exit_code;
e73c54b8 49static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
b1e90ec5
ZJS
50
51static int parse_argv(int argc, char *argv[]) {
52 enum {
53 ARG_LOG_LEVEL = 0x100,
54 ARG_LOG_TARGET,
55 ARG_LOG_COLOR,
56 ARG_LOG_LOCATION,
c5673ed0 57 ARG_LOG_TIME,
287419c1 58 ARG_EXIT_CODE,
e73c54b8 59 ARG_TIMEOUT,
b1e90ec5
ZJS
60 };
61
62 static const struct option options[] = {
63 { "log-level", required_argument, NULL, ARG_LOG_LEVEL },
64 { "log-target", required_argument, NULL, ARG_LOG_TARGET },
65 { "log-color", optional_argument, NULL, ARG_LOG_COLOR },
66 { "log-location", optional_argument, NULL, ARG_LOG_LOCATION },
c5673ed0 67 { "log-time", optional_argument, NULL, ARG_LOG_TIME },
287419c1 68 { "exit-code", required_argument, NULL, ARG_EXIT_CODE },
e73c54b8 69 { "timeout", required_argument, NULL, ARG_TIMEOUT },
b1e90ec5
ZJS
70 {}
71 };
72
73 int c, r;
74
75 assert(argc >= 1);
76 assert(argv);
77
4b5d8d0f
MS
78 /* "-" prevents getopt from permuting argv[] and moving the verb away
79 * from argv[1]. Our interface to initrd promises it'll be there. */
80 while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0)
b1e90ec5
ZJS
81 switch (c) {
82
83 case ARG_LOG_LEVEL:
84 r = log_set_max_level_from_string(optarg);
85 if (r < 0)
5e1ee764 86 log_error_errno(r, "Failed to parse log level %s, ignoring: %m", optarg);
b1e90ec5
ZJS
87
88 break;
89
90 case ARG_LOG_TARGET:
91 r = log_set_target_from_string(optarg);
92 if (r < 0)
5e1ee764 93 log_error_errno(r, "Failed to parse log target %s, ignoring: %m", optarg);
b1e90ec5
ZJS
94
95 break;
96
97 case ARG_LOG_COLOR:
98
99 if (optarg) {
100 r = log_show_color_from_string(optarg);
101 if (r < 0)
5e1ee764 102 log_error_errno(r, "Failed to parse log color setting %s, ignoring: %m", optarg);
b1e90ec5
ZJS
103 } else
104 log_show_color(true);
105
106 break;
107
108 case ARG_LOG_LOCATION:
109 if (optarg) {
110 r = log_show_location_from_string(optarg);
111 if (r < 0)
5e1ee764 112 log_error_errno(r, "Failed to parse log location setting %s, ignoring: %m", optarg);
b1e90ec5
ZJS
113 } else
114 log_show_location(true);
115
116 break;
117
c5673ed0
DS
118 case ARG_LOG_TIME:
119
120 if (optarg) {
121 r = log_show_time_from_string(optarg);
122 if (r < 0)
123 log_error_errno(r, "Failed to parse log time setting %s, ignoring: %m", optarg);
124 } else
125 log_show_time(true);
126
127 break;
128
287419c1
AC
129 case ARG_EXIT_CODE:
130 r = safe_atou8(optarg, &arg_exit_code);
131 if (r < 0)
5e1ee764 132 log_error_errno(r, "Failed to parse exit code %s, ignoring: %m", optarg);
287419c1
AC
133
134 break;
135
e73c54b8
JK
136 case ARG_TIMEOUT:
137 r = parse_sec(optarg, &arg_timeout);
138 if (r < 0)
5e1ee764 139 log_error_errno(r, "Failed to parse shutdown timeout %s, ignoring: %m", optarg);
e73c54b8
JK
140
141 break;
142
4b5d8d0f
MS
143 case '\001':
144 if (!arg_verb)
145 arg_verb = optarg;
146 else
147 log_error("Excess arguments, ignoring");
148 break;
149
b1e90ec5 150 case '?':
b1e90ec5
ZJS
151 return -EINVAL;
152
153 default:
04499a70 154 assert_not_reached();
b1e90ec5
ZJS
155 }
156
baaa35ad
ZJS
157 if (!arg_verb)
158 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
159 "Verb argument missing.");
b1e90ec5 160
b1e90ec5
ZJS
161 return 0;
162}
163
5a4bf02f 164static int switch_root_initramfs(void) {
4a62c710
MS
165 if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0)
166 return log_error_errno(errno, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
89d471d5 167
4a62c710
MS
168 if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0)
169 return log_error_errno(errno, "Failed to make /run/initramfs private mount: %m");
89d471d5 170
f131770b 171 /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file descriptors.
5a4bf02f
HH
172 * /run/initramfs/shutdown will take care of these.
173 * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
174 */
175 return switch_root("/run/initramfs", "/oldroot", false, MS_BIND);
7cb1094a
HH
176}
177
73ad712f
KW
178/* Read the following fields from /proc/meminfo:
179 *
180 * NFS_Unstable
181 * Writeback
182 * Dirty
183 *
184 * Return true if the sum of these fields is greater than the previous
185 * value input. For all other issues, report the failure and indicate that
186 * the sync is not making progress.
187 */
66034f9c 188static int sync_making_progress(unsigned long long *prev_dirty) {
73ad712f 189 _cleanup_fclose_ FILE *f = NULL;
73ad712f 190 unsigned long long val = 0;
66034f9c 191 int ret;
73ad712f
KW
192
193 f = fopen("/proc/meminfo", "re");
194 if (!f)
195 return log_warning_errno(errno, "Failed to open /proc/meminfo: %m");
196
a34f0dae
LP
197 for (;;) {
198 _cleanup_free_ char *line = NULL;
73ad712f 199 unsigned long long ull = 0;
a34f0dae
LP
200 int q;
201
202 q = read_line(f, LONG_LINE_MAX, &line);
203 if (q < 0)
204 return log_warning_errno(q, "Failed to parse /proc/meminfo: %m");
205 if (q == 0)
206 break;
73ad712f
KW
207
208 if (!first_word(line, "NFS_Unstable:") && !first_word(line, "Writeback:") && !first_word(line, "Dirty:"))
209 continue;
210
211 errno = 0;
212 if (sscanf(line, "%*s %llu %*s", &ull) != 1) {
213 if (errno != 0)
214 log_warning_errno(errno, "Failed to parse /proc/meminfo: %m");
215 else
216 log_warning("Failed to parse /proc/meminfo");
217
218 return false;
219 }
220
221 val += ull;
222 }
223
66034f9c 224 ret = *prev_dirty > val;
73ad712f 225 *prev_dirty = val;
66034f9c 226 return ret;
73ad712f
KW
227}
228
229static void sync_with_progress(void) {
8a8e84d2 230 unsigned long long dirty = ULLONG_MAX;
73ad712f
KW
231 unsigned checks;
232 pid_t pid;
233 int r;
73ad712f
KW
234
235 BLOCK_SIGNALS(SIGCHLD);
236
273d76f4
YW
237 /* Due to the possibility of the sync operation hanging, we fork a child process and monitor
238 * the progress. If the timeout lapses, the assumption is that the particular sync stalled. */
d00c2631
LP
239
240 r = asynchronous_sync(&pid);
4c253ed1 241 if (r < 0) {
d00c2631 242 log_error_errno(r, "Failed to fork sync(): %m");
73ad712f
KW
243 return;
244 }
73ad712f
KW
245
246 log_info("Syncing filesystems and block devices.");
247
248 /* Start monitoring the sync operation. If more than
249 * SYNC_PROGRESS_ATTEMPTS lapse without progress being made,
250 * we assume that the sync is stalled */
251 for (checks = 0; checks < SYNC_PROGRESS_ATTEMPTS; checks++) {
252 r = wait_for_terminate_with_timeout(pid, SYNC_TIMEOUT_USEC);
253 if (r == 0)
254 /* Sync finished without error.
255 * (The sync itself does not return an error code) */
256 return;
257 else if (r == -ETIMEDOUT) {
258 /* Reset the check counter if the "Dirty" value is
259 * decreasing */
66034f9c 260 if (sync_making_progress(&dirty) > 0)
73ad712f
KW
261 checks = 0;
262 } else {
263 log_error_errno(r, "Failed to sync filesystems and block devices: %m");
264 return;
265 }
266 }
267
268 /* Only reached in the event of a timeout. We should issue a kill
269 * to the stray process. */
270 log_error("Syncing filesystems and block devices - timed out, issuing SIGKILL to PID "PID_FMT".", pid);
271 (void) kill(pid, SIGKILL);
272}
273
827156b3
BR
274static int read_current_sysctl_printk_log_level(void) {
275 _cleanup_free_ char *sysctl_printk_vals = NULL, *sysctl_printk_curr = NULL;
701f6af6 276 int current_lvl;
827156b3
BR
277 const char *p;
278 int r;
279
280 r = sysctl_read("kernel/printk", &sysctl_printk_vals);
281 if (r < 0)
282 return log_debug_errno(r, "Cannot read sysctl kernel.printk: %m");
283
284 p = sysctl_printk_vals;
285 r = extract_first_word(&p, &sysctl_printk_curr, NULL, 0);
701f6af6
LP
286 if (r < 0)
287 return log_debug_errno(r, "Failed to split out kernel printk priority: %m");
288 if (r == 0)
289 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Short read while reading kernel.printk sysctl");
827156b3 290
701f6af6 291 r = safe_atoi(sysctl_printk_curr, &current_lvl);
827156b3 292 if (r < 0)
701f6af6 293 return log_debug_errno(r, "Failed to parse kernel.printk sysctl: %s", sysctl_printk_vals);
827156b3
BR
294
295 return current_lvl;
296}
297
298static void bump_sysctl_printk_log_level(int min_level) {
477851f5
LP
299 int current_lvl, r;
300
827156b3
BR
301 /* Set the logging level to be able to see messages with log level smaller or equal to min_level */
302
477851f5
LP
303 current_lvl = read_current_sysctl_printk_log_level();
304 if (current_lvl < 0 || current_lvl >= min_level + 1)
305 return;
306
307 r = sysctl_writef("kernel/printk", "%i", min_level + 1);
308 if (r < 0)
309 log_debug_errno(r, "Failed to bump kernel.printk to %i: %m", min_level + 1);
827156b3
BR
310}
311
484752e2
FB
312static void init_watchdog(void) {
313 const char *s;
314 int r;
315
316 s = getenv("WATCHDOG_DEVICE");
317 if (s) {
318 r = watchdog_set_device(s);
319 if (r < 0)
320 log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m", s);
321 }
322
323 s = getenv("WATCHDOG_USEC");
324 if (s) {
325 usec_t usec;
326
327 r = safe_atou64(s, &usec);
328 if (r < 0)
329 log_warning_errno(r, "Failed to parse watchdog timeout '%s', ignoring: %m", s);
330 else
331 (void) watchdog_setup(usec);
332 }
333}
334
b1b2a107 335int main(int argc, char *argv[]) {
731e5cda
LP
336 static const char* const dirs[] = {
337 SYSTEM_SHUTDOWN_PATH,
338 NULL
339 };
06beed6d 340 _cleanup_free_ char *cgroup = NULL;
484752e2 341 char *arguments[3];
5125b677 342 int cmd, r;
b1b2a107 343
e18805fb
LP
344 /* The log target defaults to console, but the original systemd process will pass its log target in through a
345 * command line argument, which will override this default. Also, ensure we'll never log to the journal or
346 * syslog, as these logging daemons are either already dead or will die very soon. */
347
348 log_set_target(LOG_TARGET_CONSOLE);
349 log_set_prohibit_ipc(true);
b1e90ec5 350 log_parse_environment();
e18805fb 351
f975f1cc
AZ
352 if (getpid_cached() == 1)
353 log_set_always_reopen_console(true);
354
b1e90ec5
ZJS
355 r = parse_argv(argc, argv);
356 if (r < 0)
357 goto error;
ec26be51 358
b1b2a107
FF
359 log_open();
360
4c12626c
LP
361 umask(0022);
362
df0ff127 363 if (getpid_cached() != 1) {
731e5cda 364 r = log_error_errno(SYNTHETIC_ERRNO(EPERM), "Not executed by init (PID 1).");
b1b2a107
FF
365 goto error;
366 }
367
b1e90ec5 368 if (streq(arg_verb, "reboot"))
b1b2a107 369 cmd = RB_AUTOBOOT;
b1e90ec5 370 else if (streq(arg_verb, "poweroff"))
b1b2a107 371 cmd = RB_POWER_OFF;
b1e90ec5 372 else if (streq(arg_verb, "halt"))
b1b2a107 373 cmd = RB_HALT_SYSTEM;
b1e90ec5 374 else if (streq(arg_verb, "kexec"))
b1b2a107 375 cmd = LINUX_REBOOT_CMD_KEXEC;
287419c1
AC
376 else if (streq(arg_verb, "exit"))
377 cmd = 0; /* ignored, just checking that arg_verb is valid */
b1b2a107 378 else {
731e5cda 379 r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown action '%s'.", arg_verb);
b1b2a107
FF
380 goto error;
381 }
382
0b9aa270 383 (void) cg_get_root_path(&cgroup);
5125b677 384 bool in_container = detect_container() > 0;
41f85451 385
9a75c652
LP
386 /* If the logging messages are going to KMSG, and if we are not running from a container, then try to
387 * update the sysctl kernel.printk current value in order to see "info" messages; This current log
388 * level is not updated if already big enough.
827156b3 389 */
9a75c652
LP
390 if (!in_container &&
391 IN_SET(log_get_target(),
392 LOG_TARGET_AUTO,
393 LOG_TARGET_JOURNAL_OR_KMSG,
394 LOG_TARGET_SYSLOG_OR_KMSG,
395 LOG_TARGET_KMSG))
396 bump_sysctl_printk_log_level(LOG_WARNING);
827156b3 397
484752e2 398 init_watchdog();
5bbf2db1 399
2e79d182 400 /* Lock us into memory */
e18805fb 401 (void) mlockall(MCL_CURRENT|MCL_FUTURE);
b1b2a107 402
2cc0cd43
VD
403 /* We need to make mounts private so that we can MS_MOVE in unmount_all(). Kernel does not allow
404 * MS_MOVE when parent mountpoints have shared propagation. */
405 if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0)
406 log_warning_errno(errno, "Failed to make mounts private, ignoring: %m");
407
2e79d182
LP
408 /* Synchronize everything that is not written to disk yet at this point already. This is a good idea so that
409 * slow IO is processed here already and the final process killing spree is not impacted by processes
73ad712f
KW
410 * desperately trying to sync IO to disk within their timeout. Do not remove this sync, data corruption will
411 * result. */
2e79d182 412 if (!in_container)
73ad712f 413 sync_with_progress();
2e79d182 414
e557b1a6 415 disable_coredumps();
0282c028 416 disable_binfmt();
27b372c1 417
ab58e291 418 log_info("Sending SIGTERM to remaining processes...");
e73c54b8 419 broadcast_signal(SIGTERM, true, true, arg_timeout);
b1b2a107 420
ab58e291 421 log_info("Sending SIGKILL to remaining processes...");
e73c54b8 422 broadcast_signal(SIGKILL, true, false, arg_timeout);
40e85d00 423
5125b677
JJ
424 bool need_umount = !in_container, need_swapoff = !in_container, need_loop_detach = !in_container,
425 need_dm_detach = !in_container, need_md_detach = !in_container, can_initrd, last_try = false;
456b2199 426 can_initrd = !in_container && !in_initrd() && access("/run/initramfs/shutdown", X_OK) == 0;
b1b2a107 427
567ea02a 428 /* Unmount all mountpoints, swaps, and loopback devices */
ac9cea5b 429 for (;;) {
12aad1d0
LP
430 bool changed = false;
431
5bbf2db1 432 (void) watchdog_ping();
e96d6be7 433
731e5cda
LP
434 /* Let's trim the cgroup tree on each iteration so that we leave an empty cgroup tree around,
435 * so that container managers get a nice notify event when we are down */
41f85451 436 if (cgroup)
3a736a32 437 (void) cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
41f85451 438
b1b2a107 439 if (need_umount) {
ab58e291 440 log_info("Unmounting file systems.");
5125b677 441 r = umount_all(&changed, last_try);
bce93b7a 442 if (r == 0) {
b1b2a107 443 need_umount = false;
bce93b7a
MS
444 log_info("All filesystems unmounted.");
445 } else if (r > 0)
ab58e291 446 log_info("Not all file systems unmounted, %d left.", r);
b1b2a107 447 else
da927ba9 448 log_error_errno(r, "Failed to unmount file systems: %m");
b1b2a107
FF
449 }
450
451 if (need_swapoff) {
735e0712 452 log_info("Deactivating swaps.");
12aad1d0 453 r = swapoff_all(&changed);
bce93b7a 454 if (r == 0) {
b1b2a107 455 need_swapoff = false;
735e0712 456 log_info("All swaps deactivated.");
bce93b7a 457 } else if (r > 0)
735e0712 458 log_info("Not all swaps deactivated, %d left.", r);
b1b2a107 459 else
da927ba9 460 log_error_errno(r, "Failed to deactivate swaps: %m");
b1b2a107
FF
461 }
462
463 if (need_loop_detach) {
464 log_info("Detaching loop devices.");
5125b677 465 r = loopback_detach_all(&changed, last_try);
bce93b7a 466 if (r == 0) {
b1b2a107 467 need_loop_detach = false;
bce93b7a
MS
468 log_info("All loop devices detached.");
469 } else if (r > 0)
ab58e291 470 log_info("Not all loop devices detached, %d left.", r);
b1b2a107 471 else
da927ba9 472 log_error_errno(r, "Failed to detach loop devices: %m");
d48141ba 473 }
b1b2a107 474
0b220a5f
HK
475 if (need_md_detach) {
476 log_info("Stopping MD devices.");
5125b677 477 r = md_detach_all(&changed, last_try);
0b220a5f
HK
478 if (r == 0) {
479 need_md_detach = false;
480 log_info("All MD devices stopped.");
481 } else if (r > 0)
482 log_info("Not all MD devices stopped, %d left.", r);
483 else
484 log_error_errno(r, "Failed to stop MD devices: %m");
485 }
486
d48141ba
LP
487 if (need_dm_detach) {
488 log_info("Detaching DM devices.");
5125b677 489 r = dm_detach_all(&changed, last_try);
bce93b7a 490 if (r == 0) {
d48141ba 491 need_dm_detach = false;
bce93b7a
MS
492 log_info("All DM devices detached.");
493 } else if (r > 0)
2569a5ce 494 log_info("Not all DM devices detached, %d left.", r);
d48141ba 495 else
da927ba9 496 log_error_errno(r, "Failed to detach DM devices: %m");
b1b2a107
FF
497 }
498
0b220a5f
HK
499 if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach
500 && !need_md_detach) {
501 log_info("All filesystems, swaps, loop devices, MD devices and DM devices detached.");
12aad1d0 502 /* Yay, done */
ac9cea5b 503 break;
a27d2184 504 }
b1b2a107 505
13d9616c 506 if (!changed && !last_try && !can_initrd) {
5125b677
JJ
507 /* There are things we cannot get rid of. Loop one more time in which we will log
508 * with higher priority to inform the user. Note that we don't need to do this if
509 * there is an initrd to switch to, because that one is likely to get rid of the
510 * remaining mounts. If not, it will log about them. */
511 last_try = true;
456b2199
JJ
512 continue;
513 }
514
731e5cda 515 /* If in this iteration we didn't manage to unmount/deactivate anything, we simply give up */
12aad1d0 516 if (!changed) {
0b220a5f 517 log_info("Cannot finalize remaining%s%s%s%s%s continuing.",
8c977838
ZJS
518 need_umount ? " file systems," : "",
519 need_swapoff ? " swap devices," : "",
520 need_loop_detach ? " loop devices," : "",
0b220a5f
HK
521 need_dm_detach ? " DM devices," : "",
522 need_md_detach ? " MD devices," : "");
ac9cea5b 523 break;
12aad1d0
LP
524 }
525
0b220a5f 526 log_debug("Couldn't finalize remaining %s%s%s%s%s trying again.",
8c977838
ZJS
527 need_umount ? " file systems," : "",
528 need_swapoff ? " swap devices," : "",
529 need_loop_detach ? " loop devices," : "",
0b220a5f
HK
530 need_dm_detach ? " DM devices," : "",
531 need_md_detach ? " MD devices," : "");
b1b2a107
FF
532 }
533
731e5cda
LP
534 /* We're done with the watchdog. Note that the watchdog is explicitly not stopped here. It remains
535 * active to guard against any issues during the rest of the shutdown sequence. */
8a2c1fbf
EJ
536 watchdog_free_device();
537
731e5cda 538 arguments[0] = NULL; /* Filled in by execute_directories(), when needed */
b1e90ec5 539 arguments[1] = arg_verb;
6edd7d0a 540 arguments[2] = NULL;
3a736a32 541 (void) execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
83cc030f 542
595225af
LP
543 (void) rlimit_nofile_safe();
544
456b2199 545 if (can_initrd) {
5a4bf02f
HH
546 r = switch_root_initramfs();
547 if (r >= 0) {
a2726e5c 548 argv[0] = (char*) "/shutdown";
30d743f4 549
ece0fe12
LP
550 (void) setsid();
551 (void) make_console_stdio();
5a4bf02f
HH
552
553 log_info("Successfully changed into root pivot.\n"
554 "Returning to initrd...");
30d743f4 555
a2726e5c 556 execv("/shutdown", argv);
56f64d95 557 log_error_errno(errno, "Failed to execute shutdown binary: %m");
5a4bf02f 558 } else
da927ba9 559 log_error_errno(r, "Failed to switch root to \"/run/initramfs\": %m");
7cb1094a
HH
560 }
561
0b220a5f
HK
562 if (need_umount || need_swapoff || need_loop_detach || need_dm_detach || need_md_detach)
563 log_error("Failed to finalize%s%s%s%s%s ignoring.",
8c977838
ZJS
564 need_umount ? " file systems," : "",
565 need_swapoff ? " swap devices," : "",
566 need_loop_detach ? " loop devices," : "",
0b220a5f
HK
567 need_dm_detach ? " DM devices," : "",
568 need_md_detach ? " MD devices," : "");
8c977838 569
731e5cda
LP
570 /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need
571 * to be sync'ed explicitly in advance. So let's do this here, but not needlessly slow down
572 * containers. Note that we sync'ed things already once above, but we did some more work since then
573 * which might have caused IO, hence let's do it once more. Do not remove this sync, data corruption
574 * will result. */
0049f05a 575 if (!in_container)
73ad712f 576 sync_with_progress();
0049f05a 577
287419c1 578 if (streq(arg_verb, "exit")) {
016f36ae
AZ
579 if (in_container) {
580 log_info("Exiting container.");
1f409a0c 581 return arg_exit_code;
016f36ae 582 }
1f409a0c
LP
583
584 cmd = RB_POWER_OFF; /* We cannot exit() on the host, fallback on another method. */
287419c1
AC
585 }
586
477def80
LP
587 switch (cmd) {
588
589 case LINUX_REBOOT_CMD_KEXEC:
cb7ec564
LP
590
591 if (!in_container) {
592 /* We cheat and exec kexec to avoid doing all its work */
477def80 593 log_info("Rebooting with kexec.");
cb7ec564 594
1f5d1e02 595 r = safe_fork("(sd-kexec)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_WAIT, NULL);
4c253ed1 596 if (r == 0) {
477def80
LP
597 const char * const args[] = {
598 KEXEC, "-e", NULL
599 };
600
cb7ec564 601 /* Child */
477def80 602
cb7ec564 603 execv(args[0], (char * const *) args);
731e5cda 604 log_debug_errno(errno, "Failed to execute '" KEXEC "' binary, proceeding with reboot(RB_KEXEC): %m");
71180f8e
A
605
606 /* execv failed (kexec binary missing?), so try simply reboot(RB_KEXEC) */
607 (void) reboot(cmd);
477def80 608 _exit(EXIT_FAILURE);
4c253ed1
LP
609 }
610
1f5d1e02 611 /* If we are still running, then the kexec can't have worked, let's fall through */
b1b2a107 612 }
e61cd186
LP
613
614 cmd = RB_AUTOBOOT;
4831981d 615 _fallthrough_;
477def80 616
c01dcddf
LP
617 case RB_AUTOBOOT:
618 (void) reboot_with_parameter(REBOOT_LOG);
477def80
LP
619 log_info("Rebooting.");
620 break;
621
622 case RB_POWER_OFF:
623 log_info("Powering off.");
624 break;
625
626 case RB_HALT_SYSTEM:
627 log_info("Halting system.");
628 break;
629
630 default:
04499a70 631 assert_not_reached();
477def80 632 }
cb7ec564 633
118cf952 634 (void) reboot(cmd);
731e5cda
LP
635 if (ERRNO_IS_PRIVILEGE(errno) && in_container) {
636 /* If we are in a container, and we lacked CAP_SYS_BOOT just exit, this will kill our
cb7ec564 637 * container for good. */
477def80 638 log_info("Exiting container.");
1f409a0c 639 return EXIT_SUCCESS;
cb7ec564
LP
640 }
641
76ef789d 642 r = log_error_errno(errno, "Failed to invoke reboot(): %m");
b1b2a107
FF
643
644 error:
da927ba9 645 log_emergency_errno(r, "Critical error while doing system shutdown: %m");
b1b2a107 646 freeze();
b1b2a107 647}