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_ITERS="1"
#TEST_ZFSTESTS_OPTIONS="-vx" #TEST_ZFSTESTS_OPTIONS="-vx"
#TEST_ZFSTESTS_RUNFILE="linux.run" #TEST_ZFSTESTS_RUNFILE="linux.run"
#TEST_ZFSTESTS_TAGS="functional" TEST_ZFSTESTS_TAGS="json"
### zfsstress ### zfsstress
#TEST_ZFSSTRESS_SKIP="yes" #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); 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. * 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 NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
#define MAX_CMD_LEN 256
zfs_command_t *current_command; zfs_command_t *current_command;
static const char * static const char *
@ -292,7 +298,7 @@ get_usage(zfs_help_t idx)
"<filesystem|volume>@<snap>[%<snap>][,...]\n" "<filesystem|volume>@<snap>[%<snap>][,...]\n"
"\tdestroy <filesystem|volume>#<bookmark>\n")); "\tdestroy <filesystem|volume>#<bookmark>\n"));
case HELP_GET: case HELP_GET:
return (gettext("\tget [-rHp] [-d max] " return (gettext("\tget [-rHp] [-j [--json-int]] [-d max] "
"[-o \"all\" | field[,...]]\n" "[-o \"all\" | field[,...]]\n"
"\t [-t type[,...]] [-s source[,...]]\n" "\t [-t type[,...]] [-s source[,...]]\n"
"\t <\"all\" | property[,...]> " "\t <\"all\" | property[,...]> "
@ -304,11 +310,12 @@ get_usage(zfs_help_t idx)
return (gettext("\tupgrade [-v]\n" return (gettext("\tupgrade [-v]\n"
"\tupgrade [-r] [-V version] <-a | filesystem ...>\n")); "\tupgrade [-r] [-V version] <-a | filesystem ...>\n"));
case HELP_LIST: case HELP_LIST:
return (gettext("\tlist [-Hp] [-r|-d max] [-o property[,...]] " return (gettext("\tlist [-Hp] [-j [--json-int]] [-r|-d max] "
"[-s property]...\n\t [-S property]... [-t type[,...]] " "[-o property[,...]] [-s property]...\n\t "
"[-S property]... [-t type[,...]] "
"[filesystem|volume|snapshot] ...\n")); "[filesystem|volume|snapshot] ...\n"));
case HELP_MOUNT: case HELP_MOUNT:
return (gettext("\tmount\n" return (gettext("\tmount [-j]\n"
"\tmount [-flvO] [-o opts] <-a|-R filesystem|" "\tmount [-flvO] [-o opts] <-a|-R filesystem|"
"filesystem>\n")); "filesystem>\n"));
case HELP_PROMOTE: case HELP_PROMOTE:
@ -420,7 +427,7 @@ get_usage(zfs_help_t idx)
"\t <filesystem|volume>\n" "\t <filesystem|volume>\n"
"\tchange-key -i [-l] <filesystem|volume>\n")); "\tchange-key -i [-l] <filesystem|volume>\n"));
case HELP_VERSION: case HELP_VERSION:
return (gettext("\tversion\n")); return (gettext("\tversion [-j]\n"));
case HELP_REDACT: case HELP_REDACT:
return (gettext("\tredact <snapshot> <bookmark> " return (gettext("\tredact <snapshot> <bookmark> "
"<redaction_snapshot> ...\n")); "<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 > ... * < all | property[,property]... > < fs | snap | vol > ...
* *
* -r recurse over any child datasets * -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 * "local,default,inherited,received,temporary,none". Default is
* all six. * all six.
* -p Display values in parsable (literal) format. * -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 * Prints properties for the given datasets. The user can control which
* columns to display as well as which property types to allow. * 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); nvlist_t *user_props = zfs_get_user_props(zhp);
zprop_list_t *pl = cbp->cb_proplist; zprop_list_t *pl = cbp->cb_proplist;
nvlist_t *propval; nvlist_t *propval;
nvlist_t *item, *d, *props;
item = d = props = NULL;
const char *strval; const char *strval;
const char *sourceval; const char *sourceval;
boolean_t received = is_recvd_column(cbp); 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) { for (; pl != NULL; pl = pl->pl_next) {
char *recvdval = NULL; char *recvdval = NULL;
@ -1954,9 +2057,9 @@ get_callback(zfs_handle_t *zhp, void *data)
cbp->cb_literal) == 0)) cbp->cb_literal) == 0))
recvdval = rbuf; 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), 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)) { } else if (zfs_prop_userquota(pl->pl_user_prop)) {
sourcetype = ZPROP_SRC_LOCAL; sourcetype = ZPROP_SRC_LOCAL;
@ -1966,8 +2069,9 @@ get_callback(zfs_handle_t *zhp, void *data)
(void) strlcpy(buf, "-", sizeof (buf)); (void) strlcpy(buf, "-", sizeof (buf));
} }
zprop_print_one_property(zfs_get_name(zhp), cbp, err = zprop_collect_property(zfs_get_name(zhp), cbp,
pl->pl_user_prop, buf, sourcetype, source, NULL); pl->pl_user_prop, buf, sourcetype, source, NULL,
props);
} else if (zfs_prop_written(pl->pl_user_prop)) { } else if (zfs_prop_written(pl->pl_user_prop)) {
sourcetype = ZPROP_SRC_LOCAL; sourcetype = ZPROP_SRC_LOCAL;
@ -1977,8 +2081,9 @@ get_callback(zfs_handle_t *zhp, void *data)
(void) strlcpy(buf, "-", sizeof (buf)); (void) strlcpy(buf, "-", sizeof (buf));
} }
zprop_print_one_property(zfs_get_name(zhp), cbp, err = zprop_collect_property(zfs_get_name(zhp), cbp,
pl->pl_user_prop, buf, sourcetype, source, NULL); pl->pl_user_prop, buf, sourcetype, source, NULL,
props);
} else { } else {
if (nvlist_lookup_nvlist(user_props, if (nvlist_lookup_nvlist(user_props,
pl->pl_user_prop, &propval) != 0) { pl->pl_user_prop, &propval) != 0) {
@ -2010,9 +2115,24 @@ get_callback(zfs_handle_t *zhp, void *data)
cbp->cb_literal) == 0)) cbp->cb_literal) == 0))
recvdval = rbuf; 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, 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 ret = 0;
int limit = 0; int limit = 0;
zprop_list_t fake_name = { 0 }; zprop_list_t fake_name = { 0 };
nvlist_t *data;
/* /*
* Set up default columns and sources. * 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_columns[3] = GET_COL_SOURCE;
cb.cb_type = ZFS_TYPE_DATASET; 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 */ /* 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) { switch (c) {
case 'p': case 'p':
cb.cb_literal = B_TRUE; cb.cb_literal = B_TRUE;
@ -2055,6 +2182,17 @@ zfs_do_get(int argc, char **argv)
case 'H': case 'H':
cb.cb_scripted = B_TRUE; cb.cb_scripted = B_TRUE;
break; 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 ':': case ':':
(void) fprintf(stderr, gettext("missing argument for " (void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt); "'%c' option\n"), optopt);
@ -2178,7 +2316,6 @@ found2:;
found3:; found3:;
} }
break; break;
case '?': case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"), (void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt); optopt);
@ -2195,6 +2332,12 @@ found3:;
usage(B_FALSE); 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]; fields = argv[0];
/* /*
@ -2235,6 +2378,9 @@ found3:;
ret = zfs_for_each(argc, argv, flags, types, NULL, ret = zfs_for_each(argc, argv, flags, types, NULL,
&cb.cb_proplist, limit, get_callback, &cb); &cb.cb_proplist, limit, get_callback, &cb);
if (cb.cb_json)
zcmd_print_json(cb.cb_jsobj);
if (cb.cb_proplist == &fake_name) if (cb.cb_proplist == &fake_name)
zprop_free_list(fake_name.pl_next); zprop_free_list(fake_name.pl_next);
else else
@ -3442,6 +3588,9 @@ typedef struct list_cbdata {
boolean_t cb_literal; boolean_t cb_literal;
boolean_t cb_scripted; boolean_t cb_scripted;
zprop_list_t *cb_proplist; zprop_list_t *cb_proplist;
boolean_t cb_json;
nvlist_t *cb_jsobj;
boolean_t cb_json_as_int;
} list_cbdata_t; } 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 * 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 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; zprop_list_t *pl = cb->cb_proplist;
boolean_t first = B_TRUE; boolean_t first = B_TRUE;
@ -3524,9 +3674,23 @@ print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
nvlist_t *propval; nvlist_t *propval;
const char *propstr; const char *propstr;
boolean_t right_justify; 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) { for (; pl != NULL; pl = pl->pl_next) {
if (!first) { if (!cb->cb_json && !first) {
if (cb->cb_scripted) if (cb->cb_scripted)
(void) putchar('\t'); (void) putchar('\t');
else else
@ -3542,69 +3706,113 @@ print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
right_justify = zfs_prop_align_right(pl->pl_prop); right_justify = zfs_prop_align_right(pl->pl_prop);
} else if (pl->pl_prop != ZPROP_USERPROP) { } else if (pl->pl_prop != ZPROP_USERPROP) {
if (zfs_prop_get(zhp, pl->pl_prop, property, if (zfs_prop_get(zhp, pl->pl_prop, property,
sizeof (property), NULL, NULL, 0, sizeof (property), &sourcetype, source,
cb->cb_literal) != 0) sizeof (source), cb->cb_literal) != 0)
propstr = "-"; propstr = "-";
else else
propstr = property; propstr = property;
right_justify = zfs_prop_align_right(pl->pl_prop); right_justify = zfs_prop_align_right(pl->pl_prop);
} else if (zfs_prop_userquota(pl->pl_user_prop)) { } else if (zfs_prop_userquota(pl->pl_user_prop)) {
sourcetype = ZPROP_SRC_LOCAL;
if (zfs_prop_get_userquota(zhp, pl->pl_user_prop, 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 = "-"; propstr = "-";
else } else {
propstr = property; propstr = property;
}
right_justify = B_TRUE; right_justify = B_TRUE;
} else if (zfs_prop_written(pl->pl_user_prop)) { } else if (zfs_prop_written(pl->pl_user_prop)) {
sourcetype = ZPROP_SRC_LOCAL;
if (zfs_prop_get_written(zhp, pl->pl_user_prop, 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 = "-"; propstr = "-";
else } else {
propstr = property; propstr = property;
}
right_justify = B_TRUE; right_justify = B_TRUE;
} else { } else {
if (nvlist_lookup_nvlist(userprops, if (nvlist_lookup_nvlist(userprops,
pl->pl_user_prop, &propval) != 0) pl->pl_user_prop, &propval) != 0) {
propstr = "-"; propstr = "-";
else sourcetype = ZPROP_SRC_NONE;
} else {
propstr = fnvlist_lookup_string(propval, propstr = fnvlist_lookup_string(propval,
ZPROP_VALUE); 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; right_justify = B_FALSE;
} }
/* if (cb->cb_json) {
* zfs_list_avail_color() needs ZFS_PROP_AVAILABLE + USED if (pl->pl_prop == ZFS_PROP_NAME)
* - so we need another for() search for the USED part continue;
* - when no colors wanted, we can skip the whole thing if (zprop_nvlist_one_property(
*/ zfs_prop_to_name(pl->pl_prop), propstr,
if (use_color() && pl->pl_prop == ZFS_PROP_AVAILABLE) { sourcetype, source, NULL, props,
zprop_list_t *pl2 = cb->cb_proplist; cb->cb_json_as_int) != 0)
for (; pl2 != NULL; pl2 = pl2->pl_next) { nomem();
if (pl2->pl_prop == ZFS_PROP_USED) { } else {
color_start(zfs_list_avail_color(zhp)); /*
/* found it, no need for more loops */ * zfs_list_avail_color() needs
break; * 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();
} }
if (cb->cb_json) {
(void) putchar('\n'); 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; list_cbdata_t *cbp = data;
if (cbp->cb_first) { if (cbp->cb_first) {
if (!cbp->cb_scripted) if (!cbp->cb_scripted && !cbp->cb_json)
print_header(cbp); print_header(cbp);
cbp->cb_first = B_FALSE; cbp->cb_first = B_FALSE;
} }
print_dataset(zhp, cbp); collect_dataset(zhp, cbp);
return (0); return (0);
} }
@ -3640,9 +3848,16 @@ zfs_do_list(int argc, char **argv)
int ret = 0; int ret = 0;
zfs_sort_column_t *sortcol = NULL; zfs_sort_column_t *sortcol = NULL;
int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS; 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 */ /* 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) { switch (c) {
case 'o': case 'o':
fields = optarg; fields = optarg;
@ -3657,6 +3872,17 @@ zfs_do_list(int argc, char **argv)
case 'r': case 'r':
flags |= ZFS_ITER_RECURSE; flags |= ZFS_ITER_RECURSE;
break; 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': case 'H':
cb.cb_scripted = B_TRUE; cb.cb_scripted = B_TRUE;
break; break;
@ -3730,6 +3956,12 @@ found3:;
argc -= optind; argc -= optind;
argv += 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. * 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, ret = zfs_for_each(argc, argv, flags, types, sortcol, &cb.cb_proplist,
limit, list_callback, &cb); limit, list_callback, &cb);
if (cb.cb_json)
zcmd_print_json(cb.cb_jsobj);
zprop_free_list(cb.cb_proplist); zprop_free_list(cb.cb_proplist);
zfs_free_sort_columns(sortcol); zfs_free_sort_columns(sortcol);
@ -7189,14 +7424,17 @@ share_mount(int op, int argc, char **argv)
int do_all = 0; int do_all = 0;
int recursive = 0; int recursive = 0;
boolean_t verbose = B_FALSE; boolean_t verbose = B_FALSE;
boolean_t json = B_FALSE;
int c, ret = 0; int c, ret = 0;
char *options = NULL; char *options = NULL;
int flags = 0; int flags = 0;
nvlist_t *jsobj, *data, *item;
const uint_t mount_nthr = 512; const uint_t mount_nthr = 512;
uint_t nthr; uint_t nthr;
jsobj = data = item = NULL;
/* check options */ /* 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) { != -1) {
switch (c) { switch (c) {
case 'a': case 'a':
@ -7211,6 +7449,11 @@ share_mount(int op, int argc, char **argv)
case 'l': case 'l':
flags |= MS_CRYPT; flags |= MS_CRYPT;
break; break;
case 'j':
json = B_TRUE;
jsobj = zfs_json_schema(0, 1);
data = fnvlist_alloc();
break;
case 'o': case 'o':
if (*optarg == '\0') { if (*optarg == '\0') {
(void) fprintf(stderr, gettext("empty mount " (void) fprintf(stderr, gettext("empty mount "
@ -7245,6 +7488,11 @@ share_mount(int op, int argc, char **argv)
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (json && argc != 0) {
(void) fprintf(stderr, gettext("too many arguments\n"));
usage(B_FALSE);
}
/* check number of arguments */ /* check number of arguments */
if (do_all || recursive) { if (do_all || recursive) {
enum sa_protocol protocol = SA_NO_PROTOCOL; 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 || if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 ||
strchr(entry.mnt_special, '@') != NULL) strchr(entry.mnt_special, '@') != NULL)
continue; continue;
if (json) {
(void) printf("%-30s %s\n", entry.mnt_special, item = fnvlist_alloc();
entry.mnt_mountp); 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); (void) fclose(mnttab);
if (json) {
fnvlist_add_nvlist(jsobj, "datasets", data);
zcmd_print_json(jsobj);
fnvlist_free(data);
}
} else { } else {
zfs_handle_t *zhp; zfs_handle_t *zhp;
@ -8811,8 +9074,39 @@ found:;
static int static int
zfs_do_version(int argc, char **argv) zfs_do_version(int argc, char **argv)
{ {
(void) argc, (void) argv; int c;
return (zfs_version_print() != 0); 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 */ /* 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 *, _LIBZFS_H nvlist_t *zpool_find_vdev(zpool_handle_t *, const char *, boolean_t *,
boolean_t *, 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 *, _LIBZFS_H nvlist_t *zpool_find_vdev_by_physpath(zpool_handle_t *, const char *,
boolean_t *, boolean_t *, boolean_t *); boolean_t *, boolean_t *, boolean_t *);
_LIBZFS_H int zpool_label_disk(libzfs_handle_t *, zpool_handle_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); char *altroot);
_LIBZFS_H int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *, _LIBZFS_H int zpool_import_props(libzfs_handle_t *, nvlist_t *, const char *,
nvlist_t *, int); 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 * Miscellaneous pool functions
@ -499,7 +502,7 @@ _LIBZFS_H void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,
size_t); size_t);
_LIBZFS_H int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *); _LIBZFS_H int zfs_ioctl(libzfs_handle_t *, int, struct zfs_cmd *);
_LIBZFS_H void zpool_explain_recover(libzfs_handle_t *, const char *, int, _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_checkpoint(zpool_handle_t *);
_LIBZFS_H int zpool_discard_checkpoint(zpool_handle_t *); _LIBZFS_H int zpool_discard_checkpoint(zpool_handle_t *);
_LIBZFS_H boolean_t zpool_is_draid_spare(const char *); _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); zfs_type_t);
_LIBZFS_H void zprop_free_list(zprop_list_t *); _LIBZFS_H void zprop_free_list(zprop_list_t *);
_LIBZFS_H void zcmd_print_json(nvlist_t *);
#define ZFS_GET_NCOLS 5 #define ZFS_GET_NCOLS 5
typedef enum { typedef enum {
@ -655,9 +660,13 @@ typedef struct zprop_get_cbdata {
boolean_t cb_scripted; boolean_t cb_scripted;
boolean_t cb_literal; boolean_t cb_literal;
boolean_t cb_first; boolean_t cb_first;
boolean_t cb_json;
zprop_list_t *cb_proplist; zprop_list_t *cb_proplist;
zfs_type_t cb_type; zfs_type_t cb_type;
vdev_cbdata_t cb_vdevs; 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; } zprop_get_cbdata_t;
#define ZFS_SET_NOMOUNT 1 #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 *, const char *, zprop_source_t, const char *,
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. * 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 const char *zfs_version_userland(void);
_LIBZFS_H char *zfs_version_kernel(void); _LIBZFS_H char *zfs_version_kernel(void);
_LIBZFS_H int zfs_version_print(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. * 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. */ /* Print a timestamp in either Unix or standard format. */
void print_timestamp(uint_t); 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 */ #endif /* _STATCOMMON_H */

View File

@ -62,3 +62,45 @@ print_timestamp(uint_t timestamp_fmt)
(void) printf("%s\n", dstr); (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_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_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='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_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='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='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='getmntany' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -1151,6 +1153,18 @@
<parameter type-id='3502e3ff' name='timestamp_fmt'/> <parameter type-id='3502e3ff' name='timestamp_fmt'/>
<return type-id='48b5725f'/> <return type-id='48b5725f'/>
</function-decl> </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>
<abi-instr address-size='64' path='lib/libuutil/uu_alloc.c' language='LANG_C99'> <abi-instr address-size='64' path='lib/libuutil/uu_alloc.c' language='LANG_C99'>
<type-decl name='char' size-in-bits='8' id='a84c031d'/> <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' 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_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='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='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_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='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='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='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='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'/> <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_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_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='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_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_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'/> <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_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_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_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_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_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'/> <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_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_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_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_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_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'/> <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_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' 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='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_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_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_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' 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_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_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_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_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'/> <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'/> <parameter type-id='3502e3ff' name='timestamp_fmt'/>
<return type-id='48b5725f'/> <return type-id='48b5725f'/>
</function-decl> </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>
<abi-instr address-size='64' path='lib/libtpool/thread_pool.c' language='LANG_C99'> <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'> <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='80f4b756' name='name'/>
<parameter type-id='95e97e5e' name='reason'/> <parameter type-id='95e97e5e' name='reason'/>
<parameter type-id='5ce45b60' name='config'/> <parameter type-id='5ce45b60' name='config'/>
<parameter type-id='26a90f95' name='buf'/>
<parameter type-id='b59d7dce' name='size'/>
<return type-id='48b5725f'/> <return type-id='48b5725f'/>
</function-decl> </function-decl>
<function-decl name='zpool_import' mangled-name='zpool_import' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_import'> <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'/> <parameter type-id='26a90f95' name='altroot'/>
<return type-id='95e97e5e'/> <return type-id='95e97e5e'/>
</function-decl> </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='5ce45b60' name='config'/>
<parameter type-id='26a90f95' name='buf'/>
<parameter type-id='b59d7dce' name='size'/>
<return type-id='48b5725f'/> <return type-id='48b5725f'/>
</function-decl> </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'> <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'/> <parameter type-id='2e45de5d' name='argtype'/>
<return type-id='9200a744'/> <return type-id='9200a744'/>
</function-decl> </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'> <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='80f4b756' name='name'/>
<parameter type-id='0d2a0670' name='cbp'/> <parameter type-id='0d2a0670' name='cbp'/>
@ -8156,6 +8192,17 @@
<parameter type-id='80f4b756' name='recvd_value'/> <parameter type-id='80f4b756' name='recvd_value'/>
<return type-id='48b5725f'/> <return type-id='48b5725f'/>
</function-decl> </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'> <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='b0382bb3' name='hdl'/>
<parameter type-id='26a90f95' name='props'/> <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'> <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'/> <return type-id='95e97e5e'/>
</function-decl> </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'> <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='color'/>
<parameter type-id='80f4b756' name='format'/> <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 void
zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason, 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; nvlist_t *nv = NULL;
int64_t loss = -1; int64_t loss = -1;
uint64_t edata = UINT64_MAX; uint64_t edata = UINT64_MAX;
uint64_t rewindto; uint64_t rewindto;
struct tm t; struct tm t;
char timestr[128]; char timestr[128], temp[1024];
if (!hdl->libzfs_printerr) if (!hdl->libzfs_printerr)
return; 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 */ /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 || if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_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, (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_DATA_ERRORS,
&edata); &edata);
(void) printf(dgettext(TEXT_DOMAIN, (void) snprintf(buf, size, dgettext(TEXT_DOMAIN,
"Recovery is possible, but will result in some data loss.\n")); "Recovery is possible, but will result in some data loss.\n"));
if (localtime_r((time_t *)&rewindto, &t) != NULL && if (localtime_r((time_t *)&rewindto, &t) != NULL &&
ctime_r((time_t *)&rewindto, timestr) != NULL) { ctime_r((time_t *)&rewindto, timestr) != NULL) {
timestr[24] = 0; 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" "\tReturning the pool to its state as of %s\n"
"\tshould correct the problem. "), "\tshould correct the problem. "), timestr);
timestr); (void) strlcat(buf, temp, size);
} else { } else {
(void) printf(dgettext(TEXT_DOMAIN, (void) strlcat(buf, dgettext(TEXT_DOMAIN,
"\tReverting the pool to an earlier state " "\tReverting the pool to an earlier state "
"should correct the problem.\n\t")); "should correct the problem.\n\t"), size);
} }
if (loss > 120) { if (loss > 120) {
(void) printf(dgettext(TEXT_DOMAIN, (void) snprintf(temp, 1024, dgettext(TEXT_DOMAIN,
"Approximately %lld minutes of data\n" "Approximately %lld minutes of data\n"
"\tmust be discarded, irreversibly. "), "\tmust be discarded, irreversibly. "),
((longlong_t)loss + 30) / 60); ((longlong_t)loss + 30) / 60);
(void) strlcat(buf, temp, size);
} else if (loss > 0) { } else if (loss > 0) {
(void) printf(dgettext(TEXT_DOMAIN, (void) snprintf(temp, 1024, dgettext(TEXT_DOMAIN,
"Approximately %lld seconds of data\n" "Approximately %lld seconds of data\n"
"\tmust be discarded, irreversibly. "), "\tmust be discarded, irreversibly. "),
(longlong_t)loss); (longlong_t)loss);
(void) strlcat(buf, temp, size);
} }
if (edata != 0 && edata != UINT64_MAX) { if (edata != 0 && edata != UINT64_MAX) {
if (edata == 1) { if (edata == 1) {
(void) printf(dgettext(TEXT_DOMAIN, (void) strlcat(buf, dgettext(TEXT_DOMAIN,
"After rewind, at least\n" "After rewind, at least\n"
"\tone persistent user-data error will remain. ")); "\tone persistent user-data error will remain. "),
size);
} else { } else {
(void) printf(dgettext(TEXT_DOMAIN, (void) strlcat(buf, dgettext(TEXT_DOMAIN,
"After rewind, several\n" "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'. "), "Recovery can be attempted\n\tby executing 'zpool %s -F %s'. "),
reason >= 0 ? "clear" : "import", name); 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" "A scrub of the pool\n"
"\tis strongly recommended after recovery.\n")); "\tis strongly recommended after recovery.\n"), size);
return; return;
no_info: no_info:
(void) printf(dgettext(TEXT_DOMAIN, (void) strlcat(buf, dgettext(TEXT_DOMAIN,
"Destroy and re-create the pool from\n\ta backup source.\n")); "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 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; nvlist_t *nvinfo, *unsup_feat;
char temp[512];
nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO); nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
unsup_feat = fnvlist_lookup_nvlist(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT); 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); for (nvpair_t *nvp = nvlist_next_nvpair(unsup_feat, NULL);
nvp != NULL; nvp = nvlist_next_nvpair(unsup_feat, nvp)) { nvp != NULL; nvp = nvlist_next_nvpair(unsup_feat, nvp)) {
const char *desc = fnvpair_value_string(nvp); const char *desc = fnvpair_value_string(nvp);
if (strlen(desc) > 0) if (strlen(desc) > 0) {
(void) printf("\t%s (%s)\n", nvpair_name(nvp), desc); (void) snprintf(temp, 512, "\t%s (%s)\n",
else nvpair_name(nvp), desc);
(void) printf("\t%s\n", nvpair_name(nvp)); (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; const char *origname;
int ret; int ret;
int error = 0; int error = 0;
char buf[2048];
char errbuf[ERRBUFLEN]; char errbuf[ERRBUFLEN];
origname = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME); 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 " (void) printf(dgettext(TEXT_DOMAIN, "This "
"pool uses the following feature(s) not " "pool uses the following feature(s) not "
"supported by this system:\n")); "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, if (nvlist_exists(nvinfo,
ZPOOL_CONFIG_CAN_RDONLY)) { ZPOOL_CONFIG_CAN_RDONLY)) {
(void) printf(dgettext(TEXT_DOMAIN, (void) printf(dgettext(TEXT_DOMAIN,
@ -2294,8 +2302,11 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
break; break;
default: default:
(void) zpool_standard_error(hdl, error, desc); (void) zpool_standard_error(hdl, error, desc);
memset(buf, 0, 2048);
zpool_explain_recover(hdl, zpool_explain_recover(hdl,
newname ? origname : thename, -error, nv); newname ? origname : thename, -error, nv,
buf, 2048);
(void) printf("\t%s", buf);
break; 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. * 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 * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL
* spare; but FALSE if its an INUSE spare. * 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 * static nvlist_t *
vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, 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; uint_t c, children;
nvlist_t **child; 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; uint64_t is_log;
const char *srchkey; const char *srchkey;
nvpair_t *pair = nvlist_next_nvpair(search, NULL); nvpair_t *pair = nvlist_next_nvpair(search, NULL);
const char *tmp = NULL;
boolean_t is_root;
/* Nothing to look for */ /* Nothing to look for */
if (search == NULL || pair == NULL) 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 */ /* Obtain the key we will use to search */
srchkey = nvpair_name(pair); 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)) { switch (nvpair_type(pair)) {
case DATA_TYPE_UINT64: case DATA_TYPE_UINT64:
if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) { 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++) { for (c = 0; c < children; c++) {
if ((ret = vdev_to_nvlist_iter(child[c], search, 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 * The 'is_log' value is only set for the toplevel
* vdev, not the leaf vdevs. So we always lookup the * 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) { is_log) {
*log = B_TRUE; *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) { &child, &children) == 0) {
for (c = 0; c < children; c++) { for (c = 0; c < children; c++) {
if ((ret = vdev_to_nvlist_iter(child[c], search, 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; *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) { &child, &children) == 0) {
for (c = 0; c < children; c++) { for (c = 0; c < children; c++) {
if ((ret = vdev_to_nvlist_iter(child[c], search, if ((ret = vdev_to_nvlist_iter(child[c], search,
avail_spare, l2cache, NULL)) != NULL) { avail_spare, l2cache, NULL, return_parent))
!= NULL) {
*l2cache = B_TRUE; *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; *l2cache = B_FALSE;
if (log != NULL) if (log != NULL)
*log = B_FALSE; *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); fnvlist_free(search);
return (ret); 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 * static nvlist_t *
zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare, __zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
boolean_t *l2cache, boolean_t *log) boolean_t *l2cache, boolean_t *log, boolean_t return_parent)
{ {
char *end; char *end;
nvlist_t *nvroot, *search, *ret; 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; *l2cache = B_FALSE;
if (log != NULL) if (log != NULL)
*log = B_FALSE; *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); fnvlist_free(search);
return (ret); 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. * Convert a vdev path to a GUID. Returns GUID or 0 on error.
* *

View File

@ -68,6 +68,7 @@
* as necessary. * as necessary.
*/ */
#define URI_REGEX "^\\([A-Za-z][A-Za-z0-9+.\\-]*\\):" #define URI_REGEX "^\\([A-Za-z][A-Za-z0-9+.\\-]*\\):"
#define STR_NUMS "0123456789"
int int
libzfs_errno(libzfs_handle_t *hdl) 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 static void
zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type) 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"); (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 * Display a single line of output, according to the settings in the callback
* structure. * structure.
@ -1484,6 +1590,26 @@ zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
(void) printf("\n"); (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 * Given a numeric suffix, convert the value into a number of bits that the
* resulting value must be shifted. * resulting value must be shifted.
@ -1985,6 +2111,34 @@ zfs_version_print(void)
return (0); 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 * Return 1 if the user requested ANSI color output, and our terminal supports
* it. Return 0 for no color. * 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_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_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='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_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='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='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='getmntany' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@ -1109,6 +1111,18 @@
<parameter type-id='3502e3ff' name='timestamp_fmt'/> <parameter type-id='3502e3ff' name='timestamp_fmt'/>
<return type-id='48b5725f'/> <return type-id='48b5725f'/>
</function-decl> </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>
<abi-instr address-size='64' path='lib/libzfs_core/libzfs_core.c' language='LANG_C99'> <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'> <array-type-def dimensions='1' type-id='03085adc' size-in-bits='192' id='083f8d58'>

View File

@ -41,6 +41,7 @@
.Cm list .Cm list
.Op Fl r Ns | Ns Fl d Ar depth .Op Fl r Ns | Ns Fl d Ar depth
.Op Fl Hp .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 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
.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. Used for scripting mode.
Do not print headers and separate fields by a single tab instead of arbitrary Do not print headers and separate fields by a single tab instead of arbitrary
white space. 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 .It Fl d Ar depth
Recursively display any children of the dataset, limiting the recursion to Recursively display any children of the dataset, limiting the recursion to
.Ar depth . .Ar depth .
@ -186,6 +192,161 @@ pool/home 315K 457G 21K /export/home
pool/home/anne 18K 457G 18K /export/home/anne pool/home/anne 18K 457G 18K /export/home/anne
pool/home/bob 276K 457G 276K /export/home/bob pool/home/bob 276K 457G 276K /export/home/bob
.Ed .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 .Sh SEE ALSO
.Xr zfsprops 7 , .Xr zfsprops 7 ,

View File

@ -39,6 +39,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm zfs .Nm zfs
.Cm mount .Cm mount
.Op Fl j
.Nm zfs .Nm zfs
.Cm mount .Cm mount
.Op Fl Oflv .Op Fl Oflv
@ -54,8 +55,13 @@
.It Xo .It Xo
.Nm zfs .Nm zfs
.Cm mount .Cm mount
.Op Fl j
.Xc .Xc
Displays all ZFS file systems currently mounted. 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 .It Xo
.Nm zfs .Nm zfs
.Cm mount .Cm mount

View File

@ -46,6 +46,7 @@
.Cm get .Cm get
.Op Fl r Ns | Ns Fl d Ar depth .Op Fl r Ns | Ns Fl d Ar depth
.Op Fl Hp .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 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 s Ar source Ns Oo , Ns Ar source Oc Ns Oc
.Oo Fl t Ar type Ns Oo , Ns Ar type Oc Ns Oc .Oo Fl t Ar type Ns Oo , Ns Ar type Oc Ns Oc
@ -91,6 +92,7 @@ dataset.
.Cm get .Cm get
.Op Fl r Ns | Ns Fl d Ar depth .Op Fl r Ns | Ns Fl d Ar depth
.Op Fl Hp .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 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 s Ar source Ns Oo , Ns Ar source Oc Ns Oc
.Oo Fl t Ar type Ns Oo , Ns Ar type 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 can be used to display all properties that apply to the given dataset's type
.Pq Sy filesystem , volume , snapshot , No or Sy bookmark . .Pq Sy filesystem , volume , snapshot , No or Sy bookmark .
.Bl -tag -width "-s source" .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 .It Fl H
Display output in a form more easily parsed by scripts. Display output in a form more easily parsed by scripts.
Any headers are omitted, and fields are explicitly separated by a single tab 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 on
.Ed .Ed
.Pp .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 The following command lists all properties with local settings for
.Ar pool/home/bob : .Ar pool/home/bob :
.Bd -literal -compact -offset Ds .Bd -literal -compact -offset Ds

View File

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

View File

@ -37,6 +37,7 @@
.Nm zpool .Nm zpool
.Cm get .Cm get
.Op Fl Hp .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 .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 .Sy all Ns | Ns Ar property Ns Oo , Ns Ar property Oc Ns
.Oo Ar pool Oc Ns .Oo Ar pool Oc Ns
@ -44,6 +45,7 @@
.Nm zpool .Nm zpool
.Cm get .Cm get
.Op Fl Hp .Op Fl Hp
.Op Fl j Op Ar --json-int
.Op Fl o Ar field Ns Oo , Ns Ar field Oc Ns .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 .Sy all Ns | Ns Ar property Ns Oo , Ns Ar property Oc Ns
.Ar pool .Ar pool
@ -67,6 +69,7 @@
.Nm zpool .Nm zpool
.Cm get .Cm get
.Op Fl Hp .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 .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 .Sy all Ns | Ns Ar property Ns Oo , Ns Ar property Oc Ns
.Oo Ar pool Oc Ns .Oo Ar pool Oc Ns
@ -95,6 +98,14 @@ See the
.Xr zpoolprops 7 .Xr zpoolprops 7
manual page for more information on the available pool properties. manual page for more information on the available pool properties.
.Bl -tag -compact -offset Ds -width "-o field" .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 .It Fl H
Scripted mode. Scripted mode.
Do not display headers, and separate fields by a single tab instead of arbitrary 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 .It Xo
.Nm zpool .Nm zpool
.Cm get .Cm get
.Op Fl j Op Ar --json-int
.Op Fl Hp .Op Fl Hp
.Op Fl o Ar field Ns Oo , Ns Ar field Oc Ns .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 .Sy all Ns | Ns Ar property Ns Oo , Ns Ar property Oc Ns
@ -145,6 +157,11 @@ See the
.Xr vdevprops 7 .Xr vdevprops 7
manual page for more information on the available pool properties. manual page for more information on the available pool properties.
.Bl -tag -compact -offset Ds -width "-o field" .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 .It Fl H
Scripted mode. Scripted mode.
Do not display headers, and separate fields by a single tab instead of arbitrary Do not display headers, and separate fields by a single tab instead of arbitrary

View File

@ -37,6 +37,7 @@
.Nm zpool .Nm zpool
.Cm list .Cm list
.Op Fl HgLpPv .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 o Ar property Ns Oo , Ns Ar property Oc Ns
.Op Fl T Sy u Ns | Ns Sy d .Op Fl T Sy u Ns | Ns Sy d
.Oo Ar pool Oc Ns .Oo Ar pool Oc Ns
@ -58,6 +59,14 @@ is specified, the command exits after
.Ar count .Ar count
reports are printed. reports are printed.
.Bl -tag -width Ds .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 .It Fl g
Display vdev GUIDs instead of the normal device names. Display vdev GUIDs instead of the normal device names.
These GUIDs can be used in place of device names for the zpool 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 - - - - - sda - - - - -
sdb - - - 10G - sdb - - - 10G -
sdc - - - - - 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 .Ed
. .
.Sh SEE ALSO .Sh SEE ALSO

View File

@ -41,6 +41,7 @@
.Op Fl c Op Ar SCRIPT1 Ns Oo , Ns Ar SCRIPT2 Oc Ns .Op Fl c Op Ar SCRIPT1 Ns Oo , Ns Ar SCRIPT2 Oc Ns
.Oo Ar pool Oc Ns .Oo Ar pool Oc Ns
.Op Ar interval Op Ar count .Op Ar interval Op Ar count
.Op Fl j Op Ar --json-int, --json-flat-vdevs, --json-pool-key-guid
. .
.Sh DESCRIPTION .Sh DESCRIPTION
Displays the detailed health status for the given pools. Displays the detailed health status for the given pools.
@ -69,6 +70,17 @@ See the
option of option of
.Nm zpool Cm iostat .Nm zpool Cm iostat
for complete details. 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 .It Fl D
Display a histogram of deduplication statistics, showing the allocated Display a histogram of deduplication statistics, showing the allocated
.Pq physically present on disk .Pq physically present on disk
@ -159,6 +171,175 @@ rpool 14.6G 54.9G 4 55 250K 2.69M
---------- ----- ----- ----- ----- ----- ----- ---- ---------- ----- ----- ----- ----- ----- ----- ----
.Ed .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 .Sh SEE ALSO
.Xr zpool-events 8 , .Xr zpool-events 8 ,
.Xr zpool-history 8 , .Xr zpool-history 8 ,

View File

@ -38,6 +38,7 @@
.Fl ?V .Fl ?V
.Nm .Nm
.Cm version .Cm version
.Op Fl j
.Nm .Nm
.Cm subcommand .Cm subcommand
.Op Ar arguments .Op Ar arguments
@ -79,10 +80,14 @@ Displays a help message.
.It Xo .It Xo
.Nm .Nm
.Cm version .Cm version
.Op Fl j
.Xc .Xc
Displays the software version of the Displays the software version of the
.Nm .Nm
userland utility and the ZFS kernel module. userland utility and the ZFS kernel module.
Use
.Fl j
option to output in JSON format.
.El .El
. .
.Ss Creation .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'] 'clean_mirror_003_pos', 'clean_mirror_004_pos']
tags = ['functional', 'clean_mirror'] tags = ['functional', 'clean_mirror']
[tests/functional/cli_root/json]
tests = ['json_sanity']
tags = ['functional', 'cli_root', 'json']
[tests/functional/cli_root/zinject] [tests/functional/cli_root/zinject]
tests = ['zinject_args'] tests = ['zinject_args']
pre = pre =

View File

@ -46,6 +46,7 @@ export SYSTEM_FILES_COMMON='awk
hostname hostname
id id
iostat iostat
jq
kill kill
ksh ksh
ldd 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/clean_mirror_004_pos.ksh \
functional/clean_mirror/cleanup.ksh \ functional/clean_mirror/cleanup.ksh \
functional/clean_mirror/setup.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/zinject/zinject_args.ksh \
functional/cli_root/zdb/zdb_002_pos.ksh \ functional/cli_root/zdb/zdb_002_pos.ksh \
functional/cli_root/zdb/zdb_003_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}