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
;
52 static int parse_argv(int argc
, char *argv
[]) {
54 ARG_LOG_LEVEL
= 0x100,
60 static const struct option options
[] = {
61 { "log-level", required_argument
, NULL
, ARG_LOG_LEVEL
},
62 { "log-target", required_argument
, NULL
, ARG_LOG_TARGET
},
63 { "log-color", optional_argument
, NULL
, ARG_LOG_COLOR
},
64 { "log-location", optional_argument
, NULL
, ARG_LOG_LOCATION
},
73 /* "-" prevents getopt from permuting argv[] and moving the verb away
74 * from argv[1]. Our interface to initrd promises it'll be there. */
75 while ((c
= getopt_long(argc
, argv
, "-", options
, NULL
)) >= 0)
79 r
= log_set_max_level_from_string(optarg
);
81 log_error("Failed to parse log level %s, ignoring.", optarg
);
86 r
= log_set_target_from_string(optarg
);
88 log_error("Failed to parse log target %s, ignoring", optarg
);
95 r
= log_show_color_from_string(optarg
);
97 log_error("Failed to parse log color setting %s, ignoring", optarg
);
103 case ARG_LOG_LOCATION
:
105 r
= log_show_location_from_string(optarg
);
107 log_error("Failed to parse log location setting %s, ignoring", optarg
);
109 log_show_location(true);
117 log_error("Excess arguments, ignoring");
124 assert_not_reached("Unhandled option code.");
128 log_error("Verb argument missing.");
135 static int switch_root_initramfs(void) {
136 if (mount("/run/initramfs", "/run/initramfs", NULL
, MS_BIND
, NULL
) < 0)
137 return log_error_errno(errno
, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
139 if (mount(NULL
, "/run/initramfs", NULL
, MS_PRIVATE
, NULL
) < 0)
140 return log_error_errno(errno
, "Failed to make /run/initramfs private mount: %m");
142 /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file descriptors.
143 * /run/initramfs/shutdown will take care of these.
144 * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
146 return switch_root("/run/initramfs", "/oldroot", false, MS_BIND
);
150 int main(int argc
, char *argv
[]) {
151 bool need_umount
, need_swapoff
, need_loop_detach
, need_dm_detach
;
152 bool in_container
, use_watchdog
= false;
153 _cleanup_free_
char *cgroup
= NULL
;
157 static const char* const dirs
[] = {SYSTEM_SHUTDOWN_PATH
, NULL
};
159 log_parse_environment();
160 r
= parse_argv(argc
, argv
);
164 /* journald will die if not gone yet. The log target defaults
165 * to console, but may have been changed by command line options. */
167 log_close_console(); /* force reopen of /dev/console */
173 log_error("Not executed by init (PID 1).");
178 if (streq(arg_verb
, "reboot"))
180 else if (streq(arg_verb
, "poweroff"))
182 else if (streq(arg_verb
, "halt"))
183 cmd
= RB_HALT_SYSTEM
;
184 else if (streq(arg_verb
, "kexec"))
185 cmd
= LINUX_REBOOT_CMD_KEXEC
;
188 log_error("Unknown action '%s'.", arg_verb
);
192 cg_get_root_path(&cgroup
);
194 use_watchdog
= !!getenv("WATCHDOG_USEC");
196 /* lock us into memory */
197 mlockall(MCL_CURRENT
|MCL_FUTURE
);
199 log_info("Sending SIGTERM to remaining processes...");
200 broadcast_signal(SIGTERM
, true, true);
202 log_info("Sending SIGKILL to remaining processes...");
203 broadcast_signal(SIGKILL
, true, false);
205 in_container
= detect_container() > 0;
207 need_umount
= !in_container
;
208 need_swapoff
= !in_container
;
209 need_loop_detach
= !in_container
;
210 need_dm_detach
= !in_container
;
212 /* Unmount all mountpoints, swaps, and loopback devices */
213 for (retries
= 0; retries
< FINALIZE_ATTEMPTS
; retries
++) {
214 bool changed
= false;
219 /* Let's trim the cgroup tree on each iteration so
220 that we leave an empty cgroup tree around, so that
221 container managers get a nice notify event when we
224 cg_trim(SYSTEMD_CGROUP_CONTROLLER
, cgroup
, false);
227 log_info("Unmounting file systems.");
228 r
= umount_all(&changed
);
231 log_info("All filesystems unmounted.");
233 log_info("Not all file systems unmounted, %d left.", r
);
235 log_error_errno(r
, "Failed to unmount file systems: %m");
239 log_info("Deactivating swaps.");
240 r
= swapoff_all(&changed
);
242 need_swapoff
= false;
243 log_info("All swaps deactivated.");
245 log_info("Not all swaps deactivated, %d left.", r
);
247 log_error_errno(r
, "Failed to deactivate swaps: %m");
250 if (need_loop_detach
) {
251 log_info("Detaching loop devices.");
252 r
= loopback_detach_all(&changed
);
254 need_loop_detach
= false;
255 log_info("All loop devices detached.");
257 log_info("Not all loop devices detached, %d left.", r
);
259 log_error_errno(r
, "Failed to detach loop devices: %m");
262 if (need_dm_detach
) {
263 log_info("Detaching DM devices.");
264 r
= dm_detach_all(&changed
);
266 need_dm_detach
= false;
267 log_info("All DM devices detached.");
269 log_info("Not all DM devices detached, %d left.", r
);
271 log_error_errno(r
, "Failed to detach DM devices: %m");
274 if (!need_umount
&& !need_swapoff
&& !need_loop_detach
&& !need_dm_detach
) {
276 log_info("All filesystems, swaps, loop devices, DM devices detached.");
281 /* If in this iteration we didn't manage to
282 * unmount/deactivate anything, we simply give up */
284 log_info("Cannot finalize remaining%s%s%s%s continuing.",
285 need_umount
? " file systems," : "",
286 need_swapoff
? " swap devices," : "",
287 need_loop_detach
? " loop devices," : "",
288 need_dm_detach
? " DM devices," : "");
292 log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
294 need_umount
? " file systems," : "",
295 need_swapoff
? " swap devices," : "",
296 need_loop_detach
? " loop devices," : "",
297 need_dm_detach
? " DM devices," : "");
300 log_error("Too many iterations, giving up.");
305 arguments
[1] = arg_verb
;
307 execute_directories(dirs
, DEFAULT_TIMEOUT_USEC
, arguments
);
309 if (!in_container
&& !in_initrd() &&
310 access("/run/initramfs/shutdown", X_OK
) == 0) {
311 r
= switch_root_initramfs();
313 argv
[0] = (char*) "/shutdown";
316 make_console_stdio();
318 log_info("Successfully changed into root pivot.\n"
319 "Returning to initrd...");
321 execv("/shutdown", argv
);
322 log_error_errno(errno
, "Failed to execute shutdown binary: %m");
324 log_error_errno(r
, "Failed to switch root to \"/run/initramfs\": %m");
328 if (need_umount
|| need_swapoff
|| need_loop_detach
|| need_dm_detach
)
329 log_error("Failed to finalize %s%s%s%s ignoring",
330 need_umount
? " file systems," : "",
331 need_swapoff
? " swap devices," : "",
332 need_loop_detach
? " loop devices," : "",
333 need_dm_detach
? " DM devices," : "");
335 /* The kernel will automaticall flush ATA disks and suchlike
336 * on reboot(), but the file systems need to be synce'd
337 * explicitly in advance. So let's do this here, but not
338 * needlessly slow down containers. */
344 case LINUX_REBOOT_CMD_KEXEC
:
347 /* We cheat and exec kexec to avoid doing all its work */
350 log_info("Rebooting with kexec.");
354 log_error_errno(errno
, "Failed to fork: %m");
357 const char * const args
[] = {
363 execv(args
[0], (char * const *) args
);
366 wait_for_terminate_and_warn("kexec", pid
, true);
375 _cleanup_free_
char *param
= NULL
;
377 if (read_one_line_file(REBOOT_PARAM_FILE
, ¶m
) >= 0) {
378 log_info("Rebooting with argument '%s'.", param
);
379 syscall(SYS_reboot
, LINUX_REBOOT_MAGIC1
, LINUX_REBOOT_MAGIC2
, LINUX_REBOOT_CMD_RESTART2
, param
);
383 log_info("Rebooting.");
387 log_info("Powering off.");
391 log_info("Halting system.");
395 assert_not_reached("Unknown magic");
399 if (errno
== EPERM
&& in_container
) {
400 /* If we are in a container, and we lacked
401 * CAP_SYS_BOOT just exit, this will kill our
402 * container for good. */
403 log_info("Exiting container.");
407 r
= log_error_errno(errno
, "Failed to invoke reboot(): %m");
410 log_emergency_errno(r
, "Critical error while doing system shutdown: %m");