JSON output support for zfs version and zfs get

This commit adds support for JSON output for zfs version and zfs get
commands. '-j' flag can be used to get output in JSON format.

Information is collected in nvlist objects which is later printed in
JSON format. Existing options that work for zfs get and zfs version
also work with '-j' flag.

man pages for zfs get and zfs version are updated accordingly.

Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Ameer Hamza <ahamza@ixsystems.com>
Signed-off-by: Umer Saleem <usaleem@ixsystems.com>
Closes #16217
This commit is contained in:
Umer Saleem
2024-04-05 21:02:30 +05:00
committed by Brian Behlendorf
parent 6c7d41a643
commit aa15b60e58
5 changed files with 412 additions and 15 deletions
+134
View File
@@ -68,6 +68,7 @@
* as necessary.
*/
#define URI_REGEX "^\\([A-Za-z][A-Za-z0-9+.\\-]*\\):"
#define STR_NUMS "0123456789"
int
libzfs_errno(libzfs_handle_t *hdl)
@@ -1267,6 +1268,14 @@ zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp)
* ================================================================
*/
void
zcmd_print_json(nvlist_t *nvl)
{
nvlist_print_json(stdout, nvl);
(void) putchar('\n');
nvlist_free(nvl);
}
static void
zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
{
@@ -1393,6 +1402,103 @@ zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
(void) printf("\n");
}
/*
* Add property value and source to provided nvlist, according to
* settings in cb structure. Later to be printed in JSON format.
*/
int
zprop_nvlist_one_property(const char *propname,
const char *value, zprop_source_t sourcetype, const char *source,
const char *recvd_value, nvlist_t *nvl, boolean_t as_int)
{
int ret = 0;
nvlist_t *src_nv, *prop;
boolean_t all_numeric = strspn(value, STR_NUMS) == strlen(value);
src_nv = prop = NULL;
if ((nvlist_alloc(&prop, NV_UNIQUE_NAME, 0) != 0) ||
(nvlist_alloc(&src_nv, NV_UNIQUE_NAME, 0) != 0)) {
ret = -1;
goto err;
}
if (as_int && all_numeric) {
uint64_t val;
sscanf(value, "%lld", (u_longlong_t *)&val);
if (nvlist_add_uint64(prop, "value", val) != 0) {
ret = -1;
goto err;
}
} else {
if (nvlist_add_string(prop, "value", value) != 0) {
ret = -1;
goto err;
}
}
switch (sourcetype) {
case ZPROP_SRC_NONE:
if (nvlist_add_string(src_nv, "type", "NONE") != 0 ||
(nvlist_add_string(src_nv, "data", "-") != 0)) {
ret = -1;
goto err;
}
break;
case ZPROP_SRC_DEFAULT:
if (nvlist_add_string(src_nv, "type", "DEFAULT") != 0 ||
(nvlist_add_string(src_nv, "data", "-") != 0)) {
ret = -1;
goto err;
}
break;
case ZPROP_SRC_LOCAL:
if (nvlist_add_string(src_nv, "type", "LOCAL") != 0 ||
(nvlist_add_string(src_nv, "data", "-") != 0)) {
ret = -1;
goto err;
}
break;
case ZPROP_SRC_TEMPORARY:
if (nvlist_add_string(src_nv, "type", "TEMPORARY") != 0 ||
(nvlist_add_string(src_nv, "data", "-") != 0)) {
ret = -1;
goto err;
}
break;
case ZPROP_SRC_INHERITED:
if (nvlist_add_string(src_nv, "type", "INHERITED") != 0 ||
(nvlist_add_string(src_nv, "data", source) != 0)) {
ret = -1;
goto err;
}
break;
case ZPROP_SRC_RECEIVED:
if (nvlist_add_string(src_nv, "type", "RECEIVED") != 0 ||
(nvlist_add_string(src_nv, "data",
(recvd_value == NULL ? "-" : recvd_value)) != 0)) {
ret = -1;
goto err;
}
break;
default:
assert(!"unhandled zprop_source_t");
if (nvlist_add_string(src_nv, "type",
"unhandled zprop_source_t") != 0) {
ret = -1;
goto err;
}
}
if ((nvlist_add_nvlist(prop, "source", src_nv) != 0) ||
(nvlist_add_nvlist(nvl, propname, prop)) != 0) {
ret = -1;
goto err;
}
err:
nvlist_free(src_nv);
nvlist_free(prop);
return (ret);
}
/*
* Display a single line of output, according to the settings in the callback
* structure.
@@ -1999,6 +2105,34 @@ zfs_version_print(void)
return (0);
}
/*
* Returns an nvlist with both zfs userland and kernel versions.
* Returns NULL on error.
*/
nvlist_t *
zfs_version_nvlist(void)
{
nvlist_t *nvl;
char kmod_ver[64];
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, 64, "zfs-kmod-%s", kver);
if (nvlist_add_string(nvl, "kernel", kmod_ver) != 0)
goto err;
return (nvl);
err:
nvlist_free(nvl);
return (NULL);
}
/*
* Return 1 if the user requested ANSI color output, and our terminal supports
* it. Return 0 for no color.