diff mbox series

[7/7] btrfs-progs: subvol show: implement json format output

Message ID 20230813094555.106052-8-christoph@c8h4.io (mailing list archive)
State New, archived
Headers show
Series btrfs-progs: implement json output for subvolume subcommands | expand

Commit Message

Christoph Heiss Aug. 13, 2023, 9:45 a.m. UTC
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 <christoph@c8h4.io>
---
 cmds/subvolume.c | 108 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 98 insertions(+), 10 deletions(-)

Comments

David Sterba Aug. 17, 2023, 8:02 p.m. UTC | #1
On Sun, Aug 13, 2023 at 11:45:02AM +0200, Christoph Heiss wrote:
> 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 <christoph@c8h4.io>
> ---
>  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);

Regarding the "more is better" approach, no conditionals for similar
data.

> +	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);
> +}
diff mbox series

Patch

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] <path>",
 	"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 <path> [<subvolid>...]",