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 #define FINALIZE_ATTEMPTS 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";
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");
66 if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) {
67 log_error("Failed to make /run/initramfs private mount: %m");
71 NULSTR_FOREACH(dir, dirs)
72 if (mkdir_p_label(dir, 0755) < 0 && errno != EEXIST) {
73 log_error("Failed to mkdir %s: %m", dir);
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");
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");
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");
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");
100 static int pivot_to_new_root(void) {
102 if (chdir("/run/initramfs") < 0) {
103 log_error("Failed to change directory to /run/initramfs: %m");
108 In case some evil process made "/" MS_SHARED
109 It works for pivot_root, but the ref count for the root device
110 is not decreasing :-/
112 if (mount(NULL, "/", NULL, MS_PRIVATE, NULL) < 0) {
113 log_error("Failed to make \"/\" private mount %m");
117 if (pivot_root(".", "oldroot") < 0) {
118 log_error("pivot failed: %m");
119 /* only chroot if pivot root succeeded */
126 make_console_stdio();
128 log_info("Successfully changed into root pivot.");
133 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;
140 log_parse_environment();
141 log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
147 log_error("Not executed by init (pid 1).");
153 log_error("Invalid number of arguments.");
158 in_container = detect_container(NULL) > 0;
160 if (streq(argv[1], "reboot"))
162 else if (streq(argv[1], "poweroff"))
164 else if (streq(argv[1], "halt"))
165 cmd = RB_HALT_SYSTEM;
166 else if (streq(argv[1], "kexec"))
167 cmd = LINUX_REBOOT_CMD_KEXEC;
169 log_error("Unknown action '%s'.", argv[1]);
174 use_watchdog = !!getenv("WATCHDOG_USEC");
176 /* lock us into memory */
177 mlockall(MCL_CURRENT|MCL_FUTURE);
179 log_info("Sending SIGTERM to remaining processes...");
180 broadcast_signal(SIGTERM, true);
182 log_info("Sending SIGKILL to remaining processes...");
183 broadcast_signal(SIGKILL, true);
186 need_swapoff = false;
187 need_dm_detach = false;
188 need_loop_detach = false;
191 /* Unmount all mountpoints, swaps, and loopback devices */
192 for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
193 bool changed = false;
199 log_info("Unmounting file systems.");
200 r = umount_all(&changed);
204 log_info("Not all file systems unmounted, %d left.", r);
206 log_error("Failed to unmount file systems: %s", strerror(-r));
210 log_info("Disabling swaps.");
211 r = swapoff_all(&changed);
213 need_swapoff = false;
215 log_info("Not all swaps are turned off, %d left.", r);
217 log_error("Failed to turn off swaps: %s", strerror(-r));
220 if (need_loop_detach) {
221 log_info("Detaching loop devices.");
222 r = loopback_detach_all(&changed);
224 need_loop_detach = false;
226 log_info("Not all loop devices detached, %d left.", r);
228 log_error("Failed to detach loop devices: %s", strerror(-r));
231 if (need_dm_detach) {
232 log_info("Detaching DM devices.");
233 r = dm_detach_all(&changed);
235 need_dm_detach = false;
237 log_warning("Not all DM devices detached, %d left.", r);
239 log_error("Failed to detach DM devices: %s", strerror(-r));
242 if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
244 log_info("All filesystems, swaps, loop devices, DM devices detached.");
249 /* If in this iteration we didn't manage to
250 * unmount/deactivate anything, we simply give up */
252 log_error("Cannot finalize remaining file systems and devices, giving up.");
256 log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1);
259 if (retries >= FINALIZE_ATTEMPTS)
260 log_error("Too many iterations, giving up.");
263 arguments[1] = argv[1];
265 execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments);
267 /* If we are in a container, just exit, this will kill our
268 * container for good. */
270 log_error("Exiting container.");
274 if (access("/run/initramfs/shutdown", X_OK) == 0) {
276 if (prepare_new_root() >= 0 &&
277 pivot_to_new_root() >= 0) {
278 execv("/shutdown", argv);
279 log_error("Failed to execute shutdown binary: %m");
285 if (cmd == LINUX_REBOOT_CMD_KEXEC) {
286 /* We cheat and exec kexec to avoid doing all its work */
290 log_error("Could not fork: %m. Falling back to normal reboot.");
292 wait_for_terminate_and_warn("kexec", pid);
293 log_warning("kexec failed. Falling back to normal reboot.");
296 const char *args[3] = { "/sbin/kexec", "-e", NULL };
297 execv(args[0], (char * const *) args);
305 log_error("Failed to invoke reboot(): %m");
309 log_error("Critical error while doing system shutdown: %s", strerror(-r));