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/>.
24 #include <linux/reboot.h>
29 #include <sys/mount.h>
30 #include <sys/reboot.h>
34 #include "cgroup-util.h"
40 #include "parse-util.h"
41 #include "process-util.h"
42 #include "string-util.h"
43 #include "switch-root.h"
44 #include "terminal-util.h"
50 #define FINALIZE_ATTEMPTS 50
52 static char* arg_verb
;
53 static uint8_t arg_exit_code
;
55 static int parse_argv(int argc
, char *argv
[]) {
57 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
},
69 { "exit-code", required_argument
, NULL
, ARG_EXIT_CODE
},
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);
119 r
= safe_atou8(optarg
, &arg_exit_code
);
121 log_error("Failed to parse exit code %s, ignoring", optarg
);
129 log_error("Excess arguments, ignoring");
136 assert_not_reached("Unhandled option code.");
140 log_error("Verb argument missing.");
147 static int switch_root_initramfs(void) {
148 if (mount("/run/initramfs", "/run/initramfs", NULL
, MS_BIND
, NULL
) < 0)
149 return log_error_errno(errno
, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
151 if (mount(NULL
, "/run/initramfs", NULL
, MS_PRIVATE
, NULL
) < 0)
152 return log_error_errno(errno
, "Failed to make /run/initramfs private mount: %m");
154 /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file descriptors.
155 * /run/initramfs/shutdown will take care of these.
156 * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
158 return switch_root("/run/initramfs", "/oldroot", false, MS_BIND
);
162 int main(int argc
, char *argv
[]) {
163 bool need_umount
, need_swapoff
, need_loop_detach
, need_dm_detach
;
164 bool in_container
, use_watchdog
= false;
165 _cleanup_free_
char *cgroup
= NULL
;
169 static const char* const dirs
[] = {SYSTEM_SHUTDOWN_PATH
, NULL
};
171 log_parse_environment();
172 r
= parse_argv(argc
, argv
);
176 /* journald will die if not gone yet. The log target defaults
177 * to console, but may have been changed by command line options. */
179 log_close_console(); /* force reopen of /dev/console */
185 log_error("Not executed by init (PID 1).");
190 if (streq(arg_verb
, "reboot"))
192 else if (streq(arg_verb
, "poweroff"))
194 else if (streq(arg_verb
, "halt"))
195 cmd
= RB_HALT_SYSTEM
;
196 else if (streq(arg_verb
, "kexec"))
197 cmd
= LINUX_REBOOT_CMD_KEXEC
;
198 else if (streq(arg_verb
, "exit"))
199 cmd
= 0; /* ignored, just checking that arg_verb is valid */
202 log_error("Unknown action '%s'.", arg_verb
);
206 cg_get_root_path(&cgroup
);
208 use_watchdog
= !!getenv("WATCHDOG_USEC");
210 /* lock us into memory */
211 mlockall(MCL_CURRENT
|MCL_FUTURE
);
213 log_info("Sending SIGTERM to remaining processes...");
214 broadcast_signal(SIGTERM
, true, true);
216 log_info("Sending SIGKILL to remaining processes...");
217 broadcast_signal(SIGKILL
, true, false);
219 in_container
= detect_container() > 0;
221 need_umount
= !in_container
;
222 need_swapoff
= !in_container
;
223 need_loop_detach
= !in_container
;
224 need_dm_detach
= !in_container
;
226 /* Unmount all mountpoints, swaps, and loopback devices */
227 for (retries
= 0; retries
< FINALIZE_ATTEMPTS
; retries
++) {
228 bool changed
= false;
233 /* Let's trim the cgroup tree on each iteration so
234 that we leave an empty cgroup tree around, so that
235 container managers get a nice notify event when we
238 cg_trim(SYSTEMD_CGROUP_CONTROLLER
, cgroup
, false);
241 log_info("Unmounting file systems.");
242 r
= umount_all(&changed
);
245 log_info("All filesystems unmounted.");
247 log_info("Not all file systems unmounted, %d left.", r
);
249 log_error_errno(r
, "Failed to unmount file systems: %m");
253 log_info("Deactivating swaps.");
254 r
= swapoff_all(&changed
);
256 need_swapoff
= false;
257 log_info("All swaps deactivated.");
259 log_info("Not all swaps deactivated, %d left.", r
);
261 log_error_errno(r
, "Failed to deactivate swaps: %m");
264 if (need_loop_detach
) {
265 log_info("Detaching loop devices.");
266 r
= loopback_detach_all(&changed
);
268 need_loop_detach
= false;
269 log_info("All loop devices detached.");
271 log_info("Not all loop devices detached, %d left.", r
);
273 log_error_errno(r
, "Failed to detach loop devices: %m");
276 if (need_dm_detach
) {
277 log_info("Detaching DM devices.");
278 r
= dm_detach_all(&changed
);
280 need_dm_detach
= false;
281 log_info("All DM devices detached.");
283 log_info("Not all DM devices detached, %d left.", r
);
285 log_error_errno(r
, "Failed to detach DM devices: %m");
288 if (!need_umount
&& !need_swapoff
&& !need_loop_detach
&& !need_dm_detach
) {
290 log_info("All filesystems, swaps, loop devices, DM devices detached.");
295 /* If in this iteration we didn't manage to
296 * unmount/deactivate anything, we simply give up */
298 log_info("Cannot finalize remaining%s%s%s%s continuing.",
299 need_umount
? " file systems," : "",
300 need_swapoff
? " swap devices," : "",
301 need_loop_detach
? " loop devices," : "",
302 need_dm_detach
? " DM devices," : "");
306 log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
308 need_umount
? " file systems," : "",
309 need_swapoff
? " swap devices," : "",
310 need_loop_detach
? " loop devices," : "",
311 need_dm_detach
? " DM devices," : "");
314 log_error("Too many iterations, giving up.");
319 arguments
[1] = arg_verb
;
321 execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, arguments
);
323 if (!in_container
&& !in_initrd() &&
324 access("/run/initramfs/shutdown", X_OK
) == 0) {
325 r
= switch_root_initramfs();
327 argv
[0] = (char*) "/shutdown";
330 make_console_stdio();
332 log_info("Successfully changed into root pivot.\n"
333 "Returning to initrd...");
335 execv("/shutdown", argv
);
336 log_error_errno(errno
, "Failed to execute shutdown binary: %m");
338 log_error_errno(r
, "Failed to switch root to \"/run/initramfs\": %m");
342 if (need_umount
|| need_swapoff
|| need_loop_detach
|| need_dm_detach
)
343 log_error("Failed to finalize %s%s%s%s ignoring",
344 need_umount
? " file systems," : "",
345 need_swapoff
? " swap devices," : "",
346 need_loop_detach
? " loop devices," : "",
347 need_dm_detach
? " DM devices," : "");
349 /* The kernel will automaticall flush ATA disks and suchlike
350 * on reboot(), but the file systems need to be synce'd
351 * explicitly in advance. So let's do this here, but not
352 * needlessly slow down containers. */
356 if (streq(arg_verb
, "exit")) {
360 /* We cannot exit() on the host, fallback on another
368 case LINUX_REBOOT_CMD_KEXEC
:
371 /* We cheat and exec kexec to avoid doing all its work */
374 log_info("Rebooting with kexec.");
378 log_error_errno(errno
, "Failed to fork: %m");
381 const char * const args
[] = {
387 execv(args
[0], (char * const *) args
);
390 wait_for_terminate_and_warn("kexec", pid
, true);
399 _cleanup_free_
char *param
= NULL
;
401 if (read_one_line_file(REBOOT_PARAM_FILE
, ¶m
) >= 0) {
402 log_info("Rebooting with argument '%s'.", param
);
403 syscall(SYS_reboot
, LINUX_REBOOT_MAGIC1
, LINUX_REBOOT_MAGIC2
, LINUX_REBOOT_CMD_RESTART2
, param
);
407 log_info("Rebooting.");
411 log_info("Powering off.");
415 log_info("Halting system.");
419 assert_not_reached("Unknown magic");
423 if (errno
== EPERM
&& in_container
) {
424 /* If we are in a container, and we lacked
425 * CAP_SYS_BOOT just exit, this will kill our
426 * container for good. */
427 log_info("Exiting container.");
431 r
= log_error_errno(errno
, "Failed to invoke reboot(): %m");
434 log_emergency_errno(r
, "Critical error while doing system shutdown: %m");