Illumos #1948: zpool list should show more detailed pool info
[zfs.git] / cmd / zpool / zpool_main.c
index fd9d69f..5661732 100644 (file)
@@ -21,6 +21,9 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
  */
 
 #include <assert.h>
@@ -40,6 +43,7 @@
 #include <priv.h>
 #include <pwd.h>
 #include <zone.h>
+#include <zfs_prop.h>
 #include <sys/fs/zfs.h>
 #include <sys/stat.h>
 #include <sys/fm/util.h>
@@ -65,6 +69,9 @@ static int zpool_do_status(int, char **);
 static int zpool_do_online(int, char **);
 static int zpool_do_offline(int, char **);
 static int zpool_do_clear(int, char **);
+static int zpool_do_reopen(int, char **);
+
+static int zpool_do_reguid(int, char **);
 
 static int zpool_do_attach(int, char **);
 static int zpool_do_detach(int, char **);
@@ -125,7 +132,9 @@ typedef enum {
        HELP_EVENTS,
        HELP_GET,
        HELP_SET,
-       HELP_SPLIT
+       HELP_SPLIT,
+       HELP_REGUID,
+       HELP_REOPEN
 } zpool_help_t;
 
 
@@ -158,6 +167,7 @@ static zpool_command_t command_table[] = {
        { "online",     zpool_do_online,        HELP_ONLINE             },
        { "offline",    zpool_do_offline,       HELP_OFFLINE            },
        { "clear",      zpool_do_clear,         HELP_CLEAR              },
+       { "reopen",     zpool_do_reopen,        HELP_REOPEN             },
        { NULL },
        { "attach",     zpool_do_attach,        HELP_ATTACH             },
        { "detach",     zpool_do_detach,        HELP_DETACH             },
@@ -169,6 +179,7 @@ static zpool_command_t command_table[] = {
        { "import",     zpool_do_import,        HELP_IMPORT             },
        { "export",     zpool_do_export,        HELP_EXPORT             },
        { "upgrade",    zpool_do_upgrade,       HELP_UPGRADE            },
+       { "reguid",     zpool_do_reguid,        HELP_REGUID             },
        { NULL },
        { "history",    zpool_do_history,       HELP_HISTORY            },
        { "events",     zpool_do_events,        HELP_EVENTS             },
@@ -231,6 +242,8 @@ get_usage(zpool_help_t idx) {
                    "[new-device]\n"));
        case HELP_REMOVE:
                return (gettext("\tremove <pool> <device> ...\n"));
+       case HELP_REOPEN:
+               return (""); /* Undocumented command */
        case HELP_SCRUB:
                return (gettext("\tscrub [-s] <pool> ...\n"));
        case HELP_STATUS:
@@ -251,6 +264,8 @@ get_usage(zpool_help_t idx) {
                return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
                    "\t    [-o property=value] <pool> <newpool> "
                    "[<device> ...]\n"));
+       case HELP_REGUID:
+               return (gettext("\treguid <pool>\n"));
        }
 
        abort();
@@ -1334,6 +1349,7 @@ show_import(nvlist_t *config)
        const char *health;
        uint_t vsc;
        int namewidth;
+       char *comment;
 
        verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
            &name) == 0);
@@ -1350,9 +1366,9 @@ show_import(nvlist_t *config)
 
        reason = zpool_import_status(config, &msgid);
 
-       (void) printf(gettext("  pool: %s\n"), name);
-       (void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
-       (void) printf(gettext(" state: %s"), health);
+       (void) printf(gettext("   pool: %s\n"), name);
+       (void) printf(gettext("     id: %llu\n"), (u_longlong_t)guid);
+       (void) printf(gettext("  state: %s"), health);
        if (pool_state == POOL_STATE_DESTROYED)
                (void) printf(gettext(" (DESTROYED)"));
        (void) printf("\n");
@@ -1361,58 +1377,59 @@ show_import(nvlist_t *config)
        case ZPOOL_STATUS_MISSING_DEV_R:
        case ZPOOL_STATUS_MISSING_DEV_NR:
        case ZPOOL_STATUS_BAD_GUID_SUM:
-               (void) printf(gettext("status: One or more devices are missing "
-                   "from the system.\n"));
+               (void) printf(gettext(" status: One or more devices are "
+                   "missing from the system.\n"));
                break;
 
        case ZPOOL_STATUS_CORRUPT_LABEL_R:
        case ZPOOL_STATUS_CORRUPT_LABEL_NR:
-               (void) printf(gettext("status: One or more devices contains "
+               (void) printf(gettext(" status: One or more devices contains "
                    "corrupted data.\n"));
                break;
 
        case ZPOOL_STATUS_CORRUPT_DATA:
-               (void) printf(gettext("status: The pool data is corrupted.\n"));
+               (void) printf(
+                   gettext(" status: The pool data is corrupted.\n"));
                break;
 
        case ZPOOL_STATUS_OFFLINE_DEV:
-               (void) printf(gettext("status: One or more devices "
+               (void) printf(gettext(" status: One or more devices "
                    "are offlined.\n"));
                break;
 
        case ZPOOL_STATUS_CORRUPT_POOL:
-               (void) printf(gettext("status: The pool metadata is "
+               (void) printf(gettext(" status: The pool metadata is "
                    "corrupted.\n"));
                break;
 
        case ZPOOL_STATUS_VERSION_OLDER:
-               (void) printf(gettext("status: The pool is formatted using an "
+               (void) printf(gettext(" status: The pool is formatted using an "
                    "older on-disk version.\n"));
                break;
 
        case ZPOOL_STATUS_VERSION_NEWER:
-               (void) printf(gettext("status: The pool is formatted using an "
+               (void) printf(gettext(" status: The pool is formatted using an "
                    "incompatible version.\n"));
                break;
 
        case ZPOOL_STATUS_HOSTID_MISMATCH:
-               (void) printf(gettext("status: The pool was last accessed by "
+               (void) printf(gettext(" status: The pool was last accessed by "
                    "another system.\n"));
                break;
 
        case ZPOOL_STATUS_FAULTED_DEV_R:
        case ZPOOL_STATUS_FAULTED_DEV_NR:
-               (void) printf(gettext("status: One or more devices are "
+               (void) printf(gettext(" status: One or more devices are "
                    "faulted.\n"));
                break;
 
        case ZPOOL_STATUS_BAD_LOG:
-               (void) printf(gettext("status: An intent log record cannot be "
+               (void) printf(gettext(" status: An intent log record cannot be "
                    "read.\n"));
                break;
 
        case ZPOOL_STATUS_RESILVERING:
-               (void) printf(gettext("status: One or more devices were being "
+               (void) printf(gettext(" status: One or more devices were being "
                    "resilvered.\n"));
                break;
 
@@ -1428,26 +1445,26 @@ show_import(nvlist_t *config)
         */
        if (vs->vs_state == VDEV_STATE_HEALTHY) {
                if (reason == ZPOOL_STATUS_VERSION_OLDER)
-                       (void) printf(gettext("action: The pool can be "
+                       (void) printf(gettext(" action: The pool can be "
                            "imported using its name or numeric identifier, "
                            "though\n\tsome features will not be available "
                            "without an explicit 'zpool upgrade'.\n"));
                else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
-                       (void) printf(gettext("action: The pool can be "
+                       (void) printf(gettext(" action: The pool can be "
                            "imported using its name or numeric "
                            "identifier and\n\tthe '-f' flag.\n"));
                else
-                       (void) printf(gettext("action: The pool can be "
+                       (void) printf(gettext(" action: The pool can be "
                            "imported using its name or numeric "
                            "identifier.\n"));
        } else if (vs->vs_state == VDEV_STATE_DEGRADED) {
-               (void) printf(gettext("action: The pool can be imported "
+               (void) printf(gettext(" action: The pool can be imported "
                    "despite missing or damaged devices.  The\n\tfault "
                    "tolerance of the pool may be compromised if imported.\n"));
        } else {
                switch (reason) {
                case ZPOOL_STATUS_VERSION_NEWER:
-                       (void) printf(gettext("action: The pool cannot be "
+                       (void) printf(gettext(" action: The pool cannot be "
                            "imported.  Access the pool on a system running "
                            "newer\n\tsoftware, or recreate the pool from "
                            "backup.\n"));
@@ -1455,16 +1472,20 @@ show_import(nvlist_t *config)
                case ZPOOL_STATUS_MISSING_DEV_R:
                case ZPOOL_STATUS_MISSING_DEV_NR:
                case ZPOOL_STATUS_BAD_GUID_SUM:
-                       (void) printf(gettext("action: The pool cannot be "
+                       (void) printf(gettext(" action: The pool cannot be "
                            "imported. Attach the missing\n\tdevices and try "
                            "again.\n"));
                        break;
                default:
-                       (void) printf(gettext("action: The pool cannot be "
+                       (void) printf(gettext(" action: The pool cannot be "
                            "imported due to damaged devices or data.\n"));
                }
        }
 
+       /* Print the comment attached to the pool. */
+       if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
+               (void) printf(gettext("comment: %s\n"), comment);
+
        /*
         * If the state is "closed" or "can't open", and the aux state
         * is "corrupt data":
@@ -1485,7 +1506,7 @@ show_import(nvlist_t *config)
                (void) printf(gettext("   see: http://zfsonlinux.org/msg/%s\n"),
                    msgid);
 
-       (void) printf(gettext("config:\n\n"));
+       (void) printf(gettext(" config:\n\n"));
 
        namewidth = max_width(NULL, nvroot, 0, 0);
        if (namewidth < 10)
@@ -1632,6 +1653,7 @@ int
 zpool_do_import(int argc, char **argv)
 {
        char **searchdirs = NULL;
+       char *env, *envdup = NULL;
        int nsearch = 0;
        int c;
        int err = 0;
@@ -1831,6 +1853,30 @@ zpool_do_import(int argc, char **argv)
                idata.unique = B_TRUE;
        }
 
+       /*
+        * Check the environment for the preferred search path.
+        */
+       if ((searchdirs == NULL) && (env = getenv("ZPOOL_IMPORT_PATH"))) {
+               char *dir;
+
+               envdup = strdup(env);
+
+               dir = strtok(envdup, ":");
+               while (dir != NULL) {
+                       if (searchdirs == NULL) {
+                               searchdirs = safe_malloc(sizeof (char *));
+                       } else {
+                               char **tmp = safe_malloc((nsearch + 1) *
+                                   sizeof (char *));
+                               bcopy(searchdirs, tmp, nsearch *
+                                   sizeof (char *));
+                               free(searchdirs);
+                               searchdirs = tmp;
+                       }
+                       searchdirs[nsearch++] = dir;
+                       dir = strtok(NULL, ":");
+               }
+       }
 
        idata.path = searchdirs;
        idata.paths = nsearch;
@@ -1867,6 +1913,8 @@ zpool_do_import(int argc, char **argv)
        if (err == 1) {
                if (searchdirs != NULL)
                        free(searchdirs);
+               if (envdup != NULL)
+                       free(envdup);
                nvlist_free(policy);
                return (1);
        }
@@ -1969,15 +2017,17 @@ error:
        nvlist_free(policy);
        if (searchdirs != NULL)
                free(searchdirs);
+       if (envdup != NULL)
+               free(envdup);
 
        return (err ? 1 : 0);
 }
 
 typedef struct iostat_cbdata {
-       zpool_list_t *cb_list;
-       int cb_verbose;
-       int cb_iteration;
+       boolean_t cb_verbose;
        int cb_namewidth;
+       int cb_iteration;
+       zpool_list_t *cb_list;
 } iostat_cbdata_t;
 
 static void
@@ -2086,10 +2136,15 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
                return;
 
        for (c = 0; c < children; c++) {
-               uint64_t ishole = B_FALSE;
+               uint64_t ishole = B_FALSE, islog = B_FALSE;
 
-               if (nvlist_lookup_uint64(newchild[c],
-                   ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
+               (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
+                   &ishole);
+
+               (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
+                   &islog);
+
+               if (ishole || islog)
                        continue;
 
                vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
@@ -2099,6 +2154,31 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
        }
 
        /*
+        * Log device section
+        */
+
+       if (num_logs(newnv) > 0) {
+               (void) printf("%-*s      -      -      -      -      -      "
+                   "-\n", cb->cb_namewidth, "logs");
+
+               for (c = 0; c < children; c++) {
+                       uint64_t islog = B_FALSE;
+                       (void) nvlist_lookup_uint64(newchild[c],
+                           ZPOOL_CONFIG_IS_LOG, &islog);
+
+                       if (islog) {
+                               vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
+                                   B_FALSE);
+                               print_vdev_stats(zhp, vname, oldnv ?
+                                   oldchild[c] : NULL, newchild[c],
+                                   cb, depth + 2);
+                               free(vname);
+                       }
+               }
+
+       }
+
+       /*
         * Include level 2 ARC devices in iostat output
         */
        if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
@@ -2175,11 +2255,30 @@ print_iostat(zpool_handle_t *zhp, void *data)
        return (0);
 }
 
+static int
+get_columns(void)
+{
+       struct winsize ws;
+       int columns = 80;
+       int error;
+
+       if (isatty(STDOUT_FILENO)) {
+               error = ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
+               if (error == 0)
+                       columns = ws.ws_col;
+       } else {
+               columns = 999;
+       }
+
+       return columns;
+}
+
 int
 get_namewidth(zpool_handle_t *zhp, void *data)
 {
        iostat_cbdata_t *cb = data;
        nvlist_t *config, *nvroot;
+       int columns;
 
        if ((config = zpool_get_config(zhp, NULL)) != NULL) {
                verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
@@ -2187,17 +2286,20 @@ get_namewidth(zpool_handle_t *zhp, void *data)
                if (!cb->cb_verbose)
                        cb->cb_namewidth = strlen(zpool_get_name(zhp));
                else
-                       cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
+                       cb->cb_namewidth = max_width(zhp, nvroot, 0,
+                           cb->cb_namewidth);
        }
 
        /*
-        * The width must fall into the range [10,38].  The upper limit is the
-        * maximum we can have and still fit in 80 columns.
+        * 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 > 38)
-               cb->cb_namewidth = 38;
+       if (cb->cb_namewidth > columns - 42)
+               cb->cb_namewidth = columns - 42;
 
        return (0);
 }
@@ -2358,7 +2460,7 @@ zpool_do_iostat(int argc, char **argv)
                pool_list_update(list);
 
                if ((npools = pool_list_count(list)) == 0)
-                       (void) printf(gettext("no pools available\n"));
+                       (void) fprintf(stderr, gettext("no pools available\n"));
                else {
                        /*
                         * Refresh all statistics.  This is done as an
@@ -2422,8 +2524,9 @@ zpool_do_iostat(int argc, char **argv)
 }
 
 typedef struct list_cbdata {
+       boolean_t       cb_verbose;
+       int             cb_namewidth;
        boolean_t       cb_scripted;
-       boolean_t       cb_first;
        zprop_list_t    *cb_proplist;
 } list_cbdata_t;
 
@@ -2431,16 +2534,27 @@ typedef struct list_cbdata {
  * Given a list of columns to display, output appropriate headers for each one.
  */
 static void
-print_header(zprop_list_t *pl)
+print_header(list_cbdata_t *cb)
 {
+       zprop_list_t *pl = cb->cb_proplist;
        const char *header;
        boolean_t first = B_TRUE;
        boolean_t right_justify;
+       size_t width = 0;
 
        for (; pl != NULL; pl = pl->pl_next) {
                if (pl->pl_prop == ZPROP_INVAL)
                        continue;
 
+               width = pl->pl_width;
+               if (first && cb->cb_verbose) {
+                       /*
+                        * Reset the width to accommodate the verbose listing
+                        * of devices.
+                        */
+                       width = cb->cb_namewidth;
+               }
+
                if (!first)
                        (void) printf("  ");
                else
@@ -2452,9 +2566,9 @@ print_header(zprop_list_t *pl)
                if (pl->pl_next == NULL && !right_justify)
                        (void) printf("%s", header);
                else if (right_justify)
-                       (void) printf("%*s", (int)pl->pl_width, header);
+                       (void) printf("%*s", (int)width, header);
                else
-                       (void) printf("%-*s", (int)pl->pl_width, header);
+                       (void) printf("%-*s", (int)width, header);
        }
 
        (void) printf("\n");
@@ -2465,17 +2579,28 @@ print_header(zprop_list_t *pl)
  * to the described layout.
  */
 static void
-print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
+print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
 {
+       zprop_list_t *pl = cb->cb_proplist;
        boolean_t first = B_TRUE;
        char property[ZPOOL_MAXPROPLEN];
        char *propstr;
        boolean_t right_justify;
-       int width;
+       size_t width;
 
        for (; pl != NULL; pl = pl->pl_next) {
+
+               width = pl->pl_width;
+               if (first && cb->cb_verbose) {
+                       /*
+                        * Reset the width to accommodate the verbose listing
+                        * of devices.
+                        */
+                       width = cb->cb_namewidth;
+               }
+
                if (!first) {
-                       if (scripted)
+                       if (cb->cb_scripted)
                                (void) printf("\t");
                        else
                                (void) printf("  ");
@@ -2485,7 +2610,10 @@ print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
 
                right_justify = B_FALSE;
                if (pl->pl_prop != ZPROP_INVAL) {
-                       if (zpool_get_prop(zhp, pl->pl_prop, property,
+                       if (pl->pl_prop == ZPOOL_PROP_EXPANDSZ &&
+                           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)
                                propstr = "-";
                        else
@@ -2496,24 +2624,118 @@ print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
                        propstr = "-";
                }
 
-               width = pl->pl_width;
 
                /*
                 * 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 (scripted || (pl->pl_next == NULL && !right_justify))
+               if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
                        (void) printf("%s", propstr);
                else if (right_justify)
-                       (void) printf("%*s", width, propstr);
+                       (void) printf("%*s", (int)width, propstr);
                else
-                       (void) printf("%-*s", width, propstr);
+                       (void) printf("%-*s", (int)width, propstr);
        }
 
        (void) printf("\n");
 }
 
+static void
+print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted)
+{
+       char propval[64];
+       boolean_t fixed;
+       size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
+
+       zfs_nicenum(value, propval, sizeof (propval));
+
+       if (prop == ZPOOL_PROP_EXPANDSZ && value == 0)
+               (void) strlcpy(propval, "-", sizeof (propval));
+
+       if (scripted)
+               (void) printf("\t%s", propval);
+       else
+               (void) printf("  %*s", (int)width, propval);
+}
+
+void
+print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
+    list_cbdata_t *cb, int depth)
+{
+       nvlist_t **child;
+       vdev_stat_t *vs;
+       uint_t c, children;
+       char *vname;
+       boolean_t scripted = cb->cb_scripted;
+
+       verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+           (uint64_t **)&vs, &c) == 0);
+
+       if (name != NULL) {
+               if (scripted)
+                       (void) printf("\t%s", name);
+               else if (strlen(name) + depth > cb->cb_namewidth)
+                       (void) printf("%*s%s", depth, "", name);
+               else
+                       (void) printf("%*s%s%*s", depth, "", name,
+                           (int)(cb->cb_namewidth - strlen(name) - depth), "");
+
+               /* only toplevel vdevs have capacity stats */
+               if (vs->vs_space == 0) {
+                       if (scripted)
+                               (void) printf("\t-\t-\t-");
+                       else
+                               (void) printf("      -      -      -");
+               } else {
+                       print_one_column(ZPOOL_PROP_SIZE, vs->vs_space,
+                           scripted);
+                       print_one_column(ZPOOL_PROP_CAPACITY, vs->vs_alloc,
+                           scripted);
+                       print_one_column(ZPOOL_PROP_FREE,
+                           vs->vs_space - vs->vs_alloc, scripted);
+               }
+               print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize,
+                   scripted);
+               (void) printf("\n");
+       }
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0)
+               return;
+
+       for (c = 0; c < children; c++) {
+               uint64_t ishole = B_FALSE;
+
+               if (nvlist_lookup_uint64(child[c],
+                   ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
+                       continue;
+
+               vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
+               print_list_stats(zhp, vname, child[c], cb, depth + 2);
+               free(vname);
+       }
+
+       /*
+        * Include level 2 ARC devices in iostat output
+        */
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+           &child, &children) != 0)
+               return;
+
+       if (children > 0) {
+               (void) printf("%-*s      -      -      -      -      -      "
+                   "-\n", cb->cb_namewidth, "cache");
+               for (c = 0; c < children; c++) {
+                       vname = zpool_vdev_name(g_zfs, zhp, child[c],
+                           B_FALSE);
+                       print_list_stats(zhp, vname, child[c], cb, depth + 2);
+                       free(vname);
+               }
+       }
+}
+
+
 /*
  * Generic callback function to list a pool.
  */
@@ -2521,14 +2743,18 @@ int
 list_callback(zpool_handle_t *zhp, void *data)
 {
        list_cbdata_t *cbp = data;
+       nvlist_t *config;
+       nvlist_t *nvroot;
 
-       if (cbp->cb_first) {
-               if (!cbp->cb_scripted)
-                       print_header(cbp->cb_proplist);
-               cbp->cb_first = B_FALSE;
-       }
+       config = zpool_get_config(zhp, NULL);
 
-       print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
+       print_pool(zhp, cbp);
+       if (!cbp->cb_verbose)
+               return (0);
+
+       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+       print_list_stats(zhp, NULL, nvroot, cbp, 0);
 
        return (0);
 }
@@ -2552,12 +2778,15 @@ zpool_do_list(int argc, char **argv)
        int ret;
        list_cbdata_t cb = { 0 };
        static char default_props[] =
-           "name,size,allocated,free,capacity,dedupratio,health,altroot";
+           "name,size,allocated,free,capacity,dedupratio,"
+           "health,altroot";
        char *props = default_props;
        unsigned long interval = 0, count = 0;
+       zpool_list_t *list;
+       boolean_t first = B_TRUE;
 
        /* check options */
-       while ((c = getopt(argc, argv, ":Ho:T:")) != -1) {
+       while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) {
                switch (c) {
                case 'H':
                        cb.cb_scripted = B_TRUE;
@@ -2568,6 +2797,9 @@ zpool_do_list(int argc, char **argv)
                case 'T':
                        get_timestamp_arg(*optarg);
                        break;
+               case 'v':
+                       cb.cb_verbose = B_TRUE;
+                       break;
                case ':':
                        (void) fprintf(stderr, gettext("missing argument for "
                            "'%c' option\n"), optopt);
@@ -2588,23 +2820,29 @@ zpool_do_list(int argc, char **argv)
        if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
                usage(B_FALSE);
 
-       cb.cb_first = B_TRUE;
+       if ((list = pool_list_get(argc, argv, &cb.cb_proplist, &ret)) == NULL)
+               return (1);
+
+       if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
+               (void) printf(gettext("no pools available\n"));
+               zprop_free_list(cb.cb_proplist);
+               return (0);
+       }
 
        for (;;) {
+               pool_list_update(list);
+
+               if (pool_list_count(list) == 0)
+                       break;
 
                if (timestamp_fmt != NODATE)
                        print_timestamp(timestamp_fmt);
 
-               ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
-                   list_callback, &cb);
-
-               if (argc == 0 && cb.cb_first)
-                       (void) printf(gettext("no pools available\n"));
-               else if (argc && cb.cb_first) {
-                       /* cannot open the given pool */
-                       zprop_free_list(cb.cb_proplist);
-                       return (1);
+               if (!cb.cb_scripted && (first || cb.cb_verbose)) {
+                       print_header(&cb);
+                       first = B_FALSE;
                }
+               ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
 
                if (interval == 0)
                        break;
@@ -2922,7 +3160,7 @@ zpool_do_split(int argc, char **argv)
        if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
            zpool_enable_datasets(zhp, mntopts, 0) != 0) {
                ret = 1;
-               (void) fprintf(stderr, gettext("Split was succssful, but "
+               (void) fprintf(stderr, gettext("Split was successful, but "
                    "the datasets could not all be mounted\n"));
                (void) fprintf(stderr, gettext("Try doing '%s' with a "
                    "different altroot\n"), "zpool import");
@@ -3151,6 +3389,82 @@ zpool_do_clear(int argc, char **argv)
        return (ret);
 }
 
+/*
+ * zpool reguid <pool>
+ */
+int
+zpool_do_reguid(int argc, char **argv)
+{
+       int c;
+       char *poolname;
+       zpool_handle_t *zhp;
+       int ret = 0;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "")) != -1) {
+               switch (c) {
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* get pool name and check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name\n"));
+               usage(B_FALSE);
+       }
+
+       if (argc > 1) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       poolname = argv[0];
+       if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+               return (1);
+
+       ret = zpool_reguid(zhp);
+
+       zpool_close(zhp);
+       return (ret);
+}
+
+
+/*
+ * zpool reopen <pool>
+ *
+ * Reopen the pool so that the kernel can update the sizes of all vdevs.
+ *
+ * NOTE: This command is currently undocumented.  If the command is ever
+ * exposed then the appropriate usage() messages will need to be made.
+ */
+int
+zpool_do_reopen(int argc, char **argv)
+{
+       int ret = 0;
+       zpool_handle_t *zhp;
+       char *pool;
+
+       argc--;
+       argv++;
+
+       if (argc != 1)
+               return (2);
+
+       pool = argv[0];
+       if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
+               return (1);
+
+       ret = zpool_reopen(zhp);
+       zpool_close(zhp);
+       return (ret);
+}
+
 typedef struct scrub_cbdata {
        int     cb_type;
        int     cb_argc;
@@ -3793,7 +4107,7 @@ zpool_do_status(int argc, char **argv)
                    status_callback, &cb);
 
                if (argc == 0 && cb.cb_count == 0)
-                       (void) printf(gettext("no pools available\n"));
+                       (void) fprintf(stderr, gettext("no pools available\n"));
                else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
                        (void) printf(gettext("all pools are healthy\n"));
 
@@ -4219,7 +4533,7 @@ zpool_do_history(int argc, char **argv)
            &cbdata);
 
        if (argc == 0 && cbdata.first == B_TRUE) {
-               (void) printf(gettext("no pools available\n"));
+               (void) fprintf(stderr, gettext("no pools available\n"));
                return (0);
        }