]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/shutdown.c
suppress status message output at shutdown when 'quiet' is given
[thirdparty/systemd.git] / src / core / shutdown.c
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
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>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/mount.h>
30 #include <sys/syscall.h>
31 #include <fcntl.h>
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
40 #include "missing.h"
41 #include "log.h"
42 #include "fileio.h"
43 #include "umount.h"
44 #include "util.h"
45 #include "mkdir.h"
46 #include "virt.h"
47 #include "watchdog.h"
48 #include "killall.h"
49
50 #define FINALIZE_ATTEMPTS 50
51
52 static 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)
73 if (mkdir_p_label(dir, 0755) < 0 && errno != EEXIST) {
74 log_error("Failed to mkdir %s: %m", dir);
75 return -errno;
76 }
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;
91 }
92
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;
99 }
100
101 static int pivot_to_new_root(void) {
102
103 if (chdir("/run/initramfs") < 0) {
104 log_error("Failed to change directory to /run/initramfs: %m");
105 return -errno;
106 }
107
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");
116
117 if (pivot_root(".", "oldroot") < 0) {
118 log_error("pivot failed: %m");
119 /* only chroot if pivot root succeeded */
120 return -errno;
121 }
122
123 chroot(".");
124
125 setsid();
126 make_console_stdio();
127
128 log_info("Successfully changed into root pivot.");
129
130 return 0;
131 }
132
133 int main(int argc, char *argv[]) {
134 _cleanup_free_ char *line = NULL;
135 int cmd, r;
136 unsigned retries;
137 bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
138 bool in_container, use_watchdog = false;
139 char *arguments[3];
140
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
154 log_parse_environment();
155 log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
156 log_open();
157
158 umask(0022);
159
160 if (getpid() != 1) {
161 log_error("Not executed by init (pid 1).");
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
172 in_container = detect_container(NULL) > 0;
173
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
188 use_watchdog = !!getenv("WATCHDOG_USEC");
189
190 /* lock us into memory */
191 mlockall(MCL_CURRENT|MCL_FUTURE);
192
193 log_info("Sending SIGTERM to remaining processes...");
194 broadcast_signal(SIGTERM, true);
195
196 log_info("Sending SIGKILL to remaining processes...");
197 broadcast_signal(SIGKILL, true);
198
199 if (in_container) {
200 need_swapoff = false;
201 need_dm_detach = false;
202 need_loop_detach = false;
203 }
204
205 /* Unmount all mountpoints, swaps, and loopback devices */
206 for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
207 bool changed = false;
208
209 if (use_watchdog)
210 watchdog_ping();
211
212 if (need_umount) {
213 log_info("Unmounting file systems.");
214 r = umount_all(&changed);
215 if (r == 0) {
216 need_umount = false;
217 log_info("All filesystems unmounted.");
218 } else if (r > 0)
219 log_info("Not all file systems unmounted, %d left.", r);
220 else
221 log_error("Failed to unmount file systems: %s", strerror(-r));
222 }
223
224 if (need_swapoff) {
225 log_info("Deactivating swaps.");
226 r = swapoff_all(&changed);
227 if (r == 0) {
228 need_swapoff = false;
229 log_info("All swaps deactivated.");
230 } else if (r > 0)
231 log_info("Not all swaps deactivated, %d left.", r);
232 else
233 log_error("Failed to deactivate swaps: %s", strerror(-r));
234 }
235
236 if (need_loop_detach) {
237 log_info("Detaching loop devices.");
238 r = loopback_detach_all(&changed);
239 if (r == 0) {
240 need_loop_detach = false;
241 log_info("All loop devices detached.");
242 } else if (r > 0)
243 log_info("Not all loop devices detached, %d left.", r);
244 else
245 log_error("Failed to detach loop devices: %s", strerror(-r));
246 }
247
248 if (need_dm_detach) {
249 log_info("Detaching DM devices.");
250 r = dm_detach_all(&changed);
251 if (r == 0) {
252 need_dm_detach = false;
253 log_info("All DM devices detached.");
254 } else if (r > 0)
255 log_info("Not all DM devices detached, %d left.", r);
256 else
257 log_error("Failed to detach DM devices: %s", strerror(-r));
258 }
259
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.");
263 /* Yay, done */
264 break;
265 }
266
267 /* If in this iteration we didn't manage to
268 * unmount/deactivate anything, we simply give up */
269 if (!changed) {
270 log_error("Cannot finalize remaining file systems and devices, giving up.");
271 break;
272 }
273
274 log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1);
275 }
276
277 if (retries >= FINALIZE_ATTEMPTS)
278 log_error("Too many iterations, giving up.");
279 else
280 log_info("Storage is finalized.");
281
282 arguments[0] = NULL;
283 arguments[1] = argv[1];
284 arguments[2] = NULL;
285 execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments);
286
287 if (!in_container && !in_initrd() &&
288 access("/run/initramfs/shutdown", X_OK) == 0) {
289
290 if (prepare_new_root() >= 0 &&
291 pivot_to_new_root() >= 0) {
292
293 log_info("Returning to initrd...");
294
295 execv("/shutdown", argv);
296 log_error("Failed to execute shutdown binary: %m");
297 }
298 }
299
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
307 if (cmd == LINUX_REBOOT_CMD_KEXEC) {
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 }
324 }
325
326 cmd = RB_AUTOBOOT;
327 }
328
329 reboot(cmd);
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
339 log_error("Failed to invoke reboot(): %m");
340 r = -errno;
341
342 error:
343 log_error("Critical error while doing system shutdown: %s", strerror(-r));
344
345 freeze();
346 return EXIT_FAILURE;
347 }