@@ -182,12 +182,19 @@ The id can be obtained from *btrfs subvolume list*, *btrfs subvolume show* or
*show* [options] <path>|<mnt>::
Show information of a given subvolume in the <path>.
+
+This command had required root privileges. From kernel 4.18,
+non-privileged user can call this unless -r/-u option is not used.
+Note that for root, output path is relative to the top-level subvolume
+while absolute path is shown for non-privileged user.
+Also for root, snapshots filed lists all the snapshots in the fs while
+only snapshots under mount point are shown for non-privileged user.
++
`Options`
+
-r|--rootid::::
-rootid of the subvolume.
+rootid of the subvolume (require root privileges).
-u|--uuid:::
-UUID of the subvolume.
+UUID of the subvolume (require root privileges).
+
If no option is specified, subvolume information of <path> is shown,
@@ -1886,8 +1886,12 @@ 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",
+ "",
+ "This command had required root privileges. From kernel 4.18,",
+ "non-privileged user can call this unless -r/-u option is not used.",
+ "",
+ "-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.",
@@ -1900,8 +1904,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;
@@ -1909,7 +1915,10 @@ 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;
+ bool root;
optind = 0;
while (1) {
@@ -1947,6 +1956,12 @@ static int cmd_subvol_show(int argc, char **argv)
usage(cmd_subvol_show_usage);
}
+ root = is_root();
+ if (!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]);
@@ -2001,19 +2016,53 @@ 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 (root) {
+ /* Construct path relative to 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 {
+ /* Show absolute path */
+ subvol_path = strdup(fullpath);
+
+ 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;
+ }
+ /* Get real name if the path is mount point */
+ if (strlen(fullpath) == strlen(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_name = strdup(arg.name);
+ } else {
+ 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 && root) ?
+ "/" : subvol_path);
printf("\tName: \t\t\t%s\n",
(subvol.id == BTRFS_FS_TREE_OBJECTID ? "<FS_TREE>" :
- basename(subvol_path)));
+ subvol_name));
if (uuid_is_null(subvol.uuid))
strcpy(uuidparse, "-");
@@ -2056,9 +2105,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 (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;
@@ -2070,9 +2128,33 @@ static int cmd_subvol_show(int argc, char **argv)
} else if (err) {
error_btrfs_util(err);
btrfs_util_destroy_subvolume_iterator(iter);
+ ret = -1;
goto out;
}
+ if (!root) {
+ /* Make path absolute */
+ char *temp = malloc(strlen(mount_point) +
+ strlen(path) + 2);
+
+ if (!temp) {
+ error("out of memory");
+ ret = -1;
+ goto out;
+ }
+
+ strcpy(temp, mount_point);
+ if (strlen(mount_point) == 1) {
+ strcpy(temp + 1, path);
+ } else {
+ temp[strlen(mount_point)] = '/';
+ strcpy(temp + strlen(mount_point) + 1, path);
+ }
+
+ free(path);
+ path = temp;
+ }
+
if (uuid_compare(subvol2.parent_uuid, subvol.uuid) == 0)
printf("\t\t\t\t%s\n", path);
@@ -2083,8 +2165,11 @@ static int cmd_subvol_show(int argc, char **argv)
ret = 0;
out:
free(subvol_path);
+ free(subvol_name);
close_file_or_dir(fd, dirstream1);
+ close_file_or_dir(fd_mnt, dirstream_mnt);
free(fullpath);
+ free(mount_point);
return !!ret;
}