From patchwork Mon Jun 18 08:41:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Misono Tomohiro X-Patchwork-Id: 10470179 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id EE6AA6029B for ; Mon, 18 Jun 2018 08:41:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E0C0428820 for ; Mon, 18 Jun 2018 08:41:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D35AF289B3; Mon, 18 Jun 2018 08:41:07 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A01852897B for ; Mon, 18 Jun 2018 08:41:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1030419AbeFRIiW (ORCPT ); Mon, 18 Jun 2018 04:38:22 -0400 Received: from mgwym01.jp.fujitsu.com ([211.128.242.40]:56209 "EHLO mgwym01.jp.fujitsu.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S968203AbeFRIiR (ORCPT ); Mon, 18 Jun 2018 04:38:17 -0400 Received: from yt-mxauth.gw.nic.fujitsu.com (unknown [192.168.229.68]) by mgwym01.jp.fujitsu.com with smtp id 7f50_7c90_20bfd05a_c57d_40ff_9eec_bcc70093a0ae; Mon, 18 Jun 2018 17:38:12 +0900 Received: from g01jpfmpwkw01.exch.g01.fujitsu.local (g01jpfmpwkw01.exch.g01.fujitsu.local [10.0.193.38]) by yt-mxauth.gw.nic.fujitsu.com (Postfix) with ESMTP id 910EFAC0267 for ; Mon, 18 Jun 2018 17:38:11 +0900 (JST) Received: from g01jpexchkw33.g01.fujitsu.local (unknown [10.0.193.4]) by g01jpfmpwkw01.exch.g01.fujitsu.local (Postfix) with ESMTP id CBA6C6925F1 for ; Mon, 18 Jun 2018 17:38:10 +0900 (JST) Received: from luna3.soft.fujitsu.com (10.124.196.199) by g01jpexchkw33.g01.fujitsu.local (10.0.193.36) with Microsoft SMTP Server id 14.3.352.0; Mon, 18 Jun 2018 17:38:08 +0900 From: Misono Tomohiro To: Subject: [PATCH v2 17/20] btrfs-progs: sub show: Allow non-privileged user to call "subvolume show" Date: Mon, 18 Jun 2018 17:41:05 +0900 Message-ID: <27d5fc2efb6b5a3e32ecc03c965cfc3f88a71103.1529310485.git.misono.tomohiro@jp.fujitsu.com> X-Mailer: git-send-email 2.14.4 In-Reply-To: References: MIME-Version: 1.0 X-SecurityPolicyCheck-GC: OK by FENCE-Mail X-TM-AS-MML: disable Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Allow non-privileged user to call subvolume show if new ioctls (BTRFS_IOC_GET_SUBVOL_INFO/BTRFS_IOC_GET_SUBVOL_ROOTREF, BTRFS_IOC_INO_LOOKUP_USER, from kernel 4.18) are available. Non-privileged user still cannot use -r or -u option. 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 absolute path list snapshots under the mountpoint (only to which the user has appropriate access right) [Example] $ sudo mkfs.btrfs -f $DEV $ sudo mount $DEV /mnt $ sudo btrfs subvolume create /mnt/AAA $ sudo btrfs subvolume snapshot /mnt/AAA /mnt/snap1 $ sudo btrfs subvolume snapshot /mnt/AAA /mnt/AAA/snap2 $ sudo umount /mnt $ sudo mount -o subvol=AAA $DEV /mnt # root $ sudo btrfs subvolume show /mnt AAA Name: AAA UUID: 15e80697-2ffb-0b4b-8e1e-e0873a7cf944 ... Snapshot(s): AAA/snap2 snap1 # non-privileged user $ btrfs subvolume show /mnt /mnt Name: AAA UUID: 15e80697-2ffb-0b4b-8e1e-e0873a7cf944 ... Snapshot(s): /mnt/snap2 Signed-off-by: Misono Tomohiro --- Documentation/btrfs-subvolume.asciidoc | 11 +++- cmds-subvolume.c | 107 +++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 13 deletions(-) diff --git a/Documentation/btrfs-subvolume.asciidoc b/Documentation/btrfs-subvolume.asciidoc index 2db1d479..fc57e6bc 100644 --- a/Documentation/btrfs-subvolume.asciidoc +++ b/Documentation/btrfs-subvolume.asciidoc @@ -194,12 +194,19 @@ The id can be obtained from *btrfs subvolume list*, *btrfs subvolume show* or *show* [options] |:: Show information of a given subvolume in the . + +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 is shown, diff --git a/cmds-subvolume.c b/cmds-subvolume.c index ef39789a..4df418b0 100644 --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -2095,8 +2095,12 @@ static int cmd_subvol_find_new(int argc, char **argv) static const char * const cmd_subvol_show_usage[] = { "btrfs subvolume show [options] |", "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, will be shown, otherwise", "the rootid or uuid are resolved relative to the path.", @@ -2109,8 +2113,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; @@ -2118,7 +2124,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; while (1) { int c; @@ -2155,6 +2164,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]); @@ -2209,19 +2224,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 ? "" : - basename(subvol_path))); + subvol_name)); if (uuid_is_null(subvol.uuid)) strcpy(uuidparse, "-"); @@ -2264,9 +2313,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; @@ -2278,9 +2336,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); @@ -2291,8 +2373,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; }