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
;
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 else if (streq(argv
[1], "poweroff"))
181 else if (streq(argv
[1], "halt"))
182 cmd
= RB_HALT_SYSTEM
;
183 else if (streq(argv
[1], "kexec"))
184 cmd
= LINUX_REBOOT_CMD_KEXEC
;
186 log_error("Unknown action '%s'.", argv
[1]);
191 cg_get_root_path(&cgroup
);
193 use_watchdog
= !!getenv("WATCHDOG_USEC");
195 /* lock us into memory */
196 mlockall(MCL_CURRENT
|MCL_FUTURE
);
198 log_info("Sending SIGTERM to remaining processes...");
199 broadcast_signal(SIGTERM
, true);
201 log_info("Sending SIGKILL to remaining processes...");
202 broadcast_signal(SIGKILL
, true);
205 need_swapoff
= false;
206 need_dm_detach
= false;
207 need_loop_detach
= false;
210 /* Unmount all mountpoints, swaps, and loopback devices */
211 for (retries
= 0; retries
< FINALIZE_ATTEMPTS
; retries
++) {
212 bool changed
= false;
217 /* Let's trim the cgroup tree on each iteration so
218 that we leave an empty cgroup tree around, so that
219 container managers get a nice notify event when we
222 cg_trim(SYSTEMD_CGROUP_CONTROLLER
, cgroup
, false);
225 log_info("Unmounting file systems.");
226 r
= umount_all(&changed
);
229 log_info("All filesystems unmounted.");
231 log_info("Not all file systems unmounted, %d left.", r
);
233 log_error("Failed to unmount file systems: %s", strerror(-r
));
237 log_info("Deactivating swaps.");
238 r
= swapoff_all(&changed
);
240 need_swapoff
= false;
241 log_info("All swaps deactivated.");
243 log_info("Not all swaps deactivated, %d left.", r
);
245 log_error("Failed to deactivate swaps: %s", strerror(-r
));
248 if (need_loop_detach
) {
249 log_info("Detaching loop devices.");
250 r
= loopback_detach_all(&changed
);
252 need_loop_detach
= false;
253 log_info("All loop devices detached.");
255 log_info("Not all loop devices detached, %d left.", r
);
257 log_error("Failed to detach loop devices: %s", strerror(-r
));
260 if (need_dm_detach
) {
261 log_info("Detaching DM devices.");
262 r
= dm_detach_all(&changed
);
264 need_dm_detach
= false;
265 log_info("All DM devices detached.");
267 log_info("Not all DM devices detached, %d left.", r
);
269 log_error("Failed to detach DM devices: %s", strerror(-r
));
272 if (!need_umount
&& !need_swapoff
&& !need_loop_detach
&& !need_dm_detach
) {
274 log_info("All filesystems, swaps, loop devices, DM devices detached.");
279 /* If in this iteration we didn't manage to
280 * unmount/deactivate anything, we simply give up */
282 log_error("Cannot finalize remaining file systems and devices, giving up.");
286 log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries
+1);
289 if (retries
>= FINALIZE_ATTEMPTS
)
290 log_error("Too many iterations, giving up.");
292 log_info("Storage is finalized.");
295 arguments
[1] = argv
[1];
297 execute_directory(SYSTEM_SHUTDOWN_PATH
, NULL
, arguments
);
299 if (!in_container
&& !in_initrd() &&
300 access("/run/initramfs/shutdown", X_OK
) == 0) {
302 if (prepare_new_root() >= 0 &&
303 pivot_to_new_root() >= 0) {
305 log_info("Returning to initrd...");
307 execv("/shutdown", argv
);
308 log_error("Failed to execute shutdown binary: %m");
312 /* The kernel will automaticall flush ATA disks and suchlike
313 * on reboot(), but the file systems need to be synce'd
314 * explicitly in advance. So let's do this here, but not
315 * needlessly slow down containers. */
321 case LINUX_REBOOT_CMD_KEXEC
:
324 /* We cheat and exec kexec to avoid doing all its work */
327 log_info("Rebooting with kexec.");
331 log_error("Failed to fork: %m");
334 const char * const args
[] = {
340 execv(args
[0], (char * const *) args
);
343 wait_for_terminate_and_warn("kexec", pid
);
352 _cleanup_free_
char *param
= NULL
;
354 if (read_one_line_file(REBOOT_PARAM_FILE
, ¶m
) >= 0) {
355 log_info("Rebooting with argument '%s'.", param
);
356 syscall(SYS_reboot
, LINUX_REBOOT_MAGIC1
, LINUX_REBOOT_MAGIC2
,
357 LINUX_REBOOT_CMD_RESTART2
, param
);
361 log_info("Rebooting.");
365 log_info("Powering off.");
369 log_info("Halting system.");
373 assert_not_reached("Unknown magic");
377 if (errno
== EPERM
&& in_container
) {
378 /* If we are in a container, and we lacked
379 * CAP_SYS_BOOT just exit, this will kill our
380 * container for good. */
381 log_info("Exiting container.");
385 log_error("Failed to invoke reboot(): %m");
389 log_error("Critical error while doing system shutdown: %s", strerror(-r
));