All of lore.kernel.org
 help / color / mirror / Atom feed
From: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
To: <linux-btrfs@vger.kernel.org>
Subject: [PATCH v2 11/20] btrfs-progs: sub list: Add -f option to follow mounted subvolumes below the path
Date: Mon, 18 Jun 2018 17:40:59 +0900	[thread overview]
Message-ID: <84d06767762b4285ddefec0392ee16e2d7e06f62.1529310485.git.misono.tomohiro@jp.fujitsu.com> (raw)
In-Reply-To: <cover.1529310485.git.misono.tomohiro@jp.fujitsu.com>

Add -f option to follow mounted subvolumes below the specified path, only
if it is the same filesystem.

[Example]
 $ mkfs.btrfs -f $DEV
 $ mkfs.btrfs -f $DEV2
 $ mount $DEV /mnt

 $ btrfs subvolume create /mnt/AAA
 $ btrfs subvolume create /mnt/BBB
 $ btrfs subvolume create /mnt/CCC
 $ mkdir /mnt/AAA/bbb
 $ mkdir /mnt/AAA/ccc
 $ mkdir /mnt/AAA/other

 $ umount /mnt
 $ mount -o subvol=AAA $DEV /mnt
 $ mount -o subvol=BBB $DEV /mnt/bbb
 $ mount -o subvol=CCC $DEV /mnt/ccc
 $ mount -o $DEV2 /mnt/other

 $ btrfs subvolume list /mnt
 ID 256 gen 9 top level 5 path .

 $ btrfs subvolume list -f /mnt
 ID 256 gen 9 top level 5 path .
 ID 258 gen 7 top level 5 path bbb
 ID 259 gen 8 top level 5 path ccc

Note that this option lists top-level subvolume if it is mounted in the
way.

Signed-off-by: Misono Tomohiro <misono.tomohiro@jp.fujitsu.com>
---
 Documentation/btrfs-subvolume.asciidoc |   4 ++
 cmds-subvolume.c                       | 116 +++++++++++++++++++++++++++++++--
 2 files changed, 113 insertions(+), 7 deletions(-)

diff --git a/Documentation/btrfs-subvolume.asciidoc b/Documentation/btrfs-subvolume.asciidoc
index fec4b769..b2461398 100644
--- a/Documentation/btrfs-subvolume.asciidoc
+++ b/Documentation/btrfs-subvolume.asciidoc
@@ -120,6 +120,10 @@ print only subvolumes below specified <path>.
 -a::::
 print all the subvolumes in the filesystem and distinguish between
 absolute and relative path with respect to the given <path>.
+-f::::
+follow mounted subvolumes below <path> recursively and list them too
+(only if it is the same filesystem). If top-level subvolume is mounted
+in the way, it is also listed.
 
 Field selection;;
 -p::::
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index ea341d50..4ebe0377 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -28,6 +28,7 @@
 #include <getopt.h>
 #include <uuid/uuid.h>
 #include <linux/magic.h>
+#include <mntent.h>
 
 #include <btrfsutil.h>
 
@@ -1157,7 +1158,8 @@ static void get_subvols_info(struct subvol_list **subvols,
 			     int fd,
 			     int tree_id,
 			     size_t *capacity,
-			     const char *prefix)
+			     const char *prefix,
+			     int show_top)
 {
 	struct btrfs_util_subvolume_iterator *iter;
 	enum btrfs_util_error err;
@@ -1195,7 +1197,7 @@ static void get_subvols_info(struct subvol_list **subvols,
 			ret = -1;
 			goto out;
 		}
-		if (id == BTRFS_FS_TREE_OBJECTID) {
+		if (!show_top && id == BTRFS_FS_TREE_OBJECTID) {
 			/* Skip top level subvolume */
 			ret = 0;
 			goto skip;
@@ -1280,6 +1282,7 @@ out:
 static struct subvol_list *btrfs_list_subvols(int fd,
 					      int is_list_all,
 					      int absolute_path,
+					      int follow_mount,
 					      const char *path,
 					      struct btrfs_list_filter_set_v2 *filter_set)
 {
@@ -1295,7 +1298,8 @@ static struct subvol_list *btrfs_list_subvols(int fd,
 
 	if (is_list_all) {
 		get_subvols_info(&subvols, filter_set, fd,
-				BTRFS_FS_TREE_OBJECTID, &capacity, NULL);
+				BTRFS_FS_TREE_OBJECTID, &capacity, NULL,
+				false);
 	} else {
 		char *fullpath;
 
@@ -1307,8 +1311,92 @@ static struct subvol_list *btrfs_list_subvols(int fd,
 		}
 
 		get_subvols_info(&subvols, filter_set, fd, 0, &capacity,
-				(absolute_path ? fullpath : NULL));
+				(absolute_path ? fullpath : NULL), false);
 
+		if (subvols == NULL) {
+			free(fullpath);
+			return NULL;
+		}
+
+		/* Follow mounted subvolumes below @path */
+		if (follow_mount) {
+			struct mntent *mnt;
+			FILE *f;
+			DIR *dirstream;
+			u8 fsid[BTRFS_FSID_SIZE];
+			u8 fsid2[BTRFS_FSID_SIZE];
+			char *c;
+			int fd2;
+			int ret;
+
+			ret = get_fsid(path, fsid, 0);
+			if (ret < 0) {
+				error("failed to get fsid: %m");
+				free(fullpath);
+				free_subvol_list(subvols);
+				return NULL;
+			}
+
+			f = setmntent("/proc/self/mounts", "r");
+			if (f == NULL) {
+				error("failed to read mount entry: %m");
+				free(fullpath);
+				free_subvol_list(subvols);
+				return NULL;
+			}
+
+			/* Iterate for each mount entry */
+			while ((mnt = getmntent(f)) != NULL) {
+				if (strcmp(mnt->mnt_type, "btrfs"))
+					continue;
+
+				if (!strcmp(mnt->mnt_dir, fullpath))
+					continue;
+
+				c = strstr(mnt->mnt_dir, fullpath);
+				if (c != mnt->mnt_dir)
+					continue;
+
+				/* If fsid is different, skip it */
+				ret = get_fsid(mnt->mnt_dir, fsid2, 1);
+				if (ret < 0) {
+					/*
+					 * ENOENT may happen when mount is
+					 * stacked
+					 */
+					if (errno == EACCES || errno == ENOENT)
+						continue;
+					error("failed to get fsid: %m");
+					free(fullpath);
+					free_subvol_list(subvols);
+					return NULL;
+				}
+				if (uuid_compare(fsid, fsid2))
+					continue;
+
+				fd2 = btrfs_open_dir(mnt->mnt_dir,
+						     &dirstream, 1);
+				if (fd2 < 0) {
+					error("cannot open '%s': %m",
+							mnt->mnt_dir);
+					free(fullpath);
+					free_subvol_list(subvols);
+					return NULL;
+				}
+				get_subvols_info(&subvols, filter_set,
+						fd2, 0, &capacity,
+						(absolute_path ? mnt->mnt_dir :
+							(strlen(fullpath) == 1 ?
+							 mnt->mnt_dir + 1 :
+							 mnt->mnt_dir + strlen(fullpath) + 1)),
+						true);
+				close_file_or_dir(fd2, dirstream);
+				if (subvols == NULL) {
+					free(fullpath);
+					return NULL;
+				}
+			}
+		}
 		free(fullpath);
 	}
 
@@ -1321,6 +1409,7 @@ static int btrfs_list_subvols_print_v2(int fd,
 				    enum btrfs_list_layout layout,
 				    int is_list_all,
 				    int absolute_path,
+				    int follow_mount,
 				    const char *path,
 				    const char *raw_prefix)
 {
@@ -1330,7 +1419,7 @@ static int btrfs_list_subvols_print_v2(int fd,
 		subvols = btrfs_list_deleted_subvols(fd, filter_set);
 	else
 		subvols = btrfs_list_subvols(fd, is_list_all, absolute_path,
-					     path, filter_set);
+					     follow_mount, path, filter_set);
 	if (!subvols)
 		return -1;
 
@@ -1454,6 +1543,8 @@ static const char * const cmd_subvol_list_usage[] = {
 	"-a           print all the subvolumes in the filesystem and",
 	"             distinguish absolute and relative path with respect",
 	"             to the given <path> (require root privileges)",
+	"-f           follow mounted subvolumes below the specified path",
+	"             and list them too (only if it is the same filesystem)",
 	"",
 	"Field selection:",
 	"-p           print parent ID",
@@ -1497,6 +1588,7 @@ static int cmd_subvol_list(int argc, char **argv)
 	int ret = -1, uerr = 0;
 	char *subvol;
 	int is_list_all = 0;
+	int follow_mount = 0;
 	int is_only_in_path = 0;
 	int absolute_path = 0;
 	DIR *dirstream = NULL;
@@ -1513,7 +1605,7 @@ static int cmd_subvol_list(int argc, char **argv)
 		};
 
 		c = getopt_long(argc, argv,
-				    "acdgopqsurARG:C:t", long_options, NULL);
+				    "acdfgopqsurARG:C:t", long_options, NULL);
 		if (c < 0)
 			break;
 
@@ -1527,6 +1619,9 @@ static int cmd_subvol_list(int argc, char **argv)
 		case 'a':
 			is_list_all = 1;
 			break;
+		case 'f':
+			follow_mount = 1;
+			break;
 		case 'c':
 			btrfs_list_setup_print_column_v2(BTRFS_LIST_OGENERATION);
 			break;
@@ -1616,6 +1711,12 @@ static int cmd_subvol_list(int argc, char **argv)
 		goto out;
 	}
 
+	if (follow_mount && (is_list_all || is_only_in_path)) {
+		ret = -1;
+		error("cannot use -f with -a or -o option");
+		goto out;
+	}
+
 	subvol = argv[optind];
 	fd = btrfs_open_dir(subvol, &dirstream, 1);
 	if (fd < 0) {
@@ -1648,7 +1749,8 @@ static int cmd_subvol_list(int argc, char **argv)
 	btrfs_list_setup_print_column_v2(BTRFS_LIST_PATH);
 
 	ret = btrfs_list_subvols_print_v2(fd, filter_set, comparer_set,
-			layout, is_list_all, absolute_path, subvol, NULL);
+			layout, is_list_all, absolute_path, follow_mount,
+			subvol, NULL);
 
 out:
 	close_file_or_dir(fd, dirstream);
-- 
2.14.4



  parent reply	other threads:[~2018-06-18  8:38 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-18  8:40 [PATCH v2 00/20] btrfs-progs: Rework of "subvolume list/show" and relax the root privileges of them Misono Tomohiro
2018-06-18  8:40 ` [PATCH v2 01/20] btrfs-progs: doc: Update man btrfs subvolume Misono Tomohiro
2018-06-18  8:40 ` [PATCH v2 02/20] btrfs-progs: ioctl/libbtrfsutil: Add 3 definitions of new unprivileged ioctl Misono Tomohiro
2018-06-18  8:40 ` [PATCH v2 03/20] btrfs-progs: libbtrfsutil: Factor out btrfs_util_subvolume_info_fd() Misono Tomohiro
2018-06-18  8:40 ` [PATCH v2 04/20] btrfs-porgs: libbtrfsutil: Relax the privileges of util_subvolume_info() Misono Tomohiro
2018-06-18  8:40 ` [PATCH v2 05/20] btrfs-progs: libbtrfsuitl: Factor out btrfs_util_subvolume_iterator_next() Misono Tomohiro
2018-06-18  8:40 ` [PATCH v2 06/20] btrfs-progs: libbtrfsutil: Relax the privileges of subvolume iterator Misono Tomohiro
2018-06-18  8:40 ` [PATCH v2 07/20] btrfs-progs: sub list: Use libbtrfsuitl for subvolume list Misono Tomohiro
2018-06-18  8:40 ` [PATCH v2 08/20] btrfs-progs: sub list: factor out main part of btrfs_list_subvols Misono Tomohiro
2018-06-18  8:40 ` [PATCH v2 09/20] btrfs-progs: sub list: Change the default behavior of "subvolume list" and allow non-privileged user to call it Misono Tomohiro
2018-06-18  8:40 ` [PATCH v2 10/20] btrfs-progs: sub list: Add -A option to output path in absolute path Misono Tomohiro
2018-06-18  8:40 ` Misono Tomohiro [this message]
2018-06-18  8:41 ` [PATCH v2 12/20] btrfs-progs: sub list: Add --nosort option to output incrementally without sort Misono Tomohiro
2018-06-18  8:41 ` [PATCH v2 13/20] btrfs-progs: sub list: Update -a option and remove meaningless filter Misono Tomohiro
2018-06-18  8:41 ` [PATCH v2 14/20] btrfs-progs: sub list: Update help message of -o option Misono Tomohiro
2018-06-18  8:41 ` [PATCH v2 15/20] btrfs-progs: sub list: Update help message of -d option Misono Tomohiro
2018-06-18  8:41 ` [PATCH v2 16/20] btrfs-progs: utils: Fallback to open without O_NOATIME flag in find_mount_root(): Misono Tomohiro
2018-06-18  8:41 ` [PATCH v2 17/20] btrfs-progs: sub show: Allow non-privileged user to call "subvolume show" Misono Tomohiro
2018-06-18  8:41 ` [PATCH v2 18/20] btrfs-progs: test: Add helper function to check if test user exists Misono Tomohiro
2018-06-18  8:41 ` [PATCH v2 19/20] btrfs-porgs: test: Add cli-test/009 to check subvolume list for both root and normal user Misono Tomohiro
2018-06-18  8:41 ` [PATCH v2 20/20] btrfs-progs: test: Add cli-test/010 to check "subvolume list -f" option Misono Tomohiro
2018-07-04  8:14 ` [PATCH v2 00/20] btrfs-progs: Rework of "subvolume list/show" and relax the root privileges of them Misono Tomohiro
2018-08-03 13:46   ` David Sterba
2018-08-09  8:21     ` Misono Tomohiro
2018-08-15 18:12 ` David Sterba
2018-08-21  7:02   ` Misono Tomohiro

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=84d06767762b4285ddefec0392ee16e2d7e06f62.1529310485.git.misono.tomohiro@jp.fujitsu.com \
    --to=misono.tomohiro@jp.fujitsu.com \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.