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 /* "-" prevents getopt from permuting argv[] and moving the verb away
79 * from argv[1]. Our interface to initrd promises it'll be there. */
80 while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0)
84 r = log_set_max_level_from_string(optarg);
86 log_error("Failed to parse log level %s, ignoring.", optarg);
91 r = log_set_target_from_string(optarg);
93 log_error("Failed to parse log target %s, ignoring", optarg);
100 r = log_show_color_from_string(optarg);
102 log_error("Failed to parse log color setting %s, ignoring", optarg);
104 log_show_color(true);
108 case ARG_LOG_LOCATION:
110 r = log_show_location_from_string(optarg);
112 log_error("Failed to parse log location setting %s, ignoring", optarg);
114 log_show_location(true);
122 log_error("Excess arguments, ignoring");
129 assert_not_reached("Unhandled option code.");
133 log_error("Verb argument missing.");
140 static int switch_root_initramfs(void) {
141 if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) {
142 log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m");
146 if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) {
147 log_error("Failed to make /run/initramfs private mount: %m");
151 /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file desriptors.
152 * /run/initramfs/shutdown will take care of these.
153 * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
155 return switch_root("/run/initramfs", "/oldroot", false, MS_BIND);
159 int main(int argc, char *argv[]) {
160 bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
161 bool in_container, use_watchdog = false;
162 _cleanup_free_ char *cgroup = NULL;
167 log_parse_environment();
168 r = parse_argv(argc, argv);
172 /* journald will die if not gone yet. The log target defaults
173 * to console, but may have been changed by command line options. */
175 log_close_console(); /* force reopen of /dev/console */
181 log_error("Not executed by init (PID 1).");
186 if (streq(arg_verb, "reboot"))
188 else if (streq(arg_verb, "poweroff"))
190 else if (streq(arg_verb, "halt"))
191 cmd = RB_HALT_SYSTEM;
192 else if (streq(arg_verb, "kexec"))
193 cmd = LINUX_REBOOT_CMD_KEXEC;
196 log_error("Unknown action '%s'.", arg_verb);
200 cg_get_root_path(&cgroup);
202 use_watchdog = !!getenv("WATCHDOG_USEC");
204 /* lock us into memory */
205 mlockall(MCL_CURRENT|MCL_FUTURE);
207 log_info("Sending SIGTERM to remaining processes...");
208 broadcast_signal(SIGTERM, true, true);
210 log_info("Sending SIGKILL to remaining processes...");
211 broadcast_signal(SIGKILL, true, false);
213 in_container = detect_container(NULL) > 0;
215 need_umount = !in_container;
216 need_swapoff = !in_container;
217 need_loop_detach = !in_container;
218 need_dm_detach = !in_container;
220 /* Unmount all mountpoints, swaps, and loopback devices */
221 for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
222 bool changed = false;
227 /* Let's trim the cgroup tree on each iteration so
228 that we leave an empty cgroup tree around, so that
229 container managers get a nice notify event when we
232 cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
235 log_info("Unmounting file systems.");
236 r = umount_all(&changed);
239 log_info("All filesystems unmounted.");
241 log_info("Not all file systems unmounted, %d left.", r);
243 log_error("Failed to unmount file systems: %s", strerror(-r));
247 log_info("Deactivating swaps.");
248 r = swapoff_all(&changed);
250 need_swapoff = false;
251 log_info("All swaps deactivated.");
253 log_info("Not all swaps deactivated, %d left.", r);
255 log_error("Failed to deactivate swaps: %s", strerror(-r));
258 if (need_loop_detach) {
259 log_info("Detaching loop devices.");
260 r = loopback_detach_all(&changed);
262 need_loop_detach = false;
263 log_info("All loop devices detached.");
265 log_info("Not all loop devices detached, %d left.", r);
267 log_error("Failed to detach loop devices: %s", strerror(-r));
270 if (need_dm_detach) {
271 log_info("Detaching DM devices.");
272 r = dm_detach_all(&changed);
274 need_dm_detach = false;
275 log_info("All DM devices detached.");
277 log_info("Not all DM devices detached, %d left.", r);
279 log_error("Failed to detach DM devices: %s", strerror(-r));
282 if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
284 log_info("All filesystems, swaps, loop devices, DM devices detached.");
289 /* If in this iteration we didn't manage to
290 * unmount/deactivate anything, we simply give up */
292 log_info("Cannot finalize remaining%s%s%s%s continuing.",
293 need_umount ? " file systems," : "",
294 need_swapoff ? " swap devices," : "",
295 need_loop_detach ? " loop devices," : "",
296 need_dm_detach ? " DM devices," : "");
300 log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
302 need_umount ? " file systems," : "",
303 need_swapoff ? " swap devices," : "",
304 need_loop_detach ? " loop devices," : "",
305 need_dm_detach ? " DM devices," : "");
308 log_error("Too many iterations, giving up.");
313 arguments[1] = arg_verb;
315 execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
317 if (!in_container && !in_initrd() &&
318 access("/run/initramfs/shutdown", X_OK) == 0) {
319 r = switch_root_initramfs();
321 argv[0] = (char*) "/shutdown";
324 make_console_stdio();
326 log_info("Successfully changed into root pivot.\n"
327 "Returning to initrd...");
329 execv("/shutdown", argv);
330 log_error("Failed to execute shutdown binary: %m");
332 log_error("Failed to switch root to \"/run/initramfs\": %s", strerror(-r));
336 if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
337 log_error("Failed to finalize %s%s%s%s ignoring",
338 need_umount ? " file systems," : "",
339 need_swapoff ? " swap devices," : "",
340 need_loop_detach ? " loop devices," : "",
341 need_dm_detach ? " DM devices," : "");
343 /* The kernel will automaticall flush ATA disks and suchlike
344 * on reboot(), but the file systems need to be synce'd
345 * explicitly in advance. So let's do this here, but not
346 * needlessly slow down containers. */
352 case LINUX_REBOOT_CMD_KEXEC:
355 /* We cheat and exec kexec to avoid doing all its work */
358 log_info("Rebooting with kexec.");
362 log_error("Failed to fork: %m");
365 const char * const args[] = {
371 execv(args[0], (char * const *) args);
374 wait_for_terminate_and_warn("kexec", pid);
383 _cleanup_free_ char *param = NULL;
385 if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) >= 0) {
386 log_info("Rebooting with argument '%s'.", param);
387 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
391 log_info("Rebooting.");
395 log_info("Powering off.");
399 log_info("Halting system.");
403 assert_not_reached("Unknown magic");
407 if (errno == EPERM && in_container) {
408 /* If we are in a container, and we lacked
409 * CAP_SYS_BOOT just exit, this will kill our
410 * container for good. */
411 log_info("Exiting container.");
415 log_error("Failed to invoke reboot(): %m");
419 log_error("Critical error while doing system shutdown: %s", strerror(-r));