]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shutdown.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.git] / src / 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"
b1b2a107 47
567ea02a 48#define TIMEOUT_USEC (5 * USEC_PER_SEC)
b1b2a107 49#define FINALIZE_ATTEMPTS 50
b1b2a107 50
b1b2a107 51static bool ignore_proc(pid_t pid) {
7e4ab3c5
LP
52 char buf[PATH_MAX];
53 FILE *f;
54 char c;
55 size_t count;
56 uid_t uid;
57 int r;
58
59 /* We are PID 1, let's not commit suicide */
b1b2a107
FF
60 if (pid == 1)
61 return true;
62
7e4ab3c5
LP
63 r = get_process_uid(pid, &uid);
64 if (r < 0)
65 return true; /* not really, but better safe than sorry */
b1b2a107 66
7e4ab3c5
LP
67 /* Non-root processes otherwise are always subject to be killed */
68 if (uid != 0)
69 return false;
b1b2a107 70
7e4ab3c5
LP
71 snprintf(buf, sizeof(buf), "/proc/%lu/cmdline", (unsigned long) pid);
72 char_array_0(buf);
b1b2a107 73
b1b2a107
FF
74 f = fopen(buf, "re");
75 if (!f)
76 return true; /* not really, but has the desired effect */
77
78 count = fread(&c, 1, 1, f);
79 fclose(f);
7e4ab3c5
LP
80
81 /* Kernel threads have an empty cmdline */
82 if (count <= 0)
83 return true;
84
85 /* Processes with argv[0][0] = '@' we ignore from the killing
bd1a6981
LP
86 * spree.
87 *
88 * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */
7e4ab3c5
LP
89 if (count == 1 && c == '@')
90 return true;
91
92 return false;
b1b2a107
FF
93}
94
95static int killall(int sign) {
96 DIR *dir;
97 struct dirent *d;
12aad1d0 98 unsigned int n_processes = 0;
b1b2a107 99
7e4ab3c5
LP
100 dir = opendir("/proc");
101 if (!dir)
b1b2a107
FF
102 return -errno;
103
104 while ((d = readdir(dir))) {
105 pid_t pid;
106
107 if (parse_pid(d->d_name, &pid) < 0)
108 continue;
109
b1b2a107
FF
110 if (ignore_proc(pid))
111 continue;
112
113 if (kill(pid, sign) == 0)
12aad1d0 114 n_processes++;
b1b2a107
FF
115 else
116 log_warning("Could not kill %d: %m", pid);
117 }
118
119 closedir(dir);
120
12aad1d0 121 return n_processes;
b1b2a107
FF
122}
123
40e85d00 124static void wait_for_children(int n_processes, sigset_t *mask) {
b1b2a107 125 usec_t until;
b1b2a107 126
40e85d00 127 assert(mask);
b1b2a107
FF
128
129 until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC;
130 for (;;) {
40e85d00 131 struct timespec ts;
ab58e291 132 int k;
40e85d00 133 usec_t n;
ab58e291 134
b1b2a107
FF
135 for (;;) {
136 pid_t pid = waitpid(-1, NULL, WNOHANG);
12aad1d0 137
b1b2a107
FF
138 if (pid == 0)
139 break;
b1b2a107 140
40e85d00
LP
141 if (pid < 0 && errno == ECHILD)
142 return;
143
144 if (n_processes > 0)
145 if (--n_processes == 0)
146 return;
b1b2a107
FF
147 }
148
40e85d00 149 n = now(CLOCK_MONOTONIC);
b1b2a107 150 if (n >= until)
40e85d00 151 return;
b1b2a107
FF
152
153 timespec_store(&ts, until - n);
40e85d00
LP
154
155 if ((k = sigtimedwait(mask, NULL, &ts)) != SIGCHLD) {
156
157 if (k < 0 && errno != EAGAIN) {
158 log_error("sigtimedwait() failed: %m");
159 return;
160 }
161
ab58e291
LP
162 if (k >= 0)
163 log_warning("sigtimedwait() returned unexpected signal.");
ab58e291 164 }
b1b2a107 165 }
40e85d00
LP
166}
167
168static void send_signal(int sign) {
169 sigset_t mask, oldmask;
170 int n_processes;
171
172 assert_se(sigemptyset(&mask) == 0);
173 assert_se(sigaddset(&mask, SIGCHLD) == 0);
174 assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0);
175
176 if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
177 log_warning("kill(-1, SIGSTOP) failed: %m");
178
179 n_processes = killall(sign);
180
181 if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
182 log_warning("kill(-1, SIGCONT) failed: %m");
183
184 if (n_processes <= 0)
185 goto finish;
186
187 wait_for_children(n_processes, &mask);
b1b2a107
FF
188
189finish:
190 sigprocmask(SIG_SETMASK, &oldmask, NULL);
b1b2a107
FF
191}
192
40e85d00 193static void ultimate_send_signal(int sign) {
b1b2a107 194 sigset_t mask, oldmask;
b1b2a107
FF
195 int r;
196
40e85d00
LP
197 assert_se(sigemptyset(&mask) == 0);
198 assert_se(sigaddset(&mask, SIGCHLD) == 0);
199 assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0);
b1b2a107 200
40e85d00 201 if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
ab58e291 202 log_warning("kill(-1, SIGSTOP) failed: %m");
b1b2a107
FF
203
204 r = kill(-1, sign);
40e85d00
LP
205 if (r < 0 && errno != ESRCH)
206 log_warning("kill(-1, %s) failed: %m", signal_to_string(sign));
b1b2a107 207
40e85d00 208 if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
ab58e291 209 log_warning("kill(-1, SIGCONT) failed: %m");
b1b2a107
FF
210
211 if (r < 0)
212 goto finish;
213
40e85d00 214 wait_for_children(0, &mask);
b1b2a107
FF
215
216finish:
217 sigprocmask(SIG_SETMASK, &oldmask, NULL);
b1b2a107
FF
218}
219
89d471d5
LP
220static int prepare_new_root(void) {
221 static const char dirs[] =
222 "/run/initramfs/oldroot\0"
223 "/run/initramfs/proc\0"
224 "/run/initramfs/sys\0"
225 "/run/initramfs/dev\0"
226 "/run/initramfs/run\0";
227
228 const char *dir;
229
230 if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) {
231 log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m");
232 return -errno;
233 }
234
235 if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) {
236 log_error("Failed to make /run/initramfs private mount: %m");
237 return -errno;
238 }
239
240 NULSTR_FOREACH(dir, dirs)
241 if (mkdir_p(dir, 0755) < 0 && errno != EEXIST) {
242 log_error("Failed to mkdir %s: %m", dir);
243 return -errno;
7cb1094a 244 }
89d471d5
LP
245
246 if (mount("/sys", "/run/initramfs/sys", NULL, MS_BIND, NULL) < 0) {
247 log_error("Failed to mount bind /sys on /run/initramfs/sys: %m");
248 return -errno;
249 }
250
251 if (mount("/proc", "/run/initramfs/proc", NULL, MS_BIND, NULL) < 0) {
252 log_error("Failed to mount bind /proc on /run/initramfs/proc: %m");
253 return -errno;
254 }
255
256 if (mount("/dev", "/run/initramfs/dev", NULL, MS_BIND, NULL) < 0) {
257 log_error("Failed to mount bind /dev on /run/initramfs/dev: %m");
258 return -errno;
7cb1094a
HH
259 }
260
89d471d5
LP
261 if (mount("/run", "/run/initramfs/run", NULL, MS_BIND, NULL) < 0) {
262 log_error("Failed to mount bind /run on /run/initramfs/run: %m");
263 return -errno;
264 }
265
266 return 0;
7cb1094a
HH
267}
268
89d471d5 269static int pivot_to_new_root(void) {
7cb1094a 270 int fd;
89d471d5 271
7cb1094a
HH
272 chdir("/run/initramfs");
273
274 /*
275 In case some evil process made "/" MS_SHARED
276 It works for pivot_root, but the ref count for the root device
277 is not decreasing :-/
278 */
89d471d5
LP
279 if (mount(NULL, "/", NULL, MS_PRIVATE, NULL) < 0) {
280 log_error("Failed to make \"/\" private mount %m");
281 return -errno;
7cb1094a
HH
282 }
283
89d471d5 284 if (pivot_root(".", "oldroot") < 0) {
7cb1094a 285 log_error("pivot failed: %m");
89d471d5
LP
286 /* only chroot if pivot root succeded */
287 return -errno;
7cb1094a 288 }
89d471d5 289
7cb1094a 290 chroot(".");
89d471d5
LP
291 log_info("Successfully changed into root pivot.");
292
293 fd = open("/dev/console", O_RDWR);
294 if (fd < 0)
295 log_error("Failed to open /dev/console: %m");
296 else {
297 make_stdio(fd);
bccc1d88
LP
298
299 /* Initialize the controlling terminal */
300 setsid();
301 ioctl(STDIN_FILENO, TIOCSCTTY, NULL);
89d471d5
LP
302 }
303
304 return 0;
7cb1094a
HH
305}
306
b1b2a107 307int main(int argc, char *argv[]) {
12aad1d0
LP
308 int cmd, r;
309 unsigned retries;
d48141ba 310 bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
e96d6be7 311 bool killed_everbody = false, in_container, use_watchdog = false;
b1b2a107
FF
312
313 log_parse_environment();
2ca1b422 314 log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
b1b2a107
FF
315 log_open();
316
4c12626c
LP
317 umask(0022);
318
b1b2a107 319 if (getpid() != 1) {
567ea02a 320 log_error("Not executed by init (pid 1).");
b1b2a107
FF
321 r = -EPERM;
322 goto error;
323 }
324
325 if (argc != 2) {
326 log_error("Invalid number of arguments.");
327 r = -EINVAL;
328 goto error;
329 }
330
40e85d00
LP
331 in_container = detect_container(NULL) > 0;
332
b1b2a107
FF
333 if (streq(argv[1], "reboot"))
334 cmd = RB_AUTOBOOT;
335 else if (streq(argv[1], "poweroff"))
336 cmd = RB_POWER_OFF;
337 else if (streq(argv[1], "halt"))
338 cmd = RB_HALT_SYSTEM;
339 else if (streq(argv[1], "kexec"))
340 cmd = LINUX_REBOOT_CMD_KEXEC;
341 else {
342 log_error("Unknown action '%s'.", argv[1]);
343 r = -EINVAL;
344 goto error;
345 }
346
e96d6be7
LP
347 use_watchdog = !!getenv("WATCHDOG_USEC");
348
b1b2a107
FF
349 /* lock us into memory */
350 if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0)
351 log_warning("Cannot lock process memory: %m");
352
ab58e291 353 log_info("Sending SIGTERM to remaining processes...");
40e85d00 354 send_signal(SIGTERM);
b1b2a107 355
ab58e291 356 log_info("Sending SIGKILL to remaining processes...");
40e85d00
LP
357 send_signal(SIGKILL);
358
359 if (in_container)
360 need_swapoff = false;
b1b2a107 361
567ea02a 362 /* Unmount all mountpoints, swaps, and loopback devices */
12aad1d0
LP
363 for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
364 bool changed = false;
365
e96d6be7
LP
366 if (use_watchdog)
367 watchdog_ping();
368
b1b2a107 369 if (need_umount) {
ab58e291 370 log_info("Unmounting file systems.");
12aad1d0 371 r = umount_all(&changed);
b1b2a107
FF
372 if (r == 0)
373 need_umount = false;
374 else if (r > 0)
ab58e291 375 log_info("Not all file systems unmounted, %d left.", r);
b1b2a107 376 else
ab58e291 377 log_error("Failed to unmount file systems: %s", strerror(-r));
b1b2a107
FF
378 }
379
380 if (need_swapoff) {
381 log_info("Disabling swaps.");
12aad1d0 382 r = swapoff_all(&changed);
b1b2a107
FF
383 if (r == 0)
384 need_swapoff = false;
385 else if (r > 0)
ab58e291 386 log_info("Not all swaps are turned off, %d left.", r);
b1b2a107 387 else
ab58e291 388 log_error("Failed to turn off swaps: %s", strerror(-r));
b1b2a107
FF
389 }
390
391 if (need_loop_detach) {
392 log_info("Detaching loop devices.");
12aad1d0 393 r = loopback_detach_all(&changed);
b1b2a107
FF
394 if (r == 0)
395 need_loop_detach = false;
396 else if (r > 0)
ab58e291 397 log_info("Not all loop devices detached, %d left.", r);
b1b2a107 398 else
ab58e291 399 log_error("Failed to detach loop devices: %s", strerror(-r));
d48141ba 400 }
b1b2a107 401
d48141ba
LP
402 if (need_dm_detach) {
403 log_info("Detaching DM devices.");
12aad1d0 404 r = dm_detach_all(&changed);
d48141ba
LP
405 if (r == 0)
406 need_dm_detach = false;
407 else if (r > 0)
ab58e291 408 log_warning("Not all DM devices detached, %d left.", r);
d48141ba 409 else
ab58e291 410 log_error("Failed to detach DM devices: %s", strerror(-r));
b1b2a107
FF
411 }
412
a27d2184
KS
413 if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
414 if (retries > 0)
415 log_info("All filesystems, swaps, loop devices, DM devices detached.");
12aad1d0
LP
416 /* Yay, done */
417 break;
a27d2184 418 }
b1b2a107 419
12aad1d0
LP
420 /* If in this iteration we didn't manage to
421 * unmount/deactivate anything, we either kill more
422 * processes, or simply give up */
423 if (!changed) {
b1b2a107 424
12aad1d0
LP
425 if (killed_everbody) {
426 /* Hmm, we already killed everybody,
427 * let's just give up */
ab58e291 428 log_error("Cannot finalize remaining file systems and devices, giving up.");
d37fb98b 429 break;
b1b2a107 430 }
12aad1d0 431
ab58e291 432 log_warning("Cannot finalize remaining file systems and devices, trying to kill remaining processes.");
40e85d00
LP
433 ultimate_send_signal(SIGTERM);
434 ultimate_send_signal(SIGKILL);
12aad1d0
LP
435 killed_everbody = true;
436 }
437
ab58e291 438 log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1);
b1b2a107
FF
439 }
440
12aad1d0 441 if (retries >= FINALIZE_ATTEMPTS)
35b8ca3a 442 log_error("Too many iterations, giving up.");
12aad1d0 443
83cc030f
LP
444 execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, NULL);
445
40e85d00
LP
446 /* If we are in a container, just exit, this will kill our
447 * container for good. */
f41de959
LP
448 if (in_container) {
449 log_error("Exiting container.");
40e85d00 450 exit(0);
f41de959 451 }
40e85d00 452
7cb1094a 453 if (access("/run/initramfs/shutdown", X_OK) == 0) {
89d471d5
LP
454
455 if (prepare_new_root() >= 0 &&
456 pivot_to_new_root() >= 0) {
457 execv("/shutdown", argv);
7cb1094a
HH
458 log_error("Failed to execute shutdown binary: %m");
459 }
460 }
461
89d471d5
LP
462 sync();
463
b1b2a107 464 if (cmd == LINUX_REBOOT_CMD_KEXEC) {
12aad1d0 465 /* We cheat and exec kexec to avoid doing all its work */
b1b2a107 466 pid_t pid = fork();
12aad1d0 467
e61cd186
LP
468 if (pid < 0)
469 log_error("Could not fork: %m. Falling back to normal reboot.");
470 else if (pid > 0) {
471 wait_for_terminate_and_warn("kexec", pid);
472 log_warning("kexec failed. Falling back to normal reboot.");
b1b2a107 473 } else {
e61cd186 474 /* Child */
f8d0ceb4 475 const char *args[3] = { "/sbin/kexec", "-e", NULL };
b1b2a107
FF
476 execv(args[0], (char * const *) args);
477 return EXIT_FAILURE;
478 }
e61cd186
LP
479
480 cmd = RB_AUTOBOOT;
b1b2a107
FF
481 }
482
483 reboot(cmd);
e61cd186
LP
484 log_error("Failed to invoke reboot(): %m");
485 r = -errno;
b1b2a107
FF
486
487 error:
e61cd186
LP
488 log_error("Critical error while doing system shutdown: %s", strerror(-r));
489
b1b2a107 490 freeze();
3c14d26c 491 return EXIT_FAILURE;
b1b2a107 492}