1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2010 ProFUSION embedded systems
8 #include <linux/dm-ioctl.h>
9 #include <linux/loop.h>
10 #include <sys/mount.h>
13 #include <sys/types.h>
16 #include "sd-device.h"
18 #include "alloc-util.h"
19 #include "blockdev-util.h"
21 #include "device-util.h"
24 #include "fstab-util.h"
25 #include "libmount-util.h"
26 #include "mount-setup.h"
27 #include "mount-util.h"
28 #include "mountpoint-util.h"
29 #include "path-util.h"
30 #include "process-util.h"
31 #include "signal-util.h"
32 #include "string-util.h"
38 static void mount_point_free(MountPoint
**head
, MountPoint
*m
) {
42 LIST_REMOVE(mount_point
, *head
, m
);
45 free(m
->remount_options
);
49 void mount_points_list_free(MountPoint
**head
) {
53 mount_point_free(head
, *head
);
56 int mount_points_list_get(const char *mountinfo
, MountPoint
**head
) {
57 _cleanup_(mnt_free_tablep
) struct libmnt_table
*table
= NULL
;
58 _cleanup_(mnt_free_iterp
) struct libmnt_iter
*iter
= NULL
;
63 r
= libmount_parse(mountinfo
, NULL
, &table
, &iter
);
65 return log_error_errno(r
, "Failed to parse %s: %m", mountinfo
?: "/proc/self/mountinfo");
69 const char *path
, *fstype
;
70 _cleanup_free_
char *options
= NULL
;
71 unsigned long remount_flags
= 0u;
72 _cleanup_free_
char *remount_options
= NULL
;
74 _cleanup_free_ MountPoint
*m
= NULL
;
76 r
= mnt_table_next_fs(table
, iter
, &fs
);
80 return log_error_errno(r
, "Failed to get next entry from %s: %m", mountinfo
?: "/proc/self/mountinfo");
82 path
= mnt_fs_get_target(fs
);
86 fstype
= mnt_fs_get_fstype(fs
);
88 /* Combine the generic VFS options with the FS-specific
89 * options. Duplicates are not a problem here, because the only
90 * options that should come up twice are typically ro/rw, which
91 * are turned into MS_RDONLY or the inversion of it.
93 * Even if there are duplicates later in mount_option_mangle()
94 * they shouldn't hurt anyways as they override each other.
96 if (!strextend_with_separator(&options
, ",",
97 mnt_fs_get_vfs_options(fs
),
100 if (!strextend_with_separator(&options
, ",",
101 mnt_fs_get_fs_options(fs
),
105 /* Ignore mount points we can't unmount because they
106 * are API or because we are keeping them open (like
107 * /dev/console). Also, ignore all mounts below API
108 * file systems, since they are likely virtual too,
109 * and hence not worth spending time on. Also, in
110 * unprivileged containers we might lack the rights to
111 * unmount these things, hence don't bother. */
112 if (mount_point_is_api(path
) ||
113 mount_point_ignore(path
) ||
114 PATH_STARTSWITH_SET(path
, "/dev", "/sys", "/proc"))
117 /* If we are in a container, don't attempt to
118 * read-only mount anything as that brings no real
119 * benefits, but might confuse the host, as we remount
120 * the superblock here, not the bind mount.
122 * If the filesystem is a network fs, also skip the
123 * remount. It brings no value (we cannot leave
124 * a "dirty fs") and could hang if the network is down.
125 * Note that umount2() is more careful and will not
126 * hang because of the network being down. */
127 try_remount_ro
= detect_container() <= 0 &&
128 !fstype_is_network(fstype
) &&
129 !fstype_is_api_vfs(fstype
) &&
130 !fstype_is_ro(fstype
) &&
131 !fstab_test_yes_no_option(options
, "ro\0rw\0");
133 if (try_remount_ro
) {
134 /* mount(2) states that mount flags and options need to be exactly the same
135 * as they were when the filesystem was mounted, except for the desired
136 * changes. So we reconstruct both here and adjust them for the later
137 * remount call too. */
139 r
= mnt_fs_get_propagation(fs
, &remount_flags
);
141 log_warning_errno(r
, "mnt_fs_get_propagation() failed for %s, ignoring: %m", path
);
145 r
= mount_option_mangle(options
, remount_flags
, &remount_flags
, &remount_options
);
147 log_warning_errno(r
, "mount_option_mangle failed for %s, ignoring: %m", path
);
151 /* MS_BIND is special. If it is provided it will only make the mount-point
152 * read-only. If left out, the super block itself is remounted, which we want. */
153 remount_flags
= (remount_flags
|MS_REMOUNT
|MS_RDONLY
) & ~MS_BIND
;
156 m
= new0(MountPoint
, 1);
160 m
->path
= strdup(path
);
164 m
->remount_options
= TAKE_PTR(remount_options
);
165 m
->remount_flags
= remount_flags
;
166 m
->try_remount_ro
= try_remount_ro
;
168 LIST_PREPEND(mount_point
, *head
, TAKE_PTR(m
));
174 int swap_list_get(const char *swaps
, MountPoint
**head
) {
175 _cleanup_(mnt_free_tablep
) struct libmnt_table
*t
= NULL
;
176 _cleanup_(mnt_free_iterp
) struct libmnt_iter
*i
= NULL
;
182 i
= mnt_new_iter(MNT_ITER_FORWARD
);
186 r
= mnt_table_parse_swaps(t
, swaps
);
187 if (r
== -ENOENT
) /* no /proc/swaps is fine */
190 return log_error_errno(r
, "Failed to parse %s: %m", swaps
?: "/proc/swaps");
193 struct libmnt_fs
*fs
;
194 _cleanup_free_ MountPoint
*swap
= NULL
;
197 r
= mnt_table_next_fs(t
, i
, &fs
);
201 return log_error_errno(r
, "Failed to get next entry from %s: %m", swaps
?: "/proc/swaps");
203 source
= mnt_fs_get_source(fs
);
207 swap
= new0(MountPoint
, 1);
211 swap
->path
= strdup(source
);
215 LIST_PREPEND(mount_point
, *head
, TAKE_PTR(swap
));
221 static int loopback_list_get(MountPoint
**head
) {
222 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
228 r
= sd_device_enumerator_new(&e
);
232 r
= sd_device_enumerator_allow_uninitialized(e
);
236 r
= sd_device_enumerator_add_match_subsystem(e
, "block", true);
240 r
= sd_device_enumerator_add_match_sysname(e
, "loop*");
244 r
= sd_device_enumerator_add_match_sysattr(e
, "loop/backing_file", NULL
, true);
248 FOREACH_DEVICE(e
, d
) {
249 _cleanup_free_
char *p
= NULL
;
254 if (sd_device_get_devnum(d
, &devnum
) < 0 ||
255 sd_device_get_devname(d
, &dn
) < 0)
262 lb
= new(MountPoint
, 1);
271 LIST_PREPEND(mount_point
, *head
, lb
);
277 static int dm_list_get(MountPoint
**head
) {
278 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
284 r
= sd_device_enumerator_new(&e
);
288 r
= sd_device_enumerator_allow_uninitialized(e
);
292 r
= sd_device_enumerator_add_match_subsystem(e
, "block", true);
296 r
= sd_device_enumerator_add_match_sysname(e
, "dm-*");
300 FOREACH_DEVICE(e
, d
) {
301 _cleanup_free_
char *p
= NULL
;
306 if (sd_device_get_devnum(d
, &devnum
) < 0 ||
307 sd_device_get_devname(d
, &dn
) < 0)
314 m
= new(MountPoint
, 1);
323 LIST_PREPEND(mount_point
, *head
, m
);
329 static int delete_loopback(const char *device
) {
330 _cleanup_close_
int fd
= -1;
331 struct loop_info64 info
;
335 fd
= open(device
, O_RDONLY
|O_CLOEXEC
);
337 return errno
== ENOENT
? 0 : -errno
;
339 if (ioctl(fd
, LOOP_CLR_FD
, 0) < 0) {
340 if (errno
== ENXIO
) /* Nothing bound, didn't do anything */
344 return log_debug_errno(errno
, "Failed to clear loopback device %s: %m", device
);
346 if (ioctl(fd
, LOOP_GET_STATUS64
, &info
) < 0) {
347 if (errno
== ENXIO
) /* What? Suddenly detached after all? That's fine by us then. */
350 log_debug_errno(errno
, "Failed to invoke LOOP_GET_STATUS64 on loopback device %s, ignoring: %m", device
);
351 return -EBUSY
; /* propagate original error */
354 if (FLAGS_SET(info
.lo_flags
, LO_FLAGS_AUTOCLEAR
)) /* someone else already set LO_FLAGS_AUTOCLEAR for us? fine by us */
355 return -EBUSY
; /* propagate original error */
357 info
.lo_flags
|= LO_FLAGS_AUTOCLEAR
;
358 if (ioctl(fd
, LOOP_SET_STATUS64
, &info
) < 0) {
359 if (errno
== ENXIO
) /* Suddenly detached after all? Fine by us */
362 log_debug_errno(errno
, "Failed to set LO_FLAGS_AUTOCLEAR flag for loop device %s, ignoring: %m", device
);
364 log_debug("Successfully set LO_FLAGS_AUTOCLEAR flag for loop device %s.", device
);
369 if (ioctl(fd
, LOOP_GET_STATUS64
, &info
) < 0) {
370 /* If the LOOP_CLR_FD above succeeded we'll see ENXIO here. */
372 log_debug("Successfully detached loopback device %s.", device
);
374 log_debug_errno(errno
, "Failed to invoke LOOP_GET_STATUS64 on loopback device %s, ignoring: %m", device
); /* the LOOP_CLR_FD at least worked, let's hope for the best */
379 /* Linux makes LOOP_CLR_FD succeed whenever LO_FLAGS_AUTOCLEAR is set without actually doing
380 * anything. Very confusing. Let's hence not claim we did anything in this case. */
381 if (FLAGS_SET(info
.lo_flags
, LO_FLAGS_AUTOCLEAR
))
382 log_debug("Successfully called LOOP_CLR_FD on a loopback device %s with autoclear set, which is a NOP.", device
);
384 log_debug("Weird, LOOP_CLR_FD succeeded but the device is still attached on %s.", device
);
386 return -EBUSY
; /* Nothing changed, the device is still attached, hence it apparently is still busy */
389 static int delete_dm(dev_t devnum
) {
391 struct dm_ioctl dm
= {
395 DM_VERSION_PATCHLEVEL
397 .data_size
= sizeof(dm
),
401 _cleanup_close_
int fd
= -1;
403 assert(major(devnum
) != 0);
405 fd
= open("/dev/mapper/control", O_RDWR
|O_CLOEXEC
);
409 if (ioctl(fd
, DM_DEV_REMOVE
, &dm
) < 0)
415 static bool nonunmountable_path(const char *path
) {
416 return path_equal(path
, "/")
418 || path_equal(path
, "/usr")
420 || path_startswith(path
, "/run/initramfs");
423 static int remount_with_timeout(MountPoint
*m
, int umount_log_level
) {
427 BLOCK_SIGNALS(SIGCHLD
);
431 /* Due to the possibility of a remount operation hanging, we
432 * fork a child process and set a timeout. If the timeout
433 * lapses, the assumption is that that particular remount
435 r
= safe_fork("(sd-remount)", FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_LOG
|FORK_REOPEN_LOG
, &pid
);
439 log_info("Remounting '%s' read-only in with options '%s'.", m
->path
, m
->remount_options
);
441 /* Start the mount operation here in the child */
442 r
= mount(NULL
, m
->path
, NULL
, m
->remount_flags
, m
->remount_options
);
444 log_full_errno(umount_log_level
, errno
, "Failed to remount '%s' read-only: %m", m
->path
);
446 _exit(r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
);
449 r
= wait_for_terminate_with_timeout(pid
, DEFAULT_TIMEOUT_USEC
);
450 if (r
== -ETIMEDOUT
) {
451 log_error_errno(r
, "Remounting '%s' timed out, issuing SIGKILL to PID " PID_FMT
".", m
->path
, pid
);
452 (void) kill(pid
, SIGKILL
);
453 } else if (r
== -EPROTO
)
454 log_debug_errno(r
, "Remounting '%s' failed abnormally, child process " PID_FMT
" aborted or exited non-zero.", m
->path
, pid
);
456 log_error_errno(r
, "Remounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT
": %m", m
->path
, pid
);
461 static int umount_with_timeout(MountPoint
*m
, int umount_log_level
) {
465 BLOCK_SIGNALS(SIGCHLD
);
469 /* Due to the possibility of a umount operation hanging, we
470 * fork a child process and set a timeout. If the timeout
471 * lapses, the assumption is that that particular umount
473 r
= safe_fork("(sd-umount)", FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_LOG
|FORK_REOPEN_LOG
, &pid
);
477 log_info("Unmounting '%s'.", m
->path
);
479 /* Start the mount operation here in the child Using MNT_FORCE
480 * causes some filesystems (e.g. FUSE and NFS and other network
481 * filesystems) to abort any pending requests and return -EIO
482 * rather than blocking indefinitely. If the filesysten is
483 * "busy", this may allow processes to die, thus making the
484 * filesystem less busy so the unmount might succeed (rather
485 * then return EBUSY).*/
486 r
= umount2(m
->path
, MNT_FORCE
);
488 log_full_errno(umount_log_level
, errno
, "Failed to unmount %s: %m", m
->path
);
490 _exit(r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
);
493 r
= wait_for_terminate_with_timeout(pid
, DEFAULT_TIMEOUT_USEC
);
494 if (r
== -ETIMEDOUT
) {
495 log_error_errno(r
, "Unmounting '%s' timed out, issuing SIGKILL to PID " PID_FMT
".", m
->path
, pid
);
496 (void) kill(pid
, SIGKILL
);
497 } else if (r
== -EPROTO
)
498 log_debug_errno(r
, "Unmounting '%s' failed abnormally, child process " PID_FMT
" aborted or exited non-zero.", m
->path
, pid
);
500 log_error_errno(r
, "Unmounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT
": %m", m
->path
, pid
);
505 /* This includes remounting readonly, which changes the kernel mount options. Therefore the list passed to
506 * this function is invalidated, and should not be reused. */
507 static int mount_points_list_umount(MountPoint
**head
, bool *changed
, int umount_log_level
) {
514 LIST_FOREACH(mount_point
, m
, *head
) {
515 if (m
->try_remount_ro
) {
516 /* We always try to remount directories read-only first, before we go on and umount
519 * Mount points can be stacked. If a mount point is stacked below / or /usr, we
520 * cannot umount or remount it directly, since there is no way to refer to the
521 * underlying mount. There's nothing we can do about it for the general case, but we
522 * can do something about it if it is aliased somewhere else via a bind mount. If we
523 * explicitly remount the super block of that alias read-only we hence should be
524 * relatively safe regarding keeping a dirty fs we cannot otherwise see.
526 * Since the remount can hang in the instance of remote filesystems, we remount
527 * asynchronously and skip the subsequent umount if it fails. */
528 if (remount_with_timeout(m
, umount_log_level
) < 0) {
529 /* Remount failed, but try unmounting anyway,
530 * unless this is a mount point we want to skip. */
531 if (nonunmountable_path(m
->path
)) {
538 /* Skip / and /usr since we cannot unmount that anyway, since we are running from it. They
539 * have already been remounted ro. */
540 if (nonunmountable_path(m
->path
))
543 /* Trying to umount */
544 if (umount_with_timeout(m
, umount_log_level
) < 0)
553 static int swap_points_list_off(MountPoint
**head
, bool *changed
) {
560 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
561 log_info("Deactivating swap %s.", m
->path
);
562 if (swapoff(m
->path
) < 0) {
563 log_warning_errno(errno
, "Could not deactivate swap %s: %m", m
->path
);
569 mount_point_free(head
, m
);
575 static int loopback_points_list_detach(MountPoint
**head
, bool *changed
, int umount_log_level
) {
583 (void) get_block_device("/", &rootdev
);
585 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
586 if (major(rootdev
) != 0 && rootdev
== m
->devnum
) {
591 log_info("Detaching loopback %s.", m
->path
);
592 r
= delete_loopback(m
->path
);
594 log_full_errno(umount_log_level
, r
, "Could not detach loopback %s: %m", m
->path
);
601 mount_point_free(head
, m
);
607 static int dm_points_list_detach(MountPoint
**head
, bool *changed
, int umount_log_level
) {
615 (void) get_block_device("/", &rootdev
);
617 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
618 if (major(rootdev
) != 0 && rootdev
== m
->devnum
) {
623 log_info("Detaching DM %s (%u:%u).", m
->path
, major(m
->devnum
), minor(m
->devnum
));
624 r
= delete_dm(m
->devnum
);
626 log_full_errno(umount_log_level
, r
, "Could not detach DM %s: %m", m
->path
);
632 mount_point_free(head
, m
);
638 static int umount_all_once(bool *changed
, int umount_log_level
) {
639 _cleanup_(mount_points_list_free
) LIST_HEAD(MountPoint
, mp_list_head
);
644 LIST_HEAD_INIT(mp_list_head
);
645 r
= mount_points_list_get(NULL
, &mp_list_head
);
649 return mount_points_list_umount(&mp_list_head
, changed
, umount_log_level
);
652 int umount_all(bool *changed
, int umount_log_level
) {
658 /* Retry umount, until nothing can be umounted anymore. Mounts are
659 * processed in order, newest first. The retries are needed when
660 * an old mount has been moved, to a path inside a newer mount. */
662 umount_changed
= false;
664 r
= umount_all_once(&umount_changed
, umount_log_level
);
667 } while (umount_changed
);
672 int swapoff_all(bool *changed
) {
673 _cleanup_(mount_points_list_free
) LIST_HEAD(MountPoint
, swap_list_head
);
678 LIST_HEAD_INIT(swap_list_head
);
680 r
= swap_list_get(NULL
, &swap_list_head
);
684 return swap_points_list_off(&swap_list_head
, changed
);
687 int loopback_detach_all(bool *changed
, int umount_log_level
) {
688 _cleanup_(mount_points_list_free
) LIST_HEAD(MountPoint
, loopback_list_head
);
693 LIST_HEAD_INIT(loopback_list_head
);
695 r
= loopback_list_get(&loopback_list_head
);
699 return loopback_points_list_detach(&loopback_list_head
, changed
, umount_log_level
);
702 int dm_detach_all(bool *changed
, int umount_log_level
) {
703 _cleanup_(mount_points_list_free
) LIST_HEAD(MountPoint
, dm_list_head
);
708 LIST_HEAD_INIT(dm_list_head
);
710 r
= dm_list_get(&dm_list_head
);
714 return dm_points_list_detach(&dm_list_head
, changed
, umount_log_level
);