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/reboot.h>
24 #include <linux/reboot.h>
26 #include <sys/mount.h>
42 #include "cgroup-util.h"
44 #include "switch-root.h"
45 #include "process-util.h"
46 #include "terminal-util.h"
48 #define FINALIZE_ATTEMPTS 50
50 static char* arg_verb
;
51 static uint8_t arg_exit_code
;
53 static int parse_argv(int argc
, char *argv
[]) {
55 ARG_LOG_LEVEL
= 0x100,
62 static const struct option options
[] = {
63 { "log-level", required_argument
, NULL
, ARG_LOG_LEVEL
},
64 { "log-target", required_argument
, NULL
, ARG_LOG_TARGET
},
65 { "log-color", optional_argument
, NULL
, ARG_LOG_COLOR
},
66 { "log-location", optional_argument
, NULL
, ARG_LOG_LOCATION
},
67 { "exit-code", required_argument
, NULL
, ARG_EXIT_CODE
},
76 /* "-" prevents getopt from permuting argv[] and moving the verb away
77 * from argv[1]. Our interface to initrd promises it'll be there. */
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);
117 r
= safe_atou8(optarg
, &arg_exit_code
);
119 log_error("Failed to parse exit code %s, ignoring", optarg
);
127 log_error("Excess arguments, ignoring");
134 assert_not_reached("Unhandled option code.");
138 log_error("Verb argument missing.");
145 static int switch_root_initramfs(void) {
146 if (mount("/run/initramfs", "/run/initramfs", NULL
, MS_BIND
, NULL
) < 0)
147 return log_error_errno(errno
, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
149 if (mount(NULL
, "/run/initramfs", NULL
, MS_PRIVATE
, NULL
) < 0)
150 return log_error_errno(errno
, "Failed to make /run/initramfs private mount: %m");
152 /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file descriptors.
153 * /run/initramfs/shutdown will take care of these.
154 * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
156 return switch_root("/run/initramfs", "/oldroot", false, MS_BIND
);
160 int main(int argc
, char *argv
[]) {
161 bool need_umount
, need_swapoff
, need_loop_detach
, need_dm_detach
;
162 bool in_container
, use_watchdog
= false;
163 _cleanup_free_
char *cgroup
= NULL
;
167 static const char* const dirs
[] = {SYSTEM_SHUTDOWN_PATH
, NULL
};
169 log_parse_environment();
170 r
= parse_argv(argc
, argv
);
174 /* journald will die if not gone yet. The log target defaults
175 * to console, but may have been changed by command line options. */
177 log_close_console(); /* force reopen of /dev/console */
183 log_error("Not executed by init (PID 1).");
188 if (streq(arg_verb
, "reboot"))
190 else if (streq(arg_verb
, "poweroff"))
192 else if (streq(arg_verb
, "halt"))
193 cmd
= RB_HALT_SYSTEM
;
194 else if (streq(arg_verb
, "kexec"))
195 cmd
= LINUX_REBOOT_CMD_KEXEC
;
196 else if (streq(arg_verb
, "exit"))
197 cmd
= 0; /* ignored, just checking that arg_verb is valid */
200 log_error("Unknown action '%s'.", arg_verb
);
204 cg_get_root_path(&cgroup
);
206 use_watchdog
= !!getenv("WATCHDOG_USEC");
208 /* lock us into memory */
209 mlockall(MCL_CURRENT
|MCL_FUTURE
);
211 log_info("Sending SIGTERM to remaining processes...");
212 broadcast_signal(SIGTERM
, true, true);
214 log_info("Sending SIGKILL to remaining processes...");
215 broadcast_signal(SIGKILL
, true, false);
217 in_container
= detect_container() > 0;
219 need_umount
= !in_container
;
220 need_swapoff
= !in_container
;
221 need_loop_detach
= !in_container
;
222 need_dm_detach
= !in_container
;
224 /* Unmount all mountpoints, swaps, and loopback devices */
225 for (retries
= 0; retries
< FINALIZE_ATTEMPTS
; retries
++) {
226 bool changed
= false;
231 /* Let's trim the cgroup tree on each iteration so
232 that we leave an empty cgroup tree around, so that
233 container managers get a nice notify event when we
236 cg_trim(SYSTEMD_CGROUP_CONTROLLER
, cgroup
, false);
239 log_info("Unmounting file systems.");
240 r
= umount_all(&changed
);
243 log_info("All filesystems unmounted.");
245 log_info("Not all file systems unmounted, %d left.", r
);
247 log_error_errno(r
, "Failed to unmount file systems: %m");
251 log_info("Deactivating swaps.");
252 r
= swapoff_all(&changed
);
254 need_swapoff
= false;
255 log_info("All swaps deactivated.");
257 log_info("Not all swaps deactivated, %d left.", r
);
259 log_error_errno(r
, "Failed to deactivate swaps: %m");
262 if (need_loop_detach
) {
263 log_info("Detaching loop devices.");
264 r
= loopback_detach_all(&changed
);
266 need_loop_detach
= false;
267 log_info("All loop devices detached.");
269 log_info("Not all loop devices detached, %d left.", r
);
271 log_error_errno(r
, "Failed to detach loop devices: %m");
274 if (need_dm_detach
) {
275 log_info("Detaching DM devices.");
276 r
= dm_detach_all(&changed
);
278 need_dm_detach
= false;
279 log_info("All DM devices detached.");
281 log_info("Not all DM devices detached, %d left.", r
);
283 log_error_errno(r
, "Failed to detach DM devices: %m");
286 if (!need_umount
&& !need_swapoff
&& !need_loop_detach
&& !need_dm_detach
) {
288 log_info("All filesystems, swaps, loop devices, DM devices detached.");
293 /* If in this iteration we didn't manage to
294 * unmount/deactivate anything, we simply give up */
296 log_info("Cannot finalize remaining%s%s%s%s continuing.",
297 need_umount
? " file systems," : "",
298 need_swapoff
? " swap devices," : "",
299 need_loop_detach
? " loop devices," : "",
300 need_dm_detach
? " DM devices," : "");
304 log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
306 need_umount
? " file systems," : "",
307 need_swapoff
? " swap devices," : "",
308 need_loop_detach
? " loop devices," : "",
309 need_dm_detach
? " DM devices," : "");
312 log_error("Too many iterations, giving up.");
317 arguments
[1] = arg_verb
;
319 execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, arguments
);
321 if (!in_container
&& !in_initrd() &&
322 access("/run/initramfs/shutdown", X_OK
) == 0) {
323 r
= switch_root_initramfs();
325 argv
[0] = (char*) "/shutdown";
328 make_console_stdio();
330 log_info("Successfully changed into root pivot.\n"
331 "Returning to initrd...");
333 execv("/shutdown", argv
);
334 log_error_errno(errno
, "Failed to execute shutdown binary: %m");
336 log_error_errno(r
, "Failed to switch root to \"/run/initramfs\": %m");
340 if (need_umount
|| need_swapoff
|| need_loop_detach
|| need_dm_detach
)
341 log_error("Failed to finalize %s%s%s%s ignoring",
342 need_umount
? " file systems," : "",
343 need_swapoff
? " swap devices," : "",
344 need_loop_detach
? " loop devices," : "",
345 need_dm_detach
? " DM devices," : "");
347 /* The kernel will automaticall flush ATA disks and suchlike
348 * on reboot(), but the file systems need to be synce'd
349 * explicitly in advance. So let's do this here, but not
350 * needlessly slow down containers. */
354 if (streq(arg_verb
, "exit")) {
358 /* We cannot exit() on the host, fallback on another
366 case LINUX_REBOOT_CMD_KEXEC
:
369 /* We cheat and exec kexec to avoid doing all its work */
372 log_info("Rebooting with kexec.");
376 log_error_errno(errno
, "Failed to fork: %m");
379 const char * const args
[] = {
385 execv(args
[0], (char * const *) args
);
388 wait_for_terminate_and_warn("kexec", pid
, true);
397 _cleanup_free_
char *param
= NULL
;
399 if (read_one_line_file(REBOOT_PARAM_FILE
, ¶m
) >= 0) {
400 log_info("Rebooting with argument '%s'.", param
);
401 syscall(SYS_reboot
, LINUX_REBOOT_MAGIC1
, LINUX_REBOOT_MAGIC2
, LINUX_REBOOT_CMD_RESTART2
, param
);
405 log_info("Rebooting.");
409 log_info("Powering off.");
413 log_info("Halting system.");
417 assert_not_reached("Unknown magic");
421 if (errno
== EPERM
&& in_container
) {
422 /* If we are in a container, and we lacked
423 * CAP_SYS_BOOT just exit, this will kill our
424 * container for good. */
425 log_info("Exiting container.");
429 r
= log_error_errno(errno
, "Failed to invoke reboot(): %m");
432 log_emergency_errno(r
, "Critical error while doing system shutdown: %m");