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