From c58b352673e88983cd2b8a388a8c7625f35e2f18 Mon Sep 17 00:00:00 2001 From: Adam Stevko Date: Tue, 25 Mar 2014 01:47:26 +0100 Subject: [PATCH] 3993 zpool(1M) and zfs(1M) should support -p for "list" and "get" 4700 "zpool get" doesn't support -H or -o options Reviewed by: Dan McDonald Reviewed by: Matthew Ahrens Approved by: Robert Mustacchi --- usr/src/cmd/zpool/zpool_main.c | 126 ++++++++++++++++++++++++---- usr/src/lib/libbe/common/be_list.c | 2 +- usr/src/lib/libgrubmgmt/common/libgrub_fs.c | 3 +- usr/src/lib/libzfs/common/libzfs.h | 2 +- usr/src/lib/libzfs/common/libzfs_dataset.c | 4 +- usr/src/lib/libzfs/common/libzfs_pool.c | 26 ++++-- usr/src/man/man1m/zpool.1m | 47 ++++++++++- 7 files changed, 177 insertions(+), 33 deletions(-) diff --git a/usr/src/cmd/zpool/zpool_main.c b/usr/src/cmd/zpool/zpool_main.c index d8839b6571..afbfd21afd 100644 --- a/usr/src/cmd/zpool/zpool_main.c +++ b/usr/src/cmd/zpool/zpool_main.c @@ -227,7 +227,7 @@ get_usage(zpool_help_t idx) { return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval " "[count]]\n")); case HELP_LIST: - return (gettext("\tlist [-H] [-o property[,...]] " + return (gettext("\tlist [-Hp] [-o property[,...]] " "[-T d|u] [pool] ... [interval [count]]\n")); case HELP_OFFLINE: return (gettext("\toffline [-t] ...\n")); @@ -250,8 +250,8 @@ get_usage(zpool_help_t idx) { "\tupgrade -v\n" "\tupgrade [-V version] <-a | pool ...>\n")); case HELP_GET: - return (gettext("\tget <\"all\" | property[,...]> " - " ...\n")); + return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] " + "<\"all\" | property[,...]> ...\n")); case HELP_SET: return (gettext("\tset \n")); case HELP_SPLIT: @@ -2619,6 +2619,7 @@ typedef struct list_cbdata { int cb_namewidth; boolean_t cb_scripted; zprop_list_t *cb_proplist; + boolean_t cb_literal; } list_cbdata_t; /* @@ -2714,7 +2715,7 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb) zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0) propstr = "-"; else if (zpool_get_prop(zhp, pl->pl_prop, property, - sizeof (property), NULL) != 0) + sizeof (property), NULL, cb->cb_literal) != 0) propstr = "-"; else propstr = property; @@ -2865,12 +2866,13 @@ list_callback(zpool_handle_t *zhp, void *data) } /* - * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] + * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]] * * -H Scripted mode. Don't display headers, and separate properties * by a single tab. * -o List of properties to display. Defaults to * "name,size,allocated,free,capacity,health,altroot" + * -p Diplay values in parsable (exact) format. * -T Display a timestamp in date(1) or Unix format * * List all pools in the system, whether or not they're healthy. Output space @@ -2891,7 +2893,7 @@ zpool_do_list(int argc, char **argv) boolean_t first = B_TRUE; /* check options */ - while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) { + while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) { switch (c) { case 'H': cb.cb_scripted = B_TRUE; @@ -2899,6 +2901,9 @@ zpool_do_list(int argc, char **argv) case 'o': props = optarg; break; + case 'p': + cb.cb_literal = B_TRUE; + break; case 'T': get_timestamp_arg(*optarg); break; @@ -4977,7 +4982,7 @@ get_callback(zpool_handle_t *zhp, void *data) } } else { if (zpool_get_prop(zhp, pl->pl_prop, value, - sizeof (value), &srctype) != 0) + sizeof (value), &srctype, cbp->cb_literal) != 0) continue; zprop_print_one_property(zpool_get_name(zhp), cbp, @@ -4988,20 +4993,32 @@ get_callback(zpool_handle_t *zhp, void *data) return (0); } +/* + * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> ... + * + * -H Scripted mode. Don't display headers, and separate properties + * by a single tab. + * -o List of columns to display. Defaults to + * "name,property,value,source". + * -p Diplay values in parsable (exact) format. + * + * Get properties of pools in the system. Output space statistics + * for each one as well as other attributes. + */ int zpool_do_get(int argc, char **argv) { zprop_get_cbdata_t cb = { 0 }; zprop_list_t fake_name = { 0 }; int ret; - - if (argc < 2) { - (void) fprintf(stderr, gettext("missing property " - "argument\n")); - usage(B_FALSE); - } + int c, i; + char *value; cb.cb_first = B_TRUE; + + /* + * Set up default columns and sources. + */ cb.cb_sources = ZPROP_SRC_ALL; cb.cb_columns[0] = GET_COL_NAME; cb.cb_columns[1] = GET_COL_PROPERTY; @@ -5009,10 +5026,89 @@ zpool_do_get(int argc, char **argv) cb.cb_columns[3] = GET_COL_SOURCE; cb.cb_type = ZFS_TYPE_POOL; - if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist, + /* check options */ + while ((c = getopt(argc, argv, ":Hpo:")) != -1) { + switch (c) { + case 'p': + cb.cb_literal = B_TRUE; + break; + case 'H': + cb.cb_scripted = B_TRUE; + break; + case 'o': + bzero(&cb.cb_columns, sizeof (cb.cb_columns)); + i = 0; + while (*optarg != '\0') { + static char *col_subopts[] = + { "name", "property", "value", "source", + "all", NULL }; + + if (i == ZFS_GET_NCOLS) { + (void) fprintf(stderr, gettext("too " + "many fields given to -o " + "option\n")); + usage(B_FALSE); + } + + switch (getsubopt(&optarg, col_subopts, + &value)) { + case 0: + cb.cb_columns[i++] = GET_COL_NAME; + break; + case 1: + cb.cb_columns[i++] = GET_COL_PROPERTY; + break; + case 2: + cb.cb_columns[i++] = GET_COL_VALUE; + break; + case 3: + cb.cb_columns[i++] = GET_COL_SOURCE; + break; + case 4: + if (i > 0) { + (void) fprintf(stderr, + gettext("\"all\" conflicts " + "with specific fields " + "given to -o option\n")); + usage(B_FALSE); + } + cb.cb_columns[0] = GET_COL_NAME; + cb.cb_columns[1] = GET_COL_PROPERTY; + cb.cb_columns[2] = GET_COL_VALUE; + cb.cb_columns[3] = GET_COL_SOURCE; + i = ZFS_GET_NCOLS; + break; + default: + (void) fprintf(stderr, + gettext("invalid column name " + "'%s'\n"), value); + usage(B_FALSE); + } + } + break; + case '?': + (void) fprintf(stderr, gettext("invalid option '%c'\n"), + optopt); + usage(B_FALSE); + } + } + + argc -= optind; + argv += optind; + + if (argc < 1) { + (void) fprintf(stderr, gettext("missing property " + "argument\n")); + usage(B_FALSE); + } + + if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist, ZFS_TYPE_POOL) != 0) usage(B_FALSE); + argc--; + argv++; + if (cb.cb_proplist != NULL) { fake_name.pl_prop = ZPOOL_PROP_NAME; fake_name.pl_width = strlen(gettext("NAME")); @@ -5020,7 +5116,7 @@ zpool_do_get(int argc, char **argv) cb.cb_proplist = &fake_name; } - ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist, + ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist, get_callback, &cb); if (cb.cb_proplist == &fake_name) diff --git a/usr/src/lib/libbe/common/be_list.c b/usr/src/lib/libbe/common/be_list.c index 29ba142bc0..1733f6dc43 100644 --- a/usr/src/lib/libbe/common/be_list.c +++ b/usr/src/lib/libbe/common/be_list.c @@ -876,7 +876,7 @@ be_get_node_data( } (void) zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf, - ZFS_MAXPROPLEN, NULL); + ZFS_MAXPROPLEN, NULL, B_FALSE); if (be_has_grub() && (be_default_grub_bootfs(rpool, &grub_default_bootfs) == BE_SUCCESS) && grub_default_bootfs != NULL) diff --git a/usr/src/lib/libgrubmgmt/common/libgrub_fs.c b/usr/src/lib/libgrubmgmt/common/libgrub_fs.c index 28a47deabb..d53b89761a 100644 --- a/usr/src/lib/libgrubmgmt/common/libgrub_fs.c +++ b/usr/src/lib/libgrubmgmt/common/libgrub_fs.c @@ -161,7 +161,8 @@ get_zfs_root(zfs_handle_t *zfh, grub_fs_t *fs, grub_root_t *root) sizeof (root->gr_physpath))) == 0 && (ret = zpool_get_prop(zph, ZPOOL_PROP_BOOTFS, root->gr_fs[GRBM_ZFS_BOOTFS].gfs_dev, - sizeof (root->gr_fs[GRBM_ZFS_BOOTFS].gfs_dev), NULL)) == 0) { + sizeof (root->gr_fs[GRBM_ZFS_BOOTFS].gfs_dev), NULL, + B_FALSE)) == 0) { (void) strlcpy(root->gr_fs[GRBM_ZFS_TOPFS].gfs_dev, name, sizeof (root->gr_fs[GRBM_ZFS_TOPFS].gfs_dev)); diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h index b99569795e..1bc53fc26d 100644 --- a/usr/src/lib/libzfs/common/libzfs.h +++ b/usr/src/lib/libzfs/common/libzfs.h @@ -266,7 +266,7 @@ extern int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *, char *); */ extern int zpool_set_prop(zpool_handle_t *, const char *, const char *); extern int zpool_get_prop(zpool_handle_t *, zpool_prop_t, char *, - size_t proplen, zprop_source_t *); + size_t proplen, zprop_source_t *, boolean_t); extern uint64_t zpool_get_prop_int(zpool_handle_t *, zpool_prop_t, zprop_source_t *); diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c index 9acb7acd32..cc79136539 100644 --- a/usr/src/lib/libzfs/common/libzfs_dataset.c +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c @@ -2195,8 +2195,8 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, } if ((zpool_get_prop(zhp->zpool_hdl, - ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL)) || - (strcmp(root, "-") == 0)) + ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL, + B_FALSE)) || (strcmp(root, "-") == 0)) root[0] = '\0'; /* * Special case an alternate root of '/'. This will diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c index 3fac8c3b93..8a9dae0764 100644 --- a/usr/src/lib/libzfs/common/libzfs_pool.c +++ b/usr/src/lib/libzfs/common/libzfs_pool.c @@ -212,7 +212,7 @@ zpool_state_to_name(vdev_state_t state, vdev_aux_t aux) */ int zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, - zprop_source_t *srctype) + zprop_source_t *srctype, boolean_t literal) { uint64_t intval; const char *strval; @@ -244,9 +244,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src), len); - if (srctype != NULL) - *srctype = src; - return (0); + break; } /* FALLTHROUGH */ default: @@ -278,12 +276,22 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len, case ZPOOL_PROP_FREE: case ZPOOL_PROP_FREEING: case ZPOOL_PROP_EXPANDSZ: - (void) zfs_nicenum(intval, buf, len); + if (literal) { + (void) snprintf(buf, len, "%llu", + (u_longlong_t)intval); + } else { + (void) zfs_nicenum(intval, buf, len); + } break; case ZPOOL_PROP_CAPACITY: - (void) snprintf(buf, len, "%llu%%", - (u_longlong_t)intval); + if (literal) { + (void) snprintf(buf, len, "%llu", + (u_longlong_t)intval); + } else { + (void) snprintf(buf, len, "%llu%%", + (u_longlong_t)intval); + } break; case ZPOOL_PROP_DEDUPRATIO: @@ -377,7 +385,7 @@ zpool_is_bootable(zpool_handle_t *zhp) char bootfs[ZPOOL_MAXNAMELEN]; return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, - sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-", + sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-", sizeof (bootfs)) != 0); } @@ -774,7 +782,7 @@ zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp) if (entry->pl_prop != ZPROP_INVAL && zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), - NULL) == 0) { + NULL, B_FALSE) == 0) { if (strlen(buf) > entry->pl_width) entry->pl_width = strlen(buf); } diff --git a/usr/src/man/man1m/zpool.1m b/usr/src/man/man1m/zpool.1m index 785611cb38..c7e7e054dc 100644 --- a/usr/src/man/man1m/zpool.1m +++ b/usr/src/man/man1m/zpool.1m @@ -61,7 +61,7 @@ zpool \- configures ZFS storage pools .LP .nf -\fBzpool get\fR "\fIall\fR" | \fIproperty\fR[,...] \fIpool\fR ... +\fBzpool get\fR [\fB-Hp\fR] [\fB-o \fR\fIfield\fR[,...]] "\fIall\fR" | \fIproperty\fR[,...] \fIpool\fR ... .fi .LP @@ -93,7 +93,7 @@ zpool \- configures ZFS storage pools .LP .nf -\fBzpool list\fR [\fB-T\fR \fBu\fR | \fBd\fR ] [\fB-Hv\fR] [\fB-o\fR \fIproperty\fR[,...]] [\fIpool\fR] ... [\fIinterval\fR[\fIcount\fR]] +\fBzpool list\fR [\fB-T\fR \fBu\fR | \fBd\fR ] [\fB-Hpv\fR] [\fB-o\fR \fIproperty\fR[,...]] [\fIpool\fR] ... [\fIinterval\fR[\fIcount\fR]] .fi .LP @@ -1151,7 +1151,8 @@ is currently being used. This may lead to potential data corruption. .sp .ne 2 .na -\fB\fBzpool get\fR "\fIall\fR" | \fIproperty\fR[,...] \fIpool\fR ...\fR +\fB\fBzpool get\fR [\fB-Hp\fR] [\fB-o \fR\fIfield\fR[,...]] "\fIall\fR" | \fIproperty\fR[,...] +\fIpool\fR ...\fR .ad .sp .6 .RS 4n @@ -1161,7 +1162,7 @@ the following fields: .sp .in +2 .nf - name Name of storage pool + name Name of storage pool property Property name value Property value source Property source, either 'default' or 'local'. @@ -1171,6 +1172,35 @@ the following fields: See the "Properties" section for more information on the available pool properties. + +.sp +.ne 2 +.na +\fB\fB-H\fR\fR +.ad +.RS 12n +Scripted mode. Do not display headers, and separate fields by a single tab +instead of arbitrary space. +.RE + +.sp +.ne 2 +.na +\fB\fB-p\fR\fR +.ad +.RS 6n +Display numbers in parsable (exact) values. +.RE + +.sp +.ne 2 +.na +\fB\fB-o\fR \fIfield\fR\fR +.ad +.RS 6n +A comma-separated list of columns to display. \fBname,property,value,source\fR +is the default value. +.RE .RE .sp @@ -1604,6 +1634,15 @@ instead of arbitrary space. .sp .ne 2 .na +\fB\fB-p\fR\fR +.ad +.RS 12n +Display numbers in parsable (exact) values. +.RE + +.sp +.ne 2 +.na \fB\fB-o\fR \fIprops\fR\fR .ad .RS 12n -- 2.11.4.GIT