]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/shutdown.c
suppress status message output at shutdown when 'quiet' is given
[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/types.h>
28#include <sys/stat.h>
29#include <sys/mount.h>
30#include <sys/syscall.h>
31#include <fcntl.h>
b1b2a107
FF
32#include <dirent.h>
33#include <errno.h>
34#include <unistd.h>
35#include <signal.h>
36#include <stdbool.h>
37#include <stdlib.h>
38#include <string.h>
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"
b1b2a107 49
b1b2a107 50#define FINALIZE_ATTEMPTS 50
b1b2a107 51
89d471d5
LP
52static int prepare_new_root(void) {
53 static const char dirs[] =
54 "/run/initramfs/oldroot\0"
55 "/run/initramfs/proc\0"
56 "/run/initramfs/sys\0"
57 "/run/initramfs/dev\0"
58 "/run/initramfs/run\0";
59
60 const char *dir;
61
62 if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) {
63 log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m");
64 return -errno;
65 }
66
67 if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) {
68 log_error("Failed to make /run/initramfs private mount: %m");
69 return -errno;
70 }
71
72 NULSTR_FOREACH(dir, dirs)
d2e54fae 73 if (mkdir_p_label(dir, 0755) < 0 && errno != EEXIST) {
89d471d5
LP
74 log_error("Failed to mkdir %s: %m", dir);
75 return -errno;
7cb1094a 76 }
89d471d5
LP
77
78 if (mount("/sys", "/run/initramfs/sys", NULL, MS_BIND, NULL) < 0) {
79 log_error("Failed to mount bind /sys on /run/initramfs/sys: %m");
80 return -errno;
81 }
82
83 if (mount("/proc", "/run/initramfs/proc", NULL, MS_BIND, NULL) < 0) {
84 log_error("Failed to mount bind /proc on /run/initramfs/proc: %m");
85 return -errno;
86 }
87
88 if (mount("/dev", "/run/initramfs/dev", NULL, MS_BIND, NULL) < 0) {
89 log_error("Failed to mount bind /dev on /run/initramfs/dev: %m");
90 return -errno;
7cb1094a
HH
91 }
92
89d471d5
LP
93 if (mount("/run", "/run/initramfs/run", NULL, MS_BIND, NULL) < 0) {
94 log_error("Failed to mount bind /run on /run/initramfs/run: %m");
95 return -errno;
96 }
97
98 return 0;
7cb1094a
HH
99}
100
89d471d5 101static int pivot_to_new_root(void) {
bd3fa1d2 102
cd3bd60a
LP
103 if (chdir("/run/initramfs") < 0) {
104 log_error("Failed to change directory to /run/initramfs: %m");
105 return -errno;
106 }
7cb1094a 107
f47fc355
LP
108 /* Work-around for a kernel bug: for some reason the kernel
109 * refuses switching root if any file systems are mounted
110 * MS_SHARED. Hence remount them MS_PRIVATE here as a
111 * work-around.
112 *
113 * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */
114 if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0)
115 log_warning("Failed to make \"/\" private mount: %m");
7cb1094a 116
89d471d5 117 if (pivot_root(".", "oldroot") < 0) {
7cb1094a 118 log_error("pivot failed: %m");
49f43d5f 119 /* only chroot if pivot root succeeded */
89d471d5 120 return -errno;
7cb1094a 121 }
89d471d5 122
7cb1094a 123 chroot(".");
89d471d5 124
cd3bd60a
LP
125 setsid();
126 make_console_stdio();
bccc1d88 127
cd3bd60a 128 log_info("Successfully changed into root pivot.");
89d471d5
LP
129
130 return 0;
7cb1094a
HH
131}
132
b1b2a107 133int main(int argc, char *argv[]) {
ec26be51 134 _cleanup_free_ char *line = NULL;
12aad1d0
LP
135 int cmd, r;
136 unsigned retries;
d48141ba 137 bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
bd3fa1d2 138 bool in_container, use_watchdog = false;
6edd7d0a 139 char *arguments[3];
b1b2a107 140
ec26be51
KS
141 /* suppress shutdown status output if 'quiet' is used */
142 r = read_one_line_file("/proc/cmdline", &line);
143 if (r >= 0) {
144 char *w, *state;
145 size_t l;
146
147 FOREACH_WORD_QUOTED(w, l, line, state)
148 if (streq(w, "quiet")) {
149 log_set_max_level(LOG_WARNING);
150 break;
151 }
152 }
153
b1b2a107 154 log_parse_environment();
2ca1b422 155 log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
b1b2a107
FF
156 log_open();
157
4c12626c
LP
158 umask(0022);
159
b1b2a107 160 if (getpid() != 1) {
567ea02a 161 log_error("Not executed by init (pid 1).");
b1b2a107
FF
162 r = -EPERM;
163 goto error;
164 }
165
166 if (argc != 2) {
167 log_error("Invalid number of arguments.");
168 r = -EINVAL;
169 goto error;
170 }
171
40e85d00
LP
172 in_container = detect_container(NULL) > 0;
173
b1b2a107
FF
174 if (streq(argv[1], "reboot"))
175 cmd = RB_AUTOBOOT;
176 else if (streq(argv[1], "poweroff"))
177 cmd = RB_POWER_OFF;
178 else if (streq(argv[1], "halt"))
179 cmd = RB_HALT_SYSTEM;
180 else if (streq(argv[1], "kexec"))
181 cmd = LINUX_REBOOT_CMD_KEXEC;
182 else {
183 log_error("Unknown action '%s'.", argv[1]);
184 r = -EINVAL;
185 goto error;
186 }
187
e96d6be7
LP
188 use_watchdog = !!getenv("WATCHDOG_USEC");
189
b1b2a107 190 /* lock us into memory */
b55d0651 191 mlockall(MCL_CURRENT|MCL_FUTURE);
b1b2a107 192
ab58e291 193 log_info("Sending SIGTERM to remaining processes...");
cee530bb 194 broadcast_signal(SIGTERM, true);
b1b2a107 195
ab58e291 196 log_info("Sending SIGKILL to remaining processes...");
cee530bb 197 broadcast_signal(SIGKILL, true);
40e85d00 198
ff644623 199 if (in_container) {
40e85d00 200 need_swapoff = false;
ff644623 201 need_dm_detach = false;
910212e7 202 need_loop_detach = false;
ff644623 203 }
b1b2a107 204
567ea02a 205 /* Unmount all mountpoints, swaps, and loopback devices */
12aad1d0
LP
206 for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
207 bool changed = false;
208
e96d6be7
LP
209 if (use_watchdog)
210 watchdog_ping();
211
b1b2a107 212 if (need_umount) {
ab58e291 213 log_info("Unmounting file systems.");
12aad1d0 214 r = umount_all(&changed);
bce93b7a 215 if (r == 0) {
b1b2a107 216 need_umount = false;
bce93b7a
MS
217 log_info("All filesystems unmounted.");
218 } else if (r > 0)
ab58e291 219 log_info("Not all file systems unmounted, %d left.", r);
b1b2a107 220 else
ab58e291 221 log_error("Failed to unmount file systems: %s", strerror(-r));
b1b2a107
FF
222 }
223
224 if (need_swapoff) {
735e0712 225 log_info("Deactivating swaps.");
12aad1d0 226 r = swapoff_all(&changed);
bce93b7a 227 if (r == 0) {
b1b2a107 228 need_swapoff = false;
735e0712 229 log_info("All swaps deactivated.");
bce93b7a 230 } else if (r > 0)
735e0712 231 log_info("Not all swaps deactivated, %d left.", r);
b1b2a107 232 else
735e0712 233 log_error("Failed to deactivate swaps: %s", strerror(-r));
b1b2a107
FF
234 }
235
236 if (need_loop_detach) {
237 log_info("Detaching loop devices.");
12aad1d0 238 r = loopback_detach_all(&changed);
bce93b7a 239 if (r == 0) {
b1b2a107 240 need_loop_detach = false;
bce93b7a
MS
241 log_info("All loop devices detached.");
242 } else if (r > 0)
ab58e291 243 log_info("Not all loop devices detached, %d left.", r);
b1b2a107 244 else
ab58e291 245 log_error("Failed to detach loop devices: %s", strerror(-r));
d48141ba 246 }
b1b2a107 247
d48141ba
LP
248 if (need_dm_detach) {
249 log_info("Detaching DM devices.");
12aad1d0 250 r = dm_detach_all(&changed);
bce93b7a 251 if (r == 0) {
d48141ba 252 need_dm_detach = false;
bce93b7a
MS
253 log_info("All DM devices detached.");
254 } else if (r > 0)
2569a5ce 255 log_info("Not all DM devices detached, %d left.", r);
d48141ba 256 else
ab58e291 257 log_error("Failed to detach DM devices: %s", strerror(-r));
b1b2a107
FF
258 }
259
a27d2184
KS
260 if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
261 if (retries > 0)
262 log_info("All filesystems, swaps, loop devices, DM devices detached.");
12aad1d0
LP
263 /* Yay, done */
264 break;
a27d2184 265 }
b1b2a107 266
12aad1d0 267 /* If in this iteration we didn't manage to
bd3fa1d2 268 * unmount/deactivate anything, we simply give up */
12aad1d0 269 if (!changed) {
bd3fa1d2
LP
270 log_error("Cannot finalize remaining file systems and devices, giving up.");
271 break;
12aad1d0
LP
272 }
273
ab58e291 274 log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1);
b1b2a107
FF
275 }
276
12aad1d0 277 if (retries >= FINALIZE_ATTEMPTS)
35b8ca3a 278 log_error("Too many iterations, giving up.");
5989dbb2
LP
279 else
280 log_info("Storage is finalized.");
12aad1d0 281
6edd7d0a
LP
282 arguments[0] = NULL;
283 arguments[1] = argv[1];
284 arguments[2] = NULL;
285 execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments);
83cc030f 286
02eaa788 287 if (!in_container && !in_initrd() &&
cb7ec564 288 access("/run/initramfs/shutdown", X_OK) == 0) {
89d471d5
LP
289
290 if (prepare_new_root() >= 0 &&
291 pivot_to_new_root() >= 0) {
30d743f4
LP
292
293 log_info("Returning to initrd...");
294
89d471d5 295 execv("/shutdown", argv);
7cb1094a
HH
296 log_error("Failed to execute shutdown binary: %m");
297 }
298 }
299
0049f05a
LP
300 /* The kernel will automaticall flush ATA disks and suchlike
301 * on reboot(), but the file systems need to be synce'd
302 * explicitly in advance. So let's do this here, but not
303 * needlessly slow down containers. */
304 if (!in_container)
305 sync();
306
b1b2a107 307 if (cmd == LINUX_REBOOT_CMD_KEXEC) {
cb7ec564
LP
308
309 if (!in_container) {
310 /* We cheat and exec kexec to avoid doing all its work */
311 pid_t pid = fork();
312
313 if (pid < 0)
314 log_error("Could not fork: %m. Falling back to normal reboot.");
315 else if (pid > 0) {
316 wait_for_terminate_and_warn("kexec", pid);
317 log_warning("kexec failed. Falling back to normal reboot.");
318 } else {
319 /* Child */
320 const char *args[3] = { "/sbin/kexec", "-e", NULL };
321 execv(args[0], (char * const *) args);
322 return EXIT_FAILURE;
323 }
b1b2a107 324 }
e61cd186
LP
325
326 cmd = RB_AUTOBOOT;
b1b2a107
FF
327 }
328
329 reboot(cmd);
cb7ec564
LP
330
331 if (errno == EPERM && in_container) {
332 /* If we are in a container, and we lacked
333 * CAP_SYS_BOOT just exit, this will kill our
334 * container for good. */
335 log_error("Exiting container.");
336 exit(0);
337 }
338
e61cd186
LP
339 log_error("Failed to invoke reboot(): %m");
340 r = -errno;
b1b2a107
FF
341
342 error:
e61cd186
LP
343 log_error("Critical error while doing system shutdown: %s", strerror(-r));
344
b1b2a107 345 freeze();
3c14d26c 346 return EXIT_FAILURE;
b1b2a107 347}