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"
54 #define FINALIZE_ATTEMPTS 50
56 static char* arg_verb
;
58 static int parse_argv(int argc
, char *argv
[]) {
60 ARG_LOG_LEVEL
= 0x100,
66 static const struct option options
[] = {
67 { "log-level", required_argument
, NULL
, ARG_LOG_LEVEL
},
68 { "log-target", required_argument
, NULL
, ARG_LOG_TARGET
},
69 { "log-color", optional_argument
, NULL
, ARG_LOG_COLOR
},
70 { "log-location", optional_argument
, NULL
, ARG_LOG_LOCATION
},
79 /* "-" prevents getopt from permuting argv[] and moving the verb away
80 * from argv[1]. Our interface to initrd promises it'll be there. */
81 while ((c
= getopt_long(argc
, argv
, "-", options
, NULL
)) >= 0)
85 r
= log_set_max_level_from_string(optarg
);
87 log_error("Failed to parse log level %s, ignoring.", optarg
);
92 r
= log_set_target_from_string(optarg
);
94 log_error("Failed to parse log target %s, ignoring", optarg
);
101 r
= log_show_color_from_string(optarg
);
103 log_error("Failed to parse log color setting %s, ignoring", optarg
);
105 log_show_color(true);
109 case ARG_LOG_LOCATION
:
111 r
= log_show_location_from_string(optarg
);
113 log_error("Failed to parse log location setting %s, ignoring", optarg
);
115 log_show_location(true);
123 log_error("Excess arguments, ignoring");
130 assert_not_reached("Unhandled option code.");
134 log_error("Verb argument missing.");
141 static int switch_root_initramfs(void) {
142 if (mount("/run/initramfs", "/run/initramfs", NULL
, MS_BIND
, NULL
) < 0)
143 return log_error_errno(errno
, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
145 if (mount(NULL
, "/run/initramfs", NULL
, MS_PRIVATE
, NULL
) < 0)
146 return log_error_errno(errno
, "Failed to make /run/initramfs private mount: %m");
148 /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file descriptors.
149 * /run/initramfs/shutdown will take care of these.
150 * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
152 return switch_root("/run/initramfs", "/oldroot", false, MS_BIND
);
156 int main(int argc
, char *argv
[]) {
157 bool need_umount
, need_swapoff
, need_loop_detach
, need_dm_detach
;
158 bool in_container
, use_watchdog
= false;
159 _cleanup_free_
char *cgroup
= NULL
;
163 static const char* const dirs
[] = {SYSTEM_SHUTDOWN_PATH
, NULL
};
165 log_parse_environment();
166 r
= parse_argv(argc
, argv
);
170 /* journald will die if not gone yet. The log target defaults
171 * to console, but may have been changed by command line options. */
173 log_close_console(); /* force reopen of /dev/console */
179 log_error("Not executed by init (PID 1).");
184 if (streq(arg_verb
, "reboot"))
186 else if (streq(arg_verb
, "poweroff"))
188 else if (streq(arg_verb
, "halt"))
189 cmd
= RB_HALT_SYSTEM
;
190 else if (streq(arg_verb
, "kexec"))
191 cmd
= LINUX_REBOOT_CMD_KEXEC
;
194 log_error("Unknown action '%s'.", arg_verb
);
198 cg_get_root_path(&cgroup
);
200 use_watchdog
= !!getenv("WATCHDOG_USEC");
202 /* lock us into memory */
203 mlockall(MCL_CURRENT
|MCL_FUTURE
);
205 log_info("Sending SIGTERM to remaining processes...");
206 broadcast_signal(SIGTERM
, true, true);
208 log_info("Sending SIGKILL to remaining processes...");
209 broadcast_signal(SIGKILL
, true, false);
211 in_container
= detect_container(NULL
) > 0;
213 need_umount
= !in_container
;
214 need_swapoff
= !in_container
;
215 need_loop_detach
= !in_container
;
216 need_dm_detach
= !in_container
;
218 /* Unmount all mountpoints, swaps, and loopback devices */
219 for (retries
= 0; retries
< FINALIZE_ATTEMPTS
; retries
++) {
220 bool changed
= false;
225 /* Let's trim the cgroup tree on each iteration so
226 that we leave an empty cgroup tree around, so that
227 container managers get a nice notify event when we
230 cg_trim(SYSTEMD_CGROUP_CONTROLLER
, cgroup
, false);
233 log_info("Unmounting file systems.");
234 r
= umount_all(&changed
);
237 log_info("All filesystems unmounted.");
239 log_info("Not all file systems unmounted, %d left.", r
);
241 log_error_errno(r
, "Failed to unmount file systems: %m");
245 log_info("Deactivating swaps.");
246 r
= swapoff_all(&changed
);
248 need_swapoff
= false;
249 log_info("All swaps deactivated.");
251 log_info("Not all swaps deactivated, %d left.", r
);
253 log_error_errno(r
, "Failed to deactivate swaps: %m");
256 if (need_loop_detach
) {
257 log_info("Detaching loop devices.");
258 r
= loopback_detach_all(&changed
);
260 need_loop_detach
= false;
261 log_info("All loop devices detached.");
263 log_info("Not all loop devices detached, %d left.", r
);
265 log_error_errno(r
, "Failed to detach loop devices: %m");
268 if (need_dm_detach
) {
269 log_info("Detaching DM devices.");
270 r
= dm_detach_all(&changed
);
272 need_dm_detach
= false;
273 log_info("All DM devices detached.");
275 log_info("Not all DM devices detached, %d left.", r
);
277 log_error_errno(r
, "Failed to detach DM devices: %m");
280 if (!need_umount
&& !need_swapoff
&& !need_loop_detach
&& !need_dm_detach
) {
282 log_info("All filesystems, swaps, loop devices, DM devices detached.");
287 /* If in this iteration we didn't manage to
288 * unmount/deactivate anything, we simply give up */
290 log_info("Cannot finalize remaining%s%s%s%s continuing.",
291 need_umount
? " file systems," : "",
292 need_swapoff
? " swap devices," : "",
293 need_loop_detach
? " loop devices," : "",
294 need_dm_detach
? " DM devices," : "");
298 log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
300 need_umount
? " file systems," : "",
301 need_swapoff
? " swap devices," : "",
302 need_loop_detach
? " loop devices," : "",
303 need_dm_detach
? " DM devices," : "");
306 log_error("Too many iterations, giving up.");
311 arguments
[1] = arg_verb
;
313 execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, arguments
);
315 if (!in_container
&& !in_initrd() &&
316 access("/run/initramfs/shutdown", X_OK
) == 0) {
317 r
= switch_root_initramfs();
319 argv
[0] = (char*) "/shutdown";
322 make_console_stdio();
324 log_info("Successfully changed into root pivot.\n"
325 "Returning to initrd...");
327 execv("/shutdown", argv
);
328 log_error_errno(errno
, "Failed to execute shutdown binary: %m");
330 log_error_errno(r
, "Failed to switch root to \"/run/initramfs\": %m");
334 if (need_umount
|| need_swapoff
|| need_loop_detach
|| need_dm_detach
)
335 log_error("Failed to finalize %s%s%s%s ignoring",
336 need_umount
? " file systems," : "",
337 need_swapoff
? " swap devices," : "",
338 need_loop_detach
? " loop devices," : "",
339 need_dm_detach
? " DM devices," : "");
341 /* The kernel will automaticall flush ATA disks and suchlike
342 * on reboot(), but the file systems need to be synce'd
343 * explicitly in advance. So let's do this here, but not
344 * needlessly slow down containers. */
350 case LINUX_REBOOT_CMD_KEXEC
:
353 /* We cheat and exec kexec to avoid doing all its work */
356 log_info("Rebooting with kexec.");
360 log_error_errno(errno
, "Failed to fork: %m");
363 const char * const args
[] = {
369 execv(args
[0], (char * const *) args
);
372 wait_for_terminate_and_warn("kexec", pid
, true);
381 _cleanup_free_
char *param
= NULL
;
383 if (read_one_line_file(REBOOT_PARAM_FILE
, ¶m
) >= 0) {
384 log_info("Rebooting with argument '%s'.", param
);
385 syscall(SYS_reboot
, LINUX_REBOOT_MAGIC1
, LINUX_REBOOT_MAGIC2
, LINUX_REBOOT_CMD_RESTART2
, param
);
389 log_info("Rebooting.");
393 log_info("Powering off.");
397 log_info("Halting system.");
401 assert_not_reached("Unknown magic");
405 if (errno
== EPERM
&& in_container
) {
406 /* If we are in a container, and we lacked
407 * CAP_SYS_BOOT just exit, this will kill our
408 * container for good. */
409 log_info("Exiting container.");
413 log_error_errno(errno
, "Failed to invoke reboot(): %m");
417 log_emergency_errno(r
, "Critical error while doing system shutdown: %m");