aboutsummaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
authorUmer Saleem <[email protected]>2024-04-25 17:59:41 +0500
committerBrian Behlendorf <[email protected]>2024-08-06 12:47:04 -0700
commit4e6b3f7e1d424c923041acecfed8f10780766e19 (patch)
tree83c3e77b666514a65e7e0d296a94ae78c5a69a9a /cmd
parenteb2b824bdec95377a4f0612e96814383b87414f6 (diff)
JSON output support for zpool list
This commit adds support for zpool list command to output the list of ZFS pools in JSON format using '-j' option.. Information about available pools is collected in nvlist which is later printed to stdout in JSON format. Existing options for zfs list command work with '-j' flag. man page for zpool list is updated accordingly. Reviewed-by: Tony Hutter <[email protected]> Reviewed-by: Ameer Hamza <[email protected]> Signed-off-by: Umer Saleem <[email protected]> Closes #16217
Diffstat (limited to 'cmd')
-rw-r--r--cmd/zpool/zpool_main.c379
1 files changed, 297 insertions, 82 deletions
diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c
index 1aaa4d77e..311591ea0 100644
--- a/cmd/zpool/zpool_main.c
+++ b/cmd/zpool/zpool_main.c
@@ -403,8 +403,8 @@ get_usage(zpool_help_t idx)
return (gettext("\tlabelclear [-f] <vdev>\n"));
case HELP_LIST:
return (gettext("\tlist [-gHLpPv] [-o property[,...]] "
- "[-T d|u] [pool] ... \n"
- "\t [interval [count]]\n"));
+ "[-j [--json-int, --json-pool-key-guid]]\n"
+ "\t [-T d|u] [pool] [interval [count]]\n"));
case HELP_PREFETCH:
return (gettext("\tprefetch -t <type> [<type opts>] <pool>\n"
"\t -t ddt <pool>\n"));
@@ -968,14 +968,15 @@ fill_pool_info(nvlist_t *list, zpool_handle_t *zhp, boolean_t addtype,
static void
fill_vdev_info(nvlist_t *list, zpool_handle_t *zhp, char *name,
- boolean_t as_int)
+ boolean_t addtype, boolean_t as_int)
{
boolean_t spare, l2c, log;
const char *path, *phys, *devid;
nvlist_t *nvdev = zpool_find_vdev(zhp, name, &spare, &l2c, &log);
fnvlist_add_string(list, "name", name);
- fnvlist_add_string(list, "type", "VDEV");
+ if (addtype)
+ fnvlist_add_string(list, "type", "VDEV");
if (nvdev) {
const char *type = fnvlist_lookup_string(nvdev,
ZPOOL_CONFIG_TYPE);
@@ -6483,9 +6484,13 @@ typedef struct list_cbdata {
boolean_t cb_verbose;
int cb_name_flags;
int cb_namewidth;
+ boolean_t cb_json;
boolean_t cb_scripted;
zprop_list_t *cb_proplist;
boolean_t cb_literal;
+ nvlist_t *cb_jsobj;
+ boolean_t cb_json_as_int;
+ boolean_t cb_json_pool_key_guid;
} list_cbdata_t;
@@ -6546,7 +6551,7 @@ print_header(list_cbdata_t *cb)
* to the described layout. Used by zpool_do_list().
*/
static void
-print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
+collect_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
{
zprop_list_t *pl = cb->cb_proplist;
boolean_t first = B_TRUE;
@@ -6554,6 +6559,20 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
const char *propstr;
boolean_t right_justify;
size_t width;
+ zprop_source_t sourcetype = ZPROP_SRC_NONE;
+ nvlist_t *item, *d, *props;
+ item = d = props = NULL;
+
+ if (cb->cb_json) {
+ item = fnvlist_alloc();
+ props = fnvlist_alloc();
+ d = fnvlist_lookup_nvlist(cb->cb_jsobj, "pools");
+ if (d == NULL) {
+ fprintf(stderr, "pools obj not found.\n");
+ exit(1);
+ }
+ fill_pool_info(item, zhp, B_TRUE, cb->cb_json_as_int);
+ }
for (; pl != NULL; pl = pl->pl_next) {
@@ -6566,7 +6585,7 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
width = cb->cb_namewidth;
}
- if (!first) {
+ if (!cb->cb_json && !first) {
if (cb->cb_scripted)
(void) fputc('\t', stdout);
else
@@ -6578,7 +6597,8 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
right_justify = B_FALSE;
if (pl->pl_prop != ZPROP_USERPROP) {
if (zpool_get_prop(zhp, pl->pl_prop, property,
- sizeof (property), NULL, cb->cb_literal) != 0)
+ sizeof (property), &sourcetype,
+ cb->cb_literal) != 0)
propstr = "-";
else
propstr = property;
@@ -6589,33 +6609,61 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
sizeof (property)) == 0) {
propstr = property;
+ sourcetype = ZPROP_SRC_LOCAL;
} else if (zfs_prop_user(pl->pl_user_prop) &&
zpool_get_userprop(zhp, pl->pl_user_prop, property,
- sizeof (property), NULL) == 0) {
+ sizeof (property), &sourcetype) == 0) {
propstr = property;
} else {
propstr = "-";
}
- /*
- * If this is being called in scripted mode, or if this is the
- * last column and it is left-justified, don't include a width
- * format specifier.
- */
- if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
- (void) fputs(propstr, stdout);
- else if (right_justify)
- (void) printf("%*s", (int)width, propstr);
- else
- (void) printf("%-*s", (int)width, propstr);
+ if (cb->cb_json) {
+ if (pl->pl_prop == ZPOOL_PROP_NAME)
+ continue;
+ (void) zprop_nvlist_one_property(
+ zpool_prop_to_name(pl->pl_prop), propstr,
+ sourcetype, NULL, NULL, props, cb->cb_json_as_int);
+ } else {
+ /*
+ * If this is being called in scripted mode, or if this
+ * is the last column and it is left-justified, don't
+ * include a width format specifier.
+ */
+ if (cb->cb_scripted || (pl->pl_next == NULL &&
+ !right_justify))
+ (void) fputs(propstr, stdout);
+ else if (right_justify)
+ (void) printf("%*s", (int)width, propstr);
+ else
+ (void) printf("%-*s", (int)width, propstr);
+ }
}
- (void) fputc('\n', stdout);
+ if (cb->cb_json) {
+ fnvlist_add_nvlist(item, "properties", props);
+ if (cb->cb_json_pool_key_guid) {
+ char pool_guid[256];
+ uint64_t guid = fnvlist_lookup_uint64(
+ zpool_get_config(zhp, NULL),
+ ZPOOL_CONFIG_POOL_GUID);
+ snprintf(pool_guid, 256, "%llu",
+ (u_longlong_t)guid);
+ fnvlist_add_nvlist(d, pool_guid, item);
+ } else {
+ fnvlist_add_nvlist(d, zpool_get_name(zhp),
+ item);
+ }
+ fnvlist_free(props);
+ fnvlist_free(item);
+ } else
+ (void) fputc('\n', stdout);
}
static void
-print_one_column(zpool_prop_t prop, uint64_t value, const char *str,
- boolean_t scripted, boolean_t valid, enum zfs_nicenum_format format)
+collect_vdev_prop(zpool_prop_t prop, uint64_t value, const char *str,
+ boolean_t scripted, boolean_t valid, enum zfs_nicenum_format format,
+ boolean_t json, nvlist_t *nvl, boolean_t as_int)
{
char propval[64];
boolean_t fixed;
@@ -6665,10 +6713,15 @@ print_one_column(zpool_prop_t prop, uint64_t value, const char *str,
if (!valid)
(void) strlcpy(propval, "-", sizeof (propval));
- if (scripted)
- (void) printf("\t%s", propval);
- else
- (void) printf(" %*s", (int)width, propval);
+ if (json) {
+ zprop_nvlist_one_property(zpool_prop_to_name(prop), propval,
+ ZPROP_SRC_NONE, NULL, NULL, nvl, as_int);
+ } else {
+ if (scripted)
+ (void) printf("\t%s", propval);
+ else
+ (void) printf(" %*s", (int)width, propval);
+ }
}
/*
@@ -6676,15 +6729,17 @@ print_one_column(zpool_prop_t prop, uint64_t value, const char *str,
* not compatible with '-o' <proplist> option
*/
static void
-print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
- list_cbdata_t *cb, int depth, boolean_t isspare)
+collect_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
+ list_cbdata_t *cb, int depth, boolean_t isspare, nvlist_t *item)
{
nvlist_t **child;
vdev_stat_t *vs;
- uint_t c, children;
+ uint_t c, children = 0;
char *vname;
boolean_t scripted = cb->cb_scripted;
uint64_t islog = B_FALSE;
+ nvlist_t *props, *ent, *ch, *obj, *l2c, *sp;
+ props = ent = ch = obj = sp = l2c = NULL;
const char *dashes = "%-*s - - - - "
"- - - - -\n";
@@ -6705,13 +6760,21 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
return;
- if (scripted)
- (void) printf("\t%s", name);
- else if (strlen(name) + depth > cb->cb_namewidth)
- (void) printf("%*s%s", depth, "", name);
- else
- (void) printf("%*s%s%*s", depth, "", name,
- (int)(cb->cb_namewidth - strlen(name) - depth), "");
+ if (cb->cb_json) {
+ props = fnvlist_alloc();
+ ent = fnvlist_alloc();
+ fill_vdev_info(ent, zhp, (char *)name, B_FALSE,
+ cb->cb_json_as_int);
+ } else {
+ if (scripted)
+ (void) printf("\t%s", name);
+ else if (strlen(name) + depth > cb->cb_namewidth)
+ (void) printf("%*s%s", depth, "", name);
+ else
+ (void) printf("%*s%s%*s", depth, "", name,
+ (int)(cb->cb_namewidth - strlen(name) -
+ depth), "");
+ }
/*
* Print the properties for the individual vdevs. Some
@@ -6719,30 +6782,39 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
* 'toplevel' boolean value is passed to the print_one_column()
* to indicate that the value is valid.
*/
- if (VDEV_STAT_VALID(vs_pspace, c) && vs->vs_pspace)
- print_one_column(ZPOOL_PROP_SIZE, vs->vs_pspace, NULL,
- scripted, B_TRUE, format);
- else
- print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, NULL,
- scripted, toplevel, format);
- print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, NULL,
- scripted, toplevel, format);
- print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc,
- NULL, scripted, toplevel, format);
- print_one_column(ZPOOL_PROP_CHECKPOINT,
- vs->vs_checkpoint_space, NULL, scripted, toplevel, format);
- print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, NULL,
- scripted, B_TRUE, format);
- print_one_column(ZPOOL_PROP_FRAGMENTATION,
+ if (VDEV_STAT_VALID(vs_pspace, c) && vs->vs_pspace) {
+ collect_vdev_prop(ZPOOL_PROP_SIZE, vs->vs_pspace, NULL,
+ scripted, B_TRUE, format, cb->cb_json, props,
+ cb->cb_json_as_int);
+ } else {
+ collect_vdev_prop(ZPOOL_PROP_SIZE, vs->vs_space, NULL,
+ scripted, toplevel, format, cb->cb_json, props,
+ cb->cb_json_as_int);
+ }
+ collect_vdev_prop(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, NULL,
+ scripted, toplevel, format, cb->cb_json, props,
+ cb->cb_json_as_int);
+ collect_vdev_prop(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc,
+ NULL, scripted, toplevel, format, cb->cb_json, props,
+ cb->cb_json_as_int);
+ collect_vdev_prop(ZPOOL_PROP_CHECKPOINT,
+ vs->vs_checkpoint_space, NULL, scripted, toplevel, format,
+ cb->cb_json, props, cb->cb_json_as_int);
+ collect_vdev_prop(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, NULL,
+ scripted, B_TRUE, format, cb->cb_json, props,
+ cb->cb_json_as_int);
+ collect_vdev_prop(ZPOOL_PROP_FRAGMENTATION,
vs->vs_fragmentation, NULL, scripted,
(vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel),
- format);
+ format, cb->cb_json, props, cb->cb_json_as_int);
cap = (vs->vs_space == 0) ? 0 :
(vs->vs_alloc * 10000 / vs->vs_space);
- print_one_column(ZPOOL_PROP_CAPACITY, cap, NULL,
- scripted, toplevel, format);
- print_one_column(ZPOOL_PROP_DEDUPRATIO, 0, NULL,
- scripted, toplevel, format);
+ collect_vdev_prop(ZPOOL_PROP_CAPACITY, cap, NULL,
+ scripted, toplevel, format, cb->cb_json, props,
+ cb->cb_json_as_int);
+ collect_vdev_prop(ZPOOL_PROP_DEDUPRATIO, 0, NULL,
+ scripted, toplevel, format, cb->cb_json, props,
+ cb->cb_json_as_int);
state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
if (isspare) {
if (vs->vs_aux == VDEV_AUX_SPARED)
@@ -6750,14 +6822,28 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
else if (vs->vs_state == VDEV_STATE_HEALTHY)
state = "AVAIL";
}
- print_one_column(ZPOOL_PROP_HEALTH, 0, state, scripted,
- B_TRUE, format);
- (void) fputc('\n', stdout);
+ collect_vdev_prop(ZPOOL_PROP_HEALTH, 0, state, scripted,
+ B_TRUE, format, cb->cb_json, props, cb->cb_json_as_int);
+
+ if (cb->cb_json) {
+ fnvlist_add_nvlist(ent, "properties", props);
+ fnvlist_free(props);
+ } else
+ (void) fputc('\n', stdout);
}
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
- &child, &children) != 0)
+ &child, &children) != 0) {
+ if (cb->cb_json) {
+ fnvlist_add_nvlist(item, name, ent);
+ fnvlist_free(ent);
+ }
return;
+ }
+
+ if (cb->cb_json) {
+ ch = fnvlist_alloc();
+ }
/* list the normal vdevs first */
for (c = 0; c < children; c++) {
@@ -6776,14 +6862,28 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
vname = zpool_vdev_name(g_zfs, zhp, child[c],
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
- print_list_stats(zhp, vname, child[c], cb, depth + 2, B_FALSE);
+
+ if (name == NULL || cb->cb_json != B_TRUE)
+ collect_list_stats(zhp, vname, child[c], cb, depth + 2,
+ B_FALSE, item);
+ else if (cb->cb_json) {
+ collect_list_stats(zhp, vname, child[c], cb, depth + 2,
+ B_FALSE, ch);
+ }
free(vname);
}
+ if (cb->cb_json) {
+ if (!nvlist_empty(ch))
+ fnvlist_add_nvlist(ent, "vdevs", ch);
+ fnvlist_free(ch);
+ }
+
/* list the classes: 'logs', 'dedup', and 'special' */
for (uint_t n = 0; n < ARRAY_SIZE(class_name); n++) {
boolean_t printed = B_FALSE;
-
+ if (cb->cb_json)
+ obj = fnvlist_alloc();
for (c = 0; c < children; c++) {
const char *bias = NULL;
const char *type = NULL;
@@ -6802,7 +6902,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
if (!islog && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
continue;
- if (!printed) {
+ if (!printed && !cb->cb_json) {
/* LINTED E_SEC_PRINTF_VAR_FMT */
(void) printf(dashes, cb->cb_namewidth,
class_name[n]);
@@ -6810,36 +6910,64 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
}
vname = zpool_vdev_name(g_zfs, zhp, child[c],
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
- print_list_stats(zhp, vname, child[c], cb, depth + 2,
- B_FALSE);
+ collect_list_stats(zhp, vname, child[c], cb, depth + 2,
+ B_FALSE, obj);
free(vname);
}
+ if (cb->cb_json) {
+ if (!nvlist_empty(obj))
+ fnvlist_add_nvlist(item, class_name[n], obj);
+ fnvlist_free(obj);
+ }
}
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
&child, &children) == 0 && children > 0) {
- /* LINTED E_SEC_PRINTF_VAR_FMT */
- (void) printf(dashes, cb->cb_namewidth, "cache");
+ if (cb->cb_json) {
+ l2c = fnvlist_alloc();
+ } else {
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ (void) printf(dashes, cb->cb_namewidth, "cache");
+ }
for (c = 0; c < children; c++) {
vname = zpool_vdev_name(g_zfs, zhp, child[c],
cb->cb_name_flags);
- print_list_stats(zhp, vname, child[c], cb, depth + 2,
- B_FALSE);
+ collect_list_stats(zhp, vname, child[c], cb, depth + 2,
+ B_FALSE, l2c);
free(vname);
}
+ if (cb->cb_json) {
+ if (!nvlist_empty(l2c))
+ fnvlist_add_nvlist(item, "l2cache", l2c);
+ fnvlist_free(l2c);
+ }
}
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child,
&children) == 0 && children > 0) {
- /* LINTED E_SEC_PRINTF_VAR_FMT */
- (void) printf(dashes, cb->cb_namewidth, "spare");
+ if (cb->cb_json) {
+ sp = fnvlist_alloc();
+ } else {
+ /* LINTED E_SEC_PRINTF_VAR_FMT */
+ (void) printf(dashes, cb->cb_namewidth, "spare");
+ }
for (c = 0; c < children; c++) {
vname = zpool_vdev_name(g_zfs, zhp, child[c],
cb->cb_name_flags);
- print_list_stats(zhp, vname, child[c], cb, depth + 2,
- B_TRUE);
+ collect_list_stats(zhp, vname, child[c], cb, depth + 2,
+ B_TRUE, sp);
free(vname);
}
+ if (cb->cb_json) {
+ if (!nvlist_empty(sp))
+ fnvlist_add_nvlist(item, "spares", sp);
+ fnvlist_free(sp);
+ }
+ }
+
+ if (name != NULL && cb->cb_json) {
+ fnvlist_add_nvlist(item, name, ent);
+ fnvlist_free(ent);
}
}
@@ -6849,17 +6977,44 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
static int
list_callback(zpool_handle_t *zhp, void *data)
{
+ nvlist_t *p, *d, *nvdevs;
+ uint64_t guid;
+ char pool_guid[256];
+ const char *pool_name = zpool_get_name(zhp);
list_cbdata_t *cbp = data;
+ p = d = nvdevs = NULL;
- print_pool(zhp, cbp);
+ collect_pool(zhp, cbp);
if (cbp->cb_verbose) {
nvlist_t *config, *nvroot;
-
config = zpool_get_config(zhp, NULL);
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
&nvroot) == 0);
- print_list_stats(zhp, NULL, nvroot, cbp, 0, B_FALSE);
+ if (cbp->cb_json) {
+ d = fnvlist_lookup_nvlist(cbp->cb_jsobj,
+ "pools");
+ if (cbp->cb_json_pool_key_guid) {
+ guid = fnvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_POOL_GUID);
+ snprintf(pool_guid, 256, "%llu",
+ (u_longlong_t)guid);
+ p = fnvlist_lookup_nvlist(d, pool_guid);
+ } else {
+ p = fnvlist_lookup_nvlist(d, pool_name);
+ }
+ nvdevs = fnvlist_alloc();
+ }
+ collect_list_stats(zhp, NULL, nvroot, cbp, 0, B_FALSE, nvdevs);
+ if (cbp->cb_json) {
+ fnvlist_add_nvlist(p, "vdevs", nvdevs);
+ if (cbp->cb_json_pool_key_guid)
+ fnvlist_add_nvlist(d, pool_guid, p);
+ else
+ fnvlist_add_nvlist(d, pool_name, p);
+ fnvlist_add_nvlist(cbp->cb_jsobj, "pools", d);
+ fnvlist_free(nvdevs);
+ }
}
return (0);
@@ -6899,6 +7054,9 @@ get_namewidth_list(zpool_handle_t *zhp, void *data)
* -p Display values in parsable (exact) format.
* -P Display full path for vdev name.
* -T Display a timestamp in date(1) or Unix format
+ * -j Display the output in JSON format
+ * --json-int Display the numbers as integer instead of strings.
+ * --json-pool-key-guid Set pool GUID as key for pool objects.
*
* List all pools in the system, whether or not they're healthy. Output space
* statistics for each one, as well as health status summary.
@@ -6917,10 +7075,19 @@ zpool_do_list(int argc, char **argv)
unsigned long count = 0;
zpool_list_t *list;
boolean_t first = B_TRUE;
+ nvlist_t *data = NULL;
current_prop_type = ZFS_TYPE_POOL;
+ struct option long_options[] = {
+ {"json-int", no_argument, NULL, ZPOOL_OPTION_JSON_NUMS_AS_INT},
+ {"json-pool-key-guid", no_argument, NULL,
+ ZPOOL_OPTION_POOL_KEY_GUID},
+ {0, 0, 0, 0}
+ };
+
/* check options */
- while ((c = getopt(argc, argv, ":gHLo:pPT:v")) != -1) {
+ while ((c = getopt_long(argc, argv, ":gjHLo:pPT:v", long_options,
+ NULL)) != -1) {
switch (c) {
case 'g':
cb.cb_name_flags |= VDEV_NAME_GUID;
@@ -6940,6 +7107,16 @@ zpool_do_list(int argc, char **argv)
case 'p':
cb.cb_literal = B_TRUE;
break;
+ case 'j':
+ cb.cb_json = B_TRUE;
+ break;
+ case ZPOOL_OPTION_JSON_NUMS_AS_INT:
+ cb.cb_json_as_int = B_TRUE;
+ cb.cb_literal = B_TRUE;
+ break;
+ case ZPOOL_OPTION_POOL_KEY_GUID:
+ cb.cb_json_pool_key_guid = B_TRUE;
+ break;
case 'T':
get_timestamp_arg(*optarg);
break;
@@ -6962,6 +7139,18 @@ zpool_do_list(int argc, char **argv)
argc -= optind;
argv += optind;
+ if (!cb.cb_json && cb.cb_json_as_int) {
+ (void) fprintf(stderr, gettext("'--json-int' only works with"
+ " '-j' option\n"));
+ usage(B_FALSE);
+ }
+
+ if (!cb.cb_json && cb.cb_json_pool_key_guid) {
+ (void) fprintf(stderr, gettext("'json-pool-key-guid' only"
+ " works with '-j' option\n"));
+ usage(B_FALSE);
+ }
+
get_interval_count(&argc, argv, &interval, &count);
if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
@@ -6975,18 +7164,43 @@ zpool_do_list(int argc, char **argv)
if (pool_list_count(list) == 0)
break;
+ if (cb.cb_json) {
+ cb.cb_jsobj = zpool_json_schema(0, 1);
+ data = fnvlist_alloc();
+ fnvlist_add_nvlist(cb.cb_jsobj, "pools", data);
+ fnvlist_free(data);
+ }
+
cb.cb_namewidth = 0;
(void) pool_list_iter(list, B_FALSE, get_namewidth_list, &cb);
- if (timestamp_fmt != NODATE)
- print_timestamp(timestamp_fmt);
+ if (timestamp_fmt != NODATE) {
+ if (cb.cb_json) {
+ if (cb.cb_json_as_int) {
+ fnvlist_add_uint64(cb.cb_jsobj, "time",
+ time(NULL));
+ } else {
+ char ts[128];
+ get_timestamp(timestamp_fmt, ts, 128);
+ fnvlist_add_string(cb.cb_jsobj, "time",
+ ts);
+ }
+ } else
+ print_timestamp(timestamp_fmt);
+ }
- if (!cb.cb_scripted && (first || cb.cb_verbose)) {
+ if (!cb.cb_scripted && (first || cb.cb_verbose) &&
+ !cb.cb_json) {
print_header(&cb);
first = B_FALSE;
}
ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
+ if (ret == 0 && cb.cb_json)
+ zcmd_print_json(cb.cb_jsobj);
+ else if (ret != 0 && cb.cb_json)
+ nvlist_free(cb.cb_jsobj);
+
if (interval == 0)
break;
@@ -6999,7 +7213,8 @@ zpool_do_list(int argc, char **argv)
(void) fsleep(interval);
}
- if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
+ if (argc == 0 && !cb.cb_scripted && !cb.cb_json &&
+ pool_list_count(list) == 0) {
(void) printf(gettext("no pools available\n"));
ret = 0;
}
@@ -10886,7 +11101,7 @@ get_callback_vdev(zpool_handle_t *zhp, char *vdevname, void *data)
if (cbp->cb_json) {
if (!nvlist_empty(props)) {
item = fnvlist_alloc();
- fill_vdev_info(item, zhp, vdevname,
+ fill_vdev_info(item, zhp, vdevname, B_TRUE,
cbp->cb_json_as_int);
fnvlist_add_nvlist(item, "properties", props);
fnvlist_add_nvlist(d, vdevname, item);