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"
51 #include "switch-root.h"
53 #define FINALIZE_ATTEMPTS 50
55 static char* arg_verb;
57 static int parse_argv(int argc, char *argv[]) {
59 ARG_LOG_LEVEL = 0x100,
65 static const struct option options[] = {
66 { "log-level", required_argument, NULL, ARG_LOG_LEVEL },
67 { "log-target", required_argument, NULL, ARG_LOG_TARGET },
68 { "log-color", optional_argument, NULL, ARG_LOG_COLOR },
69 { "log-location", optional_argument, NULL, ARG_LOG_LOCATION },
78 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
82 r = log_set_max_level_from_string(optarg);
84 log_error("Failed to parse log level %s, ignoring.", optarg);
89 r = log_set_target_from_string(optarg);
91 log_error("Failed to parse log target %s, ignoring", optarg);
98 r = log_show_color_from_string(optarg);
100 log_error("Failed to parse log color setting %s, ignoring", optarg);
102 log_show_color(true);
106 case ARG_LOG_LOCATION:
108 r = log_show_location_from_string(optarg);
110 log_error("Failed to parse log location setting %s, ignoring", optarg);
112 log_show_location(true);
120 assert_not_reached("Unhandled option code.");
123 if (optind >= argc) {
124 log_error("Verb argument missing.");
128 arg_verb = argv[optind];
130 if (optind + 1 < argc)
131 log_error("Excess arguments, ignoring");
135 static int switch_root_initramfs(void) {
136 if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) {
137 log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m");
141 if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) {
142 log_error("Failed to make /run/initramfs private mount: %m");
146 /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file desriptors.
147 * /run/initramfs/shutdown will take care of these.
148 * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
150 return switch_root("/run/initramfs", "/oldroot", false, MS_BIND);
154 int main(int argc, char *argv[]) {
155 bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
156 bool in_container, use_watchdog = false;
157 _cleanup_free_ char *cgroup = NULL;
162 log_parse_environment();
163 r = parse_argv(argc, argv);
167 /* journald will die if not gone yet. The log target defaults
168 * to console, but may have been changed by commandline options. */
170 log_close_console(); /* force reopen of /dev/console */
176 log_error("Not executed by init (PID 1).");
181 if (streq(arg_verb, "reboot"))
183 else if (streq(arg_verb, "poweroff"))
185 else if (streq(arg_verb, "halt"))
186 cmd = RB_HALT_SYSTEM;
187 else if (streq(arg_verb, "kexec"))
188 cmd = LINUX_REBOOT_CMD_KEXEC;
191 log_error("Unknown action '%s'.", arg_verb);
195 cg_get_root_path(&cgroup);
197 use_watchdog = !!getenv("WATCHDOG_USEC");
199 /* lock us into memory */
200 mlockall(MCL_CURRENT|MCL_FUTURE);
202 log_info("Sending SIGTERM to remaining processes...");
203 broadcast_signal(SIGTERM, true, true);
205 log_info("Sending SIGKILL to remaining processes...");
206 broadcast_signal(SIGKILL, true, false);
208 in_container = detect_container(NULL) > 0;
211 need_swapoff = !in_container;
212 need_loop_detach = !in_container;
213 need_dm_detach = !in_container;
215 /* Unmount all mountpoints, swaps, and loopback devices */
216 for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
217 bool changed = false;
222 /* Let's trim the cgroup tree on each iteration so
223 that we leave an empty cgroup tree around, so that
224 container managers get a nice notify event when we
227 cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
230 log_info("Unmounting file systems.");
231 r = umount_all(&changed);
234 log_info("All filesystems unmounted.");
236 log_info("Not all file systems unmounted, %d left.", r);
238 log_error("Failed to unmount file systems: %s", strerror(-r));
242 log_info("Deactivating swaps.");
243 r = swapoff_all(&changed);
245 need_swapoff = false;
246 log_info("All swaps deactivated.");
248 log_info("Not all swaps deactivated, %d left.", r);
250 log_error("Failed to deactivate swaps: %s", strerror(-r));
253 if (need_loop_detach) {
254 log_info("Detaching loop devices.");
255 r = loopback_detach_all(&changed);
257 need_loop_detach = false;
258 log_info("All loop devices detached.");
260 log_info("Not all loop devices detached, %d left.", r);
262 log_error("Failed to detach loop devices: %s", strerror(-r));
265 if (need_dm_detach) {
266 log_info("Detaching DM devices.");
267 r = dm_detach_all(&changed);
269 need_dm_detach = false;
270 log_info("All DM devices detached.");
272 log_info("Not all DM devices detached, %d left.", r);
274 log_error("Failed to detach DM devices: %s", strerror(-r));
277 if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
279 log_info("All filesystems, swaps, loop devices, DM devices detached.");
284 /* If in this iteration we didn't manage to
285 * unmount/deactivate anything, we simply give up */
287 log_info("Cannot finalize remaining%s%s%s%s continuing.",
288 need_umount ? " file systems," : "",
289 need_swapoff ? " swap devices," : "",
290 need_loop_detach ? " loop devices," : "",
291 need_dm_detach ? " DM devices," : "");
295 log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
297 need_umount ? " file systems," : "",
298 need_swapoff ? " swap devices," : "",
299 need_loop_detach ? " loop devices," : "",
300 need_dm_detach ? " DM devices," : "");
303 log_error("Too many iterations, giving up.");
308 arguments[1] = arg_verb;
310 execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
312 if (!in_container && !in_initrd() &&
313 access("/run/initramfs/shutdown", X_OK) == 0) {
314 r = switch_root_initramfs();
316 arguments[0] = (char*) "/shutdown";
319 make_console_stdio();
321 log_info("Successfully changed into root pivot.\n"
322 "Returning to initrd...");
324 execv("/shutdown", arguments);
325 log_error("Failed to execute shutdown binary: %m");
327 log_error("Failed to switch root to \"/run/initramfs\": %s", strerror(-r));
331 if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
332 log_error("Failed to finalize %s%s%s%s ignoring",
333 need_umount ? " file systems," : "",
334 need_swapoff ? " swap devices," : "",
335 need_loop_detach ? " loop devices," : "",
336 need_dm_detach ? " DM devices," : "");
338 /* The kernel will automaticall flush ATA disks and suchlike
339 * on reboot(), but the file systems need to be synce'd
340 * explicitly in advance. So let's do this here, but not
341 * needlessly slow down containers. */
347 case LINUX_REBOOT_CMD_KEXEC:
350 /* We cheat and exec kexec to avoid doing all its work */
353 log_info("Rebooting with kexec.");
357 log_error("Failed to fork: %m");
360 const char * const args[] = {
366 execv(args[0], (char * const *) args);
369 wait_for_terminate_and_warn("kexec", pid);
378 _cleanup_free_ char *param = NULL;
380 if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) >= 0) {
381 log_info("Rebooting with argument '%s'.", param);
382 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
386 log_info("Rebooting.");
390 log_info("Powering off.");
394 log_info("Halting system.");
398 assert_not_reached("Unknown magic");
402 if (errno == EPERM && in_container) {
403 /* If we are in a container, and we lacked
404 * CAP_SYS_BOOT just exit, this will kill our
405 * container for good. */
406 log_info("Exiting container.");
410 log_error("Failed to invoke reboot(): %m");
414 log_error("Critical error while doing system shutdown: %s", strerror(-r));