Skip to content

Commit

Permalink
btrfs-progs: utils: introduce find_mount_fsroot
Browse files Browse the repository at this point in the history
This new function checks for filesystem path name that was mounted, thus
being different from find_mount_root. By using libmount we can easily
parse /proc/self/mountinfo file and check for the pathname field.

The function is useful to filter bind mounts with content different from
the original mount, thus making it safe to assume that the reported path
can be accessed by the user, with the right content.

Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
  • Loading branch information
marcosps authored and kdave committed Jan 18, 2021
1 parent 61ecaff commit 57cfe29
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
102 changes: 102 additions & 0 deletions common/utils.c
Expand Up @@ -35,6 +35,7 @@
#include <linux/kdev_t.h>
#include <limits.h>
#include <blkid/blkid.h>
#include <libmount/libmount.h>
#include <sys/vfs.h>
#include <sys/statfs.h>
#include <linux/magic.h>
Expand Down Expand Up @@ -1243,6 +1244,107 @@ int ask_user(const char *question)
(!strcasecmp(answer, "yes") || !strcasecmp(answer, "y"));
}

/*
* Use libmount to compare the subvol passed with the pathname of the directory
* mounted in btrfs. The pathname inside btrfs is different from getmnt and
* friends, since it can detect bind mounts to content from the inside of the
* original mount.
*
* Example:
* # mount -o subvol=/vol /dev/sda2 /mnt
* # mount --bind /mnt/dir2 /othermnt
*
* # mounts
* ...
* /dev/sda2 on /mnt type btrfs (ro,relatime,ssd,space_cache,subvolid=256,subvol=/vol)
* /dev/sda2 on /othermnt type btrfs (ro,relatime,ssd,space_cache,subvolid=256,subvol=/vol)
*
* # cat /proc/self/mountinfo
*
* 38 30 0:32 /vol /mnt ro,relatime - btrfs /dev/sda2 ro,ssd,space_cache,subvolid=256,subvol=/vol
* 37 29 0:32 /vol/dir2 /othermnt ro,relatime - btrfs /dev/sda2 ro,ssd,space_cache,subvolid=256,subvol=/vol
*
* If we try to find a mounpoint only using subvol and subvolid from mount
* options we would get mislead to belive that /othermnt has the same content
* from /mnt.
*
* But, using mountinfo, we have the pathaname _inside_ the filesystem, so we
* can filter out the mount points with bind mounts which has different content
* from the original mounts, in this case the mount point with id 37.
*/
int find_mount_fsroot(const char *subvol, const char *subvolid, char **mount)
{
struct libmnt_cache *cache;
struct libmnt_iter *iter;
struct libmnt_fs *fs;
struct libmnt_table *tb;

tb = mnt_new_table_from_file("/proc/self/mountinfo");
if (!tb)
return -1;

iter = mnt_new_iter(MNT_ITER_FORWARD);
if (!iter)
goto out_table;

cache = mnt_new_cache();
if (!cache)
goto out_iter;

if (mnt_table_set_cache(tb, cache))
goto out_cache;

while (mnt_table_next_fs(tb, iter, &fs) == 0) {
const char *mnt_root = mnt_fs_get_root(fs);
bool found = true;
char *subid = NULL;
size_t id_siz;

/*
* Check any combination that would lead to an undesired mount
* point and remove from the table.
*/
if (strcmp(mnt_fs_get_fstype(fs), "btrfs") != 0)
found = false;
else if (strlen(mnt_root) != strlen(subvol))
found = false;
else if (strcmp(mnt_root, subvol) != 0)
found = false;
else if (mnt_fs_get_option(fs, "subvolid", &subid, &id_siz))
found = false;
else if (strncmp(subid, subvolid, id_siz) != 0)
found = false;

if (!found)
mnt_table_remove_fs(tb, fs);
}

/* Rewind the iterator to make second pass */
mnt_reset_iter(iter, MNT_ITER_FORWARD);

/*
* What remains in the list are the mount itself and possible bind mounts
* referring to the same pathname mounted by the original mount. As in
* this case the mount point would have the same content of the original
* mount, we can safely return the first entry.
*/
if (!mnt_table_is_empty(tb)) {
mnt_table_next_fs(tb, iter, &fs);
*mount = strdup(mnt_fs_get_target(fs));
}

return 0;

out_cache:
mnt_unref_cache(cache);
out_iter:
mnt_free_iter(iter);
out_table:
mnt_unref_table(tb);

return -1;
}

/*
* return 0 if a btrfs mount point is found
* return 1 if a mount point is found but not btrfs
Expand Down
1 change: 1 addition & 0 deletions common/utils.h
Expand Up @@ -107,6 +107,7 @@ int csum_tree_block(struct btrfs_fs_info *root, struct extent_buffer *buf,
int ask_user(const char *question);
int lookup_path_rootid(int fd, u64 *rootid);
int get_btrfs_mount(const char *dev, char *mp, size_t mp_size);
int find_mount_fsroot(const char *subvol, const char *subvolid, char **mount);
int find_mount_root(const char *path, char **mount_root);
int get_device_info(int fd, u64 devid,
struct btrfs_ioctl_dev_info_args *di_args);
Expand Down

0 comments on commit 57cfe29

Please sign in to comment.