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 "process-util.h"
41 #include "string-util.h"
42 #include "switch-root.h"
43 #include "terminal-util.h"
49 #define FINALIZE_ATTEMPTS 50
51 static char* arg_verb
;
52 static uint8_t arg_exit_code
;
54 static int parse_argv(int argc
, char *argv
[]) {
56 ARG_LOG_LEVEL
= 0x100,
63 static const struct option options
[] = {
64 { "log-level", required_argument
, NULL
, ARG_LOG_LEVEL
},
65 { "log-target", required_argument
, NULL
, ARG_LOG_TARGET
},
66 { "log-color", optional_argument
, NULL
, ARG_LOG_COLOR
},
67 { "log-location", optional_argument
, NULL
, ARG_LOG_LOCATION
},
68 { "exit-code", required_argument
, NULL
, ARG_EXIT_CODE
},
77 /* "-" prevents getopt from permuting argv[] and moving the verb away
78 * from argv[1]. Our interface to initrd promises it'll be there. */
79 while ((c
= getopt_long(argc
, argv
, "-", options
, NULL
)) >= 0)
83 r
= log_set_max_level_from_string(optarg
);
85 log_error("Failed to parse log level %s, ignoring.", optarg
);
90 r
= log_set_target_from_string(optarg
);
92 log_error("Failed to parse log target %s, ignoring", optarg
);
99 r
= log_show_color_from_string(optarg
);
101 log_error("Failed to parse log color setting %s, ignoring", optarg
);
103 log_show_color(true);
107 case ARG_LOG_LOCATION
:
109 r
= log_show_location_from_string(optarg
);
111 log_error("Failed to parse log location setting %s, ignoring", optarg
);
113 log_show_location(true);
118 r
= safe_atou8(optarg
, &arg_exit_code
);
120 log_error("Failed to parse exit code %s, ignoring", optarg
);
128 log_error("Excess arguments, ignoring");
135 assert_not_reached("Unhandled option code.");
139 log_error("Verb argument missing.");
146 static int switch_root_initramfs(void) {
147 if (mount("/run/initramfs", "/run/initramfs", NULL
, MS_BIND
, NULL
) < 0)
148 return log_error_errno(errno
, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
150 if (mount(NULL
, "/run/initramfs", NULL
, MS_PRIVATE
, NULL
) < 0)
151 return log_error_errno(errno
, "Failed to make /run/initramfs private mount: %m");
153 /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file descriptors.
154 * /run/initramfs/shutdown will take care of these.
155 * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
157 return switch_root("/run/initramfs", "/oldroot", false, MS_BIND
);
161 int main(int argc
, char *argv
[]) {
162 bool need_umount
, need_swapoff
, need_loop_detach
, need_dm_detach
;
163 bool in_container
, use_watchdog
= false;
164 _cleanup_free_
char *cgroup
= NULL
;
168 static const char* const dirs
[] = {SYSTEM_SHUTDOWN_PATH
, NULL
};
170 log_parse_environment();
171 r
= parse_argv(argc
, argv
);
175 /* journald will die if not gone yet. The log target defaults
176 * to console, but may have been changed by command line options. */
178 log_close_console(); /* force reopen of /dev/console */
184 log_error("Not executed by init (PID 1).");
189 if (streq(arg_verb
, "reboot"))
191 else if (streq(arg_verb
, "poweroff"))
193 else if (streq(arg_verb
, "halt"))
194 cmd
= RB_HALT_SYSTEM
;
195 else if (streq(arg_verb
, "kexec"))
196 cmd
= LINUX_REBOOT_CMD_KEXEC
;
197 else if (streq(arg_verb
, "exit"))
198 cmd
= 0; /* ignored, just checking that arg_verb is valid */
201 log_error("Unknown action '%s'.", arg_verb
);
205 cg_get_root_path(&cgroup
);
207 use_watchdog
= !!getenv("WATCHDOG_USEC");
209 /* lock us into memory */
210 mlockall(MCL_CURRENT
|MCL_FUTURE
);
212 log_info("Sending SIGTERM to remaining processes...");
213 broadcast_signal(SIGTERM
, true, true);
215 log_info("Sending SIGKILL to remaining processes...");
216 broadcast_signal(SIGKILL
, true, false);
218 in_container
= detect_container() > 0;
220 need_umount
= !in_container
;
221 need_swapoff
= !in_container
;
222 need_loop_detach
= !in_container
;
223 need_dm_detach
= !in_container
;
225 /* Unmount all mountpoints, swaps, and loopback devices */
226 for (retries
= 0; retries
< FINALIZE_ATTEMPTS
; retries
++) {
227 bool changed
= false;
232 /* Let's trim the cgroup tree on each iteration so
233 that we leave an empty cgroup tree around, so that
234 container managers get a nice notify event when we
237 cg_trim(SYSTEMD_CGROUP_CONTROLLER
, cgroup
, false);
240 log_info("Unmounting file systems.");
241 r
= umount_all(&changed
);
244 log_info("All filesystems unmounted.");
246 log_info("Not all file systems unmounted, %d left.", r
);
248 log_error_errno(r
, "Failed to unmount file systems: %m");
252 log_info("Deactivating swaps.");
253 r
= swapoff_all(&changed
);
255 need_swapoff
= false;
256 log_info("All swaps deactivated.");
258 log_info("Not all swaps deactivated, %d left.", r
);
260 log_error_errno(r
, "Failed to deactivate swaps: %m");
263 if (need_loop_detach
) {
264 log_info("Detaching loop devices.");
265 r
= loopback_detach_all(&changed
);
267 need_loop_detach
= false;
268 log_info("All loop devices detached.");
270 log_info("Not all loop devices detached, %d left.", r
);
272 log_error_errno(r
, "Failed to detach loop devices: %m");
275 if (need_dm_detach
) {
276 log_info("Detaching DM devices.");
277 r
= dm_detach_all(&changed
);
279 need_dm_detach
= false;
280 log_info("All DM devices detached.");
282 log_info("Not all DM devices detached, %d left.", r
);
284 log_error_errno(r
, "Failed to detach DM devices: %m");
287 if (!need_umount
&& !need_swapoff
&& !need_loop_detach
&& !need_dm_detach
) {
289 log_info("All filesystems, swaps, loop devices, DM devices detached.");
294 /* If in this iteration we didn't manage to
295 * unmount/deactivate anything, we simply give up */
297 log_info("Cannot finalize remaining%s%s%s%s continuing.",
298 need_umount
? " file systems," : "",
299 need_swapoff
? " swap devices," : "",
300 need_loop_detach
? " loop devices," : "",
301 need_dm_detach
? " DM devices," : "");
305 log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
307 need_umount
? " file systems," : "",
308 need_swapoff
? " swap devices," : "",
309 need_loop_detach
? " loop devices," : "",
310 need_dm_detach
? " DM devices," : "");
313 log_error("Too many iterations, giving up.");
318 arguments
[1] = arg_verb
;
320 execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, arguments
);
322 if (!in_container
&& !in_initrd() &&
323 access("/run/initramfs/shutdown", X_OK
) == 0) {
324 r
= switch_root_initramfs();
326 argv
[0] = (char*) "/shutdown";
329 make_console_stdio();
331 log_info("Successfully changed into root pivot.\n"
332 "Returning to initrd...");
334 execv("/shutdown", argv
);
335 log_error_errno(errno
, "Failed to execute shutdown binary: %m");
337 log_error_errno(r
, "Failed to switch root to \"/run/initramfs\": %m");
341 if (need_umount
|| need_swapoff
|| need_loop_detach
|| need_dm_detach
)
342 log_error("Failed to finalize %s%s%s%s ignoring",
343 need_umount
? " file systems," : "",
344 need_swapoff
? " swap devices," : "",
345 need_loop_detach
? " loop devices," : "",
346 need_dm_detach
? " DM devices," : "");
348 /* The kernel will automaticall flush ATA disks and suchlike
349 * on reboot(), but the file systems need to be synce'd
350 * explicitly in advance. So let's do this here, but not
351 * needlessly slow down containers. */
355 if (streq(arg_verb
, "exit")) {
359 /* We cannot exit() on the host, fallback on another
367 case LINUX_REBOOT_CMD_KEXEC
:
370 /* We cheat and exec kexec to avoid doing all its work */
373 log_info("Rebooting with kexec.");
377 log_error_errno(errno
, "Failed to fork: %m");
380 const char * const args
[] = {
386 execv(args
[0], (char * const *) args
);
389 wait_for_terminate_and_warn("kexec", pid
, true);
398 _cleanup_free_
char *param
= NULL
;
400 if (read_one_line_file(REBOOT_PARAM_FILE
, ¶m
) >= 0) {
401 log_info("Rebooting with argument '%s'.", param
);
402 syscall(SYS_reboot
, LINUX_REBOOT_MAGIC1
, LINUX_REBOOT_MAGIC2
, LINUX_REBOOT_CMD_RESTART2
, param
);
406 log_info("Rebooting.");
410 log_info("Powering off.");
414 log_info("Halting system.");
418 assert_not_reached("Unknown magic");
422 if (errno
== EPERM
&& in_container
) {
423 /* If we are in a container, and we lacked
424 * CAP_SYS_BOOT just exit, this will kill our
425 * container for good. */
426 log_info("Exiting container.");
430 r
= log_error_errno(errno
, "Failed to invoke reboot(): %m");
433 log_emergency_errno(r
, "Critical error while doing system shutdown: %m");