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