Allow non-privileged user to call subvolume show (-r or -u cannot be used)
if new ioctls (BTRFS_IOC_GET_SUBVOL_INFO etc.) are available.
The behavior for root user is the same as before.

There are some output differences between root and user:
  root ... subvolume path is from top-level subvolume
           list all snapshots in the fs (inc. non-accessible ones)
  user ... subvolume path is from mount point
           list snapshots under the mountpoint
           (to which the user has appropriate privileges)

Signed-off-by: Tomohiro Misono <misono.tomoh...@jp.fujitsu.com>
---
 cmds-subvolume.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 78 insertions(+), 12 deletions(-)

diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index c3952172..d88d5d76 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -1883,8 +1883,8 @@ static int cmd_subvol_find_new(int argc, char **argv)
 static const char * const cmd_subvol_show_usage[] = {
        "btrfs subvolume show [options] <subvol-path>|<mnt>",
        "Show more information about the subvolume",
-       "-r|--rootid   rootid of the subvolume",
-       "-u|--uuid     uuid of the subvolume",
+       "-r|--rootid   rootid of the subvolume (require root privileges)",
+       "-u|--uuid     uuid of the subvolume   (require root privileges)",
        "",
        "If no option is specified, <subvol-path> will be shown, otherwise",
        "the rootid or uuid are resolved relative to the <mnt> path.",
@@ -1897,8 +1897,10 @@ static int cmd_subvol_show(int argc, char **argv)
        char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
        char *fullpath = NULL;
        int fd = -1;
+       int fd_mnt = -1;
        int ret = 1;
        DIR *dirstream1 = NULL;
+       DIR *dirstream_mnt = NULL;
        int by_rootid = 0;
        int by_uuid = 0;
        u64 rootid_arg = 0;
@@ -1906,6 +1908,8 @@ static int cmd_subvol_show(int argc, char **argv)
        struct btrfs_util_subvolume_iterator *iter;
        struct btrfs_util_subvolume_info subvol;
        char *subvol_path = NULL;
+       char *subvol_name = NULL;
+       char *mount_point = NULL;
        enum btrfs_util_error err;
 
        while (1) {
@@ -1943,6 +1947,11 @@ static int cmd_subvol_show(int argc, char **argv)
                usage(cmd_subvol_show_usage);
        }
 
+       if (!is_root() && (by_rootid || by_uuid)) {
+               error("Only root can use -r or -u options");
+               return -1;
+       }
+
        fullpath = realpath(argv[optind], NULL);
        if (!fullpath) {
                error("cannot find real path for '%s': %m", argv[optind]);
@@ -1997,19 +2006,65 @@ static int cmd_subvol_show(int argc, char **argv)
                        goto out;
                }
 
-               err = btrfs_util_subvolume_path_fd(fd, subvol.id, &subvol_path);
-               if (err) {
-                       error_btrfs_util(err);
-                       goto out;
+               if (is_root()) {
+                       /* Construct path from top-level subvolume */
+                       err = btrfs_util_subvolume_path_fd(fd, subvol.id,
+                                                               &subvol_path);
+                       if (err) {
+                               error_btrfs_util(err);
+                               goto out;
+                       }
+                       subvol_name = strdup(basename(subvol_path));
+               } else {
+                       /* Construct path from mount point */
+                       ret = find_mount_root(fullpath, &mount_point);
+                       if (ret < 0) {
+                               error("cannot get mount point");
+                               goto out;
+                       }
+
+                       fd_mnt = open_file_or_dir(mount_point, &dirstream_mnt);
+                       if (fd_mnt < 0) {
+                               error("cannot open mount point");
+                               goto out;
+                       }
+
+                       if (strlen(fullpath) == strlen(mount_point)) {
+                               /* Get real name at mount point */
+                               struct btrfs_ioctl_get_subvol_info_args arg;
+
+                               ret = ioctl(fd_mnt, BTRFS_IOC_GET_SUBVOL_INFO,
+                                                       &arg);
+                               if (ret < 0) {
+                                       error("cannot get subvolume info");
+                                       goto out;
+                               }
+                               subvol_path = strdup("./");
+                               subvol_name = strdup(arg.name);
+                       } else {
+                               subvol_path = malloc(strlen(fullpath) -
+                                               strlen(mount_point) + 1);
+                               if (!subvol_path) {
+                                       error("not enough memory");
+                                       ret = 1;
+                                       goto out;
+                               }
+                               subvol_path[0] = '.';
+                               memcpy(subvol_path + 1,
+                                       fullpath + strlen(mount_point),
+                                       strlen(fullpath) - strlen(mount_point));
+                               subvol_name = strdup(basename(subvol_path));
+                       }
                }
 
        }
 
        /* print the info */
-       printf("%s\n", subvol.id == BTRFS_FS_TREE_OBJECTID ? "/" : subvol_path);
+       printf("%s\n", subvol.id == BTRFS_FS_TREE_OBJECTID ?
+                       (is_root() ? "/" : "./") : subvol_path);
        printf("\tName: \t\t\t%s\n",
-              (subvol.id == BTRFS_FS_TREE_OBJECTID ? "<FS_TREE>" :
-               basename(subvol_path)));
+               (subvol.id == BTRFS_FS_TREE_OBJECTID ? "<FS_TREE>" :
+                subvol_name));
 
        if (uuid_is_null(subvol.uuid))
                strcpy(uuidparse, "-");
@@ -2052,9 +2107,18 @@ static int cmd_subvol_show(int argc, char **argv)
        /* print the snapshots of the given subvol if any*/
        printf("\tSnapshot(s):\n");
 
-       err = btrfs_util_create_subvolume_iterator_fd(fd,
-                                                     BTRFS_FS_TREE_OBJECTID, 0,
-                                                     &iter);
+       /*
+        * For root, show all snapshots in the filesystem.
+        * For non-privileged user, show all snapshots under mount point.
+        */
+       if (is_root())
+               err = btrfs_util_create_subvolume_iterator_fd(fd,
+                                             BTRFS_FS_TREE_OBJECTID, 0,
+                                             &iter);
+       else
+               err = btrfs_util_create_subvolume_iterator_fd(fd_mnt,
+                                             0, 0,
+                                             &iter);
 
        for (;;) {
                struct btrfs_util_subvolume_info subvol2;
@@ -2080,7 +2144,9 @@ static int cmd_subvol_show(int argc, char **argv)
 out:
        free(subvol_path);
        close_file_or_dir(fd, dirstream1);
+       close_file_or_dir(fd_mnt, dirstream_mnt);
        free(fullpath);
+       free(mount_point);
        return !!ret;
 }
 
-- 
2.14.3


--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to