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>
28 #include <sys/mount.h>
29 #include <sys/syscall.h>
49 #include "cgroup-util.h"
52 #define FINALIZE_ATTEMPTS 50
54 static char* arg_verb;
56 static int parse_argv(int argc, char *argv[]) {
58 ARG_LOG_LEVEL = 0x100,
64 static const struct option options[] = {
65 { "log-level", required_argument, NULL, ARG_LOG_LEVEL },
66 { "log-target", required_argument, NULL, ARG_LOG_TARGET },
67 { "log-color", optional_argument, NULL, ARG_LOG_COLOR },
68 { "log-location", optional_argument, NULL, ARG_LOG_LOCATION },
79 while ((c = getopt_long(argc, argv, ":", options, NULL)) >= 0)
83 r = log_set_max_level_from_string(optarg);
85 log_error("Failed to parse log level %s, ignoring.", optarg);
90 r = log_set_target_from_string(optarg);
92 log_error("Failed to parse log target %s, ignoring", optarg);
99 r = log_show_color_from_string(optarg);
101 log_error("Failed to parse log color setting %s, ignoring", optarg);
103 log_show_color(true);
107 case ARG_LOG_LOCATION:
109 r = log_show_location_from_string(optarg);
111 log_error("Failed to parse log location setting %s, ignoring", optarg);
113 log_show_location(true);
118 log_error("Unknown option %s.", argv[optind-1]);
122 log_error("Missing argument to %s.", argv[optind-1]);
126 assert_not_reached("Unhandled option code.");
129 if (optind >= argc) {
130 log_error("Verb argument missing.");
134 arg_verb = argv[optind];
136 if (optind + 1 < argc)
137 log_error("Excess arguments, ignoring");
141 static int prepare_new_root(void) {
142 static const char dirs[] =
143 "/run/initramfs/oldroot\0"
144 "/run/initramfs/proc\0"
145 "/run/initramfs/sys\0"
146 "/run/initramfs/dev\0"
147 "/run/initramfs/run\0";
151 if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) {
152 log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m");
156 if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) {
157 log_error("Failed to make /run/initramfs private mount: %m");
161 NULSTR_FOREACH(dir, dirs)
162 if (mkdir_p_label(dir, 0755) < 0 && errno != EEXIST) {
163 log_error("Failed to mkdir %s: %m", dir);
167 if (mount("/sys", "/run/initramfs/sys", NULL, MS_BIND, NULL) < 0) {
168 log_error("Failed to mount bind /sys on /run/initramfs/sys: %m");
172 if (mount("/proc", "/run/initramfs/proc", NULL, MS_BIND, NULL) < 0) {
173 log_error("Failed to mount bind /proc on /run/initramfs/proc: %m");
177 if (mount("/dev", "/run/initramfs/dev", NULL, MS_BIND, NULL) < 0) {
178 log_error("Failed to mount bind /dev on /run/initramfs/dev: %m");
182 if (mount("/run", "/run/initramfs/run", NULL, MS_BIND, NULL) < 0) {
183 log_error("Failed to mount bind /run on /run/initramfs/run: %m");
190 static int pivot_to_new_root(void) {
192 if (chdir("/run/initramfs") < 0) {
193 log_error("Failed to change directory to /run/initramfs: %m");
197 /* Work-around for a kernel bug: for some reason the kernel
198 * refuses switching root if any file systems are mounted
199 * MS_SHARED. Hence remount them MS_PRIVATE here as a
202 * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */
203 if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0)
204 log_warning("Failed to make \"/\" private mount: %m");
206 if (pivot_root(".", "oldroot") < 0) {
207 log_error("pivot failed: %m");
208 /* only chroot if pivot root succeeded */
215 make_console_stdio();
217 log_info("Successfully changed into root pivot.");
222 int main(int argc, char *argv[]) {
223 bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
224 bool in_container, use_watchdog = false;
225 _cleanup_free_ char *cgroup = NULL;
230 log_parse_environment();
231 r = parse_argv(argc, argv);
235 /* journald will die if not gone yet. The log target defaults
236 * to console, but may have been changed by commandline options. */
238 log_close_console(); /* force reopen of /dev/console */
244 log_error("Not executed by init (PID 1).");
249 if (streq(arg_verb, "reboot"))
251 else if (streq(arg_verb, "poweroff"))
253 else if (streq(arg_verb, "halt"))
254 cmd = RB_HALT_SYSTEM;
255 else if (streq(arg_verb, "kexec"))
256 cmd = LINUX_REBOOT_CMD_KEXEC;
259 log_error("Unknown action '%s'.", arg_verb);
263 cg_get_root_path(&cgroup);
265 use_watchdog = !!getenv("WATCHDOG_USEC");
267 /* lock us into memory */
268 mlockall(MCL_CURRENT|MCL_FUTURE);
270 log_info("Sending SIGTERM to remaining processes...");
271 broadcast_signal(SIGTERM, true, true);
273 log_info("Sending SIGKILL to remaining processes...");
274 broadcast_signal(SIGKILL, true, false);
276 in_container = detect_container(NULL) > 0;
279 need_swapoff = !in_container;
280 need_loop_detach = !in_container;
281 need_dm_detach = !in_container;
283 /* Unmount all mountpoints, swaps, and loopback devices */
284 for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
285 bool changed = false;
290 /* Let's trim the cgroup tree on each iteration so
291 that we leave an empty cgroup tree around, so that
292 container managers get a nice notify event when we
295 cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
298 log_info("Unmounting file systems.");
299 r = umount_all(&changed);
302 log_info("All filesystems unmounted.");
304 log_info("Not all file systems unmounted, %d left.", r);
306 log_error("Failed to unmount file systems: %s", strerror(-r));
310 log_info("Deactivating swaps.");
311 r = swapoff_all(&changed);
313 need_swapoff = false;
314 log_info("All swaps deactivated.");
316 log_info("Not all swaps deactivated, %d left.", r);
318 log_error("Failed to deactivate swaps: %s", strerror(-r));
321 if (need_loop_detach) {
322 log_info("Detaching loop devices.");
323 r = loopback_detach_all(&changed);
325 need_loop_detach = false;
326 log_info("All loop devices detached.");
328 log_info("Not all loop devices detached, %d left.", r);
330 log_error("Failed to detach loop devices: %s", strerror(-r));
333 if (need_dm_detach) {
334 log_info("Detaching DM devices.");
335 r = dm_detach_all(&changed);
337 need_dm_detach = false;
338 log_info("All DM devices detached.");
340 log_info("Not all DM devices detached, %d left.", r);
342 log_error("Failed to detach DM devices: %s", strerror(-r));
345 if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
347 log_info("All filesystems, swaps, loop devices, DM devices detached.");
352 /* If in this iteration we didn't manage to
353 * unmount/deactivate anything, we simply give up */
355 log_info("Cannot finalize remaining%s%s%s%s continuing.",
356 need_umount ? " file systems," : "",
357 need_swapoff ? " swap devices," : "",
358 need_loop_detach ? " loop devices," : "",
359 need_dm_detach ? " DM devices," : "");
363 log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
365 need_umount ? " file systems," : "",
366 need_swapoff ? " swap devices," : "",
367 need_loop_detach ? " loop devices," : "",
368 need_dm_detach ? " DM devices," : "");
371 log_error("Too many iterations, giving up.");
376 arguments[1] = arg_verb;
378 execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
380 if (!in_container && !in_initrd() &&
381 access("/run/initramfs/shutdown", X_OK) == 0) {
383 if (prepare_new_root() >= 0 &&
384 pivot_to_new_root() >= 0) {
385 arguments[0] = (char*) "/shutdown";
387 log_info("Returning to initrd...");
389 execv("/shutdown", arguments);
390 log_error("Failed to execute shutdown binary: %m");
394 if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
395 log_error("Failed to finalize %s%s%s%s ignoring",
396 need_umount ? " file systems," : "",
397 need_swapoff ? " swap devices," : "",
398 need_loop_detach ? " loop devices," : "",
399 need_dm_detach ? " DM devices," : "");
401 /* The kernel will automaticall flush ATA disks and suchlike
402 * on reboot(), but the file systems need to be synce'd
403 * explicitly in advance. So let's do this here, but not
404 * needlessly slow down containers. */
410 case LINUX_REBOOT_CMD_KEXEC:
413 /* We cheat and exec kexec to avoid doing all its work */
416 log_info("Rebooting with kexec.");
420 log_error("Failed to fork: %m");
423 const char * const args[] = {
429 execv(args[0], (char * const *) args);
432 wait_for_terminate_and_warn("kexec", pid);
441 _cleanup_free_ char *param = NULL;
443 if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) >= 0) {
444 log_info("Rebooting with argument '%s'.", param);
445 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
446 LINUX_REBOOT_CMD_RESTART2, param);
450 log_info("Rebooting.");
454 log_info("Powering off.");
458 log_info("Halting system.");
462 assert_not_reached("Unknown magic");
466 if (errno == EPERM && in_container) {
467 /* If we are in a container, and we lacked
468 * CAP_SYS_BOOT just exit, this will kill our
469 * container for good. */
470 log_info("Exiting container.");
474 log_error("Failed to invoke reboot(): %m");
478 log_error("Critical error while doing system shutdown: %s", strerror(-r));