Just testing, ignore this

Signed-off-by: Tony Hutter <hutter2@llnl.gov>
This commit is contained in:
Umer Saleem 2024-04-05 21:02:30 +05:00 committed by Tony Hutter
parent a10faf5ce6
commit 7efbdc257c
25 changed files with 3604 additions and 618 deletions

2
TEST
View File

@ -35,7 +35,7 @@
#TEST_ZFSTESTS_ITERS="1"
#TEST_ZFSTESTS_OPTIONS="-vx"
#TEST_ZFSTESTS_RUNFILE="linux.run"
#TEST_ZFSTESTS_TAGS="functional"
TEST_ZFSTESTS_TAGS="json"
### zfsstress
#TEST_ZFSSTRESS_SKIP="yes"

View File

@ -134,6 +134,10 @@ static int zfs_do_unzone(int argc, char **argv);
static int zfs_do_help(int argc, char **argv);
enum zfs_options {
ZFS_OPTION_JSON_NUMS_AS_INT = 1024
};
/*
* Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
*/
@ -272,6 +276,8 @@ static zfs_command_t command_table[] = {
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
#define MAX_CMD_LEN 256
zfs_command_t *current_command;
static const char *
@ -292,7 +298,7 @@ get_usage(zfs_help_t idx)
"<filesystem|volume>@<snap>[%<snap>][,...]\n"
"\tdestroy <filesystem|volume>#<bookmark>\n"));
case HELP_GET:
return (gettext("\tget [-rHp] [-d max] "
return (gettext("\tget [-rHp] [-j [--json-int]] [-d max] "
"[-o \"all\" | field[,...]]\n"
"\t [-t type[,...]] [-s source[,...]]\n"
"\t <\"all\" | property[,...]> "
@ -304,11 +310,12 @@ get_usage(zfs_help_t idx)
return (gettext("\tupgrade [-v]\n"
"\tupgrade [-r] [-V version] <-a | filesystem ...>\n"));
case HELP_LIST:
return (gettext("\tlist [-Hp] [-r|-d max] [-o property[,...]] "
"[-s property]...\n\t [-S property]... [-t type[,...]] "
return (gettext("\tlist [-Hp] [-j [--json-int]] [-r|-d max] "
"[-o property[,...]] [-s property]...\n\t "
"[-S property]... [-t type[,...]] "
"[filesystem|volume|snapshot] ...\n"));
case HELP_MOUNT:
return (gettext("\tmount\n"
return (gettext("\tmount [-j]\n"
"\tmount [-flvO] [-o opts] <-a|-R filesystem|"
"filesystem>\n"));
case HELP_PROMOTE:
@ -420,7 +427,7 @@ get_usage(zfs_help_t idx)
"\t <filesystem|volume>\n"
"\tchange-key -i [-l] <filesystem|volume>\n"));
case HELP_VERSION:
return (gettext("\tversion\n"));
return (gettext("\tversion [-j]\n"));
case HELP_REDACT:
return (gettext("\tredact <snapshot> <bookmark> "
"<redaction_snapshot> ...\n"));
@ -1885,7 +1892,89 @@ is_recvd_column(zprop_get_cbdata_t *cbp)
}
/*
* zfs get [-rHp] [-o all | field[,field]...] [-s source[,source]...]
* Generates an nvlist with output version for every command based on params.
* Purpose of this is to add a version of JSON output, considering the schema
* format might be updated for each command in future.
*
* Schema:
*
* "output_version": {
* "command": string,
* "vers_major": integer,
* "vers_minor": integer,
* }
*/
static nvlist_t *
zfs_json_schema(int maj_v, int min_v)
{
nvlist_t *sch = NULL;
nvlist_t *ov = NULL;
char cmd[MAX_CMD_LEN];
snprintf(cmd, MAX_CMD_LEN, "zfs %s", current_command->name);
sch = fnvlist_alloc();
ov = fnvlist_alloc();
fnvlist_add_string(ov, "command", cmd);
fnvlist_add_uint32(ov, "vers_major", maj_v);
fnvlist_add_uint32(ov, "vers_minor", min_v);
fnvlist_add_nvlist(sch, "output_version", ov);
fnvlist_free(ov);
return (sch);
}
static void
fill_dataset_info(nvlist_t *list, zfs_handle_t *zhp, boolean_t as_int)
{
char createtxg[ZFS_MAXPROPLEN];
zfs_type_t type = zfs_get_type(zhp);
nvlist_add_string(list, "name", zfs_get_name(zhp));
switch (type) {
case ZFS_TYPE_FILESYSTEM:
fnvlist_add_string(list, "type", "FILESYSTEM");
break;
case ZFS_TYPE_VOLUME:
fnvlist_add_string(list, "type", "VOLUME");
break;
case ZFS_TYPE_SNAPSHOT:
fnvlist_add_string(list, "type", "SNAPSHOT");
break;
case ZFS_TYPE_POOL:
fnvlist_add_string(list, "type", "POOL");
break;
case ZFS_TYPE_BOOKMARK:
fnvlist_add_string(list, "type", "BOOKMARK");
break;
default:
fnvlist_add_string(list, "type", "UNKNOWN");
break;
}
if (type != ZFS_TYPE_POOL)
fnvlist_add_string(list, "pool", zfs_get_pool_name(zhp));
if (as_int) {
fnvlist_add_uint64(list, "createtxg", zfs_prop_get_int(zhp,
ZFS_PROP_CREATETXG));
} else {
if (zfs_prop_get(zhp, ZFS_PROP_CREATETXG, createtxg,
sizeof (createtxg), NULL, NULL, 0, B_TRUE) == 0)
fnvlist_add_string(list, "createtxg", createtxg);
}
if (type == ZFS_TYPE_SNAPSHOT) {
char *ds, *snap, *tofree;
ds = snap = tofree = strdup(zfs_get_name(zhp));
ds = strsep(&snap, "@");
fnvlist_add_string(list, "dataset", ds);
fnvlist_add_string(list, "snapshot_name", snap);
free(tofree);
}
}
/*
* zfs get [-rHp] [-j [--json-int]] [-o all | field[,field]...]
* [-s source[,source]...]
* < all | property[,property]... > < fs | snap | vol > ...
*
* -r recurse over any child datasets
@ -1898,6 +1987,8 @@ is_recvd_column(zprop_get_cbdata_t *cbp)
* "local,default,inherited,received,temporary,none". Default is
* all six.
* -p Display values in parsable (literal) format.
* -j Display output in JSON format.
* --json-int Display numbers as integers instead of strings.
*
* Prints properties for the given datasets. The user can control which
* columns to display as well as which property types to allow.
@ -1917,9 +2008,21 @@ get_callback(zfs_handle_t *zhp, void *data)
nvlist_t *user_props = zfs_get_user_props(zhp);
zprop_list_t *pl = cbp->cb_proplist;
nvlist_t *propval;
nvlist_t *item, *d, *props;
item = d = props = NULL;
const char *strval;
const char *sourceval;
boolean_t received = is_recvd_column(cbp);
int err = 0;
if (cbp->cb_json) {
d = fnvlist_lookup_nvlist(cbp->cb_jsobj, "datasets");
if (d == NULL) {
fprintf(stderr, "datasets obj not found.\n");
exit(1);
}
props = fnvlist_alloc();
}
for (; pl != NULL; pl = pl->pl_next) {
char *recvdval = NULL;
@ -1954,9 +2057,9 @@ get_callback(zfs_handle_t *zhp, void *data)
cbp->cb_literal) == 0))
recvdval = rbuf;
zprop_print_one_property(zfs_get_name(zhp), cbp,
err = zprop_collect_property(zfs_get_name(zhp), cbp,
zfs_prop_to_name(pl->pl_prop),
buf, sourcetype, source, recvdval);
buf, sourcetype, source, recvdval, props);
} else if (zfs_prop_userquota(pl->pl_user_prop)) {
sourcetype = ZPROP_SRC_LOCAL;
@ -1966,8 +2069,9 @@ get_callback(zfs_handle_t *zhp, void *data)
(void) strlcpy(buf, "-", sizeof (buf));
}
zprop_print_one_property(zfs_get_name(zhp), cbp,
pl->pl_user_prop, buf, sourcetype, source, NULL);
err = zprop_collect_property(zfs_get_name(zhp), cbp,
pl->pl_user_prop, buf, sourcetype, source, NULL,
props);
} else if (zfs_prop_written(pl->pl_user_prop)) {
sourcetype = ZPROP_SRC_LOCAL;
@ -1977,8 +2081,9 @@ get_callback(zfs_handle_t *zhp, void *data)
(void) strlcpy(buf, "-", sizeof (buf));
}
zprop_print_one_property(zfs_get_name(zhp), cbp,
pl->pl_user_prop, buf, sourcetype, source, NULL);
err = zprop_collect_property(zfs_get_name(zhp), cbp,
pl->pl_user_prop, buf, sourcetype, source, NULL,
props);
} else {
if (nvlist_lookup_nvlist(user_props,
pl->pl_user_prop, &propval) != 0) {
@ -2010,9 +2115,24 @@ get_callback(zfs_handle_t *zhp, void *data)
cbp->cb_literal) == 0))
recvdval = rbuf;
zprop_print_one_property(zfs_get_name(zhp), cbp,
err = zprop_collect_property(zfs_get_name(zhp), cbp,
pl->pl_user_prop, strval, sourcetype,
source, recvdval);
source, recvdval, props);
}
if (err != 0)
return (err);
}
if (cbp->cb_json) {
if (!nvlist_empty(props)) {
item = fnvlist_alloc();
fill_dataset_info(item, zhp, cbp->cb_json_as_int);
fnvlist_add_nvlist(item, "properties", props);
fnvlist_add_nvlist(d, zfs_get_name(zhp), item);
fnvlist_free(props);
fnvlist_free(item);
} else {
fnvlist_free(props);
}
}
@ -2029,6 +2149,7 @@ zfs_do_get(int argc, char **argv)
int ret = 0;
int limit = 0;
zprop_list_t fake_name = { 0 };
nvlist_t *data;
/*
* Set up default columns and sources.
@ -2040,8 +2161,14 @@ zfs_do_get(int argc, char **argv)
cb.cb_columns[3] = GET_COL_SOURCE;
cb.cb_type = ZFS_TYPE_DATASET;
struct option long_options[] = {
{"json-int", no_argument, NULL, ZFS_OPTION_JSON_NUMS_AS_INT},
{0, 0, 0, 0}
};
/* check options */
while ((c = getopt(argc, argv, ":d:o:s:rt:Hp")) != -1) {
while ((c = getopt_long(argc, argv, ":d:o:s:jrt:Hp", long_options,
NULL)) != -1) {
switch (c) {
case 'p':
cb.cb_literal = B_TRUE;
@ -2055,6 +2182,17 @@ zfs_do_get(int argc, char **argv)
case 'H':
cb.cb_scripted = B_TRUE;
break;
case 'j':
cb.cb_json = B_TRUE;
cb.cb_jsobj = zfs_json_schema(0, 1);
data = fnvlist_alloc();
fnvlist_add_nvlist(cb.cb_jsobj, "datasets", data);
fnvlist_free(data);
break;
case ZFS_OPTION_JSON_NUMS_AS_INT:
cb.cb_json_as_int = B_TRUE;
cb.cb_literal = B_TRUE;
break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
@ -2178,7 +2316,6 @@ found2:;
found3:;
}
break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
@ -2195,6 +2332,12 @@ found3:;
usage(B_FALSE);
}
if (!cb.cb_json && cb.cb_json_as_int) {
(void) fprintf(stderr, gettext("'--json-int' only works with"
" '-j' option\n"));
usage(B_FALSE);
}
fields = argv[0];
/*
@ -2235,6 +2378,9 @@ found3:;
ret = zfs_for_each(argc, argv, flags, types, NULL,
&cb.cb_proplist, limit, get_callback, &cb);
if (cb.cb_json)
zcmd_print_json(cb.cb_jsobj);
if (cb.cb_proplist == &fake_name)
zprop_free_list(fake_name.pl_next);
else
@ -3442,6 +3588,9 @@ typedef struct list_cbdata {
boolean_t cb_literal;
boolean_t cb_scripted;
zprop_list_t *cb_proplist;
boolean_t cb_json;
nvlist_t *cb_jsobj;
boolean_t cb_json_as_int;
} list_cbdata_t;
/*
@ -3512,10 +3661,11 @@ zfs_list_avail_color(zfs_handle_t *zhp)
/*
* Given a dataset and a list of fields, print out all the properties according
* to the described layout.
* to the described layout, or return an nvlist containing all the fields, later
* to be printed out as JSON object.
*/
static void
print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
collect_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
{
zprop_list_t *pl = cb->cb_proplist;
boolean_t first = B_TRUE;
@ -3524,9 +3674,23 @@ print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
nvlist_t *propval;
const char *propstr;
boolean_t right_justify;
nvlist_t *item, *d, *props;
item = d = props = NULL;
zprop_source_t sourcetype;
char source[ZFS_MAX_DATASET_NAME_LEN];
if (cb->cb_json) {
d = fnvlist_lookup_nvlist(cb->cb_jsobj, "datasets");
if (d == NULL) {
fprintf(stderr, "datasets obj not found.\n");
exit(1);
}
item = fnvlist_alloc();
props = fnvlist_alloc();
fill_dataset_info(item, zhp, cb->cb_json_as_int);
}
for (; pl != NULL; pl = pl->pl_next) {
if (!first) {
if (!cb->cb_json && !first) {
if (cb->cb_scripted)
(void) putchar('\t');
else
@ -3542,69 +3706,113 @@ print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
right_justify = zfs_prop_align_right(pl->pl_prop);
} else if (pl->pl_prop != ZPROP_USERPROP) {
if (zfs_prop_get(zhp, pl->pl_prop, property,
sizeof (property), NULL, NULL, 0,
cb->cb_literal) != 0)
sizeof (property), &sourcetype, source,
sizeof (source), cb->cb_literal) != 0)
propstr = "-";
else
propstr = property;
right_justify = zfs_prop_align_right(pl->pl_prop);
} else if (zfs_prop_userquota(pl->pl_user_prop)) {
sourcetype = ZPROP_SRC_LOCAL;
if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
property, sizeof (property), cb->cb_literal) != 0)
property, sizeof (property), cb->cb_literal) != 0) {
sourcetype = ZPROP_SRC_NONE;
propstr = "-";
else
} else {
propstr = property;
}
right_justify = B_TRUE;
} else if (zfs_prop_written(pl->pl_user_prop)) {
sourcetype = ZPROP_SRC_LOCAL;
if (zfs_prop_get_written(zhp, pl->pl_user_prop,
property, sizeof (property), cb->cb_literal) != 0)
property, sizeof (property), cb->cb_literal) != 0) {
sourcetype = ZPROP_SRC_NONE;
propstr = "-";
else
} else {
propstr = property;
}
right_justify = B_TRUE;
} else {
if (nvlist_lookup_nvlist(userprops,
pl->pl_user_prop, &propval) != 0)
pl->pl_user_prop, &propval) != 0) {
propstr = "-";
else
sourcetype = ZPROP_SRC_NONE;
} else {
propstr = fnvlist_lookup_string(propval,
ZPROP_VALUE);
strlcpy(source,
fnvlist_lookup_string(propval,
ZPROP_SOURCE), ZFS_MAX_DATASET_NAME_LEN);
if (strcmp(source,
zfs_get_name(zhp)) == 0) {
sourcetype = ZPROP_SRC_LOCAL;
} else if (strcmp(source,
ZPROP_SOURCE_VAL_RECVD) == 0) {
sourcetype = ZPROP_SRC_RECEIVED;
} else {
sourcetype = ZPROP_SRC_INHERITED;
}
}
right_justify = B_FALSE;
}
/*
* zfs_list_avail_color() needs ZFS_PROP_AVAILABLE + USED
* - so we need another for() search for the USED part
* - when no colors wanted, we can skip the whole thing
*/
if (use_color() && pl->pl_prop == ZFS_PROP_AVAILABLE) {
zprop_list_t *pl2 = cb->cb_proplist;
for (; pl2 != NULL; pl2 = pl2->pl_next) {
if (pl2->pl_prop == ZFS_PROP_USED) {
color_start(zfs_list_avail_color(zhp));
/* found it, no need for more loops */
break;
if (cb->cb_json) {
if (pl->pl_prop == ZFS_PROP_NAME)
continue;
if (zprop_nvlist_one_property(
zfs_prop_to_name(pl->pl_prop), propstr,
sourcetype, source, NULL, props,
cb->cb_json_as_int) != 0)
nomem();
} else {
/*
* zfs_list_avail_color() needs
* ZFS_PROP_AVAILABLE + USED, so we need another
* for() search for the USED part when no colors
* wanted, we can skip the whole thing
*/
if (use_color() && pl->pl_prop == ZFS_PROP_AVAILABLE) {
zprop_list_t *pl2 = cb->cb_proplist;
for (; pl2 != NULL; pl2 = pl2->pl_next) {
if (pl2->pl_prop == ZFS_PROP_USED) {
color_start(
zfs_list_avail_color(zhp));
/*
* found it, no need for more
* loops
*/
break;
}
}
}
/*
* 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)pl->pl_width,
propstr);
} else {
(void) printf("%-*s", (int)pl->pl_width,
propstr);
}
if (pl->pl_prop == ZFS_PROP_AVAILABLE)
color_end();
}
/*
* 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)pl->pl_width, propstr);
else
(void) printf("%-*s", (int)pl->pl_width, propstr);
if (pl->pl_prop == ZFS_PROP_AVAILABLE)
color_end();
}
(void) putchar('\n');
if (cb->cb_json) {
fnvlist_add_nvlist(item, "properties", props);
fnvlist_add_nvlist(d, zfs_get_name(zhp), item);
fnvlist_free(props);
fnvlist_free(item);
} else
(void) putchar('\n');
}
/*
@ -3616,12 +3824,12 @@ list_callback(zfs_handle_t *zhp, void *data)
list_cbdata_t *cbp = data;
if (cbp->cb_first) {
if (!cbp->cb_scripted)
if (!cbp->cb_scripted && !cbp->cb_json)
print_header(cbp);
cbp->cb_first = B_FALSE;
}
print_dataset(zhp, cbp);
collect_dataset(zhp, cbp);
return (0);
}
@ -3640,9 +3848,16 @@ zfs_do_list(int argc, char **argv)
int ret = 0;
zfs_sort_column_t *sortcol = NULL;
int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS;
nvlist_t *data = NULL;
struct option long_options[] = {
{"json-int", no_argument, NULL, ZFS_OPTION_JSON_NUMS_AS_INT},
{0, 0, 0, 0}
};
/* check options */
while ((c = getopt(argc, argv, "HS:d:o:prs:t:")) != -1) {
while ((c = getopt_long(argc, argv, "jHS:d:o:prs:t:", long_options,
NULL)) != -1) {
switch (c) {
case 'o':
fields = optarg;
@ -3657,6 +3872,17 @@ zfs_do_list(int argc, char **argv)
case 'r':
flags |= ZFS_ITER_RECURSE;
break;
case 'j':
cb.cb_json = B_TRUE;
cb.cb_jsobj = zfs_json_schema(0, 1);
data = fnvlist_alloc();
fnvlist_add_nvlist(cb.cb_jsobj, "datasets", data);
fnvlist_free(data);
break;
case ZFS_OPTION_JSON_NUMS_AS_INT:
cb.cb_json_as_int = B_TRUE;
cb.cb_literal = B_TRUE;
break;
case 'H':
cb.cb_scripted = B_TRUE;
break;
@ -3730,6 +3956,12 @@ found3:;
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 "-o space" and no types were specified, don't display snapshots.
*/
@ -3769,6 +4001,9 @@ found3:;
ret = zfs_for_each(argc, argv, flags, types, sortcol, &cb.cb_proplist,
limit, list_callback, &cb);
if (cb.cb_json)
zcmd_print_json(cb.cb_jsobj);
zprop_free_list(cb.cb_proplist);
zfs_free_sort_columns(sortcol);
@ -7189,14 +7424,17 @@ share_mount(int op, int argc, char **argv)
int do_all = 0;
int recursive = 0;
boolean_t verbose = B_FALSE;
boolean_t json = B_FALSE;
int c, ret = 0;
char *options = NULL;
int flags = 0;
nvlist_t *jsobj, *data, *item;
const uint_t mount_nthr = 512;
uint_t nthr;
jsobj = data = item = NULL;
/* check options */
while ((c = getopt(argc, argv, op == OP_MOUNT ? ":aRlvo:Of" : "al"))
while ((c = getopt(argc, argv, op == OP_MOUNT ? ":ajRlvo:Of" : "al"))
!= -1) {
switch (c) {
case 'a':
@ -7211,6 +7449,11 @@ share_mount(int op, int argc, char **argv)
case 'l':
flags |= MS_CRYPT;
break;
case 'j':
json = B_TRUE;
jsobj = zfs_json_schema(0, 1);
data = fnvlist_alloc();
break;
case 'o':
if (*optarg == '\0') {
(void) fprintf(stderr, gettext("empty mount "
@ -7245,6 +7488,11 @@ share_mount(int op, int argc, char **argv)
argc -= optind;
argv += optind;
if (json && argc != 0) {
(void) fprintf(stderr, gettext("too many arguments\n"));
usage(B_FALSE);
}
/* check number of arguments */
if (do_all || recursive) {
enum sa_protocol protocol = SA_NO_PROTOCOL;
@ -7348,12 +7596,27 @@ share_mount(int op, int argc, char **argv)
if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 ||
strchr(entry.mnt_special, '@') != NULL)
continue;
(void) printf("%-30s %s\n", entry.mnt_special,
entry.mnt_mountp);
if (json) {
item = fnvlist_alloc();
fnvlist_add_string(item, "filesystem",
entry.mnt_special);
fnvlist_add_string(item, "mountpoint",
entry.mnt_mountp);
fnvlist_add_nvlist(data, entry.mnt_special,
item);
fnvlist_free(item);
} else {
(void) printf("%-30s %s\n", entry.mnt_special,
entry.mnt_mountp);
}
}
(void) fclose(mnttab);
if (json) {
fnvlist_add_nvlist(jsobj, "datasets", data);
zcmd_print_json(jsobj);
fnvlist_free(data);
}
} else {
zfs_handle_t *zhp;
@ -8811,8 +9074,39 @@ found:;
static int
zfs_do_version(int argc, char **argv)
{
(void) argc, (void) argv;
return (zfs_version_print() != 0);
int c;
nvlist_t *jsobj = NULL, *zfs_ver = NULL;
boolean_t json = B_FALSE;
while ((c = getopt(argc, argv, "j")) != -1) {
switch (c) {
case 'j':
json = B_TRUE;
jsobj = zfs_json_schema(0, 1);
break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
usage(B_FALSE);
}
}
argc -= optind;
if (argc != 0) {
(void) fprintf(stderr, "too many arguments\n");
usage(B_FALSE);
}
if (json) {
zfs_ver = zfs_version_nvlist();
if (zfs_ver) {
fnvlist_add_nvlist(jsobj, "zfs_version", zfs_ver);
zcmd_print_json(jsobj);
fnvlist_free(zfs_ver);
return (0);
} else
return (-1);
} else
return (zfs_version_print() != 0);
}
/* Display documentation */

File diff suppressed because it is too large Load Diff

View File

@ -327,6 +327,8 @@ _LIBZFS_H int zpool_vdev_clear(zpool_handle_t *, uint64_t);
_LIBZFS_H nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *,
boolean_t *, boolean_t *);
_LIBZFS_H nvlist_t *zpool_find_parent_vdev(zpool_handle_t *, const char *,
boolean_t *, boolean_t *, boolean_t *);
_LIBZFS_H nvlist_t *zpool_find_vdev_by_physpath(zpool_handle_t *, const char *,
boolean_t *, boolean_t *, boolean_t *);
_LIBZFS_H int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *,
@ -468,7 +470,8 @@ _LIBZFS_H int zpool_import(libzfs_handle_t *, nvlist_t *, const char *,
char *altroot);
_LIBZFS_H int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *,
nvlist_t *, int);
_LIBZFS_H void zpool_print_unsup_feat(nvlist_t *config);
_LIBZFS_H void zpool_collect_unsup_feat(nvlist_t *config, char *buf,
size_t size);
/*
* Miscellaneous pool functions
@ -499,7 +502,7 @@ _LIBZFS_H void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
size_t);
_LIBZFS_H int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *);
_LIBZFS_H void zpool_explain_recover(libzfs_handle_t *, const char *, int,
nvlist_t *);
nvlist_t *, char *, size_t);
_LIBZFS_H int zpool_checkpoint(zpool_handle_t *);
_LIBZFS_H int zpool_discard_checkpoint(zpool_handle_t *);
_LIBZFS_H boolean_t zpool_is_draid_spare(const char *);
@ -628,6 +631,8 @@ _LIBZFS_H int zprop_get_list(libzfs_handle_t *, char *, zprop_list_t **,
zfs_type_t);
_LIBZFS_H void zprop_free_list(zprop_list_t *);
_LIBZFS_H void zcmd_print_json(nvlist_t *);
#define ZFS_GET_NCOLS 5
typedef enum {
@ -655,9 +660,13 @@ typedef struct zprop_get_cbdata {
boolean_t cb_scripted;
boolean_t cb_literal;
boolean_t cb_first;
boolean_t cb_json;
zprop_list_t *cb_proplist;
zfs_type_t cb_type;
vdev_cbdata_t cb_vdevs;
nvlist_t *cb_jsobj;
boolean_t cb_json_as_int;
boolean_t cb_json_pool_key_guid;
} zprop_get_cbdata_t;
#define ZFS_SET_NOMOUNT 1
@ -671,6 +680,13 @@ _LIBZFS_H void zprop_print_one_property(const char *, zprop_get_cbdata_t *,
const char *, const char *, zprop_source_t, const char *,
const char *);
_LIBZFS_H int zprop_nvlist_one_property(const char *, const char *,
zprop_source_t, const char *, const char *, nvlist_t *, boolean_t);
_LIBZFS_H int zprop_collect_property(const char *, zprop_get_cbdata_t *,
const char *, const char *, zprop_source_t, const char *,
const char *, nvlist_t *);
/*
* Iterator functions.
*/
@ -976,6 +992,7 @@ _LIBZFS_H boolean_t libzfs_envvar_is_set(const char *);
_LIBZFS_H const char *zfs_version_userland(void);
_LIBZFS_H char *zfs_version_kernel(void);
_LIBZFS_H int zfs_version_print(void);
_LIBZFS_H nvlist_t *zfs_version_nvlist(void);
/*
* Given a device or file, determine if it is part of a pool.

View File

@ -37,5 +37,9 @@
/* 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);
/* convert time_t to standard format */
void format_timestamp(time_t, char *, int);
#endif /* _STATCOMMON_H */

View File

@ -62,3 +62,45 @@ 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));
}
}
/*
* Format the provided time stamp to human readable format
*/
void
format_timestamp(time_t t, char *buf, int len)
{
struct tm tm;
static const char *fmt = NULL;
if (t == 0) {
snprintf(buf, len, "-");
return;
}
/* We only need to retrieve this once per invocation */
if (fmt == NULL)
fmt = nl_langinfo(_DATE_FMT);
strftime(buf, len, fmt, localtime_r(&t, &tm));
}

View File

@ -143,7 +143,9 @@
<elf-symbol name='avl_update_gt' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='avl_update_lt' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='avl_walk' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='format_timestamp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='get_system_hostid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='get_timestamp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getexecname' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getextmntent' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getmntany' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -1151,6 +1153,18 @@
<parameter type-id='3502e3ff' name='timestamp_fmt'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='get_timestamp' mangled-name='get_timestamp' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='get_timestamp'>
<parameter type-id='3502e3ff' name='timestamp_fmt'/>
<parameter type-id='26a90f95' name='buf'/>
<parameter type-id='95e97e5e' name='len'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='format_timestamp' mangled-name='format_timestamp' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='format_timestamp'>
<parameter type-id='c9d12d66' name='t'/>
<parameter type-id='26a90f95' name='buf'/>
<parameter type-id='95e97e5e' name='len'/>
<return type-id='48b5725f'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libuutil/uu_alloc.c' language='LANG_C99'>
<type-decl name='char' size-in-bits='8' id='a84c031d'/>

View File

@ -179,10 +179,12 @@
<elf-symbol name='fletcher_4_native' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='fletcher_4_native_varsize' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='fletcher_init' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='format_timestamp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='fsleep' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='get_dataset_depth' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='get_system_hostid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getexecname' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='get_timestamp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getextmntent' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getmntany' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getprop_uint64' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -280,6 +282,7 @@
<elf-symbol name='vdev_prop_to_name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='vdev_prop_user' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='vdev_prop_values' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zcmd_print_json' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfeature_depends_on' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfeature_is_supported' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfeature_is_valid_guid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -452,6 +455,7 @@
<elf-symbol name='zfs_userspace' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_valid_proplist' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_version_kernel' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_version_nvlist' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_version_print' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_version_userland' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zfs_wait_status' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -522,7 +526,7 @@
<elf-symbol name='zpool_pool_state_to_name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_prepare_and_label_disk' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_prepare_disk' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_print_unsup_feat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_collect_unsup_feat' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_prop_align_right' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_prop_column_name' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_prop_default_numeric' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -575,12 +579,14 @@
<elf-symbol name='zpool_vdev_split' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_wait' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zpool_wait_status' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zprop_collect_property' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zprop_free_list' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zprop_get_list' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zprop_index_to_string' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zprop_iter' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zprop_iter_common' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zprop_name_to_prop' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zprop_nvlist_one_property' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zprop_print_one_property' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zprop_random_value' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='zprop_register_hidden' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -1282,6 +1288,18 @@
<parameter type-id='3502e3ff' name='timestamp_fmt'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='get_timestamp' mangled-name='get_timestamp' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='get_timestamp'>
<parameter type-id='3502e3ff' name='timestamp_fmt'/>
<parameter type-id='26a90f95' name='buf'/>
<parameter type-id='95e97e5e' name='len'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='format_timestamp' mangled-name='format_timestamp' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='format_timestamp'>
<parameter type-id='c9d12d66' name='t'/>
<parameter type-id='26a90f95' name='buf'/>
<parameter type-id='95e97e5e' name='len'/>
<return type-id='48b5725f'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libtpool/thread_pool.c' language='LANG_C99'>
<array-type-def dimensions='1' type-id='49ef3ffd' size-in-bits='1024' id='a14403f5'>
@ -6413,6 +6431,8 @@
<parameter type-id='80f4b756' name='name'/>
<parameter type-id='95e97e5e' name='reason'/>
<parameter type-id='5ce45b60' name='config'/>
<parameter type-id='26a90f95' name='buf'/>
<parameter type-id='b59d7dce' name='size'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='zpool_import' mangled-name='zpool_import' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_import'>
@ -6422,8 +6442,10 @@
<parameter type-id='26a90f95' name='altroot'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='zpool_print_unsup_feat' mangled-name='zpool_print_unsup_feat' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_print_unsup_feat'>
<function-decl name='zpool_collect_unsup_feat' mangled-name='zpool_collect_unsup_feat' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_collect_unsup_feat'>
<parameter type-id='5ce45b60' name='config'/>
<parameter type-id='26a90f95' name='buf'/>
<parameter type-id='b59d7dce' name='size'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='zpool_import_props' mangled-name='zpool_import_props' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_import_props'>
@ -8146,6 +8168,20 @@
<parameter type-id='2e45de5d' name='argtype'/>
<return type-id='9200a744'/>
</function-decl>
<function-decl name='zcmd_print_json' mangled-name='zcmd_print_json' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zcmd_print_json'>
<parameter type-id='5ce45b60' name='nvl'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='zprop_nvlist_one_property' mangled-name='zprop_nvlist_one_property' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zprop_nvlist_one_property'>
<parameter type-id='80f4b756' name='propname'/>
<parameter type-id='80f4b756' name='value'/>
<parameter type-id='a2256d42' name='sourcetype'/>
<parameter type-id='80f4b756' name='source'/>
<parameter type-id='80f4b756' name='recvd_value'/>
<parameter type-id='5ce45b60' name='nvl'/>
<parameter type-id='c19b74c3' name='as_int'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='zprop_print_one_property' mangled-name='zprop_print_one_property' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zprop_print_one_property'>
<parameter type-id='80f4b756' name='name'/>
<parameter type-id='0d2a0670' name='cbp'/>
@ -8156,6 +8192,17 @@
<parameter type-id='80f4b756' name='recvd_value'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='zprop_collect_property' mangled-name='zprop_collect_property' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zprop_collect_property'>
<parameter type-id='80f4b756' name='name'/>
<parameter type-id='0d2a0670' name='cbp'/>
<parameter type-id='80f4b756' name='propname'/>
<parameter type-id='80f4b756' name='value'/>
<parameter type-id='a2256d42' name='sourcetype'/>
<parameter type-id='80f4b756' name='source'/>
<parameter type-id='80f4b756' name='recvd_value'/>
<parameter type-id='5ce45b60' name='nvl'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='zprop_get_list' mangled-name='zprop_get_list' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zprop_get_list'>
<parameter type-id='b0382bb3' name='hdl'/>
<parameter type-id='26a90f95' name='props'/>
@ -8184,6 +8231,9 @@
<function-decl name='use_color' mangled-name='use_color' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='use_color'>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='zfs_version_nvlist' mangled-name='zfs_version_nvlist' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zfs_version_nvlist'>
<return type-id='5ce45b60'/>
</function-decl>
<function-decl name='printf_color' mangled-name='printf_color' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='printf_color'>
<parameter type-id='80f4b756' name='color'/>
<parameter type-id='80f4b756' name='format'/>

View File

@ -1932,23 +1932,18 @@ zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun,
void
zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason,
nvlist_t *config)
nvlist_t *config, char *buf, size_t size)
{
nvlist_t *nv = NULL;
int64_t loss = -1;
uint64_t edata = UINT64_MAX;
uint64_t rewindto;
struct tm t;
char timestr[128];
char timestr[128], temp[1024];
if (!hdl->libzfs_printerr)
return;
if (reason >= 0)
(void) printf(dgettext(TEXT_DOMAIN, "action: "));
else
(void) printf(dgettext(TEXT_DOMAIN, "\t"));
/* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0 ||
@ -1959,56 +1954,61 @@ zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason,
(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_DATA_ERRORS,
&edata);
(void) printf(dgettext(TEXT_DOMAIN,
(void) snprintf(buf, size, dgettext(TEXT_DOMAIN,
"Recovery is possible, but will result in some data loss.\n"));
if (localtime_r((time_t *)&rewindto, &t) != NULL &&
ctime_r((time_t *)&rewindto, timestr) != NULL) {
timestr[24] = 0;
(void) printf(dgettext(TEXT_DOMAIN,
(void) snprintf(temp, 1024, dgettext(TEXT_DOMAIN,
"\tReturning the pool to its state as of %s\n"
"\tshould correct the problem. "),
timestr);
"\tshould correct the problem. "), timestr);
(void) strlcat(buf, temp, size);
} else {
(void) printf(dgettext(TEXT_DOMAIN,
(void) strlcat(buf, dgettext(TEXT_DOMAIN,
"\tReverting the pool to an earlier state "
"should correct the problem.\n\t"));
"should correct the problem.\n\t"), size);
}
if (loss > 120) {
(void) printf(dgettext(TEXT_DOMAIN,
(void) snprintf(temp, 1024, dgettext(TEXT_DOMAIN,
"Approximately %lld minutes of data\n"
"\tmust be discarded, irreversibly. "),
((longlong_t)loss + 30) / 60);
(void) strlcat(buf, temp, size);
} else if (loss > 0) {
(void) printf(dgettext(TEXT_DOMAIN,
(void) snprintf(temp, 1024, dgettext(TEXT_DOMAIN,
"Approximately %lld seconds of data\n"
"\tmust be discarded, irreversibly. "),
(longlong_t)loss);
(void) strlcat(buf, temp, size);
}
if (edata != 0 && edata != UINT64_MAX) {
if (edata == 1) {
(void) printf(dgettext(TEXT_DOMAIN,
(void) strlcat(buf, dgettext(TEXT_DOMAIN,
"After rewind, at least\n"
"\tone persistent user-data error will remain. "));
"\tone persistent user-data error will remain. "),
size);
} else {
(void) printf(dgettext(TEXT_DOMAIN,
(void) strlcat(buf, dgettext(TEXT_DOMAIN,
"After rewind, several\n"
"\tpersistent user-data errors will remain. "));
"\tpersistent user-data errors will remain. "),
size);
}
}
(void) printf(dgettext(TEXT_DOMAIN,
(void) snprintf(temp, 1024, dgettext(TEXT_DOMAIN,
"Recovery can be attempted\n\tby executing 'zpool %s -F %s'. "),
reason >= 0 ? "clear" : "import", name);
(void) strlcat(buf, temp, size);
(void) printf(dgettext(TEXT_DOMAIN,
(void) strlcat(buf, dgettext(TEXT_DOMAIN,
"A scrub of the pool\n"
"\tis strongly recommended after recovery.\n"));
"\tis strongly recommended after recovery.\n"), size);
return;
no_info:
(void) printf(dgettext(TEXT_DOMAIN,
"Destroy and re-create the pool from\n\ta backup source.\n"));
(void) strlcat(buf, dgettext(TEXT_DOMAIN,
"Destroy and re-create the pool from\n\ta backup source.\n"), size);
}
/*
@ -2077,9 +2077,10 @@ print_vdev_tree(libzfs_handle_t *hdl, const char *name, nvlist_t *nv,
}
void
zpool_print_unsup_feat(nvlist_t *config)
zpool_collect_unsup_feat(nvlist_t *config, char *buf, size_t size)
{
nvlist_t *nvinfo, *unsup_feat;
char temp[512];
nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
unsup_feat = fnvlist_lookup_nvlist(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT);
@ -2087,10 +2088,14 @@ zpool_print_unsup_feat(nvlist_t *config)
for (nvpair_t *nvp = nvlist_next_nvpair(unsup_feat, NULL);
nvp != NULL; nvp = nvlist_next_nvpair(unsup_feat, nvp)) {
const char *desc = fnvpair_value_string(nvp);
if (strlen(desc) > 0)
(void) printf("\t%s (%s)\n", nvpair_name(nvp), desc);
else
(void) printf("\t%s\n", nvpair_name(nvp));
if (strlen(desc) > 0) {
(void) snprintf(temp, 512, "\t%s (%s)\n",
nvpair_name(nvp), desc);
(void) strlcat(buf, temp, size);
} else {
(void) snprintf(temp, 512, "\t%s\n", nvpair_name(nvp));
(void) strlcat(buf, temp, size);
}
}
}
@ -2113,6 +2118,7 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
const char *origname;
int ret;
int error = 0;
char buf[2048];
char errbuf[ERRBUFLEN];
origname = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME);
@ -2195,7 +2201,9 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
(void) printf(dgettext(TEXT_DOMAIN, "This "
"pool uses the following feature(s) not "
"supported by this system:\n"));
zpool_print_unsup_feat(nv);
memset(buf, 0, 2048);
zpool_collect_unsup_feat(nv, buf, 2048);
(void) printf("%s", buf);
if (nvlist_exists(nvinfo,
ZPOOL_CONFIG_CAN_RDONLY)) {
(void) printf(dgettext(TEXT_DOMAIN,
@ -2294,8 +2302,11 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
break;
default:
(void) zpool_standard_error(hdl, error, desc);
memset(buf, 0, 2048);
zpool_explain_recover(hdl,
newname ? origname : thename, -error, nv);
newname ? origname : thename, -error, nv,
buf, 2048);
(void) printf("\t%s", buf);
break;
}
@ -2794,10 +2805,13 @@ zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func, pool_scrub_cmd_t cmd)
* the nvpair name to determine how we should look for the device.
* 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL
* spare; but FALSE if its an INUSE spare.
*
* If 'return_parent' is set, then return the *parent* of the vdev you're
* searching for rather than the vdev itself.
*/
static nvlist_t *
vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
boolean_t *l2cache, boolean_t *log)
boolean_t *l2cache, boolean_t *log, boolean_t return_parent)
{
uint_t c, children;
nvlist_t **child;
@ -2805,6 +2819,8 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
uint64_t is_log;
const char *srchkey;
nvpair_t *pair = nvlist_next_nvpair(search, NULL);
const char *tmp = NULL;
boolean_t is_root;
/* Nothing to look for */
if (search == NULL || pair == NULL)
@ -2813,6 +2829,12 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
/* Obtain the key we will use to search */
srchkey = nvpair_name(pair);
nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &tmp);
if (strcmp(tmp, "root") == 0)
is_root = B_TRUE;
else
is_root = B_FALSE;
switch (nvpair_type(pair)) {
case DATA_TYPE_UINT64:
if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) {
@ -2943,7 +2965,7 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
for (c = 0; c < children; c++) {
if ((ret = vdev_to_nvlist_iter(child[c], search,
avail_spare, l2cache, NULL)) != NULL) {
avail_spare, l2cache, NULL, return_parent)) != NULL) {
/*
* The 'is_log' value is only set for the toplevel
* vdev, not the leaf vdevs. So we always lookup the
@ -2956,7 +2978,7 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
is_log) {
*log = B_TRUE;
}
return (ret);
return (ret && return_parent && !is_root ? nv : ret);
}
}
@ -2964,9 +2986,11 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
&child, &children) == 0) {
for (c = 0; c < children; c++) {
if ((ret = vdev_to_nvlist_iter(child[c], search,
avail_spare, l2cache, NULL)) != NULL) {
avail_spare, l2cache, NULL, return_parent))
!= NULL) {
*avail_spare = B_TRUE;
return (ret);
return (ret && return_parent &&
!is_root ? nv : ret);
}
}
}
@ -2975,9 +2999,11 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
&child, &children) == 0) {
for (c = 0; c < children; c++) {
if ((ret = vdev_to_nvlist_iter(child[c], search,
avail_spare, l2cache, NULL)) != NULL) {
avail_spare, l2cache, NULL, return_parent))
!= NULL) {
*l2cache = B_TRUE;
return (ret);
return (ret && return_parent &&
!is_root ? nv : ret);
}
}
}
@ -3012,7 +3038,8 @@ zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath,
*l2cache = B_FALSE;
if (log != NULL)
*log = B_FALSE;
ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log,
B_FALSE);
fnvlist_free(search);
return (ret);
@ -3040,11 +3067,12 @@ zpool_vdev_is_interior(const char *name)
}
/*
* Lookup the nvlist for a given vdev.
* Lookup the nvlist for a given vdev or vdev's parent (depending on
* if 'return_parent' is set).
*/
nvlist_t *
zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
boolean_t *l2cache, boolean_t *log)
static nvlist_t *
__zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
boolean_t *l2cache, boolean_t *log, boolean_t return_parent)
{
char *end;
nvlist_t *nvroot, *search, *ret;
@ -3081,12 +3109,30 @@ zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
*l2cache = B_FALSE;
if (log != NULL)
*log = B_FALSE;
ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log,
return_parent);
fnvlist_free(search);
return (ret);
}
nvlist_t *
zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
boolean_t *l2cache, boolean_t *log)
{
return (__zpool_find_vdev(zhp, path, avail_spare, l2cache, log,
B_FALSE));
}
/* Given a vdev path, return its parent's nvlist */
nvlist_t *
zpool_find_parent_vdev(zpool_handle_t *zhp, const char *path,
boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log)
{
return (__zpool_find_vdev(zhp, path, avail_spare, l2cache, log,
B_TRUE));
}
/*
* Convert a vdev path to a GUID. Returns GUID or 0 on error.
*

View File

@ -68,6 +68,7 @@
* as necessary.
*/
#define URI_REGEX "^\\([A-Za-z][A-Za-z0-9+.\\-]*\\):"
#define STR_NUMS "0123456789"
int
libzfs_errno(libzfs_handle_t *hdl)
@ -1267,6 +1268,14 @@ zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp)
* ================================================================
*/
void
zcmd_print_json(nvlist_t *nvl)
{
nvlist_print_json(stdout, nvl);
(void) putchar('\n');
nvlist_free(nvl);
}
static void
zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
{
@ -1393,6 +1402,103 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
(void) printf("\n");
}
/*
* Add property value and source to provided nvlist, according to
* settings in cb structure. Later to be printed in JSON format.
*/
int
zprop_nvlist_one_property(const char *propname,
const char *value, zprop_source_t sourcetype, const char *source,
const char *recvd_value, nvlist_t *nvl, boolean_t as_int)
{
int ret = 0;
nvlist_t *src_nv, *prop;
boolean_t all_numeric = strspn(value, STR_NUMS) == strlen(value);
src_nv = prop = NULL;
if ((nvlist_alloc(&prop, NV_UNIQUE_NAME, 0) != 0) ||
(nvlist_alloc(&src_nv, NV_UNIQUE_NAME, 0) != 0)) {
ret = -1;
goto err;
}
if (as_int && all_numeric) {
uint64_t val;
sscanf(value, "%lld", (u_longlong_t *)&val);
if (nvlist_add_uint64(prop, "value", val) != 0) {
ret = -1;
goto err;
}
} else {
if (nvlist_add_string(prop, "value", value) != 0) {
ret = -1;
goto err;
}
}
switch (sourcetype) {
case ZPROP_SRC_NONE:
if (nvlist_add_string(src_nv, "type", "NONE") != 0 ||
(nvlist_add_string(src_nv, "data", "-") != 0)) {
ret = -1;
goto err;
}
break;
case ZPROP_SRC_DEFAULT:
if (nvlist_add_string(src_nv, "type", "DEFAULT") != 0 ||
(nvlist_add_string(src_nv, "data", "-") != 0)) {
ret = -1;
goto err;
}
break;
case ZPROP_SRC_LOCAL:
if (nvlist_add_string(src_nv, "type", "LOCAL") != 0 ||
(nvlist_add_string(src_nv, "data", "-") != 0)) {
ret = -1;
goto err;
}
break;
case ZPROP_SRC_TEMPORARY:
if (nvlist_add_string(src_nv, "type", "TEMPORARY") != 0 ||
(nvlist_add_string(src_nv, "data", "-") != 0)) {
ret = -1;
goto err;
}
break;
case ZPROP_SRC_INHERITED:
if (nvlist_add_string(src_nv, "type", "INHERITED") != 0 ||
(nvlist_add_string(src_nv, "data", source) != 0)) {
ret = -1;
goto err;
}
break;
case ZPROP_SRC_RECEIVED:
if (nvlist_add_string(src_nv, "type", "RECEIVED") != 0 ||
(nvlist_add_string(src_nv, "data",
(recvd_value == NULL ? "-" : recvd_value)) != 0)) {
ret = -1;
goto err;
}
break;
default:
assert(!"unhandled zprop_source_t");
if (nvlist_add_string(src_nv, "type",
"unhandled zprop_source_t") != 0) {
ret = -1;
goto err;
}
}
if ((nvlist_add_nvlist(prop, "source", src_nv) != 0) ||
(nvlist_add_nvlist(nvl, propname, prop)) != 0) {
ret = -1;
goto err;
}
err:
nvlist_free(src_nv);
nvlist_free(prop);
return (ret);
}
/*
* Display a single line of output, according to the settings in the callback
* structure.
@ -1484,6 +1590,26 @@ zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
(void) printf("\n");
}
int
zprop_collect_property(const char *name, zprop_get_cbdata_t *cbp,
const char *propname, const char *value, zprop_source_t sourcetype,
const char *source, const char *recvd_value, nvlist_t *nvl)
{
if (cbp->cb_json) {
if ((sourcetype & cbp->cb_sources) == 0)
return (0);
else {
return (zprop_nvlist_one_property(propname, value,
sourcetype, source, recvd_value, nvl,
cbp->cb_json_as_int));
}
} else {
zprop_print_one_property(name, cbp,
propname, value, sourcetype, source, recvd_value);
return (0);
}
}
/*
* Given a numeric suffix, convert the value into a number of bits that the
* resulting value must be shifted.
@ -1985,6 +2111,34 @@ zfs_version_print(void)
return (0);
}
/*
* Returns an nvlist with both zfs userland and kernel versions.
* Returns NULL on error.
*/
nvlist_t *
zfs_version_nvlist(void)
{
nvlist_t *nvl;
char kmod_ver[256];
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
return (NULL);
if (nvlist_add_string(nvl, "userland", ZFS_META_ALIAS) != 0)
goto err;
char *kver = zfs_version_kernel();
if (kver == NULL) {
fprintf(stderr, "zfs_version_kernel() failed: %s\n",
zfs_strerror(errno));
goto err;
}
(void) snprintf(kmod_ver, 256, "zfs-kmod-%s", kver);
if (nvlist_add_string(nvl, "kernel", kmod_ver) != 0)
goto err;
return (nvl);
err:
nvlist_free(nvl);
return (NULL);
}
/*
* Return 1 if the user requested ANSI color output, and our terminal supports
* it. Return 0 for no color.

View File

@ -126,7 +126,9 @@
<elf-symbol name='atomic_swap_uint' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='atomic_swap_ulong' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='atomic_swap_ushort' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='format_timestamp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='get_system_hostid' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='get_timestamp' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getexecname' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getextmntent' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='getmntany' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -1109,6 +1111,18 @@
<parameter type-id='3502e3ff' name='timestamp_fmt'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='get_timestamp' mangled-name='get_timestamp' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='get_timestamp'>
<parameter type-id='3502e3ff' name='timestamp_fmt'/>
<parameter type-id='26a90f95' name='buf'/>
<parameter type-id='95e97e5e' name='len'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='format_timestamp' mangled-name='format_timestamp' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='format_timestamp'>
<parameter type-id='c9d12d66' name='t'/>
<parameter type-id='26a90f95' name='buf'/>
<parameter type-id='95e97e5e' name='len'/>
<return type-id='48b5725f'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfs_core/libzfs_core.c' language='LANG_C99'>
<array-type-def dimensions='1' type-id='03085adc' size-in-bits='192' id='083f8d58'>

View File

@ -41,6 +41,7 @@
.Cm list
.Op Fl r Ns | Ns Fl d Ar depth
.Op Fl Hp
.Op Fl j Op Ar --json-int
.Oo Fl o Ar property Ns Oo , Ns Ar property Oc Ns Oc
.Oo Fl s Ar property Oc Ns
.Oo Fl S Ar property Oc Ns
@ -70,6 +71,11 @@ The following fields are displayed:
Used for scripting mode.
Do not print headers and separate fields by a single tab instead of arbitrary
white space.
.It Fl j Op Ar --json-int
Print the output in JSON format.
Specify
.Sy --json-int
to print the numbers in integer format instead of strings in JSON output.
.It Fl d Ar depth
Recursively display any children of the dataset, limiting the recursion to
.Ar depth .
@ -186,6 +192,161 @@ pool/home 315K 457G 21K /export/home
pool/home/anne 18K 457G 18K /export/home/anne
pool/home/bob 276K 457G 276K /export/home/bob
.Ed
.Ss Example 2 : No Listing ZFS filesystems and snapshots in JSON format
.Bd -literal -compact -offset Ds
.No # Nm zfs Cm list Fl j Fl t Ar filesystem,snapshot | Cm jq
{
"output_version": {
"command": "zfs list",
"vers_major": 0,
"vers_minor": 1
},
"datasets": {
"pool": {
"name": "pool",
"type": "FILESYSTEM",
"pool": "pool",
"properties": {
"used": {
"value": "290K",
"source": {
"type": "NONE",
"data": "-"
}
},
"available": {
"value": "30.5G",
"source": {
"type": "NONE",
"data": "-"
}
},
"referenced": {
"value": "24K",
"source": {
"type": "NONE",
"data": "-"
}
},
"mountpoint": {
"value": "/pool",
"source": {
"type": "DEFAULT",
"data": "-"
}
}
}
},
"pool/home": {
"name": "pool/home",
"type": "FILESYSTEM",
"pool": "pool",
"properties": {
"used": {
"value": "48K",
"source": {
"type": "NONE",
"data": "-"
}
},
"available": {
"value": "30.5G",
"source": {
"type": "NONE",
"data": "-"
}
},
"referenced": {
"value": "24K",
"source": {
"type": "NONE",
"data": "-"
}
},
"mountpoint": {
"value": "/mnt/home",
"source": {
"type": "LOCAL",
"data": "-"
}
}
}
},
"pool/home/bob": {
"name": "pool/home/bob",
"type": "FILESYSTEM",
"pool": "pool",
"properties": {
"used": {
"value": "24K",
"source": {
"type": "NONE",
"data": "-"
}
},
"available": {
"value": "30.5G",
"source": {
"type": "NONE",
"data": "-"
}
},
"referenced": {
"value": "24K",
"source": {
"type": "NONE",
"data": "-"
}
},
"mountpoint": {
"value": "/mnt/home/bob",
"source": {
"type": "INHERITED",
"data": "pool/home"
}
}
}
},
"pool/home/bob@v1": {
"name": "pool/home/bob@v1",
"type": "SNAPSHOT",
"pool": "pool",
"dataset": "pool/home/bob",
"snapshot_name": "v1",
"properties": {
"used": {
"value": "0B",
"source": {
"type": "NONE",
"data": "-"
}
},
"available": {
"value": "-",
"source": {
"type": "NONE",
"data": "-"
}
},
"referenced": {
"value": "24K",
"source": {
"type": "NONE",
"data": "-"
}
},
"mountpoint": {
"value": "-",
"source": {
"type": "NONE",
"data": "-"
}
}
}
}
}
}
.Ed
.
.Sh SEE ALSO
.Xr zfsprops 7 ,

View File

@ -39,6 +39,7 @@
.Sh SYNOPSIS
.Nm zfs
.Cm mount
.Op Fl j
.Nm zfs
.Cm mount
.Op Fl Oflv
@ -54,8 +55,13 @@
.It Xo
.Nm zfs
.Cm mount
.Op Fl j
.Xc
Displays all ZFS file systems currently mounted.
.Bl -tag -width "-j"
.It Fl j
Displays all mounted file systems in JSON format.
.El
.It Xo
.Nm zfs
.Cm mount

View File

@ -46,6 +46,7 @@
.Cm get
.Op Fl r Ns | Ns Fl d Ar depth
.Op Fl Hp
.Op Fl j Op Ar --json-int
.Oo Fl o Ar field Ns Oo , Ns Ar field Oc Ns Oc
.Oo Fl s Ar source Ns Oo , Ns Ar source Oc Ns Oc
.Oo Fl t Ar type Ns Oo , Ns Ar type Oc Ns Oc
@ -91,6 +92,7 @@ dataset.
.Cm get
.Op Fl r Ns | Ns Fl d Ar depth
.Op Fl Hp
.Op Fl j Op Ar --json-int
.Oo Fl o Ar field Ns Oo , Ns Ar field Oc Ns Oc
.Oo Fl s Ar source Ns Oo , Ns Ar source Oc Ns Oc
.Oo Fl t Ar type Ns Oo , Ns Ar type Oc Ns Oc
@ -128,6 +130,11 @@ The value
can be used to display all properties that apply to the given dataset's type
.Pq Sy filesystem , volume , snapshot , No or Sy bookmark .
.Bl -tag -width "-s source"
.It Fl j Op Ar --json-int
Display the output in JSON format.
Specify
.Sy --json-int
to display numbers in integer format instead of strings for JSON output.
.It Fl H
Display output in a form more easily parsed by scripts.
Any headers are omitted, and fields are explicitly separated by a single tab
@ -283,6 +290,50 @@ The following command gets a single property value:
on
.Ed
.Pp
The following command gets a single property value recursively in JSON format:
.Bd -literal -compact -offset Ds
.No # Nm zfs Cm get Fl j Fl r Sy mountpoint Ar pool/home | Nm jq
{
"output_version": {
"command": "zfs get",
"vers_major": 0,
"vers_minor": 1
},
"datasets": {
"pool/home": {
"name": "pool/home",
"type": "FILESYSTEM",
"pool": "pool",
"createtxg": "10",
"properties": {
"mountpoint": {
"value": "/pool/home",
"source": {
"type": "DEFAULT",
"data": "-"
}
}
}
},
"pool/home/bob": {
"name": "pool/home/bob",
"type": "FILESYSTEM",
"pool": "pool",
"createtxg": "1176",
"properties": {
"mountpoint": {
"value": "/pool/home/bob",
"source": {
"type": "DEFAULT",
"data": "-"
}
}
}
}
}
}
.Ed
.Pp
The following command lists all properties with local settings for
.Ar pool/home/bob :
.Bd -literal -compact -offset Ds

View File

@ -48,6 +48,7 @@
.Fl ?V
.Nm
.Cm version
.Op Fl j
.Nm
.Cm subcommand
.Op Ar arguments
@ -153,10 +154,14 @@ Displays a help message.
.It Xo
.Nm
.Cm version
.Op Fl j
.Xc
Displays the software version of the
.Nm
userland utility and the zfs kernel module.
Use
.Fl j
option to output in JSON format.
.El
.
.Ss Dataset Management

View File

@ -37,6 +37,7 @@
.Nm zpool
.Cm get
.Op Fl Hp
.Op Fl j Op Ar --json-int, --json-pool-key-guid
.Op Fl o Ar field Ns Oo , Ns Ar field Oc Ns
.Sy all Ns | Ns Ar property Ns Oo , Ns Ar property Oc Ns
.Oo Ar pool Oc Ns
@ -44,6 +45,7 @@
.Nm zpool
.Cm get
.Op Fl Hp
.Op Fl j Op Ar --json-int
.Op Fl o Ar field Ns Oo , Ns Ar field Oc Ns
.Sy all Ns | Ns Ar property Ns Oo , Ns Ar property Oc Ns
.Ar pool
@ -67,6 +69,7 @@
.Nm zpool
.Cm get
.Op Fl Hp
.Op Fl j Op Ar --json-int, --json-pool-key-guid
.Op Fl o Ar field Ns Oo , Ns Ar field Oc Ns
.Sy all Ns | Ns Ar property Ns Oo , Ns Ar property Oc Ns
.Oo Ar pool Oc Ns
@ -95,6 +98,14 @@ See the
.Xr zpoolprops 7
manual page for more information on the available pool properties.
.Bl -tag -compact -offset Ds -width "-o field"
.It Fl j Op Ar --json-int, --json-pool-key-guid
Display the list of properties in JSON format.
Specify
.Sy --json-int
to display the numbers in integer format instead of strings in JSON output.
Specify
.Sy --json-pool-key-guid
to set pool GUID as key for pool objects instead of pool name.
.It Fl H
Scripted mode.
Do not display headers, and separate fields by a single tab instead of arbitrary
@ -108,6 +119,7 @@ Display numbers in parsable (exact) values.
.It Xo
.Nm zpool
.Cm get
.Op Fl j Op Ar --json-int
.Op Fl Hp
.Op Fl o Ar field Ns Oo , Ns Ar field Oc Ns
.Sy all Ns | Ns Ar property Ns Oo , Ns Ar property Oc Ns
@ -145,6 +157,11 @@ See the
.Xr vdevprops 7
manual page for more information on the available pool properties.
.Bl -tag -compact -offset Ds -width "-o field"
.It Fl j Op Ar --json-int
Display the list of properties in JSON format.
Specify
.Sy --json-int
to display the numbers in integer format instead of strings in JSON output.
.It Fl H
Scripted mode.
Do not display headers, and separate fields by a single tab instead of arbitrary

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

View File

@ -41,6 +41,7 @@
.Op Fl c Op Ar SCRIPT1 Ns Oo , Ns Ar SCRIPT2 Oc Ns
.Oo Ar pool Oc Ns
.Op Ar interval Op Ar count
.Op Fl j Op Ar --json-int, --json-flat-vdevs, --json-pool-key-guid
.
.Sh DESCRIPTION
Displays the detailed health status for the given pools.
@ -69,6 +70,17 @@ See the
option of
.Nm zpool Cm iostat
for complete details.
.It Fl j Op Ar --json-int, --json-flat-vdevs, --json-pool-key-guid
Display the status for ZFS pools in JSON format.
Specify
.Sy --json-int
to display numbers in integer format instead of strings.
Specify
.Sy --json-flat-vdevs
to display vdevs in flat hierarchy instead of nested vdev objects.
Specify
.Sy --json-pool-key-guid
to set pool GUID as key for pool objects instead of pool names.
.It Fl D
Display a histogram of deduplication statistics, showing the allocated
.Pq physically present on disk
@ -159,6 +171,175 @@ rpool 14.6G 54.9G 4 55 250K 2.69M
---------- ----- ----- ----- ----- ----- ----- ----
.Ed
.
.Ss Example 2 : No Display the status output in JSON format
.Nm zpool Cm status No can output in JSON format if
.Fl j
is specified.
.Fl c
can be used to run a script on each VDEV.
.Bd -literal -compact -offset Ds
.No # Nm zpool Cm status Fl j Fl c Pa vendor , Ns Pa model , Ns Pa size | Nm jq
{
"output_version": {
"command": "zpool status",
"vers_major": 0,
"vers_minor": 1
},
"pools": {
"tank": {
"name": "tank",
"state": "ONLINE",
"guid": "3920273586464696295",
"txg": "16597",
"spa_version": "5000",
"zpl_version": "5",
"status": "OK",
"vdevs": {
"tank": {
"name": "tank",
"alloc_space": "62.6G",
"total_space": "15.0T",
"def_space": "11.3T",
"read_errors": "0",
"write_errors": "0",
"checksum_errors": "0",
"vdevs": {
"raidz1-0": {
"name": "raidz1-0",
"vdev_type": "raidz",
"guid": "763132626387621737",
"state": "HEALTHY",
"alloc_space": "62.5G",
"total_space": "10.9T",
"def_space": "7.26T",
"rep_dev_size": "10.9T",
"read_errors": "0",
"write_errors": "0",
"checksum_errors": "0",
"vdevs": {
"ca1eb824-c371-491d-ac13-37637e35c683": {
"name": "ca1eb824-c371-491d-ac13-37637e35c683",
"vdev_type": "disk",
"guid": "12841765308123764671",
"path": "/dev/disk/by-partuuid/ca1eb824-c371-491d-ac13-37637e35c683",
"state": "HEALTHY",
"rep_dev_size": "3.64T",
"phys_space": "3.64T",
"read_errors": "0",
"write_errors": "0",
"checksum_errors": "0",
"vendor": "ATA",
"model": "WDC WD40EFZX-68AWUN0",
"size": "3.6T"
},
"97cd98fb-8fb8-4ac4-bc84-bd8950a7ace7": {
"name": "97cd98fb-8fb8-4ac4-bc84-bd8950a7ace7",
"vdev_type": "disk",
"guid": "1527839927278881561",
"path": "/dev/disk/by-partuuid/97cd98fb-8fb8-4ac4-bc84-bd8950a7ace7",
"state": "HEALTHY",
"rep_dev_size": "3.64T",
"phys_space": "3.64T",
"read_errors": "0",
"write_errors": "0",
"checksum_errors": "0",
"vendor": "ATA",
"model": "WDC WD40EFZX-68AWUN0",
"size": "3.6T"
},
"e9ddba5f-f948-4734-a472-cb8aa5f0ff65": {
"name": "e9ddba5f-f948-4734-a472-cb8aa5f0ff65",
"vdev_type": "disk",
"guid": "6982750226085199860",
"path": "/dev/disk/by-partuuid/e9ddba5f-f948-4734-a472-cb8aa5f0ff65",
"state": "HEALTHY",
"rep_dev_size": "3.64T",
"phys_space": "3.64T",
"read_errors": "0",
"write_errors": "0",
"checksum_errors": "0",
"vendor": "ATA",
"model": "WDC WD40EFZX-68AWUN0",
"size": "3.6T"
}
}
}
}
}
},
"dedup": {
"mirror-2": {
"name": "mirror-2",
"vdev_type": "mirror",
"guid": "2227766268377771003",
"state": "HEALTHY",
"alloc_space": "89.1M",
"total_space": "3.62T",
"def_space": "3.62T",
"rep_dev_size": "3.62T",
"read_errors": "0",
"write_errors": "0",
"checksum_errors": "0",
"vdevs": {
"db017360-d8e9-4163-961b-144ca75293a3": {
"name": "db017360-d8e9-4163-961b-144ca75293a3",
"vdev_type": "disk",
"guid": "17880913061695450307",
"path": "/dev/disk/by-partuuid/db017360-d8e9-4163-961b-144ca75293a3",
"state": "HEALTHY",
"rep_dev_size": "3.63T",
"phys_space": "3.64T",
"read_errors": "0",
"write_errors": "0",
"checksum_errors": "0",
"vendor": "ATA",
"model": "WDC WD40EFZX-68AWUN0",
"size": "3.6T"
},
"952c3baf-b08a-4a8c-b7fa-33a07af5fe6f": {
"name": "952c3baf-b08a-4a8c-b7fa-33a07af5fe6f",
"vdev_type": "disk",
"guid": "10276374011610020557",
"path": "/dev/disk/by-partuuid/952c3baf-b08a-4a8c-b7fa-33a07af5fe6f",
"state": "HEALTHY",
"rep_dev_size": "3.63T",
"phys_space": "3.64T",
"read_errors": "0",
"write_errors": "0",
"checksum_errors": "0",
"vendor": "ATA",
"model": "WDC WD40EFZX-68AWUN0",
"size": "3.6T"
}
}
}
},
"special": {
"25d418f8-92bd-4327-b59f-7ef5d5f50d81": {
"name": "25d418f8-92bd-4327-b59f-7ef5d5f50d81",
"vdev_type": "disk",
"guid": "3935742873387713123",
"path": "/dev/disk/by-partuuid/25d418f8-92bd-4327-b59f-7ef5d5f50d81",
"state": "HEALTHY",
"alloc_space": "37.4M",
"total_space": "444G",
"def_space": "444G",
"rep_dev_size": "444G",
"phys_space": "447G",
"read_errors": "0",
"write_errors": "0",
"checksum_errors": "0",
"vendor": "ATA",
"model": "Micron_5300_MTFDDAK480TDS",
"size": "447.1G"
}
},
"error_count": "0"
}
}
}
.Ed
.
.Sh SEE ALSO
.Xr zpool-events 8 ,
.Xr zpool-history 8 ,

View File

@ -38,6 +38,7 @@
.Fl ?V
.Nm
.Cm version
.Op Fl j
.Nm
.Cm subcommand
.Op Ar arguments
@ -79,10 +80,14 @@ Displays a help message.
.It Xo
.Nm
.Cm version
.Op Fl j
.Xc
Displays the software version of the
.Nm
userland utility and the ZFS kernel module.
Use
.Fl j
option to output in JSON format.
.El
.
.Ss Creation

View File

@ -153,6 +153,10 @@ tests = [ 'clean_mirror_001_pos', 'clean_mirror_002_pos',
'clean_mirror_003_pos', 'clean_mirror_004_pos']
tags = ['functional', 'clean_mirror']
[tests/functional/cli_root/json]
tests = ['json_sanity']
tags = ['functional', 'cli_root', 'json']
[tests/functional/cli_root/zinject]
tests = ['zinject_args']
pre =

View File

@ -46,6 +46,7 @@ export SYSTEM_FILES_COMMON='awk
hostname
id
iostat
jq
kill
ksh
ldd

View File

@ -606,6 +606,9 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/clean_mirror/clean_mirror_004_pos.ksh \
functional/clean_mirror/cleanup.ksh \
functional/clean_mirror/setup.ksh \
functional/cli_root/json/cleanup.ksh \
functional/cli_root/json/setup.ksh \
functional/cli_root/json/json_sanity.ksh \
functional/cli_root/zinject/zinject_args.ksh \
functional/cli_root/zdb/zdb_002_pos.ksh \
functional/cli_root/zdb/zdb_003_pos.ksh \

View File

@ -0,0 +1,31 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# Copyright (c) 2024 by Lawrence Livermore National Security, LLC.
. $STF_SUITE/include/libtest.shlib
zpool destroy testpool1
zpool destroy testpool2
rm $TESTDIR/file{1..28}
rmdir $TESTDIR

View File

@ -0,0 +1,61 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
# Copyright (c) 2024 by Lawrence Livermore National Security, LLC.
. $STF_SUITE/include/libtest.shlib
#
# DESCRIPTION:
# Basic sanity check for valid JSON from zfs & zpool commands.
#
# STRATEGY:
# 1. Run different zfs/zpool -j commands and check for valid JSON
list=(
"zpool status -j -g --json-int --json-flat-vdevs --json-pool-key-guid"
"zpool status -p -j -g --json-int --json-flat-vdevs --json-pool-key-guid"
"zpool status -j -c upath"
"zpool status -j"
"zpool status -j testpool1"
"zpool list -j"
"zpool list -j -g"
"zpool list -j -o fragmentation"
"zpool get -j size"
"zpool get -j all"
"zpool version -j"
"zfs list -j"
"zfs list -j testpool1"
"zfs get -j all"
"zfs get -j available"
"zfs mount -j"
"zfs version -j"
)
log_note "RPM $(rpm -qa)"
log_note "jq=$(which jq)"
log_note "JQRPM: $(rpm -ql jq)"
for cmd in "${list[@]}" ; do
log_must eval "$cmd | jq > /dev/null"
done
log_pass "zpool and zfs commands outputted valid JSON"

View File

@ -0,0 +1,50 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# Copyright (c) 2024 by Lawrence Livermore National Security, LLC.
. $STF_SUITE/include/libtest.shlib
# Sanity check that 'testpool1' or 'testpool2' don't exist
log_mustnot zpool status -j | \
jq -e '.pools | has("testpool1") or has("testpool2")' &> /dev/null
mkdir -p $TESTDIR
truncate -s 80M $TESTDIR/file{1..28}
DISK=${DISKS%% *}
# Create complex pool configs to exercise JSON
zpool create -f testpool1 draid $TESTDIR/file{1..10} \
special $DISK \
dedup $TESTDIR/file11 \
special $TESTDIR/file12 \
cache $TESTDIR/file13 \
log $TESTDIR/file14
zpool create -f testpool2 mirror $TESTDIR/file{15,16} \
raidz1 $TESTDIR/file{17,18,19} \
cache $TESTDIR/file20 \
log $TESTDIR/file21 \
special mirror $TESTDIR/file{22,23} \
dedup mirror $TESTDIR/file{24,25} \
spare $TESTDIR/file{26,27,28}