]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/shutdown.c
delete unused variables
[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/stat.h>
28#include <sys/mount.h>
29#include <sys/syscall.h>
30#include <fcntl.h>
b1b2a107
FF
31#include <dirent.h>
32#include <errno.h>
33#include <unistd.h>
34#include <signal.h>
35#include <stdbool.h>
36#include <stdlib.h>
37#include <string.h>
38
7cb1094a 39#include "missing.h"
b1b2a107 40#include "log.h"
ec26be51 41#include "fileio.h"
b1b2a107
FF
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"
41f85451 48#include "cgroup-util.h"
37185ec8 49#include "def.h"
b1b2a107 50
b1b2a107 51#define FINALIZE_ATTEMPTS 50
b1b2a107 52
89d471d5
LP
53static int prepare_new_root(void) {
54 static const char dirs[] =
55 "/run/initramfs/oldroot\0"
56 "/run/initramfs/proc\0"
57 "/run/initramfs/sys\0"
58 "/run/initramfs/dev\0"
59 "/run/initramfs/run\0";
60
61 const char *dir;
62
63 if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) {
64 log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m");
65 return -errno;
66 }
67
68 if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) {
69 log_error("Failed to make /run/initramfs private mount: %m");
70 return -errno;
71 }
72
73 NULSTR_FOREACH(dir, dirs)
d2e54fae 74 if (mkdir_p_label(dir, 0755) < 0 && errno != EEXIST) {
89d471d5
LP
75 log_error("Failed to mkdir %s: %m", dir);
76 return -errno;
7cb1094a 77 }
89d471d5
LP
78
79 if (mount("/sys", "/run/initramfs/sys", NULL, MS_BIND, NULL) < 0) {
80 log_error("Failed to mount bind /sys on /run/initramfs/sys: %m");
81 return -errno;
82 }
83
84 if (mount("/proc", "/run/initramfs/proc", NULL, MS_BIND, NULL) < 0) {
85 log_error("Failed to mount bind /proc on /run/initramfs/proc: %m");
86 return -errno;
87 }
88
89 if (mount("/dev", "/run/initramfs/dev", NULL, MS_BIND, NULL) < 0) {
90 log_error("Failed to mount bind /dev on /run/initramfs/dev: %m");
91 return -errno;
7cb1094a
HH
92 }
93
89d471d5
LP
94 if (mount("/run", "/run/initramfs/run", NULL, MS_BIND, NULL) < 0) {
95 log_error("Failed to mount bind /run on /run/initramfs/run: %m");
96 return -errno;
97 }
98
99 return 0;
7cb1094a
HH
100}
101
89d471d5 102static int pivot_to_new_root(void) {
bd3fa1d2 103
cd3bd60a
LP
104 if (chdir("/run/initramfs") < 0) {
105 log_error("Failed to change directory to /run/initramfs: %m");
106 return -errno;
107 }
7cb1094a 108
f47fc355
LP
109 /* Work-around for a kernel bug: for some reason the kernel
110 * refuses switching root if any file systems are mounted
111 * MS_SHARED. Hence remount them MS_PRIVATE here as a
112 * work-around.
113 *
114 * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */
115 if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0)
116 log_warning("Failed to make \"/\" private mount: %m");
7cb1094a 117
89d471d5 118 if (pivot_root(".", "oldroot") < 0) {
7cb1094a 119 log_error("pivot failed: %m");
49f43d5f 120 /* only chroot if pivot root succeeded */
89d471d5 121 return -errno;
7cb1094a 122 }
89d471d5 123
7cb1094a 124 chroot(".");
89d471d5 125
cd3bd60a
LP
126 setsid();
127 make_console_stdio();
bccc1d88 128
cd3bd60a 129 log_info("Successfully changed into root pivot.");
89d471d5
LP
130
131 return 0;
7cb1094a
HH
132}
133
b1b2a107 134int main(int argc, char *argv[]) {
d48141ba 135 bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
bd3fa1d2 136 bool in_container, use_watchdog = false;
477def80 137 _cleanup_free_ char *line = NULL, *cgroup = NULL;
6edd7d0a 138 char *arguments[3];
41f85451
LP
139 unsigned retries;
140 int cmd, r;
b1b2a107 141
ec26be51 142 /* suppress shutdown status output if 'quiet' is used */
74df0fca
LP
143 r = proc_cmdline(&line);
144 if (r > 0) {
ec26be51
KS
145 char *w, *state;
146 size_t l;
147
8577e672 148 FOREACH_WORD_QUOTED(w, l, line, state) {
f6940be7 149 if (l == 5 && memcmp(w, "quiet", 5) == 0) {
ec26be51
KS
150 log_set_max_level(LOG_WARNING);
151 break;
152 }
8577e672 153 }
ec26be51
KS
154 }
155
b1b2a107 156 log_parse_environment();
2ca1b422 157 log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
b1b2a107
FF
158 log_open();
159
4c12626c
LP
160 umask(0022);
161
b1b2a107 162 if (getpid() != 1) {
567ea02a 163 log_error("Not executed by init (pid 1).");
b1b2a107
FF
164 r = -EPERM;
165 goto error;
166 }
167
168 if (argc != 2) {
169 log_error("Invalid number of arguments.");
170 r = -EINVAL;
171 goto error;
172 }
173
40e85d00
LP
174 in_container = detect_container(NULL) > 0;
175
477def80 176 if (streq(argv[1], "reboot"))
b1b2a107 177 cmd = RB_AUTOBOOT;
477def80 178 else if (streq(argv[1], "poweroff"))
b1b2a107
FF
179 cmd = RB_POWER_OFF;
180 else if (streq(argv[1], "halt"))
181 cmd = RB_HALT_SYSTEM;
182 else if (streq(argv[1], "kexec"))
183 cmd = LINUX_REBOOT_CMD_KEXEC;
184 else {
185 log_error("Unknown action '%s'.", argv[1]);
186 r = -EINVAL;
187 goto error;
188 }
189
41f85451
LP
190 cg_get_root_path(&cgroup);
191
e96d6be7
LP
192 use_watchdog = !!getenv("WATCHDOG_USEC");
193
b1b2a107 194 /* lock us into memory */
b55d0651 195 mlockall(MCL_CURRENT|MCL_FUTURE);
b1b2a107 196
ab58e291 197 log_info("Sending SIGTERM to remaining processes...");
cee530bb 198 broadcast_signal(SIGTERM, true);
b1b2a107 199
ab58e291 200 log_info("Sending SIGKILL to remaining processes...");
cee530bb 201 broadcast_signal(SIGKILL, true);
40e85d00 202
ff644623 203 if (in_container) {
40e85d00 204 need_swapoff = false;
ff644623 205 need_dm_detach = false;
910212e7 206 need_loop_detach = false;
ff644623 207 }
b1b2a107 208
567ea02a 209 /* Unmount all mountpoints, swaps, and loopback devices */
12aad1d0
LP
210 for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
211 bool changed = false;
212
e96d6be7
LP
213 if (use_watchdog)
214 watchdog_ping();
215
41f85451
LP
216 /* Let's trim the cgroup tree on each iteration so
217 that we leave an empty cgroup tree around, so that
218 container managers get a nice notify event when we
219 are down */
220 if (cgroup)
221 cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
222
b1b2a107 223 if (need_umount) {
ab58e291 224 log_info("Unmounting file systems.");
12aad1d0 225 r = umount_all(&changed);
bce93b7a 226 if (r == 0) {
b1b2a107 227 need_umount = false;
bce93b7a
MS
228 log_info("All filesystems unmounted.");
229 } else if (r > 0)
ab58e291 230 log_info("Not all file systems unmounted, %d left.", r);
b1b2a107 231 else
ab58e291 232 log_error("Failed to unmount file systems: %s", strerror(-r));
b1b2a107
FF
233 }
234
235 if (need_swapoff) {
735e0712 236 log_info("Deactivating swaps.");
12aad1d0 237 r = swapoff_all(&changed);
bce93b7a 238 if (r == 0) {
b1b2a107 239 need_swapoff = false;
735e0712 240 log_info("All swaps deactivated.");
bce93b7a 241 } else if (r > 0)
735e0712 242 log_info("Not all swaps deactivated, %d left.", r);
b1b2a107 243 else
735e0712 244 log_error("Failed to deactivate swaps: %s", strerror(-r));
b1b2a107
FF
245 }
246
247 if (need_loop_detach) {
248 log_info("Detaching loop devices.");
12aad1d0 249 r = loopback_detach_all(&changed);
bce93b7a 250 if (r == 0) {
b1b2a107 251 need_loop_detach = false;
bce93b7a
MS
252 log_info("All loop devices detached.");
253 } else if (r > 0)
ab58e291 254 log_info("Not all loop devices detached, %d left.", r);
b1b2a107 255 else
ab58e291 256 log_error("Failed to detach loop devices: %s", strerror(-r));
d48141ba 257 }
b1b2a107 258
d48141ba
LP
259 if (need_dm_detach) {
260 log_info("Detaching DM devices.");
12aad1d0 261 r = dm_detach_all(&changed);
bce93b7a 262 if (r == 0) {
d48141ba 263 need_dm_detach = false;
bce93b7a
MS
264 log_info("All DM devices detached.");
265 } else if (r > 0)
2569a5ce 266 log_info("Not all DM devices detached, %d left.", r);
d48141ba 267 else
ab58e291 268 log_error("Failed to detach DM devices: %s", strerror(-r));
b1b2a107
FF
269 }
270
a27d2184
KS
271 if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
272 if (retries > 0)
273 log_info("All filesystems, swaps, loop devices, DM devices detached.");
12aad1d0
LP
274 /* Yay, done */
275 break;
a27d2184 276 }
b1b2a107 277
12aad1d0 278 /* If in this iteration we didn't manage to
bd3fa1d2 279 * unmount/deactivate anything, we simply give up */
12aad1d0 280 if (!changed) {
bd3fa1d2
LP
281 log_error("Cannot finalize remaining file systems and devices, giving up.");
282 break;
12aad1d0
LP
283 }
284
ab58e291 285 log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1);
b1b2a107
FF
286 }
287
12aad1d0 288 if (retries >= FINALIZE_ATTEMPTS)
35b8ca3a 289 log_error("Too many iterations, giving up.");
5989dbb2
LP
290 else
291 log_info("Storage is finalized.");
12aad1d0 292
6edd7d0a
LP
293 arguments[0] = NULL;
294 arguments[1] = argv[1];
295 arguments[2] = NULL;
296 execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments);
83cc030f 297
02eaa788 298 if (!in_container && !in_initrd() &&
cb7ec564 299 access("/run/initramfs/shutdown", X_OK) == 0) {
89d471d5
LP
300
301 if (prepare_new_root() >= 0 &&
302 pivot_to_new_root() >= 0) {
30d743f4
LP
303
304 log_info("Returning to initrd...");
305
89d471d5 306 execv("/shutdown", argv);
7cb1094a
HH
307 log_error("Failed to execute shutdown binary: %m");
308 }
309 }
310
0049f05a
LP
311 /* The kernel will automaticall flush ATA disks and suchlike
312 * on reboot(), but the file systems need to be synce'd
313 * explicitly in advance. So let's do this here, but not
314 * needlessly slow down containers. */
315 if (!in_container)
316 sync();
317
477def80
LP
318 switch (cmd) {
319
320 case LINUX_REBOOT_CMD_KEXEC:
cb7ec564
LP
321
322 if (!in_container) {
323 /* We cheat and exec kexec to avoid doing all its work */
477def80
LP
324 pid_t pid;
325
326 log_info("Rebooting with kexec.");
cb7ec564 327
477def80 328 pid = fork();
cb7ec564 329 if (pid < 0)
477def80
LP
330 log_error("Failed to fork: %m");
331 else if (pid == 0) {
332
333 const char * const args[] = {
334 KEXEC, "-e", NULL
335 };
336
cb7ec564 337 /* Child */
477def80 338
cb7ec564 339 execv(args[0], (char * const *) args);
477def80
LP
340 _exit(EXIT_FAILURE);
341 } else
342 wait_for_terminate_and_warn("kexec", pid);
b1b2a107 343 }
e61cd186
LP
344
345 cmd = RB_AUTOBOOT;
477def80 346 /* Fall through */
b1b2a107 347
477def80
LP
348 case RB_AUTOBOOT:
349
350 if (!in_container) {
351 _cleanup_free_ char *param = NULL;
352
353 if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
354 log_info("Rebooting with argument '%s'.", param);
355 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
356 LINUX_REBOOT_CMD_RESTART2, param);
357 }
358 }
359
360 log_info("Rebooting.");
361 break;
362
363 case RB_POWER_OFF:
364 log_info("Powering off.");
365 break;
366
367 case RB_HALT_SYSTEM:
368 log_info("Halting system.");
369 break;
370
371 default:
372 assert_not_reached("Unknown magic");
373 }
cb7ec564 374
477def80 375 reboot(cmd);
cb7ec564
LP
376 if (errno == EPERM && in_container) {
377 /* If we are in a container, and we lacked
378 * CAP_SYS_BOOT just exit, this will kill our
379 * container for good. */
477def80 380 log_info("Exiting container.");
cb7ec564
LP
381 exit(0);
382 }
383
e61cd186
LP
384 log_error("Failed to invoke reboot(): %m");
385 r = -errno;
b1b2a107
FF
386
387 error:
e61cd186
LP
388 log_error("Critical error while doing system shutdown: %s", strerror(-r));
389
b1b2a107 390 freeze();
3c14d26c 391 return EXIT_FAILURE;
b1b2a107 392}