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 <hutter2@llnl.gov>
Reviewed-by: Ameer Hamza <ahamza@ixsystems.com>
Signed-off-by: Umer Saleem <usaleem@ixsystems.com>
Closes #16217
This commit is contained in:
Umer Saleem 2024-04-25 17:59:41 +05:00 committed by Brian Behlendorf
parent eb2b824bde
commit 4e6b3f7e1d
4 changed files with 428 additions and 82 deletions

View File

@ -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);

View File

@ -37,5 +37,7 @@
/* Print a timestamp in either Unix or standard format. */
void print_timestamp(uint_t);
/* Return timestamp in either Unix or standard format in provided buffer */
void get_timestamp(uint_t, char *, int);
#endif /* _STATCOMMON_H */

View File

@ -62,3 +62,25 @@ print_timestamp(uint_t timestamp_fmt)
(void) printf("%s\n", dstr);
}
}
/*
* Return timestamp as decimal reprentation (in string) of time_t
* value (-T u was specified) or in date(1) format (-T d was specified).
*/
void
get_timestamp(uint_t timestamp_fmt, char *buf, int len)
{
time_t t = time(NULL);
static const char *fmt = NULL;
/* We only need to retrieve this once per invocation */
if (fmt == NULL)
fmt = nl_langinfo(_DATE_FMT);
if (timestamp_fmt == UDATE) {
(void) snprintf(buf, len, "%lld", (longlong_t)t);
} else if (timestamp_fmt == DDATE) {
struct tm tm;
strftime(buf, len, fmt, localtime_r(&t, &tm));
}
}

View File

@ -37,6 +37,7 @@
.Nm zpool
.Cm list
.Op Fl HgLpPv
.Op Fl j Op Ar --json-int, --json-pool-key-guid
.Op Fl o Ar property Ns Oo , Ns Ar property Oc Ns
.Op Fl T Sy u Ns | Ns Sy d
.Oo Ar pool Oc Ns
@ -58,6 +59,14 @@ is specified, the command exits after
.Ar count
reports are printed.
.Bl -tag -width Ds
.It Fl j Op Ar --json-int, --json-pool-key-guid
Display the list of pools in JSON format.
Specify
.Sy --json-int
to display the numbers in integer format instead of strings.
Specify
.Sy --json-pool-key-guid
to set pool GUID as key for pool objects instead of pool names.
.It Fl g
Display vdev GUIDs instead of the normal device names.
These GUIDs can be used in place of device names for the zpool
@ -139,6 +148,104 @@ data 23.9G 14.6G 9.30G - 48% 61% 1.00x ONLINE -
sda - - - - -
sdb - - - 10G -
sdc - - - - -
.Ed
.
.Ss Example 3 : No Displaying expanded space on a device
The following command lists all available pools on the system in JSON
format.
.Bd -literal -compact -offset Ds
.No # Nm zpool Cm list Fl j | Nm jq
{
"output_version": {
"command": "zpool list",
"vers_major": 0,
"vers_minor": 1
},
"pools": {
"tank": {
"name": "tank",
"type": "POOL",
"state": "ONLINE",
"guid": "15220353080205405147",
"txg": "2671",
"spa_version": "5000",
"zpl_version": "5",
"properties": {
"size": {
"value": "111G",
"source": {
"type": "NONE",
"data": "-"
}
},
"allocated": {
"value": "30.8G",
"source": {
"type": "NONE",
"data": "-"
}
},
"free": {
"value": "80.2G",
"source": {
"type": "NONE",
"data": "-"
}
},
"checkpoint": {
"value": "-",
"source": {
"type": "NONE",
"data": "-"
}
},
"expandsize": {
"value": "-",
"source": {
"type": "NONE",
"data": "-"
}
},
"fragmentation": {
"value": "0%",
"source": {
"type": "NONE",
"data": "-"
}
},
"capacity": {
"value": "27%",
"source": {
"type": "NONE",
"data": "-"
}
},
"dedupratio": {
"value": "1.00x",
"source": {
"type": "NONE",
"data": "-"
}
},
"health": {
"value": "ONLINE",
"source": {
"type": "NONE",
"data": "-"
}
},
"altroot": {
"value": "-",
"source": {
"type": "DEFAULT",
"data": "-"
}
}
}
}
}
}
.Ed
.
.Sh SEE ALSO