]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/umount.c
core: rework how we track service and scope PIDs
[thirdparty/systemd.git] / src / core / umount.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
e3478379
FF
2/***
3 This file is part of systemd.
4
5 Copyright 2010 ProFUSION embedded systems
e3478379
FF
6***/
7
8#include <errno.h>
9#include <fcntl.h>
4f5dd394 10#include <linux/loop.h>
e3478379
FF
11#include <string.h>
12#include <sys/mount.h>
13#include <sys/swap.h>
e3478379 14
95b862b0
ZJS
15/* This needs to be after sys/mount.h :( */
16#include <libmount.h>
17
b4bbcaa9
TA
18#include "libudev.h"
19
b5efdb8a 20#include "alloc-util.h"
18c528e9 21#include "blockdev-util.h"
d5641e0d 22#include "def.h"
07630cea 23#include "escape.h"
3ffd4af2 24#include "fd-util.h"
471b48ed 25#include "fstab-util.h"
dcce98a4 26#include "linux-3.13/dm-ioctl.h"
e3478379 27#include "mount-setup.h"
18c528e9 28#include "mount-util.h"
9eb977db 29#include "path-util.h"
dccca82b 30#include "process-util.h"
d5641e0d 31#include "signal-util.h"
07630cea 32#include "string-util.h"
4f5dd394 33#include "udev-util.h"
3ffd4af2 34#include "umount.h"
e3478379 35#include "util.h"
024f268d 36#include "virt.h"
e3478379 37
95b862b0
ZJS
38DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_table*, mnt_free_table);
39DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_iter*, mnt_free_iter);
40
12aad1d0
LP
41static void mount_point_free(MountPoint **head, MountPoint *m) {
42 assert(head);
43 assert(m);
e3478379 44
71fda00f 45 LIST_REMOVE(mount_point, *head, m);
12aad1d0
LP
46
47 free(m->path);
3bc341be 48 free(m->remount_options);
12aad1d0 49 free(m);
e3478379
FF
50}
51
6fa392bf 52void mount_points_list_free(MountPoint **head) {
12aad1d0
LP
53 assert(head);
54
55 while (*head)
56 mount_point_free(head, *head);
e3478379
FF
57}
58
6fa392bf 59int mount_points_list_get(const char *mountinfo, MountPoint **head) {
95b862b0
ZJS
60 _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL;
61 _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL;
527b7a42 62 int r;
e3478379 63
12aad1d0
LP
64 assert(head);
65
95b862b0
ZJS
66 t = mnt_new_table();
67 i = mnt_new_iter(MNT_ITER_FORWARD);
68 if (!t || !i)
69 return log_oom();
70
6fa392bf 71 r = mnt_table_parse_mtab(t, mountinfo);
95b862b0 72 if (r < 0)
6fa392bf 73 return log_error_errno(r, "Failed to parse %s: %m", mountinfo);
95b862b0
ZJS
74
75 for (;;) {
76 struct libmnt_fs *fs;
77 const char *path, *options, *fstype;
c7543606 78 _cleanup_free_ char *p = NULL;
95b862b0
ZJS
79 unsigned long remount_flags = 0u;
80 _cleanup_free_ char *remount_options = NULL;
81 bool try_remount_ro;
12aad1d0 82 MountPoint *m;
e3478379 83
95b862b0
ZJS
84 r = mnt_table_next_fs(t, i, &fs);
85 if (r == 1)
86 break;
527b7a42 87 if (r < 0)
6fa392bf 88 return log_error_errno(r, "Failed to get next entry from %s: %m", mountinfo);
95b862b0
ZJS
89
90 path = mnt_fs_get_target(fs);
91 if (!path)
92 continue;
93
94 if (cunescape(path, UNESCAPE_RELAX, &p) < 0)
95 return log_oom();
96
97 options = mnt_fs_get_options(fs);
98 fstype = mnt_fs_get_fstype(fs);
e3478379 99
46108b3b
LP
100 /* Ignore mount points we can't unmount because they
101 * are API or because we are keeping them open (like
874d3404
LP
102 * /dev/console). Also, ignore all mounts below API
103 * file systems, since they are likely virtual too,
104 * and hence not worth spending time on. Also, in
105 * unprivileged containers we might lack the rights to
106 * unmount these things, hence don't bother. */
46108b3b
LP
107 if (mount_point_is_api(p) ||
108 mount_point_ignore(p) ||
874d3404
LP
109 path_startswith(p, "/dev") ||
110 path_startswith(p, "/sys") ||
1d62d22d 111 path_startswith(p, "/proc"))
2054a5b8 112 continue;
2054a5b8 113
1d62d22d
JJ
114 /* If we are in a container, don't attempt to
115 * read-only mount anything as that brings no real
116 * benefits, but might confuse the host, as we remount
117 * the superblock here, not the bind mount.
118 *
119 * If the filesystem is a network fs, also skip the
120 * remount. It brings no value (we cannot leave
121 * a "dirty fs") and could hang if the network is down.
122 * Note that umount2() is more careful and will not
123 * hang because of the network being down. */
95b862b0
ZJS
124 try_remount_ro = detect_container() <= 0 &&
125 !fstype_is_network(fstype) &&
126 !fstype_is_api_vfs(fstype) &&
127 !fstype_is_ro(fstype) &&
128 !fstab_test_yes_no_option(options, "ro\0rw\0");
3bc341be 129
95b862b0 130 if (try_remount_ro) {
3bc341be
JJ
131 /* mount(2) states that mount flags and options need to be exactly the same
132 * as they were when the filesystem was mounted, except for the desired
133 * changes. So we reconstruct both here and adjust them for the later
134 * remount call too. */
135
95b862b0
ZJS
136 r = mnt_fs_get_propagation(fs, &remount_flags);
137 if (r < 0) {
138 log_warning_errno(r, "mnt_fs_get_propagation() failed for %s, ignoring: %m", path);
139 continue;
140 }
3bc341be 141
95b862b0
ZJS
142 r = mount_option_mangle(options, remount_flags, &remount_flags, &remount_options);
143 if (r < 0) {
144 log_warning_errno(r, "mount_option_mangle failed for %s, ignoring: %m", path);
145 continue;
146 }
3bc341be
JJ
147
148 /* MS_BIND is special. If it is provided it will only make the mount-point
149 * read-only. If left out, the super block itself is remounted, which we want. */
95b862b0 150 remount_flags = (remount_flags|MS_REMOUNT|MS_RDONLY) & ~MS_BIND;
3bc341be 151 }
471b48ed 152
95b862b0
ZJS
153 m = new0(MountPoint, 1);
154 if (!m)
155 return log_oom();
156
157 free_and_replace(m->path, p);
158 free_and_replace(m->remount_options, remount_options);
159 m->remount_flags = remount_flags;
160 m->try_remount_ro = try_remount_ro;
161
71fda00f 162 LIST_PREPEND(mount_point, *head, m);
e3478379
FF
163 }
164
c3544e8d 165 return 0;
e3478379
FF
166}
167
1fd8edb5 168int swap_list_get(const char *swaps, MountPoint **head) {
71ae04c4
ZJS
169 _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL;
170 _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL;
527b7a42 171 int r;
e3478379 172
12aad1d0
LP
173 assert(head);
174
71ae04c4
ZJS
175 t = mnt_new_table();
176 i = mnt_new_iter(MNT_ITER_FORWARD);
177 if (!t || !i)
178 return log_oom();
e3478379 179
71ae04c4
ZJS
180 r = mnt_table_parse_swaps(t, swaps);
181 if (r < 0)
182 return log_error_errno(r, "Failed to parse %s: %m", swaps);
183
184 for (;;) {
185 struct libmnt_fs *fs;
e3478379 186
e3478379 187 MountPoint *swap;
71ae04c4
ZJS
188 const char *source;
189 _cleanup_free_ char *d = NULL;
190
191 r = mnt_table_next_fs(t, i, &fs);
192 if (r == 1)
193 break;
194 if (r < 0)
195 return log_error_errno(r, "Failed to get next entry from %s: %m", swaps);
e3478379 196
71ae04c4
ZJS
197 source = mnt_fs_get_source(fs);
198 if (!source)
e3478379 199 continue;
e3478379 200
71ae04c4 201 r = cunescape(source, UNESCAPE_RELAX, &d);
527b7a42
LP
202 if (r < 0)
203 return r;
e3478379 204
527b7a42 205 swap = new0(MountPoint, 1);
595c66a3 206 if (!swap)
e1d75803 207 return -ENOMEM;
e3478379 208
595c66a3 209 free_and_replace(swap->path, d);
71fda00f 210 LIST_PREPEND(mount_point, *head, swap);
e3478379
FF
211 }
212
e1d75803 213 return 0;
e3478379
FF
214}
215
12aad1d0 216static int loopback_list_get(MountPoint **head) {
8e766630 217 _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
e3478379 218 struct udev_list_entry *item = NULL, *first = NULL;
8e766630 219 _cleanup_(udev_unrefp) struct udev *udev = NULL;
06acf2d4 220 int r;
e3478379 221
12aad1d0
LP
222 assert(head);
223
1ca208fb
ZJS
224 udev = udev_new();
225 if (!udev)
226 return -ENOMEM;
e3478379 227
1ca208fb
ZJS
228 e = udev_enumerate_new(udev);
229 if (!e)
230 return -ENOMEM;
e3478379 231
06acf2d4
LP
232 r = udev_enumerate_add_match_subsystem(e, "block");
233 if (r < 0)
234 return r;
235
236 r = udev_enumerate_add_match_sysname(e, "loop*");
237 if (r < 0)
238 return r;
239
240 r = udev_enumerate_add_match_sysattr(e, "loop/backing_file", NULL);
241 if (r < 0)
242 return r;
e3478379 243
06acf2d4
LP
244 r = udev_enumerate_scan_devices(e);
245 if (r < 0)
246 return r;
e3478379
FF
247
248 first = udev_enumerate_get_list_entry(e);
e3478379 249 udev_list_entry_foreach(item, first) {
8e766630 250 _cleanup_(udev_device_unrefp) struct udev_device *d;
b854a7e7 251 const char *dn;
a6dcd229 252 _cleanup_free_ MountPoint *lb = NULL;
e3478379 253
1ca208fb
ZJS
254 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
255 if (!d)
256 return -ENOMEM;
e3478379 257
1ca208fb
ZJS
258 dn = udev_device_get_devnode(d);
259 if (!dn)
2d9a3397 260 continue;
b854a7e7 261
1ca208fb 262 lb = new0(MountPoint, 1);
a6dcd229 263 if (!lb)
1ca208fb 264 return -ENOMEM;
e3478379 265
a6dcd229
ZJS
266 r = free_and_strdup(&lb->path, dn);
267 if (r < 0)
268 return r;
269
71fda00f 270 LIST_PREPEND(mount_point, *head, lb);
a6dcd229 271 lb = NULL;
e3478379
FF
272 }
273
1ca208fb 274 return 0;
e3478379
FF
275}
276
12aad1d0 277static int dm_list_get(MountPoint **head) {
8e766630 278 _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
d48141ba 279 struct udev_list_entry *item = NULL, *first = NULL;
8e766630 280 _cleanup_(udev_unrefp) struct udev *udev = NULL;
06acf2d4 281 int r;
d48141ba 282
12aad1d0
LP
283 assert(head);
284
1ca208fb
ZJS
285 udev = udev_new();
286 if (!udev)
287 return -ENOMEM;
d48141ba 288
1ca208fb
ZJS
289 e = udev_enumerate_new(udev);
290 if (!e)
291 return -ENOMEM;
d48141ba 292
06acf2d4
LP
293 r = udev_enumerate_add_match_subsystem(e, "block");
294 if (r < 0)
295 return r;
d48141ba 296
06acf2d4
LP
297 r = udev_enumerate_add_match_sysname(e, "dm-*");
298 if (r < 0)
299 return r;
d48141ba 300
06acf2d4
LP
301 r = udev_enumerate_scan_devices(e);
302 if (r < 0)
303 return r;
d48141ba 304
06acf2d4 305 first = udev_enumerate_get_list_entry(e);
d48141ba 306 udev_list_entry_foreach(item, first) {
8e766630 307 _cleanup_(udev_device_unrefp) struct udev_device *d;
2d9a3397 308 dev_t devnum;
2d9a3397 309 const char *dn;
a6dcd229 310 _cleanup_free_ MountPoint *m = NULL;
d48141ba 311
1ca208fb
ZJS
312 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
313 if (!d)
314 return -ENOMEM;
d48141ba 315
2d9a3397
LP
316 devnum = udev_device_get_devnum(d);
317 dn = udev_device_get_devnode(d);
1ca208fb 318 if (major(devnum) == 0 || !dn)
2d9a3397 319 continue;
d48141ba 320
b9361864 321 m = new0(MountPoint, 1);
a6dcd229 322 if (!m)
1ca208fb 323 return -ENOMEM;
d48141ba 324
2d9a3397 325 m->devnum = devnum;
a6dcd229
ZJS
326 r = free_and_strdup(&m->path, dn);
327 if (r < 0)
328 return r;
329
71fda00f 330 LIST_PREPEND(mount_point, *head, m);
a6dcd229 331 m = NULL;
d48141ba
LP
332 }
333
1ca208fb 334 return 0;
d48141ba
LP
335}
336
e3478379 337static int delete_loopback(const char *device) {
03e334a1
LP
338 _cleanup_close_ int fd = -1;
339 int r;
e3478379 340
0494cae0
JJ
341 assert(device);
342
03e334a1
LP
343 fd = open(device, O_RDONLY|O_CLOEXEC);
344 if (fd < 0)
c4f8bd1a 345 return errno == ENOENT ? 0 : -errno;
e3478379 346
ce726252 347 r = ioctl(fd, LOOP_CLR_FD, 0);
12aad1d0
LP
348 if (r >= 0)
349 return 1;
350
ce726252 351 /* ENXIO: not bound, so no error */
12aad1d0
LP
352 if (errno == ENXIO)
353 return 0;
354
355 return -errno;
e3478379
FF
356}
357
2d9a3397 358static int delete_dm(dev_t devnum) {
cf139e60 359
b92bea5d 360 struct dm_ioctl dm = {
cf139e60
LP
361 .version = {
362 DM_VERSION_MAJOR,
363 DM_VERSION_MINOR,
364 DM_VERSION_PATCHLEVEL
365 },
b92bea5d
ZJS
366 .data_size = sizeof(dm),
367 .dev = devnum,
368 };
d48141ba 369
cf139e60
LP
370 _cleanup_close_ int fd = -1;
371
2d9a3397 372 assert(major(devnum) != 0);
d48141ba 373
e62d8c39
ZJS
374 fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
375 if (fd < 0)
d48141ba
LP
376 return -errno;
377
cf139e60
LP
378 if (ioctl(fd, DM_DEV_REMOVE, &dm) < 0)
379 return -errno;
380
381 return 0;
d48141ba
LP
382}
383
c826cd3f
ZJS
384static bool nonunmountable_path(const char *path) {
385 return path_equal(path, "/")
349cc4a5 386#if ! HAVE_SPLIT_USR
c826cd3f
ZJS
387 || path_equal(path, "/usr")
388#endif
389 || path_startswith(path, "/run/initramfs");
390}
391
456b2199 392static int remount_with_timeout(MountPoint *m, int umount_log_level) {
d5641e0d
KW
393 pid_t pid;
394 int r;
395
396 BLOCK_SIGNALS(SIGCHLD);
397
0494cae0 398 assert(m);
0494cae0 399
d5641e0d
KW
400 /* Due to the possiblity of a remount operation hanging, we
401 * fork a child process and set a timeout. If the timeout
402 * lapses, the assumption is that that particular remount
403 * failed. */
0b1f3c76 404 r = safe_fork("(sd-remount)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &pid);
4c253ed1 405 if (r < 0)
b6e1fff1 406 return r;
4c253ed1 407 if (r == 0) {
3bc341be 408 log_info("Remounting '%s' read-only in with options '%s'.", m->path, m->remount_options);
d5641e0d
KW
409
410 /* Start the mount operation here in the child */
3bc341be 411 r = mount(NULL, m->path, NULL, m->remount_flags, m->remount_options);
d5641e0d 412 if (r < 0)
456b2199 413 log_full_errno(umount_log_level, errno, "Failed to remount '%s' read-only: %m", m->path);
d5641e0d
KW
414
415 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
416 }
417
418 r = wait_for_terminate_with_timeout(pid, DEFAULT_TIMEOUT_USEC);
419 if (r == -ETIMEDOUT) {
00adeed9 420 log_error_errno(r, "Remounting '%s' timed out, issuing SIGKILL to PID " PID_FMT ".", m->path, pid);
d5641e0d 421 (void) kill(pid, SIGKILL);
00adeed9 422 } else if (r == -EPROTO)
456b2199 423 log_debug_errno(r, "Remounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
00adeed9
LP
424 else if (r < 0)
425 log_error_errno(r, "Remounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT ": %m", m->path, pid);
d5641e0d
KW
426
427 return r;
428}
429
456b2199 430static int umount_with_timeout(MountPoint *m, int umount_log_level) {
d5641e0d
KW
431 pid_t pid;
432 int r;
433
434 BLOCK_SIGNALS(SIGCHLD);
435
0494cae0
JJ
436 assert(m);
437
d5641e0d
KW
438 /* Due to the possiblity of a umount operation hanging, we
439 * fork a child process and set a timeout. If the timeout
440 * lapses, the assumption is that that particular umount
441 * failed. */
0b1f3c76 442 r = safe_fork("(sd-umount)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &pid);
4c253ed1 443 if (r < 0)
b6e1fff1 444 return r;
4c253ed1 445 if (r == 0) {
d5641e0d
KW
446 log_info("Unmounting '%s'.", m->path);
447
448 /* Start the mount operation here in the child Using MNT_FORCE
449 * causes some filesystems (e.g. FUSE and NFS and other network
450 * filesystems) to abort any pending requests and return -EIO
451 * rather than blocking indefinitely. If the filesysten is
452 * "busy", this may allow processes to die, thus making the
453 * filesystem less busy so the unmount might succeed (rather
454 * then return EBUSY).*/
455 r = umount2(m->path, MNT_FORCE);
456 if (r < 0)
456b2199 457 log_full_errno(umount_log_level, errno, "Failed to unmount %s: %m", m->path);
d5641e0d
KW
458
459 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
460 }
461
462 r = wait_for_terminate_with_timeout(pid, DEFAULT_TIMEOUT_USEC);
463 if (r == -ETIMEDOUT) {
00adeed9 464 log_error_errno(r, "Unmounting '%s' timed out, issuing SIGKILL to PID " PID_FMT ".", m->path, pid);
d5641e0d 465 (void) kill(pid, SIGKILL);
00adeed9 466 } else if (r == -EPROTO)
456b2199 467 log_debug_errno(r, "Unmounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
00adeed9
LP
468 else if (r < 0)
469 log_error_errno(r, "Unmounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT ": %m", m->path, pid);
d5641e0d
KW
470
471 return r;
472}
473
116e6d96
AJ
474/* This includes remounting readonly, which changes the kernel mount options.
475 * Therefore the list passed to this function is invalidated, and should not be reused. */
456b2199 476static int mount_points_list_umount(MountPoint **head, bool *changed, int umount_log_level) {
116e6d96 477 MountPoint *m;
12aad1d0 478 int n_failed = 0;
e3478379 479
12aad1d0 480 assert(head);
0494cae0 481 assert(changed);
12aad1d0 482
116e6d96 483 LIST_FOREACH(mount_point, m, *head) {
1d62d22d 484 if (m->try_remount_ro) {
93bd1577
LP
485 /* We always try to remount directories
486 * read-only first, before we go on and umount
487 * them.
488 *
489 * Mount points can be stacked. If a mount
490 * point is stacked below / or /usr, we
ab06eef8 491 * cannot umount or remount it directly,
93bd1577
LP
492 * since there is no way to refer to the
493 * underlying mount. There's nothing we can do
494 * about it for the general case, but we can
495 * do something about it if it is aliased
496 * somehwere else via a bind mount. If we
497 * explicitly remount the super block of that
498 * alias read-only we hence should be
8645ffd1 499 * relatively safe regarding keeping a dirty fs
d5641e0d
KW
500 * we cannot otherwise see.
501 *
502 * Since the remount can hang in the instance of
503 * remote filesystems, we remount asynchronously
8645ffd1 504 * and skip the subsequent umount if it fails. */
456b2199 505 if (remount_with_timeout(m, umount_log_level) < 0) {
8645ffd1
JJ
506 /* Remount failed, but try unmounting anyway,
507 * unless this is a mount point we want to skip. */
508 if (nonunmountable_path(m->path)) {
c826cd3f 509 n_failed++;
8645ffd1
JJ
510 continue;
511 }
c826cd3f 512 }
93bd1577
LP
513 }
514
515 /* Skip / and /usr since we cannot unmount that
5a6f9d23
HG
516 * anyway, since we are running from it. They have
517 * already been remounted ro. */
c826cd3f 518 if (nonunmountable_path(m->path))
e3478379
FF
519 continue;
520
d5641e0d 521 /* Trying to umount */
456b2199 522 if (umount_with_timeout(m, umount_log_level) < 0)
d5641e0d 523 n_failed++;
0494cae0
JJ
524 else
525 *changed = true;
e3478379
FF
526 }
527
12aad1d0 528 return n_failed;
e3478379
FF
529}
530
12aad1d0
LP
531static int swap_points_list_off(MountPoint **head, bool *changed) {
532 MountPoint *m, *n;
533 int n_failed = 0;
534
535 assert(head);
0494cae0 536 assert(changed);
e3478379 537
12aad1d0 538 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
735e0712 539 log_info("Deactivating swap %s.", m->path);
12aad1d0 540 if (swapoff(m->path) == 0) {
0494cae0 541 *changed = true;
12aad1d0
LP
542 mount_point_free(head, m);
543 } else {
56f64d95 544 log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
12aad1d0 545 n_failed++;
e3478379
FF
546 }
547 }
548
12aad1d0 549 return n_failed;
e3478379
FF
550}
551
456b2199 552static int loopback_points_list_detach(MountPoint **head, bool *changed, int umount_log_level) {
12aad1d0 553 MountPoint *m, *n;
7fc942b2
LP
554 int n_failed = 0, k;
555 struct stat root_st;
12aad1d0
LP
556
557 assert(head);
0494cae0 558 assert(changed);
12aad1d0 559
7fc942b2
LP
560 k = lstat("/", &root_st);
561
12aad1d0
LP
562 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
563 int r;
7fc942b2
LP
564 struct stat loopback_st;
565
566 if (k >= 0 &&
567 major(root_st.st_dev) != 0 &&
568 lstat(m->path, &loopback_st) >= 0 &&
569 root_st.st_dev == loopback_st.st_rdev) {
313cefa1 570 n_failed++;
7fc942b2
LP
571 continue;
572 }
e3478379 573
735e0712 574 log_info("Detaching loopback %s.", m->path);
bce93b7a
MS
575 r = delete_loopback(m->path);
576 if (r >= 0) {
0494cae0 577 if (r > 0)
12aad1d0
LP
578 *changed = true;
579
580 mount_point_free(head, m);
581 } else {
456b2199 582 log_full_errno(umount_log_level, errno, "Could not detach loopback %s: %m", m->path);
12aad1d0 583 n_failed++;
e3478379
FF
584 }
585 }
586
12aad1d0 587 return n_failed;
e3478379
FF
588}
589
456b2199 590static int dm_points_list_detach(MountPoint **head, bool *changed, int umount_log_level) {
12aad1d0 591 MountPoint *m, *n;
33e8d8af
FB
592 int n_failed = 0, r;
593 dev_t rootdev;
12aad1d0
LP
594
595 assert(head);
0494cae0 596 assert(changed);
12aad1d0 597
33e8d8af
FB
598 r = get_block_device("/", &rootdev);
599 if (r <= 0)
600 rootdev = 0;
7fc942b2 601
12aad1d0 602 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
12aad1d0 603
0494cae0
JJ
604 if (major(rootdev) != 0 && rootdev == m->devnum) {
605 n_failed ++;
606 continue;
607 }
7fc942b2 608
735e0712 609 log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum));
bce93b7a
MS
610 r = delete_dm(m->devnum);
611 if (r >= 0) {
0494cae0 612 *changed = true;
12aad1d0
LP
613 mount_point_free(head, m);
614 } else {
456b2199 615 log_full_errno(umount_log_level, errno, "Could not detach DM %s: %m", m->path);
12aad1d0 616 n_failed++;
d48141ba
LP
617 }
618 }
619
12aad1d0 620 return n_failed;
d48141ba
LP
621}
622
456b2199 623static int umount_all_once(bool *changed, int umount_log_level) {
e3478379 624 int r;
a6dcd229 625 _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head);
e3478379 626
0494cae0
JJ
627 assert(changed);
628
71fda00f 629 LIST_HEAD_INIT(mp_list_head);
6fa392bf 630 r = mount_points_list_get(NULL, &mp_list_head);
e3478379 631 if (r < 0)
a6dcd229 632 return r;
116e6d96 633
a6dcd229 634 return mount_points_list_umount(&mp_list_head, changed, umount_log_level);
116e6d96
AJ
635}
636
456b2199 637int umount_all(bool *changed, int umount_log_level) {
116e6d96
AJ
638 bool umount_changed;
639 int r;
640
0494cae0
JJ
641 assert(changed);
642
d5641e0d
KW
643 /* Retry umount, until nothing can be umounted anymore. Mounts are
644 * processed in order, newest first. The retries are needed when
645 * an old mount has been moved, to a path inside a newer mount. */
6f7f51f7
HH
646 do {
647 umount_changed = false;
3e085b6c 648
456b2199 649 r = umount_all_once(&umount_changed, umount_log_level);
6f7f51f7
HH
650 if (umount_changed)
651 *changed = true;
3e085b6c
LP
652 } while (umount_changed);
653
e3478379
FF
654 return r;
655}
656
12aad1d0 657int swapoff_all(bool *changed) {
a6dcd229 658 _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, swap_list_head);
e3478379 659 int r;
e3478379 660
0494cae0
JJ
661 assert(changed);
662
71fda00f 663 LIST_HEAD_INIT(swap_list_head);
e3478379 664
1fd8edb5 665 r = swap_list_get(NULL, &swap_list_head);
e3478379 666 if (r < 0)
a6dcd229 667 return r;
e3478379 668
a6dcd229 669 return swap_points_list_off(&swap_list_head, changed);
e3478379
FF
670}
671
456b2199 672int loopback_detach_all(bool *changed, int umount_log_level) {
a6dcd229 673 _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, loopback_list_head);
e3478379 674 int r;
e3478379 675
0494cae0
JJ
676 assert(changed);
677
71fda00f 678 LIST_HEAD_INIT(loopback_list_head);
e3478379
FF
679
680 r = loopback_list_get(&loopback_list_head);
681 if (r < 0)
a6dcd229 682 return r;
e3478379 683
a6dcd229 684 return loopback_points_list_detach(&loopback_list_head, changed, umount_log_level);
e3478379 685}
d48141ba 686
456b2199 687int dm_detach_all(bool *changed, int umount_log_level) {
a6dcd229 688 _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, dm_list_head);
d48141ba 689 int r;
d48141ba 690
0494cae0
JJ
691 assert(changed);
692
71fda00f 693 LIST_HEAD_INIT(dm_list_head);
d48141ba
LP
694
695 r = dm_list_get(&dm_list_head);
696 if (r < 0)
a6dcd229 697 return r;
d48141ba 698
a6dcd229 699 return dm_points_list_detach(&dm_list_head, changed, umount_log_level);
d48141ba 700}