btrfs-progs: subvol list: implement json format output
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 <christoph@c8h4.io> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
da440e66fb
commit
ee233db769
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue