]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/shutdown.c
Spelling fixes.
[thirdparty/systemd.git] / src / core / shutdown.c
CommitLineData
b1b2a107
FF
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 ProFUSION embedded systems
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
b1b2a107
FF
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
b1b2a107 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
b1b2a107
FF
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <sys/mman.h>
23#include <sys/types.h>
24#include <sys/reboot.h>
25#include <linux/reboot.h>
26#include <sys/wait.h>
7cb1094a
HH
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/mount.h>
30#include <sys/syscall.h>
31#include <fcntl.h>
b1b2a107
FF
32#include <dirent.h>
33#include <errno.h>
34#include <unistd.h>
35#include <signal.h>
36#include <stdbool.h>
37#include <stdlib.h>
38#include <string.h>
39
7cb1094a 40#include "missing.h"
b1b2a107
FF
41#include "log.h"
42#include "umount.h"
43#include "util.h"
49e942b2 44#include "mkdir.h"
b52aae1d 45#include "virt.h"
e96d6be7 46#include "watchdog.h"
39d6464c 47#include "killall.h"
b1b2a107 48
b1b2a107 49#define FINALIZE_ATTEMPTS 50
b1b2a107 50
89d471d5
LP
51static int prepare_new_root(void) {
52 static const char dirs[] =
53 "/run/initramfs/oldroot\0"
54 "/run/initramfs/proc\0"
55 "/run/initramfs/sys\0"
56 "/run/initramfs/dev\0"
57 "/run/initramfs/run\0";
58
59 const char *dir;
60
61 if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) {
62 log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m");
63 return -errno;
64 }
65
66 if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) {
67 log_error("Failed to make /run/initramfs private mount: %m");
68 return -errno;
69 }
70
71 NULSTR_FOREACH(dir, dirs)
d2e54fae 72 if (mkdir_p_label(dir, 0755) < 0 && errno != EEXIST) {
89d471d5
LP
73 log_error("Failed to mkdir %s: %m", dir);
74 return -errno;
7cb1094a 75 }
89d471d5
LP
76
77 if (mount("/sys", "/run/initramfs/sys", NULL, MS_BIND, NULL) < 0) {
78 log_error("Failed to mount bind /sys on /run/initramfs/sys: %m");
79 return -errno;
80 }
81
82 if (mount("/proc", "/run/initramfs/proc", NULL, MS_BIND, NULL) < 0) {
83 log_error("Failed to mount bind /proc on /run/initramfs/proc: %m");
84 return -errno;
85 }
86
87 if (mount("/dev", "/run/initramfs/dev", NULL, MS_BIND, NULL) < 0) {
88 log_error("Failed to mount bind /dev on /run/initramfs/dev: %m");
89 return -errno;
7cb1094a
HH
90 }
91
89d471d5
LP
92 if (mount("/run", "/run/initramfs/run", NULL, MS_BIND, NULL) < 0) {
93 log_error("Failed to mount bind /run on /run/initramfs/run: %m");
94 return -errno;
95 }
96
97 return 0;
7cb1094a
HH
98}
99
89d471d5 100static int pivot_to_new_root(void) {
bd3fa1d2 101
cd3bd60a
LP
102 if (chdir("/run/initramfs") < 0) {
103 log_error("Failed to change directory to /run/initramfs: %m");
104 return -errno;
105 }
7cb1094a
HH
106
107 /*
108 In case some evil process made "/" MS_SHARED
109 It works for pivot_root, but the ref count for the root device
110 is not decreasing :-/
111 */
89d471d5
LP
112 if (mount(NULL, "/", NULL, MS_PRIVATE, NULL) < 0) {
113 log_error("Failed to make \"/\" private mount %m");
114 return -errno;
7cb1094a
HH
115 }
116
89d471d5 117 if (pivot_root(".", "oldroot") < 0) {
7cb1094a 118 log_error("pivot failed: %m");
49f43d5f 119 /* only chroot if pivot root succeeded */
89d471d5 120 return -errno;
7cb1094a 121 }
89d471d5 122
7cb1094a 123 chroot(".");
89d471d5 124
cd3bd60a
LP
125 setsid();
126 make_console_stdio();
bccc1d88 127
cd3bd60a 128 log_info("Successfully changed into root pivot.");
89d471d5
LP
129
130 return 0;
7cb1094a
HH
131}
132
b1b2a107 133int main(int argc, char *argv[]) {
12aad1d0
LP
134 int cmd, r;
135 unsigned retries;
d48141ba 136 bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
bd3fa1d2 137 bool in_container, use_watchdog = false;
6edd7d0a 138 char *arguments[3];
b1b2a107
FF
139
140 log_parse_environment();
2ca1b422 141 log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
b1b2a107
FF
142 log_open();
143
4c12626c
LP
144 umask(0022);
145
b1b2a107 146 if (getpid() != 1) {
567ea02a 147 log_error("Not executed by init (pid 1).");
b1b2a107
FF
148 r = -EPERM;
149 goto error;
150 }
151
152 if (argc != 2) {
153 log_error("Invalid number of arguments.");
154 r = -EINVAL;
155 goto error;
156 }
157
40e85d00
LP
158 in_container = detect_container(NULL) > 0;
159
b1b2a107
FF
160 if (streq(argv[1], "reboot"))
161 cmd = RB_AUTOBOOT;
162 else if (streq(argv[1], "poweroff"))
163 cmd = RB_POWER_OFF;
164 else if (streq(argv[1], "halt"))
165 cmd = RB_HALT_SYSTEM;
166 else if (streq(argv[1], "kexec"))
167 cmd = LINUX_REBOOT_CMD_KEXEC;
168 else {
169 log_error("Unknown action '%s'.", argv[1]);
170 r = -EINVAL;
171 goto error;
172 }
173
e96d6be7
LP
174 use_watchdog = !!getenv("WATCHDOG_USEC");
175
b1b2a107 176 /* lock us into memory */
b55d0651 177 mlockall(MCL_CURRENT|MCL_FUTURE);
b1b2a107 178
ab58e291 179 log_info("Sending SIGTERM to remaining processes...");
bd3fa1d2 180 broadcast_signal(SIGTERM);
b1b2a107 181
ab58e291 182 log_info("Sending SIGKILL to remaining processes...");
bd3fa1d2 183 broadcast_signal(SIGKILL);
40e85d00 184
ff644623 185 if (in_container) {
40e85d00 186 need_swapoff = false;
ff644623 187 need_dm_detach = false;
910212e7 188 need_loop_detach = false;
ff644623 189 }
b1b2a107 190
567ea02a 191 /* Unmount all mountpoints, swaps, and loopback devices */
12aad1d0
LP
192 for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
193 bool changed = false;
194
e96d6be7
LP
195 if (use_watchdog)
196 watchdog_ping();
197
b1b2a107 198 if (need_umount) {
ab58e291 199 log_info("Unmounting file systems.");
12aad1d0 200 r = umount_all(&changed);
b1b2a107
FF
201 if (r == 0)
202 need_umount = false;
203 else if (r > 0)
ab58e291 204 log_info("Not all file systems unmounted, %d left.", r);
b1b2a107 205 else
ab58e291 206 log_error("Failed to unmount file systems: %s", strerror(-r));
b1b2a107
FF
207 }
208
209 if (need_swapoff) {
210 log_info("Disabling swaps.");
12aad1d0 211 r = swapoff_all(&changed);
b1b2a107
FF
212 if (r == 0)
213 need_swapoff = false;
214 else if (r > 0)
ab58e291 215 log_info("Not all swaps are turned off, %d left.", r);
b1b2a107 216 else
ab58e291 217 log_error("Failed to turn off swaps: %s", strerror(-r));
b1b2a107
FF
218 }
219
220 if (need_loop_detach) {
221 log_info("Detaching loop devices.");
12aad1d0 222 r = loopback_detach_all(&changed);
b1b2a107
FF
223 if (r == 0)
224 need_loop_detach = false;
225 else if (r > 0)
ab58e291 226 log_info("Not all loop devices detached, %d left.", r);
b1b2a107 227 else
ab58e291 228 log_error("Failed to detach loop devices: %s", strerror(-r));
d48141ba 229 }
b1b2a107 230
d48141ba
LP
231 if (need_dm_detach) {
232 log_info("Detaching DM devices.");
12aad1d0 233 r = dm_detach_all(&changed);
d48141ba
LP
234 if (r == 0)
235 need_dm_detach = false;
236 else if (r > 0)
ab58e291 237 log_warning("Not all DM devices detached, %d left.", r);
d48141ba 238 else
ab58e291 239 log_error("Failed to detach DM devices: %s", strerror(-r));
b1b2a107
FF
240 }
241
a27d2184
KS
242 if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
243 if (retries > 0)
244 log_info("All filesystems, swaps, loop devices, DM devices detached.");
12aad1d0
LP
245 /* Yay, done */
246 break;
a27d2184 247 }
b1b2a107 248
12aad1d0 249 /* If in this iteration we didn't manage to
bd3fa1d2 250 * unmount/deactivate anything, we simply give up */
12aad1d0 251 if (!changed) {
bd3fa1d2
LP
252 log_error("Cannot finalize remaining file systems and devices, giving up.");
253 break;
12aad1d0
LP
254 }
255
ab58e291 256 log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1);
b1b2a107
FF
257 }
258
12aad1d0 259 if (retries >= FINALIZE_ATTEMPTS)
35b8ca3a 260 log_error("Too many iterations, giving up.");
12aad1d0 261
6edd7d0a
LP
262 arguments[0] = NULL;
263 arguments[1] = argv[1];
264 arguments[2] = NULL;
265 execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments);
83cc030f 266
40e85d00
LP
267 /* If we are in a container, just exit, this will kill our
268 * container for good. */
f41de959
LP
269 if (in_container) {
270 log_error("Exiting container.");
40e85d00 271 exit(0);
f41de959 272 }
40e85d00 273
7cb1094a 274 if (access("/run/initramfs/shutdown", X_OK) == 0) {
89d471d5
LP
275
276 if (prepare_new_root() >= 0 &&
277 pivot_to_new_root() >= 0) {
278 execv("/shutdown", argv);
7cb1094a
HH
279 log_error("Failed to execute shutdown binary: %m");
280 }
281 }
282
89d471d5
LP
283 sync();
284
b1b2a107 285 if (cmd == LINUX_REBOOT_CMD_KEXEC) {
12aad1d0 286 /* We cheat and exec kexec to avoid doing all its work */
b1b2a107 287 pid_t pid = fork();
12aad1d0 288
e61cd186
LP
289 if (pid < 0)
290 log_error("Could not fork: %m. Falling back to normal reboot.");
291 else if (pid > 0) {
292 wait_for_terminate_and_warn("kexec", pid);
293 log_warning("kexec failed. Falling back to normal reboot.");
b1b2a107 294 } else {
e61cd186 295 /* Child */
f8d0ceb4 296 const char *args[3] = { "/sbin/kexec", "-e", NULL };
b1b2a107
FF
297 execv(args[0], (char * const *) args);
298 return EXIT_FAILURE;
299 }
e61cd186
LP
300
301 cmd = RB_AUTOBOOT;
b1b2a107
FF
302 }
303
304 reboot(cmd);
e61cd186
LP
305 log_error("Failed to invoke reboot(): %m");
306 r = -errno;
b1b2a107
FF
307
308 error:
e61cd186
LP
309 log_error("Critical error while doing system shutdown: %s", strerror(-r));
310
b1b2a107 311 freeze();
3c14d26c 312 return EXIT_FAILURE;
b1b2a107 313}