From patchwork Sun Aug 13 09:44:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Heiss X-Patchwork-Id: 13352046 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B66AAC001B0 for ; Sun, 13 Aug 2023 09:51:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231172AbjHMJvR (ORCPT ); Sun, 13 Aug 2023 05:51:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33376 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230271AbjHMJvQ (ORCPT ); Sun, 13 Aug 2023 05:51:16 -0400 Received: from mail-108-mta195.mxroute.com (mail-108-mta195.mxroute.com [136.175.108.195]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E1CB1170C for ; Sun, 13 Aug 2023 02:51:16 -0700 (PDT) Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta195.mxroute.com (ZoneMTA) with ESMTPSA id 189ee49dfb500023b6.001 for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 13 Aug 2023 09:46:06 +0000 X-Zone-Loop: 09e8e10f3fd6261d0ff55bfd02634dd18b7b9c607a91 X-Originating-IP: [136.175.111.2] DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=c8h4.io; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=ditxff6QaCBmgFhZlCCIEE+0ywBGpM6B/2aGgFyB014=; b=hfl78wi8I7tu7kOUW+5CWlZKJF gOkRwo1pFD0dPgVN0IANzN8TqgiQ8E/LU+8llu9hJB4HxtYpnv/5DeCsm3kSN7rrp2Wul0A6Nf19D k2FtIfi3Hu/otIMsNJ/HHK1TT71i2sEpUYPNYX+XwzSFM9oQua0VVhWKfdwTtzMHvMgT4flVEumdw 8lMarIpw3L5MTmNJesChLv8LL8sevyrFq1Uj+fKCP1mCxukfnPZzy+tbd8VIaO6GJ6XiI4zgsM+Kl wL9BoVUnShspU5vZ+Qo1DSsIg9q77iTesVeLgl1sUhpFklVD///dlOSLb/5y7AFfA0iIeI8FtwDeZ 6hoPPvYA==; From: Christoph Heiss To: linux-btrfs@vger.kernel.org Subject: [PATCH 1/7] btrfs-progs: common: document `time-long` output format Date: Sun, 13 Aug 2023 11:44:56 +0200 Message-ID: <20230813094555.106052-2-christoph@c8h4.io> In-Reply-To: <20230813094555.106052-1-christoph@c8h4.io> References: <20230813094555.106052-1-christoph@c8h4.io> MIME-Version: 1.0 X-Authenticated-Id: christoph@c8h4.io Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Seems this was forgotten; rectify that. Signed-off-by: Christoph Heiss --- common/format-output.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/format-output.h b/common/format-output.h index 95e2a117..ab12a7f1 100644 --- a/common/format-output.h +++ b/common/format-output.h @@ -28,6 +28,8 @@ struct rowspec { * (values: va_args) * - uuid: format UUID as text * (value: u8 *uuid) + * - time-long: pretty print timestamp, including timezone + * (values: time_t) * - list: print list opening bracket [ * (values printed separately) * - map: start a new group, opens { From patchwork Sun Aug 13 09:44:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Heiss X-Patchwork-Id: 13352048 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B55A8C41513 for ; Sun, 13 Aug 2023 09:51:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230271AbjHMJvT (ORCPT ); Sun, 13 Aug 2023 05:51:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57404 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231163AbjHMJvQ (ORCPT ); Sun, 13 Aug 2023 05:51:16 -0400 Received: from mail-108-mta227.mxroute.com (mail-108-mta227.mxroute.com [136.175.108.227]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E1DD8170E for ; Sun, 13 Aug 2023 02:51:16 -0700 (PDT) Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta227.mxroute.com (ZoneMTA) with ESMTPSA id 189ee49e1a900023b6.001 for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 13 Aug 2023 09:46:06 +0000 X-Zone-Loop: 18079c2d65d26ccf92cb301a1afdfb99e4203a8ec740 X-Originating-IP: [136.175.111.2] DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=c8h4.io; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=cgrdauJJLi+22I4oU0p+myNIz0Q5ENrDAebkct7NuFs=; b=dqK/2Cs4UgorCHa+LEyh6+wHZe dGI9b5xkYC3iMz6g8iBuoBA6g/3nbVlLbxQWBsnudWfvgRO3sRByvPns8ueL0QdzGcfqHD5o2NlVX CHdYz01pnlAsMpxIBPmDHR60Kqpl9+Q9J4UzIyLxUB06VFt68AFIAl461h+i/L7RKoQb3EBPe/k/0 i+98bNAwnz4FfuW7cPZm7r2GveaxWFeO71Z42ifCDrBf+exnGKngdQdABZyWJx17O8g57eLEuD4CG KUgR2+V3a59YbzX6e+9/R5pM/tPdUMEp//13+YtMA/YIvs0ovvlaUKBKJPVHXWoV5xOrFlBA7+JeL ZYX8IJXg==; From: Christoph Heiss To: linux-btrfs@vger.kernel.org Subject: [PATCH 2/7] btrfs-progs: subvol show: remove duplicated quotas error check Date: Sun, 13 Aug 2023 11:44:57 +0200 Message-ID: <20230813094555.106052-3-christoph@c8h4.io> In-Reply-To: <20230813094555.106052-1-christoph@c8h4.io> References: <20230813094555.106052-1-christoph@c8h4.io> MIME-Version: 1.0 X-Authenticated-Id: christoph@c8h4.io Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org The exact same check is repeated here, with the second being dead code. Keep the second instance, as that informs the user what is happening. Signed-off-by: Christoph Heiss --- cmds/subvolume.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cmds/subvolume.c b/cmds/subvolume.c index 0691157c..a5423759 100644 --- a/cmds/subvolume.c +++ b/cmds/subvolume.c @@ -1466,11 +1466,6 @@ static int cmd_subvolume_show(const struct cmd_struct *cmd, int argc, char **arg btrfs_util_destroy_subvolume_iterator(iter); ret = btrfs_qgroup_query(fd, subvol.id, &stats); - if (ret == -ENOTTY) { - /* Quotas not enabled */ - ret = 0; - goto out; - } if (ret == -ENOTTY) { /* Quota information not available, not fatal */ pr_verbose(LOG_DEFAULT, "\tQuota group:\t\tn/a\n"); From patchwork Sun Aug 13 09:44:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Heiss X-Patchwork-Id: 13352050 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C199EC04A6A for ; Sun, 13 Aug 2023 09:51:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231167AbjHMJvV (ORCPT ); Sun, 13 Aug 2023 05:51:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57482 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231152AbjHMJvU (ORCPT ); Sun, 13 Aug 2023 05:51:20 -0400 Received: from mail-108-mta231.mxroute.com (mail-108-mta231.mxroute.com [136.175.108.231]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E1AED10FE for ; Sun, 13 Aug 2023 02:51:16 -0700 (PDT) Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta231.mxroute.com (ZoneMTA) with ESMTPSA id 189ee49e40300023b6.001 for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 13 Aug 2023 09:46:07 +0000 X-Zone-Loop: ab7c8a571c2c45539a82f4dc730fbec72a081cbfbcbd X-Originating-IP: [136.175.111.2] DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=c8h4.io; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=wOrs6ZCSsovN1VntlVdgmEr9ceHBhCNp9NO6L3xvDxc=; b=ibH82YwP/u/ffy+u6OjWF+U+an /q4R1HOuQnpP0LJ3DY/4da1jPwHSr5/B1T4/XKoIWRRjCGZEwPQDd9rB1opTwssIvTHQEcasMNMWY QcHmL4UztD3Iu6UJjhAjjfvEKm/1bhcmkUkJHhItvW4iQUjpJt8kvgSHZMPdzdUSXjHCyzmTqwv5d 3vviuLLPqndxCjUxBf6W25x+IVp4WBmLBD5V9qml3UnGY460xPOtpLUBvZWtv8fJsV/16F3SHxnEM x1SPKkyOpgxiQAU8lnWS4xrDxfxSrYN778nTx5nKwqzzKL0OkC0f3dFmPBIL5SUdRgeLI5kv1usEO 6R+vc31w==; From: Christoph Heiss To: linux-btrfs@vger.kernel.org Subject: [PATCH 3/7] btrfs-progs: subvol show: factor out text printing to own function Date: Sun, 13 Aug 2023 11:44:58 +0200 Message-ID: <20230813094555.106052-4-christoph@c8h4.io> In-Reply-To: <20230813094555.106052-1-christoph@c8h4.io> References: <20230813094555.106052-1-christoph@c8h4.io> MIME-Version: 1.0 X-Authenticated-Id: christoph@c8h4.io Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Implements JSON-formatted output for the `subvolume list` command using the `--format json` global option, much like it is implemented for other commands. Signed-off-by: Christoph Heiss --- cmds/subvolume.c | 190 ++++++++++++++++++++++++++--------------------- 1 file changed, 107 insertions(+), 83 deletions(-) diff --git a/cmds/subvolume.c b/cmds/subvolume.c index a5423759..65cff24b 100644 --- a/cmds/subvolume.c +++ b/cmds/subvolume.c @@ -1232,6 +1232,105 @@ static int cmd_subvolume_find_new(const struct cmd_struct *cmd, int argc, char * } static DEFINE_SIMPLE_COMMAND(subvolume_find_new, "find-new"); +static void print_subvolume_show_text(const struct btrfs_util_subvolume_info *subvol, + const char *subvol_path, const char *subvol_name) +{ + char tstr[256]; + char uuidparse[BTRFS_UUID_UNPARSED_SIZE]; + + /* Warn if it's a read-write subvolume with received_uuid */ + if (!uuid_is_null(subvol->received_uuid) && + !(subvol->flags & BTRFS_ROOT_SUBVOL_RDONLY)) { + warning("the subvolume is read-write and has received_uuid set,\n" + "\t don't use it for incremental send. Please see section\n" + "\t 'SUBVOLUME FLAGS' in manual page btrfs-subvolume for\n" + "\t further information."); + } + + /* print the info */ + pr_verbose(LOG_DEFAULT, "%s\n", + subvol->id == BTRFS_FS_TREE_OBJECTID ? "/" : subvol_path); + pr_verbose(LOG_DEFAULT, "\tName: \t\t\t%s\n", subvol_name); + + if (uuid_is_null(subvol->uuid)) + strcpy(uuidparse, "-"); + else + uuid_unparse(subvol->uuid, uuidparse); + pr_verbose(LOG_DEFAULT, "\tUUID: \t\t\t%s\n", uuidparse); + + if (uuid_is_null(subvol->parent_uuid)) + strcpy(uuidparse, "-"); + else + uuid_unparse(subvol->parent_uuid, uuidparse); + pr_verbose(LOG_DEFAULT, "\tParent UUID: \t\t%s\n", uuidparse); + + if (uuid_is_null(subvol->received_uuid)) + strcpy(uuidparse, "-"); + else + uuid_unparse(subvol->received_uuid, uuidparse); + pr_verbose(LOG_DEFAULT, "\tReceived UUID: \t\t%s\n", uuidparse); + + if (subvol->otime.tv_sec) { + struct tm tm; + + localtime_r(&subvol->otime.tv_sec, &tm); + strftime(tstr, 256, "%Y-%m-%d %X %z", &tm); + } else + strcpy(tstr, "-"); + pr_verbose(LOG_DEFAULT, "\tCreation time: \t\t%s\n", tstr); + + pr_verbose(LOG_DEFAULT, "\tSubvolume ID: \t\t%" PRIu64 "\n", subvol->id); + pr_verbose(LOG_DEFAULT, "\tGeneration: \t\t%" PRIu64 "\n", subvol->generation); + pr_verbose(LOG_DEFAULT, "\tGen at creation: \t%" PRIu64 "\n", subvol->otransid); + pr_verbose(LOG_DEFAULT, "\tParent ID: \t\t%" PRIu64 "\n", subvol->parent_id); + pr_verbose(LOG_DEFAULT, "\tTop level ID: \t\t%" PRIu64 "\n", subvol->parent_id); + + if (subvol->flags & BTRFS_ROOT_SUBVOL_RDONLY) + pr_verbose(LOG_DEFAULT, "\tFlags: \t\t\treadonly\n"); + else + pr_verbose(LOG_DEFAULT, "\tFlags: \t\t\t-\n"); + + pr_verbose(LOG_DEFAULT, "\tSend transid: \t\t%" PRIu64 "\n", subvol->stransid); + pr_verbose(LOG_DEFAULT, "\tSend time: \t\t%s\n", tstr); + if (subvol->stime.tv_sec) { + struct tm tm; + + localtime_r(&subvol->stime.tv_sec, &tm); + strftime(tstr, 256, "%Y-%m-%d %X %z", &tm); + } else { + strcpy(tstr, "-"); + } + pr_verbose(LOG_DEFAULT, "\tReceive transid: \t%" PRIu64 "\n", subvol->rtransid); + if (subvol->rtime.tv_sec) { + struct tm tm; + + localtime_r(&subvol->rtime.tv_sec, &tm); + strftime(tstr, 256, "%Y-%m-%d %X %z", &tm); + } else { + strcpy(tstr, "-"); + } + pr_verbose(LOG_DEFAULT, "\tReceive time: \t\t%s\n", tstr); +} + +static void print_subvolume_show_quota_text(const struct btrfs_util_subvolume_info *subvol, + const struct btrfs_qgroup_stats *stats, + unsigned int unit_mode) +{ + pr_verbose(LOG_DEFAULT, "\tQuota group:\t\t0/%" PRIu64 "\n", subvol->id); + fflush(stdout); + + pr_verbose(LOG_DEFAULT, "\t Limit referenced:\t%s\n", + stats->limit.max_referenced == 0 ? "-" : + pretty_size_mode(stats->limit.max_referenced, unit_mode)); + pr_verbose(LOG_DEFAULT, "\t Limit exclusive:\t%s\n", + stats->limit.max_exclusive == 0 ? "-" : + pretty_size_mode(stats->limit.max_exclusive, unit_mode)); + pr_verbose(LOG_DEFAULT, "\t Usage referenced:\t%s\n", + pretty_size_mode(stats->info.referenced, unit_mode)); + pr_verbose(LOG_DEFAULT, "\t Usage exclusive:\t%s\n", + pretty_size_mode(stats->info.exclusive, unit_mode)); +} + static const char * const cmd_subvolume_show_usage[] = { "btrfs subvolume show [options] ", "Show more information about the subvolume (UUIDs, generations, times, snapshots)", @@ -1247,7 +1346,6 @@ static const char * const cmd_subvolume_show_usage[] = { static int cmd_subvolume_show(const struct cmd_struct *cmd, int argc, char **argv) { - char tstr[256]; char uuidparse[BTRFS_UUID_UNPARSED_SIZE]; char *fullpath = NULL; int fd = -1; @@ -1260,6 +1358,7 @@ static int cmd_subvolume_show(const struct cmd_struct *cmd, int argc, char **arg struct btrfs_util_subvolume_iterator *iter; struct btrfs_util_subvolume_info subvol; char *subvol_path = NULL; + char *subvol_name = NULL; enum btrfs_util_error err; struct btrfs_qgroup_stats stats; unsigned int unit_mode; @@ -1365,78 +1464,15 @@ static int cmd_subvolume_show(const struct cmd_struct *cmd, int argc, char **arg } - /* Warn if it's a read-write subvolume with received_uuid */ - if (!uuid_is_null(subvol.received_uuid) && - !(subvol.flags & BTRFS_ROOT_SUBVOL_RDONLY)) { - warning("the subvolume is read-write and has received_uuid set,\n" - "\t don't use it for incremental send. Please see section\n" - "\t 'SUBVOLUME FLAGS' in manual page btrfs-subvolume for\n" - "\t further information."); - } - /* print the info */ - pr_verbose(LOG_DEFAULT, "%s\n", subvol.id == BTRFS_FS_TREE_OBJECTID ? "/" : subvol_path); - pr_verbose(LOG_DEFAULT, "\tName: \t\t\t%s\n", - (subvol.id == BTRFS_FS_TREE_OBJECTID ? "" : - basename(subvol_path))); - - if (uuid_is_null(subvol.uuid)) - strcpy(uuidparse, "-"); - else - uuid_unparse(subvol.uuid, uuidparse); - pr_verbose(LOG_DEFAULT, "\tUUID: \t\t\t%s\n", uuidparse); - - if (uuid_is_null(subvol.parent_uuid)) - strcpy(uuidparse, "-"); - else - uuid_unparse(subvol.parent_uuid, uuidparse); - pr_verbose(LOG_DEFAULT, "\tParent UUID: \t\t%s\n", uuidparse); - - if (uuid_is_null(subvol.received_uuid)) - strcpy(uuidparse, "-"); - else - uuid_unparse(subvol.received_uuid, uuidparse); - pr_verbose(LOG_DEFAULT, "\tReceived UUID: \t\t%s\n", uuidparse); - - if (subvol.otime.tv_sec) { - struct tm tm; - - localtime_r(&subvol.otime.tv_sec, &tm); - strftime(tstr, 256, "%Y-%m-%d %X %z", &tm); - } else - strcpy(tstr, "-"); - pr_verbose(LOG_DEFAULT, "\tCreation time: \t\t%s\n", tstr); - - pr_verbose(LOG_DEFAULT, "\tSubvolume ID: \t\t%" PRIu64 "\n", subvol.id); - pr_verbose(LOG_DEFAULT, "\tGeneration: \t\t%" PRIu64 "\n", subvol.generation); - pr_verbose(LOG_DEFAULT, "\tGen at creation: \t%" PRIu64 "\n", subvol.otransid); - pr_verbose(LOG_DEFAULT, "\tParent ID: \t\t%" PRIu64 "\n", subvol.parent_id); - pr_verbose(LOG_DEFAULT, "\tTop level ID: \t\t%" PRIu64 "\n", subvol.parent_id); - - if (subvol.flags & BTRFS_ROOT_SUBVOL_RDONLY) - pr_verbose(LOG_DEFAULT, "\tFlags: \t\t\treadonly\n"); - else - pr_verbose(LOG_DEFAULT, "\tFlags: \t\t\t-\n"); - - pr_verbose(LOG_DEFAULT, "\tSend transid: \t\t%" PRIu64 "\n", subvol.stransid); - pr_verbose(LOG_DEFAULT, "\tSend time: \t\t%s\n", tstr); - if (subvol.stime.tv_sec) { - struct tm tm; - - localtime_r(&subvol.stime.tv_sec, &tm); - strftime(tstr, 256, "%Y-%m-%d %X %z", &tm); + if (subvol.id == BTRFS_FS_TREE_OBJECTID) { + free(subvol_path); + subvol_path = strdup("/"); + subvol_name = ""; } else { - strcpy(tstr, "-"); + subvol_name = basename(subvol_path); } - pr_verbose(LOG_DEFAULT, "\tReceive transid: \t%" PRIu64 "\n", subvol.rtransid); - if (subvol.rtime.tv_sec) { - struct tm tm; - localtime_r(&subvol.rtime.tv_sec, &tm); - strftime(tstr, 256, "%Y-%m-%d %X %z", &tm); - } else { - strcpy(tstr, "-"); - } - pr_verbose(LOG_DEFAULT, "\tReceive time: \t\t%s\n", tstr); + print_subvolume_show_text(&subvol, subvol_path, subvol_name); /* print the snapshots of the given subvol if any*/ pr_verbose(LOG_DEFAULT, "\tSnapshot(s):\n"); @@ -1478,19 +1514,7 @@ static int cmd_subvolume_show(const struct cmd_struct *cmd, int argc, char **arg goto out; } - pr_verbose(LOG_DEFAULT, "\tQuota group:\t\t0/%" PRIu64 "\n", subvol.id); - fflush(stdout); - - pr_verbose(LOG_DEFAULT, "\t Limit referenced:\t%s\n", - stats.limit.max_referenced == 0 ? "-" : - pretty_size_mode(stats.limit.max_referenced, unit_mode)); - pr_verbose(LOG_DEFAULT, "\t Limit exclusive:\t%s\n", - stats.limit.max_exclusive == 0 ? "-" : - pretty_size_mode(stats.limit.max_exclusive, unit_mode)); - pr_verbose(LOG_DEFAULT, "\t Usage referenced:\t%s\n", - pretty_size_mode(stats.info.referenced, unit_mode)); - pr_verbose(LOG_DEFAULT, "\t Usage exclusive:\t%s\n", - pretty_size_mode(stats.info.exclusive, unit_mode)); + print_subvolume_show_quota_text(&subvol, &stats, unit_mode); out: free(subvol_path); From patchwork Sun Aug 13 09:44:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Heiss X-Patchwork-Id: 13352049 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 763DFC001B0 for ; Sun, 13 Aug 2023 09:51:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231161AbjHMJvU (ORCPT ); Sun, 13 Aug 2023 05:51:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57446 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231167AbjHMJvQ (ORCPT ); Sun, 13 Aug 2023 05:51:16 -0400 Received: from mail-108-mta39.mxroute.com (mail-108-mta39.mxroute.com [136.175.108.39]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E1BF71700 for ; Sun, 13 Aug 2023 02:51:16 -0700 (PDT) Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta39.mxroute.com (ZoneMTA) with ESMTPSA id 189ee49e5fa00023b6.001 for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 13 Aug 2023 09:46:07 +0000 X-Zone-Loop: aa6b3f83f03e9767c3ae162c5cfac81d8d3a2f952aa7 X-Originating-IP: [136.175.111.2] DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=c8h4.io; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=NDLLnyGyq/UIsbHA2VT4Kr9AGL//iNQbw4+KF4VcVuc=; b=OgCGXfPNe8l/cKB49yjfsgppWE SMBVQLsStOxmu3DKbe06EIBvgvRxpKpGhCAhd0rdLeh4hOgbvuaH0Py/aOPjSOaqx6pl99b89ke3A FBPQ370pdPnPBqEQ0Ng0ReELpF/TzP1hehtsq34rf/RK6UGh8EHAs10Mjd7yLf7vd/9QY2ockHf4Q jHKgsEoKoKybbvqIFrhXjx0q0e6VwGX8aC6z3oXgUb8Gl3wYzXsHGGtMkkEQB5OMtUzfrjTmlW2uM kSbEtF2d7tCocA7xJa7xdUPHG5yilGXzEjAMriEFU9zAU1i4mlb+yHqsZM7FDjSA4nDzQPUtH6qmO NZ8yB56A==; From: Christoph Heiss To: linux-btrfs@vger.kernel.org Subject: [PATCH 4/7] btrfs-progs: subvol: introduce rowspec definition for json output Date: Sun, 13 Aug 2023 11:44:59 +0200 Message-ID: <20230813094555.106052-5-christoph@c8h4.io> In-Reply-To: <20230813094555.106052-1-christoph@c8h4.io> References: <20230813094555.106052-1-christoph@c8h4.io> MIME-Version: 1.0 X-Authenticated-Id: christoph@c8h4.io Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Includes all fields that are needed by the various `btrfs subvolume` subcommands. Signed-off-by: Christoph Heiss --- cmds/subvolume.c | 25 +++++++++++++++++++++++++ cmds/subvolume.h | 19 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 cmds/subvolume.h diff --git a/cmds/subvolume.c b/cmds/subvolume.c index 65cff24b..cb863ac7 100644 --- a/cmds/subvolume.c +++ b/cmds/subvolume.c @@ -41,9 +41,34 @@ #include "common/open-utils.h" #include "common/string-utils.h" #include "common/units.h" +#include "common/format-output.h" #include "cmds/commands.h" #include "cmds/qgroup.h" +const struct rowspec btrfs_subvolume_rowspec[] = { + { .key = "ID", .fmt = "%llu", .out_json = "id" }, + { .key = "name", .fmt = "%s", .out_json = "name" }, + { .key = "gen", .fmt = "%llu", .out_json = "gen" }, + { .key = "cgen", .fmt = "%llu", .out_json = "cgen" }, + { .key = "parent", .fmt = "%llu", .out_json = "parent" }, + { .key = "top level", .fmt = "%llu", .out_json = "top_level" }, + { .key = "otime", .fmt = "time-long", .out_json = "otime" }, + { .key = "parent_uuid", .fmt = "uuid", .out_json = "parent_uuid" }, + { .key = "received_uuid", .fmt = "uuid", .out_json = "received_uuid" }, + { .key = "uuid", .fmt = "uuid", .out_json = "uuid" }, + { .key = "path", .fmt = "%s", .out_json = "path" }, + { .key = "flag-list-item", .fmt = "%s" }, + { .key = "stransid", .fmt = "%llu", .out_json = "stransid" }, + { .key = "stime", .fmt = "time-long", .out_json = "stime" }, + { .key = "rtransid", .fmt = "%llu", .out_json = "rtransid" }, + { .key = "rtime", .fmt = "time-long", .out_json = "rtime" }, + { .key = "snapshot-list-item", .fmt = "%s" }, + { .key = "quota-group", .fmt = "qgroupid", .out_json = "group" }, + { .key = "quota-ref", .fmt = "%llu", .out_json = "referenced" }, + { .key = "quota-excl", .fmt = "%llu", .out_json = "exclusive" }, + ROWSPEC_END +}; + static int wait_for_subvolume_cleaning(int fd, size_t count, uint64_t *ids, int sleep_interval) { diff --git a/cmds/subvolume.h b/cmds/subvolume.h new file mode 100644 index 00000000..041ea865 --- /dev/null +++ b/cmds/subvolume.h @@ -0,0 +1,19 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +struct rowspec; + +extern const struct rowspec btrfs_subvolume_rowspec[]; From patchwork Sun Aug 13 09:45:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Heiss X-Patchwork-Id: 13352051 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2C95EC001E0 for ; Sun, 13 Aug 2023 09:51:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231190AbjHMJvX (ORCPT ); Sun, 13 Aug 2023 05:51:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57500 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231162AbjHMJvV (ORCPT ); Sun, 13 Aug 2023 05:51:21 -0400 Received: from mail-108-mta155.mxroute.com (mail-108-mta155.mxroute.com [136.175.108.155]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BB45C1710 for ; Sun, 13 Aug 2023 02:51:21 -0700 (PDT) Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta155.mxroute.com (ZoneMTA) with ESMTPSA id 189ee49e8c600023b6.001 for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 13 Aug 2023 09:46:08 +0000 X-Zone-Loop: c8d07d44ba2b396021e37d7c839687867f1daecf41ec X-Originating-IP: [136.175.111.2] DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=c8h4.io; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=DJRya04kart+Tx59DLAWo+K2dJaDrWgO5TBnAmqSgfQ=; b=KijIPd+/1S4sAFcFbJi/JR11/n iiSdJV2Nf2NOp4vwhEQhb7TaLwJI0AcupVxYHV6YKYvKVjwia0cv7AbjQmI/UUAscYgkzYdzhIm+J d/o79MpQMKCI6Ix7Go63HGecBZUlSkLeG2vZ8j8j838TgFaeEPLSXn3LPRaGFfMp5q9ae6+SfuQ9P iRNj4QEqOS0sDgWiTF0iM43sjKopyVkehgvV1iqd/uXZbI/foNc7/mCMCm5bnR0v0MhXSw52kHUE0 UFu6VXoI35b844tSAbousB+rtj0oh4xOaQZ5tqnSqisah5EK5rACFvMSz+uPkWwtavCtteMKL1IWr yMDIyBqg==; From: Christoph Heiss To: linux-btrfs@vger.kernel.org Subject: [PATCH 5/7] btrfs-progs: subvol list: implement json format output Date: Sun, 13 Aug 2023 11:45:00 +0200 Message-ID: <20230813094555.106052-6-christoph@c8h4.io> In-Reply-To: <20230813094555.106052-1-christoph@c8h4.io> References: <20230813094555.106052-1-christoph@c8h4.io> MIME-Version: 1.0 X-Authenticated-Id: christoph@c8h4.io Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Implements JSON-formatted output for the `subvolume list` command using the `--format json` global option, much like it is implemented for other commands. Re-uses the `btrfs_list_layout` infrastructure to nicely fit it into the existing formatting code. A notable difference to the normal, text-based output is that in the JSON output, timestamps include the timezone offset as well. Signed-off-by: Christoph Heiss --- cmds/subvolume-list.c | 91 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 3 deletions(-) diff --git a/cmds/subvolume-list.c b/cmds/subvolume-list.c index 382b0676..be7faca6 100644 --- a/cmds/subvolume-list.c +++ b/cmds/subvolume-list.c @@ -35,7 +35,9 @@ #include "common/open-utils.h" #include "common/string-utils.h" #include "common/utils.h" +#include "common/format-output.h" #include "cmds/commands.h" +#include "cmds/subvolume.h" /* * Naming of options: @@ -75,6 +77,8 @@ static const char * const cmd_subvolume_list_usage[] = { OPTLINE("--sort=gen,ogen,rootid,path", "list the subvolume in order of gen, ogen, rootid or path " "you also can add '+' or '-' in front of each items. " "(+:ascending, -:descending, ascending default)"), + HELPINFO_INSERT_GLOBALS, + HELPINFO_INSERT_FORMAT, NULL, }; @@ -84,7 +88,8 @@ static const char * const cmd_subvolume_list_usage[] = { enum btrfs_list_layout { BTRFS_LIST_LAYOUT_DEFAULT = 0, BTRFS_LIST_LAYOUT_TABLE, - BTRFS_LIST_LAYOUT_RAW + BTRFS_LIST_LAYOUT_RAW, + BTRFS_LIST_LAYOUT_JSON }; /* @@ -1269,14 +1274,83 @@ static void print_all_subvol_info_tab_head(void) } } +static void print_subvol_json_key(struct format_ctx *fctx, + const struct root_info *subv, + const enum btrfs_list_column_enum column) +{ + const char *column_name; + + UASSERT(0 <= column && column < BTRFS_LIST_ALL); + + column_name = btrfs_list_columns[column].name; + switch (column) { + case BTRFS_LIST_OBJECTID: + fmt_print(fctx, column_name, subv->root_id); + break; + case BTRFS_LIST_GENERATION: + fmt_print(fctx, column_name, subv->gen); + break; + case BTRFS_LIST_OGENERATION: + fmt_print(fctx, column_name, subv->ogen); + break; + case BTRFS_LIST_PARENT: + fmt_print(fctx, column_name, subv->ref_tree); + break; + case BTRFS_LIST_TOP_LEVEL: + fmt_print(fctx, column_name, subv->top_id); + break; + case BTRFS_LIST_OTIME: + fmt_print(fctx, column_name, subv->otime); + break; + case BTRFS_LIST_UUID: + fmt_print(fctx, column_name, subv->uuid); + break; + case BTRFS_LIST_PUUID: + fmt_print(fctx, column_name, subv->puuid); + break; + case BTRFS_LIST_RUUID: + fmt_print(fctx, column_name, subv->ruuid); + break; + case BTRFS_LIST_PATH: + BUG_ON(!subv->full_path); + fmt_print(fctx, column_name, subv->full_path); + break; + default: + break; + } +} + +static void print_one_subvol_info_json(struct format_ctx *fctx, + struct root_info *subv) +{ + int i; + + fmt_print_start_group(fctx, NULL, JSON_TYPE_MAP); + + for (i = 0; i < BTRFS_LIST_ALL; i++) { + if (!btrfs_list_columns[i].need_print) + continue; + + print_subvol_json_key(fctx, subv, i); + } + + fmt_print_end_group(fctx, NULL); +} + + static void print_all_subvol_info(struct rb_root *sorted_tree, enum btrfs_list_layout layout, const char *raw_prefix) { struct rb_node *n; struct root_info *entry; + struct format_ctx fctx; - if (layout == BTRFS_LIST_LAYOUT_TABLE) + if (layout == BTRFS_LIST_LAYOUT_TABLE) { print_all_subvol_info_tab_head(); + } else if (layout == BTRFS_LIST_LAYOUT_JSON) { + fmt_start(&fctx, btrfs_subvolume_rowspec, 1, 0); + fmt_print_start_group(&fctx, "subvolume-list", JSON_TYPE_ARRAY); + } n = rb_first(sorted_tree); while (n) { @@ -1296,10 +1370,18 @@ static void print_all_subvol_info(struct rb_root *sorted_tree, case BTRFS_LIST_LAYOUT_RAW: print_one_subvol_info_raw(entry, raw_prefix); break; + case BTRFS_LIST_LAYOUT_JSON: + print_one_subvol_info_json(&fctx, entry); + break; } next: n = rb_next(n); } + + if (layout == BTRFS_LIST_LAYOUT_JSON) { + fmt_print_end_group(&fctx, "subvolume-list"); + fmt_end(&fctx); + } } static int btrfs_list_subvols(int fd, struct rb_root *root_lookup) @@ -1631,6 +1713,9 @@ static int cmd_subvolume_list(const struct cmd_struct *cmd, int argc, char **arg btrfs_list_setup_print_column(BTRFS_LIST_TOP_LEVEL); btrfs_list_setup_print_column(BTRFS_LIST_PATH); + if (bconf.output_format == CMD_FORMAT_JSON) + layout = BTRFS_LIST_LAYOUT_JSON; + ret = btrfs_list_subvols_print(fd, filter_set, comparer_set, layout, !is_list_all && !is_only_in_path, NULL); @@ -1644,4 +1729,4 @@ out: usage(cmd, 1); return !!ret; } -DEFINE_SIMPLE_COMMAND(subvolume_list, "list"); +DEFINE_COMMAND_WITH_FLAGS(subvolume_list, "list", CMD_FORMAT_JSON); From patchwork Sun Aug 13 09:45:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Heiss X-Patchwork-Id: 13352052 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4C4A9C04A94 for ; Sun, 13 Aug 2023 09:51:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231176AbjHMJvY (ORCPT ); Sun, 13 Aug 2023 05:51:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57502 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231163AbjHMJvV (ORCPT ); Sun, 13 Aug 2023 05:51:21 -0400 Received: from mail-108-mta98.mxroute.com (mail-108-mta98.mxroute.com [136.175.108.98]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BB6891718 for ; Sun, 13 Aug 2023 02:51:21 -0700 (PDT) Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta98.mxroute.com (ZoneMTA) with ESMTPSA id 189ee49eb1000023b6.001 for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 13 Aug 2023 09:46:09 +0000 X-Zone-Loop: af3278ed87ca2e15cdf2442caee45a39ba62aac6b761 X-Originating-IP: [136.175.111.2] DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=c8h4.io; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=FB9saJ73aePHW12/2NAYHB+pC/mx/z3q0o4a5z26h+w=; b=VUc8UiaXpeZZNvg28sq6P979mi mUiQCRZ/d9Yv63MaZle5591Ti37S7i0dGIilT/0zdP+mW/VPjNZcbVJwj9f30ISERERfaghcdVgZ6 D8eNBUf4MDFOgrIVkWVbWPGUFtcKS+S3i8/n3foYKFrBGq7ztQYfrtHGrBLQ06a0yKwPmzPcKh9pq X1lA/OvPjdRIzBtAimhUK4h1erm/kLTryjOXD9rVcXXHNpi5UXI6OE95N7+ZfLvCWqE+uXRCg1KOB XLrDFckSMNp/Q+czMSUiSDBPMboB3WOKyC4HKKhipKOJ53t9ULufQmmEMxtq3V/Lrb9uoWgWDoyXm tYCvMGmg==; From: Christoph Heiss To: linux-btrfs@vger.kernel.org Subject: [PATCH 6/7] btrfs-progs: subvol get-default: implement json format output Date: Sun, 13 Aug 2023 11:45:01 +0200 Message-ID: <20230813094555.106052-7-christoph@c8h4.io> In-Reply-To: <20230813094555.106052-1-christoph@c8h4.io> References: <20230813094555.106052-1-christoph@c8h4.io> MIME-Version: 1.0 X-Authenticated-Id: christoph@c8h4.io Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Implements JSON-formatted output for the `subvolume get-default` command using the `--format json` global option, much like it is implemented for other commands. Signed-off-by: Christoph Heiss --- cmds/subvolume.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/cmds/subvolume.c b/cmds/subvolume.c index cb863ac7..f7076655 100644 --- a/cmds/subvolume.c +++ b/cmds/subvolume.c @@ -701,6 +701,8 @@ static DEFINE_SIMPLE_COMMAND(subvolume_snapshot, "snapshot"); static const char * const cmd_subvolume_get_default_usage[] = { "btrfs subvolume get-default ", "Get the default subvolume of a filesystem", + HELPINFO_INSERT_GLOBALS, + HELPINFO_INSERT_FORMAT, NULL }; @@ -712,6 +714,7 @@ static int cmd_subvolume_get_default(const struct cmd_struct *cmd, int argc, cha DIR *dirstream = NULL; enum btrfs_util_error err; struct btrfs_util_subvolume_info subvol; + struct format_ctx fctx; char *path; clean_args_no_options(cmd, argc, argv); @@ -731,7 +734,14 @@ static int cmd_subvolume_get_default(const struct cmd_struct *cmd, int argc, cha /* no need to resolve roots if FS_TREE is default */ if (default_id == BTRFS_FS_TREE_OBJECTID) { - pr_verbose(LOG_DEFAULT, "ID 5 (FS_TREE)\n"); + if (bconf.output_format == CMD_FORMAT_JSON) { + fmt_start(&fctx, btrfs_subvolume_rowspec, 1, 0); + fmt_print(&fctx, "ID", 5); + fmt_end(&fctx); + } else { + pr_verbose(LOG_DEFAULT, "ID 5 (FS_TREE)\n"); + } + ret = 0; goto out; } @@ -748,8 +758,17 @@ static int cmd_subvolume_get_default(const struct cmd_struct *cmd, int argc, cha goto out; } - pr_verbose(LOG_DEFAULT, "ID %" PRIu64 " gen %" PRIu64 " top level %" PRIu64 " path %s\n", - subvol.id, subvol.generation, subvol.parent_id, path); + if (bconf.output_format == CMD_FORMAT_JSON) { + fmt_start(&fctx, btrfs_subvolume_rowspec, 1, 0); + fmt_print(&fctx, "ID", subvol.id); + fmt_print(&fctx, "gen", subvol.generation); + fmt_print(&fctx, "top level", subvol.parent_id); + fmt_print(&fctx, "path", path); + fmt_end(&fctx); + } else { + pr_verbose(LOG_DEFAULT, "ID %" PRIu64 " gen %" PRIu64 " top level %" PRIu64 " path %s\n", + subvol.id, subvol.generation, subvol.parent_id, path); + } free(path); @@ -758,7 +777,7 @@ out: close_file_or_dir(fd, dirstream); return ret; } -static DEFINE_SIMPLE_COMMAND(subvolume_get_default, "get-default"); +static DEFINE_COMMAND_WITH_FLAGS(subvolume_get_default, "get-default", CMD_FORMAT_JSON); static const char * const cmd_subvolume_set_default_usage[] = { "btrfs subvolume set-default \n" From patchwork Sun Aug 13 09:45:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoph Heiss X-Patchwork-Id: 13352053 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 04024C001B0 for ; Sun, 13 Aug 2023 09:51:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231163AbjHMJvZ (ORCPT ); Sun, 13 Aug 2023 05:51:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57522 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231175AbjHMJvW (ORCPT ); Sun, 13 Aug 2023 05:51:22 -0400 Received: from mail-108-mta160.mxroute.com (mail-108-mta160.mxroute.com [136.175.108.160]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BB54F1712 for ; Sun, 13 Aug 2023 02:51:21 -0700 (PDT) Received: from mail-111-mta2.mxroute.com ([136.175.111.2] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta160.mxroute.com (ZoneMTA) with ESMTPSA id 189ee49ed1200023b6.001 for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 13 Aug 2023 09:46:09 +0000 X-Zone-Loop: 1336b6fb27cafbaa9d87ceb81e384f554e1ce389494d X-Originating-IP: [136.175.111.2] DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=c8h4.io; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Sender:Reply-To:Cc:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=hhQKnP2IWlvKtVIhpv86VFiOlUCM34ifxp8u6AljrK0=; b=MkkNRkjx0rdVbM9DIDeeSo4IwF /1t1W4H5BFh0fmcEvqbq44Gaw2C/ObBUjtPPlUu9GVQ6Cxd6clnZvOBHBCcFP0cUQFYhBOwbW9eyb cWmHwDEGWe9mbmSRLy2vW3uhNOhc6wUq8VobCEL7WMM0/RvKZ/LTji5CPH7OHLW859nRuPPn3VTim TJ4BQPXEZcStcE81s5Xsl6rj1apiJHUCnkbre8yypvVaBOgMn3SoplrKtjOCjxaxRBUooqU50Np5E Kw/93j0r2gAyi5J0oaLnVcdAv2ylxsvy4RDFmUyB8dk7H332QioKemViXWFxHueJd8TIb7V+7C1JF YblOejEQ==; From: Christoph Heiss To: linux-btrfs@vger.kernel.org Subject: [PATCH 7/7] btrfs-progs: subvol show: implement json format output Date: Sun, 13 Aug 2023 11:45:02 +0200 Message-ID: <20230813094555.106052-8-christoph@c8h4.io> In-Reply-To: <20230813094555.106052-1-christoph@c8h4.io> References: <20230813094555.106052-1-christoph@c8h4.io> MIME-Version: 1.0 X-Authenticated-Id: christoph@c8h4.io Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org Implements JSON-formatted output for the `subvolume list` command using the `--format json` global option, much like it is implemented for other commands. Signed-off-by: Christoph Heiss --- cmds/subvolume.c | 108 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 98 insertions(+), 10 deletions(-) diff --git a/cmds/subvolume.c b/cmds/subvolume.c index f7076655..1f513a4a 100644 --- a/cmds/subvolume.c +++ b/cmds/subvolume.c @@ -1375,6 +1375,64 @@ static void print_subvolume_show_quota_text(const struct btrfs_util_subvolume_in pretty_size_mode(stats->info.exclusive, unit_mode)); } +static void print_subvolume_show_json(struct format_ctx *fctx, + const struct btrfs_util_subvolume_info *subvol, + const char *subvol_path, const char *subvol_name) +{ + fmt_print(fctx, "name", subvol_name); + + if (!uuid_is_null(subvol->uuid)) + fmt_print(fctx, "uuid", subvol->uuid); + if (!uuid_is_null(subvol->parent_uuid)) + fmt_print(fctx, "parent_uuid", subvol->parent_uuid); + if (!uuid_is_null(subvol->received_uuid)) + fmt_print(fctx, "received_uuid", subvol->received_uuid); + + fmt_print(fctx, "otime", subvol->otime); + fmt_print(fctx, "ID", subvol->id); + fmt_print(fctx, "gen", subvol->generation); + fmt_print(fctx, "cgen", subvol->otransid); + fmt_print(fctx, "parent", subvol->parent_id); + fmt_print(fctx, "top level", subvol->parent_id); + + fmt_print_start_group(fctx, "flags", JSON_TYPE_ARRAY); + if (subvol->flags & BTRFS_ROOT_SUBVOL_RDONLY) + fmt_print(fctx, "flag-list-item", "readonly"); + fmt_print_end_group(fctx, "flags"); + + if (subvol->stransid) + fmt_print(fctx, "stransid", subvol->stransid); + + if (subvol->stime.tv_sec) + fmt_print(fctx, "stime", subvol->stime); + + if (subvol->rtransid) + fmt_print(fctx, "rtransid", subvol->rtransid); + + if (subvol->rtime.tv_sec) + fmt_print(fctx, "rtime", subvol->rtime); +} + +static void print_subvolume_show_quota_json(struct format_ctx *fctx, + const struct btrfs_util_subvolume_info *subvol, + const struct btrfs_qgroup_stats *stats) +{ + fmt_print_start_group(fctx, "quota", JSON_TYPE_MAP); + fmt_print(fctx, "quota-group", 0, subvol->id); + + fmt_print_start_group(fctx, "limit", JSON_TYPE_MAP); + fmt_print(fctx, "quota-ref", stats->limit.max_referenced); + fmt_print(fctx, "quota-excl", stats->limit.max_exclusive); + fmt_print_end_group(fctx, "limit"); + + fmt_print_start_group(fctx, "usage", JSON_TYPE_MAP); + fmt_print(fctx, "quota-ref", stats->info.referenced); + fmt_print(fctx, "quota-excl", stats->info.exclusive); + fmt_print_end_group(fctx, "usage"); + + fmt_print_end_group(fctx, "quota"); +} + static const char * const cmd_subvolume_show_usage[] = { "btrfs subvolume show [options] ", "Show more information about the subvolume (UUIDs, generations, times, snapshots)", @@ -1385,6 +1443,8 @@ static const char * const cmd_subvolume_show_usage[] = { OPTLINE("-r|--rootid ID", "root id of the subvolume"), OPTLINE("-u|--uuid UUID", "UUID of the subvolum"), HELPINFO_UNITS_SHORT_LONG, + HELPINFO_INSERT_GLOBALS, + HELPINFO_INSERT_FORMAT, NULL }; @@ -1406,6 +1466,7 @@ static int cmd_subvolume_show(const struct cmd_struct *cmd, int argc, char **arg enum btrfs_util_error err; struct btrfs_qgroup_stats stats; unsigned int unit_mode; + struct format_ctx fctx; unit_mode = get_unit_mode_from_arg(&argc, argv, 1); @@ -1516,10 +1577,19 @@ static int cmd_subvolume_show(const struct cmd_struct *cmd, int argc, char **arg subvol_name = basename(subvol_path); } - print_subvolume_show_text(&subvol, subvol_path, subvol_name); + if (bconf.output_format == CMD_FORMAT_JSON) { + fmt_start(&fctx, btrfs_subvolume_rowspec, 1, 0); + fmt_print_start_group(&fctx, subvol_path, JSON_TYPE_MAP); + print_subvolume_show_json(&fctx, &subvol, subvol_path, subvol_name); + } else { + print_subvolume_show_text(&subvol, subvol_path, subvol_name); + } /* print the snapshots of the given subvol if any*/ - pr_verbose(LOG_DEFAULT, "\tSnapshot(s):\n"); + if (bconf.output_format == CMD_FORMAT_JSON) + fmt_print_start_group(&fctx, "snapshots", JSON_TYPE_ARRAY); + else + pr_verbose(LOG_DEFAULT, "\tSnapshot(s):\n"); err = btrfs_util_create_subvolume_iterator_fd(fd, BTRFS_FS_TREE_OBJECTID, 0, @@ -1535,30 +1605,48 @@ static int cmd_subvolume_show(const struct cmd_struct *cmd, int argc, char **arg } else if (err) { error_btrfs_util(err); btrfs_util_destroy_subvolume_iterator(iter); - goto out; + goto out2; } - if (uuid_compare(subvol2.parent_uuid, subvol.uuid) == 0) - pr_verbose(LOG_DEFAULT, "\t\t\t\t%s\n", path); + if (uuid_compare(subvol2.parent_uuid, subvol.uuid) == 0) { + if (bconf.output_format == CMD_FORMAT_JSON) + fmt_print(&fctx, "snapshot-list-item", path); + else + pr_verbose(LOG_DEFAULT, "\t\t\t\t%s\n", path); + } free(path); } + + if (bconf.output_format == CMD_FORMAT_JSON) + fmt_print_end_group(&fctx, "snapshots"); + btrfs_util_destroy_subvolume_iterator(iter); ret = btrfs_qgroup_query(fd, subvol.id, &stats); if (ret == -ENOTTY) { /* Quota information not available, not fatal */ - pr_verbose(LOG_DEFAULT, "\tQuota group:\t\tn/a\n"); + if (bconf.output_format == CMD_FORMAT_TEXT) + pr_verbose(LOG_DEFAULT, "\tQuota group:\t\tn/a\n"); ret = 0; - goto out; + goto out2; } if (ret) { error("quota query failed: %m"); - goto out; + goto out2; } - print_subvolume_show_quota_text(&subvol, &stats, unit_mode); + if (bconf.output_format == CMD_FORMAT_JSON) + print_subvolume_show_quota_json(&fctx, &subvol, &stats); + else + print_subvolume_show_quota_text(&subvol, &stats, unit_mode); + +out2: + if (bconf.output_format == CMD_FORMAT_JSON) { + fmt_print_end_group(&fctx, subvol_path); + fmt_end(&fctx); + } out: free(subvol_path); @@ -1566,7 +1654,7 @@ out: free(fullpath); return !!ret; } -static DEFINE_SIMPLE_COMMAND(subvolume_show, "show"); +static DEFINE_COMMAND_WITH_FLAGS(subvolume_show, "show", CMD_FORMAT_JSON); static const char * const cmd_subvolume_sync_usage[] = { "btrfs subvolume sync [...]",