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