From f7b518c3b8cb5fc70851913f7b017d965ce54579 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Wed, 21 Nov 2018 12:51:35 -0800 Subject: [PATCH] Fix 'zpool list -v' alignment The verbose output of 'zpool list' was not correctly aligned due to differences in the vdev name lengths. Minimally update the code the correct the alignment using the same strategy employed by 'zpool status'. Missing dashes were added for the empty defaults columns, and the vdev state is now printed for all vdevs. The ALTROOT properly was removed from the default output to get close to staying within an 80 character width. At least for short vdev names. Signed-off-by: Brian Behlendorf --- cmd/zpool/zpool_main.c | 159 +++++++++++++++++++++++++++-------------- man/man8/zpool.8 | 2 +- 2 files changed, 107 insertions(+), 54 deletions(-) diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index 0b820a39a2e8..a9eaf3cb0f57 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -4266,34 +4266,25 @@ get_columns(void) return (columns); } -int -get_namewidth(zpool_handle_t *zhp, void *data) +static int +get_namewidth(zpool_handle_t *zhp, int *width, int flags, boolean_t verbose) { - iostat_cbdata_t *cb = data; nvlist_t *config, *nvroot; - int columns; + int tmp_width = *width; if ((config = zpool_get_config(zhp, NULL)) != NULL) { verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); unsigned int poolname_len = strlen(zpool_get_name(zhp)); - if (!cb->cb_verbose) - cb->cb_namewidth = MAX(poolname_len, cb->cb_namewidth); - else - cb->cb_namewidth = MAX(poolname_len, - max_width(zhp, nvroot, 0, cb->cb_namewidth, - cb->cb_name_flags)); + if (verbose == B_FALSE) { + tmp_width = MAX(poolname_len, tmp_width); + } else { + tmp_width = MAX(poolname_len, + max_width(zhp, nvroot, 0, tmp_width, flags)); + } } - /* - * The width must be at least 10, but may be as large as the - * column width - 42 so that we can still fit in one line. - */ - columns = get_columns(); - if (cb->cb_namewidth < 10) - cb->cb_namewidth = 10; - if (cb->cb_namewidth > columns - 42) - cb->cb_namewidth = columns - 42; + *width = tmp_width; return (0); } @@ -4712,6 +4703,32 @@ print_zpool_script_list(char *subcommand) free(sp); } +static int +get_namewidth_iostat(zpool_handle_t *zhp, void *data) +{ + iostat_cbdata_t *cb = data; + int error, width = cb->cb_namewidth; + + error = get_namewidth(zhp, &width, cb->cb_name_flags, cb->cb_verbose); + if (error) + return (error); + + /* + * The width must be at least 10, but may be as large as the + * column width - 42 so that we can still fit in one line. + */ + int columns = get_columns(); + + if (width < 10) + width = 10; + if (width > columns - 42) + width = columns - 42; + + cb->cb_namewidth = width; + + return (0); +} + /* * zpool iostat [[-c [script1,script2,...]] [-lq]|[-rw]] [-ghHLpPvy] [-n name] * [-T d|u] [[ pool ...]|[pool vdev ...]|[vdev ...]] @@ -5013,8 +5030,8 @@ zpool_do_iostat(int argc, char **argv) * for the pool / device name column across all pools. */ cb.cb_namewidth = 0; - (void) pool_list_iter(list, B_FALSE, get_namewidth, - &cb); + (void) pool_list_iter(list, B_FALSE, + get_namewidth_iostat, &cb); if (timestamp_fmt != NODATE) print_timestamp(timestamp_fmt); @@ -5225,8 +5242,8 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb) } static void -print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted, - boolean_t valid, enum zfs_nicenum_format format) +print_one_column(zpool_prop_t prop, uint64_t value, const char *str, + boolean_t scripted, boolean_t valid, enum zfs_nicenum_format format) { char propval[64]; boolean_t fixed; @@ -5235,6 +5252,7 @@ print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted, switch (prop) { case ZPOOL_PROP_EXPANDSZ: case ZPOOL_PROP_CHECKPOINT: + case ZPOOL_PROP_DEDUPRATIO: if (value == 0) (void) strlcpy(propval, "-", sizeof (propval)); else @@ -5262,6 +5280,10 @@ print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted, value < 1000 ? "%1.2f%%" : value < 10000 ? "%2.1f%%" : "%3.0f%%", value / 100.0); break; + case ZPOOL_PROP_HEALTH: + strlcpy(propval, str, sizeof (propval)); + width = strlen(propval); + break; default: zfs_nicenum_format(value, propval, sizeof (propval), format); } @@ -5281,7 +5303,7 @@ print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted, */ void print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, - list_cbdata_t *cb, int depth) + list_cbdata_t *cb, int depth, boolean_t isspare) { nvlist_t **child; vdev_stat_t *vs; @@ -5289,7 +5311,8 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, char *vname; boolean_t scripted = cb->cb_scripted; uint64_t islog = B_FALSE; - char *dashes = "%-*s - - - - - -\n"; + char *dashes = "%-*s - - - - " + "- - - - -\n"; verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &c) == 0); @@ -5298,6 +5321,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, boolean_t toplevel = (vs->vs_space != 0); uint64_t cap; enum zfs_nicenum_format format; + const char *state; if (cb->cb_literal) format = ZFS_NICENUM_RAW; @@ -5321,24 +5345,35 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, * 'toplevel' boolean value is passed to the print_one_column() * to indicate that the value is valid. */ - print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted, + print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, NULL, scripted, toplevel, format); - print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted, - toplevel, format); - print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc, + print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, NULL, scripted, toplevel, format); + print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc, + NULL, scripted, toplevel, format); print_one_column(ZPOOL_PROP_CHECKPOINT, - vs->vs_checkpoint_space, scripted, toplevel, format); - print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted, - B_TRUE, format); + vs->vs_checkpoint_space, NULL, scripted, toplevel, format); + print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, NULL, + scripted, B_TRUE, format); print_one_column(ZPOOL_PROP_FRAGMENTATION, - vs->vs_fragmentation, scripted, + vs->vs_fragmentation, NULL, scripted, (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel), format); cap = (vs->vs_space == 0) ? 0 : (vs->vs_alloc * 10000 / vs->vs_space); - print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel, - format); + print_one_column(ZPOOL_PROP_CAPACITY, cap, NULL, + scripted, toplevel, format); + print_one_column(ZPOOL_PROP_DEDUPRATIO, 0, NULL, + scripted, toplevel, format); + state = zpool_state_to_name(vs->vs_state, vs->vs_aux); + if (isspare) { + if (vs->vs_aux == VDEV_AUX_SPARED) + state = "INUSE"; + else if (vs->vs_state == VDEV_STATE_HEALTHY) + state = "AVAIL"; + } + print_one_column(ZPOOL_PROP_HEALTH, 0, state, scripted, + 1, format); (void) printf("\n"); } @@ -5363,7 +5398,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, vname = zpool_vdev_name(g_zfs, zhp, child[c], cb->cb_name_flags); - print_list_stats(zhp, vname, child[c], cb, depth + 2); + print_list_stats(zhp, vname, child[c], cb, depth + 2, B_FALSE); free(vname); } @@ -5397,7 +5432,8 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, } vname = zpool_vdev_name(g_zfs, zhp, child[c], cb->cb_name_flags); - print_list_stats(zhp, vname, child[c], cb, depth + 2); + print_list_stats(zhp, vname, child[c], cb, depth + 2, + B_FALSE); free(vname); } } @@ -5409,7 +5445,8 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, for (c = 0; c < children; c++) { vname = zpool_vdev_name(g_zfs, zhp, child[c], cb->cb_name_flags); - print_list_stats(zhp, vname, child[c], cb, depth + 2); + print_list_stats(zhp, vname, child[c], cb, depth + 2, + B_FALSE); free(vname); } } @@ -5421,7 +5458,8 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv, for (c = 0; c < children; c++) { vname = zpool_vdev_name(g_zfs, zhp, child[c], cb->cb_name_flags); - print_list_stats(zhp, vname, child[c], cb, depth + 2); + print_list_stats(zhp, vname, child[c], cb, depth + 2, + B_TRUE); free(vname); } } @@ -5434,26 +5472,38 @@ int list_callback(zpool_handle_t *zhp, void *data) { list_cbdata_t *cbp = data; - nvlist_t *config; - nvlist_t *nvroot; - config = zpool_get_config(zhp, NULL); + print_pool(zhp, cbp); if (cbp->cb_verbose) { - config = zpool_get_config(zhp, NULL); + nvlist_t *config, *nvroot; + config = zpool_get_config(zhp, NULL); verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); + print_list_stats(zhp, NULL, nvroot, cbp, 0, B_FALSE); } - if (cbp->cb_verbose) - cbp->cb_namewidth = max_width(zhp, nvroot, 0, 0, - cbp->cb_name_flags); + return (0); +} - print_pool(zhp, cbp); +static int +get_namewidth_list(zpool_handle_t *zhp, void *data) +{ + list_cbdata_t *cb = data; + int error, width = cb->cb_namewidth; - if (cbp->cb_verbose) - print_list_stats(zhp, NULL, nvroot, cbp, 0); + error = get_namewidth(zhp, &width, cb->cb_name_flags, cb->cb_verbose); + if (error) + return (error); + + /* + * The width must be at least 9, but may be as large as needed. + */ + if (width < 9) + width = 9; + + cb->cb_namewidth = width; return (0); } @@ -5466,9 +5516,9 @@ list_callback(zpool_handle_t *zhp, void *data) * by a single tab. * -L Follow links when resolving vdev path name. * -o List of properties to display. Defaults to - * "name,size,allocated,free,expandsize,fragmentation,capacity," - * "dedupratio,health,altroot" - * -p Display values in parsable (exact) format. + * "name,size,allocated,free,fragmentation,capacity," + * "dedupratio,health" + * -p Display values in parsable (exact) format. * -P Display full path for vdev name. * -T Display a timestamp in date(1) or Unix format * @@ -5483,7 +5533,7 @@ zpool_do_list(int argc, char **argv) list_cbdata_t cb = { 0 }; static char default_props[] = "name,size,allocated,free,checkpoint,expandsize,fragmentation," - "capacity,dedupratio,health,altroot"; + "capacity,dedupratio,health"; char *props = default_props; float interval = 0; unsigned long count = 0; @@ -5546,6 +5596,9 @@ zpool_do_list(int argc, char **argv) if (pool_list_count(list) == 0) break; + cb.cb_namewidth = 0; + (void) pool_list_iter(list, B_FALSE, get_namewidth_list, &cb); + if (timestamp_fmt != NODATE) print_timestamp(timestamp_fmt); diff --git a/man/man8/zpool.8 b/man/man8/zpool.8 index b9e0e1ad4a95..52107b1aa6cb 100644 --- a/man/man8/zpool.8 +++ b/man/man8/zpool.8 @@ -1835,7 +1835,7 @@ See the section for a list of valid properties. The default list is .Cm name , size , allocated , free , checkpoint, expandsize , fragmentation , -.Cm capacity , dedupratio , health , altroot . +.Cm capacity , dedupratio , health . .It Fl L Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the