1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 ProFUSION embedded systems
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.
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.
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/>.
23 #include <sys/types.h>
24 #include <sys/reboot.h>
25 #include <linux/reboot.h>
27 #include <sys/types.h>
29 #include <sys/mount.h>
30 #include <sys/syscall.h>
49 #include "cgroup-util.h"
51 #define FINALIZE_ATTEMPTS 50
53 static int prepare_new_root(void) {
54 static const char dirs
[] =
55 "/run/initramfs/oldroot\0"
56 "/run/initramfs/proc\0"
57 "/run/initramfs/sys\0"
58 "/run/initramfs/dev\0"
59 "/run/initramfs/run\0";
63 if (mount("/run/initramfs", "/run/initramfs", NULL
, MS_BIND
, NULL
) < 0) {
64 log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m");
68 if (mount(NULL
, "/run/initramfs", NULL
, MS_PRIVATE
, NULL
) < 0) {
69 log_error("Failed to make /run/initramfs private mount: %m");
73 NULSTR_FOREACH(dir
, dirs
)
74 if (mkdir_p_label(dir
, 0755) < 0 && errno
!= EEXIST
) {
75 log_error("Failed to mkdir %s: %m", dir
);
79 if (mount("/sys", "/run/initramfs/sys", NULL
, MS_BIND
, NULL
) < 0) {
80 log_error("Failed to mount bind /sys on /run/initramfs/sys: %m");
84 if (mount("/proc", "/run/initramfs/proc", NULL
, MS_BIND
, NULL
) < 0) {
85 log_error("Failed to mount bind /proc on /run/initramfs/proc: %m");
89 if (mount("/dev", "/run/initramfs/dev", NULL
, MS_BIND
, NULL
) < 0) {
90 log_error("Failed to mount bind /dev on /run/initramfs/dev: %m");
94 if (mount("/run", "/run/initramfs/run", NULL
, MS_BIND
, NULL
) < 0) {
95 log_error("Failed to mount bind /run on /run/initramfs/run: %m");
102 static int pivot_to_new_root(void) {
104 if (chdir("/run/initramfs") < 0) {
105 log_error("Failed to change directory to /run/initramfs: %m");
109 /* Work-around for a kernel bug: for some reason the kernel
110 * refuses switching root if any file systems are mounted
111 * MS_SHARED. Hence remount them MS_PRIVATE here as a
114 * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */
115 if (mount(NULL
, "/", NULL
, MS_REC
|MS_PRIVATE
, NULL
) < 0)
116 log_warning("Failed to make \"/\" private mount: %m");
118 if (pivot_root(".", "oldroot") < 0) {
119 log_error("pivot failed: %m");
120 /* only chroot if pivot root succeeded */
127 make_console_stdio();
129 log_info("Successfully changed into root pivot.");
134 int main(int argc
, char *argv
[]) {
135 bool need_umount
= true, need_swapoff
= true, need_loop_detach
= true, need_dm_detach
= true;
136 bool in_container
, use_watchdog
= false;
137 _cleanup_free_
char *line
= NULL
, *cgroup
= NULL
;
142 /* suppress shutdown status output if 'quiet' is used */
143 r
= proc_cmdline(&line
);
148 FOREACH_WORD_QUOTED(w
, l
, line
, state
) {
149 if (l
== 5 && memcmp(w
, "quiet", 5) == 0) {
150 log_set_max_level(LOG_WARNING
);
156 log_parse_environment();
157 log_set_target(LOG_TARGET_CONSOLE
); /* syslog will die if not gone yet */
163 log_error("Not executed by init (pid 1).");
169 log_error("Invalid number of arguments.");
174 in_container
= detect_container(NULL
) > 0;
176 if (streq(argv
[1], "reboot"))
178 else if (streq(argv
[1], "poweroff"))
180 else if (streq(argv
[1], "halt"))
181 cmd
= RB_HALT_SYSTEM
;
182 else if (streq(argv
[1], "kexec"))
183 cmd
= LINUX_REBOOT_CMD_KEXEC
;
185 log_error("Unknown action '%s'.", argv
[1]);
190 cg_get_root_path(&cgroup
);
192 use_watchdog
= !!getenv("WATCHDOG_USEC");
194 /* lock us into memory */
195 mlockall(MCL_CURRENT
|MCL_FUTURE
);
197 log_info("Sending SIGTERM to remaining processes...");
198 broadcast_signal(SIGTERM
, true);
200 log_info("Sending SIGKILL to remaining processes...");
201 broadcast_signal(SIGKILL
, true);
204 need_swapoff
= false;
205 need_dm_detach
= false;
206 need_loop_detach
= false;
209 /* Unmount all mountpoints, swaps, and loopback devices */
210 for (retries
= 0; retries
< FINALIZE_ATTEMPTS
; retries
++) {
211 bool changed
= false;
216 /* Let's trim the cgroup tree on each iteration so
217 that we leave an empty cgroup tree around, so that
218 container managers get a nice notify event when we
221 cg_trim(SYSTEMD_CGROUP_CONTROLLER
, cgroup
, false);
224 log_info("Unmounting file systems.");
225 r
= umount_all(&changed
);
228 log_info("All filesystems unmounted.");
230 log_info("Not all file systems unmounted, %d left.", r
);
232 log_error("Failed to unmount file systems: %s", strerror(-r
));
236 log_info("Deactivating swaps.");
237 r
= swapoff_all(&changed
);
239 need_swapoff
= false;
240 log_info("All swaps deactivated.");
242 log_info("Not all swaps deactivated, %d left.", r
);
244 log_error("Failed to deactivate swaps: %s", strerror(-r
));
247 if (need_loop_detach
) {
248 log_info("Detaching loop devices.");
249 r
= loopback_detach_all(&changed
);
251 need_loop_detach
= false;
252 log_info("All loop devices detached.");
254 log_info("Not all loop devices detached, %d left.", r
);
256 log_error("Failed to detach loop devices: %s", strerror(-r
));
259 if (need_dm_detach
) {
260 log_info("Detaching DM devices.");
261 r
= dm_detach_all(&changed
);
263 need_dm_detach
= false;
264 log_info("All DM devices detached.");
266 log_info("Not all DM devices detached, %d left.", r
);
268 log_error("Failed to detach DM devices: %s", strerror(-r
));
271 if (!need_umount
&& !need_swapoff
&& !need_loop_detach
&& !need_dm_detach
) {
273 log_info("All filesystems, swaps, loop devices, DM devices detached.");
278 /* If in this iteration we didn't manage to
279 * unmount/deactivate anything, we simply give up */
281 log_error("Cannot finalize remaining file systems and devices, giving up.");
285 log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries
+1);
288 if (retries
>= FINALIZE_ATTEMPTS
)
289 log_error("Too many iterations, giving up.");
291 log_info("Storage is finalized.");
294 arguments
[1] = argv
[1];
296 execute_directory(SYSTEM_SHUTDOWN_PATH
, NULL
, arguments
);
298 if (!in_container
&& !in_initrd() &&
299 access("/run/initramfs/shutdown", X_OK
) == 0) {
301 if (prepare_new_root() >= 0 &&
302 pivot_to_new_root() >= 0) {
304 log_info("Returning to initrd...");
306 execv("/shutdown", argv
);
307 log_error("Failed to execute shutdown binary: %m");
311 /* The kernel will automaticall flush ATA disks and suchlike
312 * on reboot(), but the file systems need to be synce'd
313 * explicitly in advance. So let's do this here, but not
314 * needlessly slow down containers. */
318 if (cmd
== LINUX_REBOOT_CMD_KEXEC
) {
321 /* We cheat and exec kexec to avoid doing all its work */
325 log_error("Could not fork: %m. Falling back to normal reboot.");
327 wait_for_terminate_and_warn("kexec", pid
);
328 log_warning("kexec failed. Falling back to normal reboot.");
331 const char *args
[3] = { KEXEC
, "-e", NULL
};
332 execv(args
[0], (char * const *) args
);
342 if (errno
== EPERM
&& in_container
) {
343 /* If we are in a container, and we lacked
344 * CAP_SYS_BOOT just exit, this will kill our
345 * container for good. */
346 log_error("Exiting container.");
350 log_error("Failed to invoke reboot(): %m");
354 log_error("Critical error while doing system shutdown: %s", strerror(-r
));