]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/shutdown.c
treewide: use log_*_errno whenever %m is in the format string
[thirdparty/systemd.git] / src / core / shutdown.c
CommitLineData
b1b2a107
FF
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 ProFUSION embedded systems
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
b1b2a107
FF
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
b1b2a107 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
b1b2a107
FF
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <sys/mman.h>
23#include <sys/types.h>
24#include <sys/reboot.h>
25#include <linux/reboot.h>
26#include <sys/wait.h>
7cb1094a
HH
27#include <sys/stat.h>
28#include <sys/mount.h>
29#include <sys/syscall.h>
30#include <fcntl.h>
b1b2a107
FF
31#include <dirent.h>
32#include <errno.h>
33#include <unistd.h>
34#include <signal.h>
35#include <stdbool.h>
36#include <stdlib.h>
37#include <string.h>
b1e90ec5 38#include <getopt.h>
b1b2a107 39
7cb1094a 40#include "missing.h"
b1b2a107 41#include "log.h"
ec26be51 42#include "fileio.h"
b1b2a107
FF
43#include "umount.h"
44#include "util.h"
49e942b2 45#include "mkdir.h"
b52aae1d 46#include "virt.h"
e96d6be7 47#include "watchdog.h"
39d6464c 48#include "killall.h"
41f85451 49#include "cgroup-util.h"
37185ec8 50#include "def.h"
5a4bf02f 51#include "switch-root.h"
b1b2a107 52
b1b2a107 53#define FINALIZE_ATTEMPTS 50
b1b2a107 54
b1e90ec5
ZJS
55static char* arg_verb;
56
57static int parse_argv(int argc, char *argv[]) {
58 enum {
59 ARG_LOG_LEVEL = 0x100,
60 ARG_LOG_TARGET,
61 ARG_LOG_COLOR,
62 ARG_LOG_LOCATION,
63 };
64
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 {}
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)
86 log_error("Failed to parse log level %s, ignoring.", optarg);
87
88 break;
89
90 case ARG_LOG_TARGET:
91 r = log_set_target_from_string(optarg);
92 if (r < 0)
93 log_error("Failed to parse log target %s, ignoring", optarg);
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)
102 log_error("Failed to parse log color setting %s, ignoring", optarg);
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)
112 log_error("Failed to parse log location setting %s, ignoring", optarg);
113 } else
114 log_show_location(true);
115
116 break;
117
4b5d8d0f
MS
118 case '\001':
119 if (!arg_verb)
120 arg_verb = optarg;
121 else
122 log_error("Excess arguments, ignoring");
123 break;
124
b1e90ec5 125 case '?':
b1e90ec5
ZJS
126 return -EINVAL;
127
128 default:
129 assert_not_reached("Unhandled option code.");
130 }
131
4b5d8d0f 132 if (!arg_verb) {
b1e90ec5
ZJS
133 log_error("Verb argument missing.");
134 return -EINVAL;
135 }
136
b1e90ec5
ZJS
137 return 0;
138}
139
5a4bf02f 140static int switch_root_initramfs(void) {
89d471d5 141 if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) {
56f64d95 142 log_error_errno(errno, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
89d471d5
LP
143 return -errno;
144 }
145
146 if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) {
56f64d95 147 log_error_errno(errno, "Failed to make /run/initramfs private mount: %m");
89d471d5
LP
148 return -errno;
149 }
150
5a4bf02f
HH
151 /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file desriptors.
152 * /run/initramfs/shutdown will take care of these.
153 * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
154 */
155 return switch_root("/run/initramfs", "/oldroot", false, MS_BIND);
7cb1094a
HH
156}
157
7cb1094a 158
b1b2a107 159int main(int argc, char *argv[]) {
8c977838 160 bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
bd3fa1d2 161 bool in_container, use_watchdog = false;
06beed6d 162 _cleanup_free_ char *cgroup = NULL;
6edd7d0a 163 char *arguments[3];
41f85451
LP
164 unsigned retries;
165 int cmd, r;
b1b2a107 166
b1e90ec5
ZJS
167 log_parse_environment();
168 r = parse_argv(argc, argv);
169 if (r < 0)
170 goto error;
ec26be51 171
b1e90ec5 172 /* journald will die if not gone yet. The log target defaults
3f85ef0f 173 * to console, but may have been changed by command line options. */
ec26be51 174
99f09825 175 log_close_console(); /* force reopen of /dev/console */
b1b2a107
FF
176 log_open();
177
4c12626c
LP
178 umask(0022);
179
b1b2a107 180 if (getpid() != 1) {
b1e90ec5 181 log_error("Not executed by init (PID 1).");
b1b2a107
FF
182 r = -EPERM;
183 goto error;
184 }
185
b1e90ec5 186 if (streq(arg_verb, "reboot"))
b1b2a107 187 cmd = RB_AUTOBOOT;
b1e90ec5 188 else if (streq(arg_verb, "poweroff"))
b1b2a107 189 cmd = RB_POWER_OFF;
b1e90ec5 190 else if (streq(arg_verb, "halt"))
b1b2a107 191 cmd = RB_HALT_SYSTEM;
b1e90ec5 192 else if (streq(arg_verb, "kexec"))
b1b2a107
FF
193 cmd = LINUX_REBOOT_CMD_KEXEC;
194 else {
b1b2a107 195 r = -EINVAL;
b1e90ec5 196 log_error("Unknown action '%s'.", arg_verb);
b1b2a107
FF
197 goto error;
198 }
199
41f85451
LP
200 cg_get_root_path(&cgroup);
201
e96d6be7
LP
202 use_watchdog = !!getenv("WATCHDOG_USEC");
203
b1b2a107 204 /* lock us into memory */
b55d0651 205 mlockall(MCL_CURRENT|MCL_FUTURE);
b1b2a107 206
ab58e291 207 log_info("Sending SIGTERM to remaining processes...");
0bee65f0 208 broadcast_signal(SIGTERM, true, true);
b1b2a107 209
ab58e291 210 log_info("Sending SIGKILL to remaining processes...");
0bee65f0 211 broadcast_signal(SIGKILL, true, false);
40e85d00 212
8c977838
ZJS
213 in_container = detect_container(NULL) > 0;
214
d89b5fed 215 need_umount = !in_container;
8c977838
ZJS
216 need_swapoff = !in_container;
217 need_loop_detach = !in_container;
218 need_dm_detach = !in_container;
b1b2a107 219
567ea02a 220 /* Unmount all mountpoints, swaps, and loopback devices */
12aad1d0
LP
221 for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
222 bool changed = false;
223
e96d6be7
LP
224 if (use_watchdog)
225 watchdog_ping();
226
41f85451
LP
227 /* Let's trim the cgroup tree on each iteration so
228 that we leave an empty cgroup tree around, so that
229 container managers get a nice notify event when we
230 are down */
231 if (cgroup)
232 cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
233
b1b2a107 234 if (need_umount) {
ab58e291 235 log_info("Unmounting file systems.");
12aad1d0 236 r = umount_all(&changed);
bce93b7a 237 if (r == 0) {
b1b2a107 238 need_umount = false;
bce93b7a
MS
239 log_info("All filesystems unmounted.");
240 } else if (r > 0)
ab58e291 241 log_info("Not all file systems unmounted, %d left.", r);
b1b2a107 242 else
da927ba9 243 log_error_errno(r, "Failed to unmount file systems: %m");
b1b2a107
FF
244 }
245
246 if (need_swapoff) {
735e0712 247 log_info("Deactivating swaps.");
12aad1d0 248 r = swapoff_all(&changed);
bce93b7a 249 if (r == 0) {
b1b2a107 250 need_swapoff = false;
735e0712 251 log_info("All swaps deactivated.");
bce93b7a 252 } else if (r > 0)
735e0712 253 log_info("Not all swaps deactivated, %d left.", r);
b1b2a107 254 else
da927ba9 255 log_error_errno(r, "Failed to deactivate swaps: %m");
b1b2a107
FF
256 }
257
258 if (need_loop_detach) {
259 log_info("Detaching loop devices.");
12aad1d0 260 r = loopback_detach_all(&changed);
bce93b7a 261 if (r == 0) {
b1b2a107 262 need_loop_detach = false;
bce93b7a
MS
263 log_info("All loop devices detached.");
264 } else if (r > 0)
ab58e291 265 log_info("Not all loop devices detached, %d left.", r);
b1b2a107 266 else
da927ba9 267 log_error_errno(r, "Failed to detach loop devices: %m");
d48141ba 268 }
b1b2a107 269
d48141ba
LP
270 if (need_dm_detach) {
271 log_info("Detaching DM devices.");
12aad1d0 272 r = dm_detach_all(&changed);
bce93b7a 273 if (r == 0) {
d48141ba 274 need_dm_detach = false;
bce93b7a
MS
275 log_info("All DM devices detached.");
276 } else if (r > 0)
2569a5ce 277 log_info("Not all DM devices detached, %d left.", r);
d48141ba 278 else
da927ba9 279 log_error_errno(r, "Failed to detach DM devices: %m");
b1b2a107
FF
280 }
281
a27d2184
KS
282 if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
283 if (retries > 0)
284 log_info("All filesystems, swaps, loop devices, DM devices detached.");
12aad1d0 285 /* Yay, done */
8c977838 286 goto initrd_jump;
a27d2184 287 }
b1b2a107 288
12aad1d0 289 /* If in this iteration we didn't manage to
bd3fa1d2 290 * unmount/deactivate anything, we simply give up */
12aad1d0 291 if (!changed) {
8c977838
ZJS
292 log_info("Cannot finalize remaining%s%s%s%s continuing.",
293 need_umount ? " file systems," : "",
294 need_swapoff ? " swap devices," : "",
295 need_loop_detach ? " loop devices," : "",
296 need_dm_detach ? " DM devices," : "");
297 goto initrd_jump;
12aad1d0
LP
298 }
299
8c977838
ZJS
300 log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
301 retries + 1,
302 need_umount ? " file systems," : "",
303 need_swapoff ? " swap devices," : "",
304 need_loop_detach ? " loop devices," : "",
305 need_dm_detach ? " DM devices," : "");
b1b2a107
FF
306 }
307
8c977838
ZJS
308 log_error("Too many iterations, giving up.");
309
310 initrd_jump:
12aad1d0 311
6edd7d0a 312 arguments[0] = NULL;
b1e90ec5 313 arguments[1] = arg_verb;
6edd7d0a 314 arguments[2] = NULL;
e2680723 315 execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
83cc030f 316
02eaa788 317 if (!in_container && !in_initrd() &&
cb7ec564 318 access("/run/initramfs/shutdown", X_OK) == 0) {
5a4bf02f
HH
319 r = switch_root_initramfs();
320 if (r >= 0) {
a2726e5c 321 argv[0] = (char*) "/shutdown";
30d743f4 322
5a4bf02f
HH
323 setsid();
324 make_console_stdio();
325
326 log_info("Successfully changed into root pivot.\n"
327 "Returning to initrd...");
30d743f4 328
a2726e5c 329 execv("/shutdown", argv);
56f64d95 330 log_error_errno(errno, "Failed to execute shutdown binary: %m");
5a4bf02f 331 } else
da927ba9 332 log_error_errno(r, "Failed to switch root to \"/run/initramfs\": %m");
5a4bf02f 333
7cb1094a
HH
334 }
335
8c977838
ZJS
336 if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
337 log_error("Failed to finalize %s%s%s%s ignoring",
338 need_umount ? " file systems," : "",
339 need_swapoff ? " swap devices," : "",
340 need_loop_detach ? " loop devices," : "",
341 need_dm_detach ? " DM devices," : "");
342
0049f05a
LP
343 /* The kernel will automaticall flush ATA disks and suchlike
344 * on reboot(), but the file systems need to be synce'd
345 * explicitly in advance. So let's do this here, but not
346 * needlessly slow down containers. */
347 if (!in_container)
348 sync();
349
477def80
LP
350 switch (cmd) {
351
352 case LINUX_REBOOT_CMD_KEXEC:
cb7ec564
LP
353
354 if (!in_container) {
355 /* We cheat and exec kexec to avoid doing all its work */
477def80
LP
356 pid_t pid;
357
358 log_info("Rebooting with kexec.");
cb7ec564 359
477def80 360 pid = fork();
cb7ec564 361 if (pid < 0)
56f64d95 362 log_error_errno(errno, "Failed to fork: %m");
477def80
LP
363 else if (pid == 0) {
364
365 const char * const args[] = {
366 KEXEC, "-e", NULL
367 };
368
cb7ec564 369 /* Child */
477def80 370
cb7ec564 371 execv(args[0], (char * const *) args);
477def80
LP
372 _exit(EXIT_FAILURE);
373 } else
374 wait_for_terminate_and_warn("kexec", pid);
b1b2a107 375 }
e61cd186
LP
376
377 cmd = RB_AUTOBOOT;
477def80 378 /* Fall through */
b1b2a107 379
477def80
LP
380 case RB_AUTOBOOT:
381
382 if (!in_container) {
383 _cleanup_free_ char *param = NULL;
384
385 if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
386 log_info("Rebooting with argument '%s'.", param);
f07756bf 387 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
477def80
LP
388 }
389 }
390
391 log_info("Rebooting.");
392 break;
393
394 case RB_POWER_OFF:
395 log_info("Powering off.");
396 break;
397
398 case RB_HALT_SYSTEM:
399 log_info("Halting system.");
400 break;
401
402 default:
403 assert_not_reached("Unknown magic");
404 }
cb7ec564 405
477def80 406 reboot(cmd);
cb7ec564
LP
407 if (errno == EPERM && in_container) {
408 /* If we are in a container, and we lacked
409 * CAP_SYS_BOOT just exit, this will kill our
410 * container for good. */
477def80 411 log_info("Exiting container.");
cb7ec564
LP
412 exit(0);
413 }
414
56f64d95 415 log_error_errno(errno, "Failed to invoke reboot(): %m");
e61cd186 416 r = -errno;
b1b2a107
FF
417
418 error:
da927ba9 419 log_emergency_errno(r, "Critical error while doing system shutdown: %m");
e61cd186 420
b1b2a107 421 freeze();
b1b2a107 422}