]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/shutdown.c
mkdir: append _label to all mkdir() calls that explicitly set the selinux context
[thirdparty/systemd.git] / src / core / shutdown.c
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
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.
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
16 Lesser General Public License for more details.
17
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/>.
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>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/mount.h>
30 #include <sys/syscall.h>
31 #include <fcntl.h>
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
40 #include "missing.h"
41 #include "log.h"
42 #include "umount.h"
43 #include "util.h"
44 #include "mkdir.h"
45 #include "virt.h"
46 #include "watchdog.h"
47
48 #define TIMEOUT_USEC (5 * USEC_PER_SEC)
49 #define FINALIZE_ATTEMPTS 50
50
51 static bool ignore_proc(pid_t pid) {
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 */
60 if (pid == 1)
61 return true;
62
63 r = get_process_uid(pid, &uid);
64 if (r < 0)
65 return true; /* not really, but better safe than sorry */
66
67 /* Non-root processes otherwise are always subject to be killed */
68 if (uid != 0)
69 return false;
70
71 snprintf(buf, sizeof(buf), "/proc/%lu/cmdline", (unsigned long) pid);
72 char_array_0(buf);
73
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);
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
86 * spree.
87 *
88 * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */
89 if (count == 1 && c == '@')
90 return true;
91
92 return false;
93 }
94
95 static int killall(int sign) {
96 DIR *dir;
97 struct dirent *d;
98 unsigned int n_processes = 0;
99
100 dir = opendir("/proc");
101 if (!dir)
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
110 if (ignore_proc(pid))
111 continue;
112
113 if (kill(pid, sign) == 0)
114 n_processes++;
115 else
116 log_warning("Could not kill %d: %m", pid);
117 }
118
119 closedir(dir);
120
121 return n_processes;
122 }
123
124 static void wait_for_children(int n_processes, sigset_t *mask) {
125 usec_t until;
126
127 assert(mask);
128
129 until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC;
130 for (;;) {
131 struct timespec ts;
132 int k;
133 usec_t n;
134
135 for (;;) {
136 pid_t pid = waitpid(-1, NULL, WNOHANG);
137
138 if (pid == 0)
139 break;
140
141 if (pid < 0 && errno == ECHILD)
142 return;
143
144 if (n_processes > 0)
145 if (--n_processes == 0)
146 return;
147 }
148
149 n = now(CLOCK_MONOTONIC);
150 if (n >= until)
151 return;
152
153 timespec_store(&ts, until - n);
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
162 if (k >= 0)
163 log_warning("sigtimedwait() returned unexpected signal.");
164 }
165 }
166 }
167
168 static 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);
188
189 finish:
190 sigprocmask(SIG_SETMASK, &oldmask, NULL);
191 }
192
193 static void ultimate_send_signal(int sign) {
194 sigset_t mask, oldmask;
195 int r;
196
197 assert_se(sigemptyset(&mask) == 0);
198 assert_se(sigaddset(&mask, SIGCHLD) == 0);
199 assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0);
200
201 if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
202 log_warning("kill(-1, SIGSTOP) failed: %m");
203
204 r = kill(-1, sign);
205 if (r < 0 && errno != ESRCH)
206 log_warning("kill(-1, %s) failed: %m", signal_to_string(sign));
207
208 if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
209 log_warning("kill(-1, SIGCONT) failed: %m");
210
211 if (r < 0)
212 goto finish;
213
214 wait_for_children(0, &mask);
215
216 finish:
217 sigprocmask(SIG_SETMASK, &oldmask, NULL);
218 }
219
220 static 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_label(dir, 0755) < 0 && errno != EEXIST) {
242 log_error("Failed to mkdir %s: %m", dir);
243 return -errno;
244 }
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;
259 }
260
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;
267 }
268
269 static int pivot_to_new_root(void) {
270 int fd;
271
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 */
279 if (mount(NULL, "/", NULL, MS_PRIVATE, NULL) < 0) {
280 log_error("Failed to make \"/\" private mount %m");
281 return -errno;
282 }
283
284 if (pivot_root(".", "oldroot") < 0) {
285 log_error("pivot failed: %m");
286 /* only chroot if pivot root succeded */
287 return -errno;
288 }
289
290 chroot(".");
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);
298
299 /* Initialize the controlling terminal */
300 setsid();
301 ioctl(STDIN_FILENO, TIOCSCTTY, NULL);
302 }
303
304 return 0;
305 }
306
307 int main(int argc, char *argv[]) {
308 int cmd, r;
309 unsigned retries;
310 bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
311 bool killed_everbody = false, in_container, use_watchdog = false;
312 char *arguments[3];
313
314 log_parse_environment();
315 log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
316 log_open();
317
318 umask(0022);
319
320 if (getpid() != 1) {
321 log_error("Not executed by init (pid 1).");
322 r = -EPERM;
323 goto error;
324 }
325
326 if (argc != 2) {
327 log_error("Invalid number of arguments.");
328 r = -EINVAL;
329 goto error;
330 }
331
332 in_container = detect_container(NULL) > 0;
333
334 if (streq(argv[1], "reboot"))
335 cmd = RB_AUTOBOOT;
336 else if (streq(argv[1], "poweroff"))
337 cmd = RB_POWER_OFF;
338 else if (streq(argv[1], "halt"))
339 cmd = RB_HALT_SYSTEM;
340 else if (streq(argv[1], "kexec"))
341 cmd = LINUX_REBOOT_CMD_KEXEC;
342 else {
343 log_error("Unknown action '%s'.", argv[1]);
344 r = -EINVAL;
345 goto error;
346 }
347
348 use_watchdog = !!getenv("WATCHDOG_USEC");
349
350 /* lock us into memory */
351 mlockall(MCL_CURRENT|MCL_FUTURE);
352
353 log_info("Sending SIGTERM to remaining processes...");
354 send_signal(SIGTERM);
355
356 log_info("Sending SIGKILL to remaining processes...");
357 send_signal(SIGKILL);
358
359 if (in_container) {
360 need_swapoff = false;
361 need_dm_detach = false;
362 }
363
364 /* Unmount all mountpoints, swaps, and loopback devices */
365 for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
366 bool changed = false;
367
368 if (use_watchdog)
369 watchdog_ping();
370
371 if (need_umount) {
372 log_info("Unmounting file systems.");
373 r = umount_all(&changed);
374 if (r == 0)
375 need_umount = false;
376 else if (r > 0)
377 log_info("Not all file systems unmounted, %d left.", r);
378 else
379 log_error("Failed to unmount file systems: %s", strerror(-r));
380 }
381
382 if (need_swapoff) {
383 log_info("Disabling swaps.");
384 r = swapoff_all(&changed);
385 if (r == 0)
386 need_swapoff = false;
387 else if (r > 0)
388 log_info("Not all swaps are turned off, %d left.", r);
389 else
390 log_error("Failed to turn off swaps: %s", strerror(-r));
391 }
392
393 if (need_loop_detach) {
394 log_info("Detaching loop devices.");
395 r = loopback_detach_all(&changed);
396 if (r == 0)
397 need_loop_detach = false;
398 else if (r > 0)
399 log_info("Not all loop devices detached, %d left.", r);
400 else
401 log_error("Failed to detach loop devices: %s", strerror(-r));
402 }
403
404 if (need_dm_detach) {
405 log_info("Detaching DM devices.");
406 r = dm_detach_all(&changed);
407 if (r == 0)
408 need_dm_detach = false;
409 else if (r > 0)
410 log_warning("Not all DM devices detached, %d left.", r);
411 else
412 log_error("Failed to detach DM devices: %s", strerror(-r));
413 }
414
415 if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
416 if (retries > 0)
417 log_info("All filesystems, swaps, loop devices, DM devices detached.");
418 /* Yay, done */
419 break;
420 }
421
422 /* If in this iteration we didn't manage to
423 * unmount/deactivate anything, we either kill more
424 * processes, or simply give up */
425 if (!changed) {
426
427 if (killed_everbody) {
428 /* Hmm, we already killed everybody,
429 * let's just give up */
430 log_error("Cannot finalize remaining file systems and devices, giving up.");
431 break;
432 }
433
434 log_warning("Cannot finalize remaining file systems and devices, trying to kill remaining processes.");
435 ultimate_send_signal(SIGTERM);
436 ultimate_send_signal(SIGKILL);
437 killed_everbody = true;
438 }
439
440 log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1);
441 }
442
443 if (retries >= FINALIZE_ATTEMPTS)
444 log_error("Too many iterations, giving up.");
445
446 arguments[0] = NULL;
447 arguments[1] = argv[1];
448 arguments[2] = NULL;
449 execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments);
450
451 /* If we are in a container, just exit, this will kill our
452 * container for good. */
453 if (in_container) {
454 log_error("Exiting container.");
455 exit(0);
456 }
457
458 if (access("/run/initramfs/shutdown", X_OK) == 0) {
459
460 if (prepare_new_root() >= 0 &&
461 pivot_to_new_root() >= 0) {
462 execv("/shutdown", argv);
463 log_error("Failed to execute shutdown binary: %m");
464 }
465 }
466
467 sync();
468
469 if (cmd == LINUX_REBOOT_CMD_KEXEC) {
470 /* We cheat and exec kexec to avoid doing all its work */
471 pid_t pid = fork();
472
473 if (pid < 0)
474 log_error("Could not fork: %m. Falling back to normal reboot.");
475 else if (pid > 0) {
476 wait_for_terminate_and_warn("kexec", pid);
477 log_warning("kexec failed. Falling back to normal reboot.");
478 } else {
479 /* Child */
480 const char *args[3] = { "/sbin/kexec", "-e", NULL };
481 execv(args[0], (char * const *) args);
482 return EXIT_FAILURE;
483 }
484
485 cmd = RB_AUTOBOOT;
486 }
487
488 reboot(cmd);
489 log_error("Failed to invoke reboot(): %m");
490 r = -errno;
491
492 error:
493 log_error("Critical error while doing system shutdown: %s", strerror(-r));
494
495 freeze();
496 return EXIT_FAILURE;
497 }