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