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"
52 #define FINALIZE_ATTEMPTS 50
54 static int prepare_new_root(void) {
55 static const char dirs[] =
56 "/run/initramfs/oldroot\0"
57 "/run/initramfs/proc\0"
58 "/run/initramfs/sys\0"
59 "/run/initramfs/dev\0"
60 "/run/initramfs/run\0";
64 if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) {
65 log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m");
69 if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) {
70 log_error("Failed to make /run/initramfs private mount: %m");
74 NULSTR_FOREACH(dir, dirs)
75 if (mkdir_p_label(dir, 0755) < 0 && errno != EEXIST) {
76 log_error("Failed to mkdir %s: %m", dir);
80 if (mount("/sys", "/run/initramfs/sys", NULL, MS_BIND, NULL) < 0) {
81 log_error("Failed to mount bind /sys on /run/initramfs/sys: %m");
85 if (mount("/proc", "/run/initramfs/proc", NULL, MS_BIND, NULL) < 0) {
86 log_error("Failed to mount bind /proc on /run/initramfs/proc: %m");
90 if (mount("/dev", "/run/initramfs/dev", NULL, MS_BIND, NULL) < 0) {
91 log_error("Failed to mount bind /dev on /run/initramfs/dev: %m");
95 if (mount("/run", "/run/initramfs/run", NULL, MS_BIND, NULL) < 0) {
96 log_error("Failed to mount bind /run on /run/initramfs/run: %m");
103 static int pivot_to_new_root(void) {
105 if (chdir("/run/initramfs") < 0) {
106 log_error("Failed to change directory to /run/initramfs: %m");
110 /* Work-around for a kernel bug: for some reason the kernel
111 * refuses switching root if any file systems are mounted
112 * MS_SHARED. Hence remount them MS_PRIVATE here as a
115 * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */
116 if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0)
117 log_warning("Failed to make \"/\" private mount: %m");
119 if (pivot_root(".", "oldroot") < 0) {
120 log_error("pivot failed: %m");
121 /* only chroot if pivot root succeeded */
128 make_console_stdio();
130 log_info("Successfully changed into root pivot.");
135 int main(int argc, char *argv[]) {
136 bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
137 bool in_container, use_watchdog = false;
138 _cleanup_free_ char *line = NULL, *cgroup = NULL, *param = NULL;
143 /* suppress shutdown status output if 'quiet' is used */
144 r = proc_cmdline(&line);
149 FOREACH_WORD_QUOTED(w, l, line, state) {
150 if (l == 5 && memcmp(w, "quiet", 5) == 0) {
151 log_set_max_level(LOG_WARNING);
157 log_parse_environment();
158 log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
164 log_error("Not executed by init (pid 1).");
170 log_error("Invalid number of arguments.");
175 in_container = detect_container(NULL) > 0;
177 if (streq(argv[1], "reboot")) {
179 /* if this fails, that's OK */
180 read_one_line_file(REBOOT_PARAM_FILE, ¶m);
181 } else if (streq(argv[1], "poweroff"))
183 else if (streq(argv[1], "halt"))
184 cmd = RB_HALT_SYSTEM;
185 else if (streq(argv[1], "kexec"))
186 cmd = LINUX_REBOOT_CMD_KEXEC;
188 log_error("Unknown action '%s'.", argv[1]);
193 cg_get_root_path(&cgroup);
195 use_watchdog = !!getenv("WATCHDOG_USEC");
197 /* lock us into memory */
198 mlockall(MCL_CURRENT|MCL_FUTURE);
200 log_info("Sending SIGTERM to remaining processes...");
201 broadcast_signal(SIGTERM, true);
203 log_info("Sending SIGKILL to remaining processes...");
204 broadcast_signal(SIGKILL, true);
207 need_swapoff = false;
208 need_dm_detach = false;
209 need_loop_detach = false;
212 /* Unmount all mountpoints, swaps, and loopback devices */
213 for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
214 bool changed = false;
219 /* Let's trim the cgroup tree on each iteration so
220 that we leave an empty cgroup tree around, so that
221 container managers get a nice notify event when we
224 cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
227 log_info("Unmounting file systems.");
228 r = umount_all(&changed);
231 log_info("All filesystems unmounted.");
233 log_info("Not all file systems unmounted, %d left.", r);
235 log_error("Failed to unmount file systems: %s", strerror(-r));
239 log_info("Deactivating swaps.");
240 r = swapoff_all(&changed);
242 need_swapoff = false;
243 log_info("All swaps deactivated.");
245 log_info("Not all swaps deactivated, %d left.", r);
247 log_error("Failed to deactivate swaps: %s", strerror(-r));
250 if (need_loop_detach) {
251 log_info("Detaching loop devices.");
252 r = loopback_detach_all(&changed);
254 need_loop_detach = false;
255 log_info("All loop devices detached.");
257 log_info("Not all loop devices detached, %d left.", r);
259 log_error("Failed to detach loop devices: %s", strerror(-r));
262 if (need_dm_detach) {
263 log_info("Detaching DM devices.");
264 r = dm_detach_all(&changed);
266 need_dm_detach = false;
267 log_info("All DM devices detached.");
269 log_info("Not all DM devices detached, %d left.", r);
271 log_error("Failed to detach DM devices: %s", strerror(-r));
274 if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
276 log_info("All filesystems, swaps, loop devices, DM devices detached.");
281 /* If in this iteration we didn't manage to
282 * unmount/deactivate anything, we simply give up */
284 log_error("Cannot finalize remaining file systems and devices, giving up.");
288 log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1);
291 if (retries >= FINALIZE_ATTEMPTS)
292 log_error("Too many iterations, giving up.");
294 log_info("Storage is finalized.");
297 arguments[1] = argv[1];
299 execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments);
301 if (!in_container && !in_initrd() &&
302 access("/run/initramfs/shutdown", X_OK) == 0) {
304 if (prepare_new_root() >= 0 &&
305 pivot_to_new_root() >= 0) {
307 log_info("Returning to initrd...");
309 execv("/shutdown", argv);
310 log_error("Failed to execute shutdown binary: %m");
314 /* The kernel will automaticall flush ATA disks and suchlike
315 * on reboot(), but the file systems need to be synce'd
316 * explicitly in advance. So let's do this here, but not
317 * needlessly slow down containers. */
321 if (cmd == LINUX_REBOOT_CMD_KEXEC) {
324 /* We cheat and exec kexec to avoid doing all its work */
328 log_error("Could not fork: %m. Falling back to normal reboot.");
330 wait_for_terminate_and_warn("kexec", pid);
331 log_warning("kexec failed. Falling back to normal reboot.");
334 const char *args[3] = { KEXEC, "-e", NULL };
335 execv(args[0], (char * const *) args);
344 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
345 LINUX_REBOOT_CMD_RESTART2, param);
349 if (errno == EPERM && in_container) {
350 /* If we are in a container, and we lacked
351 * CAP_SYS_BOOT just exit, this will kill our
352 * container for good. */
353 log_error("Exiting container.");
357 log_error("Failed to invoke reboot(): %m");
361 log_error("Critical error while doing system shutdown: %s", strerror(-r));