]> git.proxmox.com Git - mirror_zfs-debian.git/blobdiff - cmd/zpool/zpool_main.c
Merge branch 'master' of git+ssh://git.debian.org/git/pkg-zfsonlinux/zfs
[mirror_zfs-debian.git] / cmd / zpool / zpool_main.c
index b96fbe4ace5bfffe5e1acc385df2a0cfb71d4c70..aa9b21dadf0c7b7a75c33bc77c917322717caf20 100644 (file)
 /*
  * 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) 2011, 2014 by Delphix. All rights reserved.
  * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
  * Copyright (c) 2012 by Cyril Plisko. All rights reserved.
+ * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
  */
 
 #include <assert.h>
@@ -49,6 +50,7 @@
 #include <sys/stat.h>
 #include <sys/fm/util.h>
 #include <sys/fm/protocol.h>
+#include <sys/zfs_ioctl.h>
 
 #include <libzfs.h>
 
@@ -196,9 +198,9 @@ static zpool_command_t command_table[] = {
 
 #define        NCOMMAND        (sizeof (command_table) / sizeof (command_table[0]))
 
-zpool_command_t *current_command;
+static zpool_command_t *current_command;
 static char history_str[HIS_MAX_RECORD_LEN];
-
+static boolean_t log_history = B_TRUE;
 static uint_t timestamp_fmt = NODATE;
 
 static const char *
@@ -221,7 +223,7 @@ get_usage(zpool_help_t idx) {
        case HELP_DETACH:
                return (gettext("\tdetach <pool> <device>\n"));
        case HELP_EXPORT:
-               return (gettext("\texport [-f] <pool> ...\n"));
+               return (gettext("\texport [-af] <pool> ...\n"));
        case HELP_HISTORY:
                return (gettext("\thistory [-il] [<pool>] ...\n"));
        case HELP_IMPORT:
@@ -235,8 +237,8 @@ get_usage(zpool_help_t idx) {
                    "[-R root] [-F [-n]]\n"
                    "\t    <pool | id> [newpool]\n"));
        case HELP_IOSTAT:
-               return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
-                   "[count]]\n"));
+               return (gettext("\tiostat [-v] [-T d|u] [-y] [pool] ... "
+                   "[interval [count]]\n"));
        case HELP_LABELCLEAR:
                return (gettext("\tlabelclear [-f] <vdev>\n"));
        case HELP_LIST:
@@ -247,8 +249,8 @@ get_usage(zpool_help_t idx) {
        case HELP_ONLINE:
                return (gettext("\tonline <pool> <device> ...\n"));
        case HELP_REPLACE:
-               return (gettext("\treplace [-f] <pool> <device> "
-                   "[new-device]\n"));
+               return (gettext("\treplace [-f] [-o property=value] "
+                   "<pool> <device> [new-device]\n"));
        case HELP_REMOVE:
                return (gettext("\tremove <pool> <device> ...\n"));
        case HELP_REOPEN:
@@ -256,7 +258,7 @@ get_usage(zpool_help_t idx) {
        case HELP_SCRUB:
                return (gettext("\tscrub [-s] <pool> ...\n"));
        case HELP_STATUS:
-               return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
+               return (gettext("\tstatus [-vxD] [-T d|u] [pool] ... [interval "
                    "[count]]\n"));
        case HELP_UPGRADE:
                return (gettext("\tupgrade\n"
@@ -265,7 +267,7 @@ get_usage(zpool_help_t idx) {
        case HELP_EVENTS:
                return (gettext("\tevents [-vHfc]\n"));
        case HELP_GET:
-               return (gettext("\tget <\"all\" | property[,...]> "
+               return (gettext("\tget [-pH] <\"all\" | property[,...]> "
                    "<pool> ...\n"));
        case HELP_SET:
                return (gettext("\tset <property=value> <pool> \n"));
@@ -484,6 +486,21 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props,
        return (0);
 }
 
+/*
+ * Set a default property pair (name, string-value) in a property nvlist
+ */
+static int
+add_prop_list_default(const char *propname, char *propval, nvlist_t **props,
+    boolean_t poolprop)
+{
+       char *pval;
+
+       if (nvlist_lookup_string(*props, propname, &pval) == 0)
+               return (0);
+
+       return (add_prop_list(propname, propval, props, B_TRUE));
+}
+
 /*
  * zpool add [-fn] [-o property=value] <pool> <vdev> ...
  *
@@ -577,6 +594,10 @@ zpool_do_add(int argc, char **argv)
 
        if (dryrun) {
                nvlist_t *poolnvroot;
+               nvlist_t **l2child;
+               uint_t l2children, c;
+               char *vname;
+               boolean_t hadcache = B_FALSE;
 
                verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
                    &poolnvroot) == 0);
@@ -596,6 +617,30 @@ zpool_do_add(int argc, char **argv)
                        print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
                }
 
+               /* Do the same for the caches */
+               if (nvlist_lookup_nvlist_array(poolnvroot, ZPOOL_CONFIG_L2CACHE,
+                   &l2child, &l2children) == 0 && l2children) {
+                       hadcache = B_TRUE;
+                       (void) printf(gettext("\tcache\n"));
+                       for (c = 0; c < l2children; c++) {
+                               vname = zpool_vdev_name(g_zfs, NULL,
+                                   l2child[c], B_FALSE);
+                               (void) printf("\t  %s\n", vname);
+                               free(vname);
+                       }
+               }
+               if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+                   &l2child, &l2children) == 0 && l2children) {
+                       if (!hadcache)
+                               (void) printf(gettext("\tcache\n"));
+                       for (c = 0; c < l2children; c++) {
+                               vname = zpool_vdev_name(g_zfs, NULL,
+                                   l2child[c], B_FALSE);
+                               (void) printf("\t  %s\n", vname);
+                               free(vname);
+                       }
+               }
+
                ret = 0;
        } else {
                ret = (zpool_add(zhp, nvroot) != 0);
@@ -798,6 +843,7 @@ zpool_do_create(int argc, char **argv)
        int c;
        nvlist_t *nvroot = NULL;
        char *poolname;
+       char *tname = NULL;
        int ret = 1;
        char *altroot = NULL;
        char *mountpoint = NULL;
@@ -806,7 +852,7 @@ zpool_do_create(int argc, char **argv)
        char *propval;
 
        /* check options */
-       while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) {
+       while ((c = getopt(argc, argv, ":fndR:m:o:O:t:")) != -1) {
                switch (c) {
                case 'f':
                        force = B_TRUE;
@@ -822,15 +868,12 @@ zpool_do_create(int argc, char **argv)
                        if (add_prop_list(zpool_prop_to_name(
                            ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
                                goto errout;
-                       if (nvlist_lookup_string(props,
-                           zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
-                           &propval) == 0)
-                               break;
-                       if (add_prop_list(zpool_prop_to_name(
+                       if (add_prop_list_default(zpool_prop_to_name(
                            ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
                                goto errout;
                        break;
                case 'm':
+                       /* Equivalent to -O mountpoint=optarg */
                        mountpoint = optarg;
                        break;
                case 'o':
@@ -869,8 +912,39 @@ zpool_do_create(int argc, char **argv)
                        *propval = '\0';
                        propval++;
 
-                       if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
+                       /*
+                        * Mountpoints are checked and then added later.
+                        * Uniquely among properties, they can be specified
+                        * more than once, to avoid conflict with -m.
+                        */
+                       if (0 == strcmp(optarg,
+                           zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) {
+                               mountpoint = propval;
+                       } else if (add_prop_list(optarg, propval, &fsprops,
+                           B_FALSE)) {
+                               goto errout;
+                       }
+                       break;
+               case 't':
+                       /*
+                        * Sanity check temporary pool name.
+                        */
+                       if (strchr(optarg, '/') != NULL) {
+                               (void) fprintf(stderr, gettext("cannot create "
+                                   "'%s': invalid character '/' in temporary "
+                                   "name\n"), optarg);
+                               (void) fprintf(stderr, gettext("use 'zfs "
+                                   "create' to create a dataset\n"));
+                               goto errout;
+                       }
+
+                       if (add_prop_list(zpool_prop_to_name(
+                           ZPOOL_PROP_TNAME), optarg, &props, B_TRUE))
+                               goto errout;
+                       if (add_prop_list_default(zpool_prop_to_name(
+                           ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
                                goto errout;
+                       tname = optarg;
                        break;
                case ':':
                        (void) fprintf(stderr, gettext("missing argument for "
@@ -987,6 +1061,18 @@ zpool_do_create(int argc, char **argv)
                }
        }
 
+       /*
+        * Now that the mountpoint's validity has been checked, ensure that
+        * the property is set appropriately prior to creating the pool.
+        */
+       if (mountpoint != NULL) {
+               ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
+                   mountpoint, &fsprops, B_FALSE);
+               if (ret != 0)
+                       goto errout;
+       }
+
+       ret = 1;
        if (dryrun) {
                /*
                 * For a dry run invocation, print out a basic message and run
@@ -1006,7 +1092,7 @@ zpool_do_create(int argc, char **argv)
                 * Hand off to libzfs.
                 */
                if (enable_all_pool_feat) {
-                       int i;
+                       spa_feature_t i;
                        for (i = 0; i < SPA_FEATURES; i++) {
                                char propname[MAXPATHLEN];
                                zfeature_info_t *feat = &spa_feature_table[i];
@@ -1021,21 +1107,19 @@ zpool_do_create(int argc, char **argv)
                                if (nvlist_exists(props, propname))
                                        continue;
 
-                               if (add_prop_list(propname, ZFS_FEATURE_ENABLED,
-                                   &props, B_TRUE) != 0)
+                               ret = add_prop_list(propname,
+                                   ZFS_FEATURE_ENABLED, &props, B_TRUE);
+                               if (ret != 0)
                                        goto errout;
                        }
                }
+
+               ret = 1;
                if (zpool_create(g_zfs, poolname,
                    nvroot, props, fsprops) == 0) {
-                       zfs_handle_t *pool = zfs_open(g_zfs, poolname,
-                           ZFS_TYPE_FILESYSTEM);
+                       zfs_handle_t *pool = zfs_open(g_zfs,
+                           tname ? tname : poolname, ZFS_TYPE_FILESYSTEM);
                        if (pool != NULL) {
-                               if (mountpoint != NULL)
-                                       verify(zfs_prop_set(pool,
-                                           zfs_prop_to_name(
-                                           ZFS_PROP_MOUNTPOINT),
-                                           mountpoint) == 0);
                                if (zfs_mount(pool, NULL, 0) == 0)
                                        ret = zfs_shareall(pool);
                                zfs_close(pool);
@@ -1119,16 +1203,49 @@ zpool_do_destroy(int argc, char **argv)
                return (1);
        }
 
-       ret = (zpool_destroy(zhp) != 0);
+       /* The history must be logged as part of the export */
+       log_history = B_FALSE;
+
+       ret = (zpool_destroy(zhp, history_str) != 0);
 
        zpool_close(zhp);
 
        return (ret);
 }
 
+typedef struct export_cbdata {
+       boolean_t force;
+       boolean_t hardforce;
+} export_cbdata_t;
+
+/*
+ * Export one pool
+ */
+int
+zpool_export_one(zpool_handle_t *zhp, void *data)
+{
+       export_cbdata_t *cb = data;
+
+       if (zpool_disable_datasets(zhp, cb->force) != 0)
+               return (1);
+
+       /* The history must be logged as part of the export */
+       log_history = B_FALSE;
+
+       if (cb->hardforce) {
+               if (zpool_export_force(zhp, history_str) != 0)
+                       return (1);
+       } else if (zpool_export(zhp, cb->force, history_str) != 0) {
+               return (1);
+       }
+
+       return (0);
+}
+
 /*
  * zpool export [-f] <pool> ...
  *
+ *     -a      Export all pools
  *     -f      Forcefully unmount datasets
  *
  * Export the given pools.  By default, the command will attempt to cleanly
@@ -1138,16 +1255,18 @@ zpool_do_destroy(int argc, char **argv)
 int
 zpool_do_export(int argc, char **argv)
 {
+       export_cbdata_t cb;
+       boolean_t do_all = B_FALSE;
        boolean_t force = B_FALSE;
        boolean_t hardforce = B_FALSE;
-       int c;
-       zpool_handle_t *zhp;
-       int ret;
-       int i;
+       int c, ret;
 
        /* check options */
-       while ((c = getopt(argc, argv, "fF")) != -1) {
+       while ((c = getopt(argc, argv, "afF")) != -1) {
                switch (c) {
+               case 'a':
+                       do_all = B_TRUE;
+                       break;
                case 'f':
                        force = B_TRUE;
                        break;
@@ -1161,37 +1280,28 @@ zpool_do_export(int argc, char **argv)
                }
        }
 
+       cb.force = force;
+       cb.hardforce = hardforce;
        argc -= optind;
        argv += optind;
 
+       if (do_all) {
+               if (argc != 0) {
+                       (void) fprintf(stderr, gettext("too many arguments\n"));
+                       usage(B_FALSE);
+               }
+
+               return (for_each_pool(argc, argv, B_TRUE, NULL,
+                   zpool_export_one, &cb));
+       }
+
        /* check arguments */
        if (argc < 1) {
                (void) fprintf(stderr, gettext("missing pool argument\n"));
                usage(B_FALSE);
        }
 
-       ret = 0;
-       for (i = 0; i < argc; i++) {
-               if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
-                       ret = 1;
-                       continue;
-               }
-
-               if (zpool_disable_datasets(zhp, force) != 0) {
-                       ret = 1;
-                       zpool_close(zhp);
-                       continue;
-               }
-
-               if (hardforce) {
-                       if (zpool_export_force(zhp) != 0)
-                               ret = 1;
-               } else if (zpool_export(zhp, force) != 0) {
-                       ret = 1;
-               }
-
-               zpool_close(zhp);
-       }
+       ret = for_each_pool(argc, argv, B_TRUE, NULL, zpool_export_one, &cb);
 
        return (ret);
 }
@@ -1581,7 +1691,8 @@ show_import(nvlist_t *config)
        uint64_t guid;
        char *msgid;
        nvlist_t *nvroot;
-       int reason;
+       zpool_status_t reason;
+       zpool_errata_t errata;
        const char *health;
        uint_t vsc;
        int namewidth;
@@ -1600,7 +1711,7 @@ show_import(nvlist_t *config)
            (uint64_t **)&vs, &vsc) == 0);
        health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
 
-       reason = zpool_import_status(config, &msgid);
+       reason = zpool_import_status(config, &msgid, &errata);
 
        (void) printf(gettext("   pool: %s\n"), name);
        (void) printf(gettext("     id: %llu\n"), (u_longlong_t)guid);
@@ -1688,6 +1799,11 @@ show_import(nvlist_t *config)
                    "resilvered.\n"));
                break;
 
+       case ZPOOL_STATUS_ERRATA:
+               (void) printf(gettext(" status: Errata #%d detected.\n"),
+                   errata);
+               break;
+
        default:
                /*
                 * No other status can be seen when importing pools.
@@ -1709,6 +1825,34 @@ show_import(nvlist_t *config)
                        (void) printf(gettext(" action: The pool can be "
                            "imported using its name or numeric "
                            "identifier and\n\tthe '-f' flag.\n"));
+               } else if (reason == ZPOOL_STATUS_ERRATA) {
+                       switch (errata) {
+                       case ZPOOL_ERRATA_NONE:
+                               break;
+
+                       case ZPOOL_ERRATA_ZOL_2094_SCRUB:
+                               (void) printf(gettext(" action: The pool can "
+                                   "be imported using its name or numeric "
+                                   "identifier,\n\thowever there is a compat"
+                                   "ibility issue which should be corrected"
+                                   "\n\tby running 'zpool scrub'\n"));
+                               break;
+
+                       case ZPOOL_ERRATA_ZOL_2094_ASYNC_DESTROY:
+                               (void) printf(gettext(" action: The pool can"
+                                   "not be imported with this version of ZFS "
+                                   "due to\n\tan active asynchronous destroy. "
+                                   "Revert to an earlier version\n\tand "
+                                   "allow the destroy to complete before "
+                                   "updating.\n"));
+                               break;
+
+                       default:
+                               /*
+                                * All errata must contain an action message.
+                                */
+                               assert(0);
+                       }
                } else {
                        (void) printf(gettext(" action: The pool can be "
                            "imported using its name or numeric "
@@ -1821,37 +1965,30 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
                return (1);
        } else if (state != POOL_STATE_EXPORTED &&
            !(flags & ZFS_IMPORT_ANY_HOST)) {
-               uint64_t hostid;
-
-               if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
-                   &hostid) == 0) {
-                       unsigned long system_hostid = gethostid() & 0xffffffff;
-
-                       if ((unsigned long)hostid != system_hostid) {
-                               char *hostname;
-                               uint64_t timestamp;
-                               time_t t;
-
-                               verify(nvlist_lookup_string(config,
-                                   ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
-                               verify(nvlist_lookup_uint64(config,
-                                   ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
-                               t = timestamp;
-                               (void) fprintf(stderr, gettext("cannot import "
-                                   "'%s': pool may be in use from other "
-                                   "system, it was last accessed by %s "
-                                   "(hostid: 0x%lx) on %s"), name, hostname,
-                                   (unsigned long)hostid,
-                                   asctime(localtime(&t)));
-                               (void) fprintf(stderr, gettext("use '-f' to "
-                                   "import anyway\n"));
-                               return (1);
-                       }
-               } else {
-                       (void) fprintf(stderr, gettext("cannot import '%s': "
-                           "pool may be in use from other system\n"), name);
-                       (void) fprintf(stderr, gettext("use '-f' to import "
-                           "anyway\n"));
+               uint64_t hostid = 0;
+               unsigned long system_hostid = get_system_hostid();
+
+               (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
+                   &hostid);
+
+               if (hostid != 0 && (unsigned long)hostid != system_hostid) {
+                       char *hostname;
+                       uint64_t timestamp;
+                       time_t t;
+
+                       verify(nvlist_lookup_string(config,
+                           ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
+                       verify(nvlist_lookup_uint64(config,
+                           ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
+                       t = timestamp;
+                       (void) fprintf(stderr, gettext("cannot import "
+                           "'%s': pool may be in use from other "
+                           "system, it was last accessed by %s "
+                           "(hostid: 0x%lx) on %s"), name, hostname,
+                           (unsigned long)hostid,
+                           asctime(localtime(&t)));
+                       (void) fprintf(stderr, gettext("use '-f' to "
+                           "import anyway\n"));
                        return (1);
                }
        }
@@ -1952,7 +2089,7 @@ zpool_do_import(int argc, char **argv)
        char *endptr;
 
        /* check options */
-       while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) {
+       while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:R:tT:VX")) != -1) {
                switch (c) {
                case 'a':
                        do_all = B_TRUE;
@@ -2006,17 +2143,20 @@ zpool_do_import(int argc, char **argv)
                        if (add_prop_list(zpool_prop_to_name(
                            ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
                                goto error;
-                       if (nvlist_lookup_string(props,
-                           zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
-                           &propval) == 0)
-                               break;
-                       if (add_prop_list(zpool_prop_to_name(
+                       if (add_prop_list_default(zpool_prop_to_name(
+                           ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+                               goto error;
+                       break;
+               case 't':
+                       flags |= ZFS_IMPORT_TEMP_NAME;
+                       if (add_prop_list_default(zpool_prop_to_name(
                            ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
                                goto error;
                        break;
+
                case 'T':
                        errno = 0;
-                       txg = strtoull(optarg, &endptr, 10);
+                       txg = strtoull(optarg, &endptr, 0);
                        if (errno != 0 || *endptr != '\0') {
                                (void) fprintf(stderr,
                                    gettext("invalid txg value\n"));
@@ -2114,8 +2254,10 @@ zpool_do_import(int argc, char **argv)
 
                errno = 0;
                searchguid = strtoull(argv[0], &endptr, 10);
-               if (errno != 0 || *endptr != '\0')
+               if (errno != 0 || *endptr != '\0') {
                        searchname = argv[0];
+                       searchguid = 0;
+               }
                found_config = NULL;
 
                /*
@@ -2541,7 +2683,7 @@ get_columns(void)
                columns = 999;
        }
 
-       return columns;
+       return (columns);
 }
 
 int
@@ -2678,10 +2820,11 @@ zpool_do_iostat(int argc, char **argv)
        unsigned long interval = 0, count = 0;
        zpool_list_t *list;
        boolean_t verbose = B_FALSE;
+       boolean_t omit_since_boot = B_FALSE;
        iostat_cbdata_t cb;
 
        /* check options */
-       while ((c = getopt(argc, argv, "T:v")) != -1) {
+       while ((c = getopt(argc, argv, "T:vy")) != -1) {
                switch (c) {
                case 'T':
                        get_timestamp_arg(*optarg);
@@ -2689,6 +2832,9 @@ zpool_do_iostat(int argc, char **argv)
                case 'v':
                        verbose = B_TRUE;
                        break;
+               case 'y':
+                       omit_since_boot = B_TRUE;
+                       break;
                case '?':
                        (void) fprintf(stderr, gettext("invalid option '%c'\n"),
                            optopt);
@@ -2728,11 +2874,16 @@ zpool_do_iostat(int argc, char **argv)
        cb.cb_namewidth = 0;
 
        for (;;) {
-               pool_list_update(list);
-
                if ((npools = pool_list_count(list)) == 0)
                        (void) fprintf(stderr, gettext("no pools available\n"));
                else {
+                       /*
+                        * If this is the first iteration and -y was supplied
+                        * we skip any printing.
+                        */
+                       boolean_t skip = (omit_since_boot &&
+                               cb.cb_iteration == 0);
+
                        /*
                         * Refresh all statistics.  This is done as an
                         * explicit step before calculating the maximum name
@@ -2754,12 +2905,18 @@ zpool_do_iostat(int argc, char **argv)
                                print_timestamp(timestamp_fmt);
 
                        /*
-                        * If it's the first time, or verbose mode, print the
-                        * header.
+                        * If it's the first time and we're not skipping it,
+                        * or either skip or verbose mode, print the header.
                         */
-                       if (++cb.cb_iteration == 1 || verbose)
+                       if ((++cb.cb_iteration == 1 && !skip) ||
+                               (skip != verbose))
                                print_iostat_header(&cb);
 
+                       if (skip) {
+                               (void) sleep(interval);
+                               continue;
+                       }
+
                        (void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
 
                        /*
@@ -2889,10 +3046,7 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
 
                right_justify = B_FALSE;
                if (pl->pl_prop != ZPROP_INVAL) {
-                       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,
+                       if (zpool_get_prop(zhp, pl->pl_prop, property,
                            sizeof (property), NULL) != 0)
                                propstr = "-";
                        else
@@ -2926,15 +3080,37 @@ 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)
+print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted,
+    boolean_t valid)
 {
        char propval[64];
        boolean_t fixed;
        size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
 
-       zfs_nicenum(value, propval, sizeof (propval));
+       switch (prop) {
+       case ZPOOL_PROP_EXPANDSZ:
+               if (value == 0)
+                       (void) strlcpy(propval, "-", sizeof (propval));
+               else
+                       zfs_nicenum(value, propval, sizeof (propval));
+               break;
+       case ZPOOL_PROP_FRAGMENTATION:
+               if (value == ZFS_FRAG_INVALID) {
+                       (void) strlcpy(propval, "-", sizeof (propval));
+               } else {
+                       (void) snprintf(propval, sizeof (propval), "%llu%%",
+                           (unsigned long long)value);
+               }
+               break;
+       case ZPOOL_PROP_CAPACITY:
+               (void) snprintf(propval, sizeof (propval), "%llu%%",
+                   (unsigned long long)value);
+               break;
+       default:
+               zfs_nicenum(value, propval, sizeof (propval));
+       }
 
-       if (prop == ZPOOL_PROP_EXPANDSZ && value == 0)
+       if (!valid)
                (void) strlcpy(propval, "-", sizeof (propval));
 
        if (scripted)
@@ -2957,6 +3133,9 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
            (uint64_t **)&vs, &c) == 0);
 
        if (name != NULL) {
+               boolean_t toplevel = (vs->vs_space != 0);
+               uint64_t cap;
+
                if (scripted)
                        (void) printf("\t%s", name);
                else if (strlen(name) + depth > cb->cb_namewidth)
@@ -2965,22 +3144,26 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
                        (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);
+               /*
+                * Print the properties for the individual vdevs. Some
+                * properties are only applicable to toplevel vdevs. The
+                * '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,
+                   toplevel);
+               print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted,
+                   toplevel);
+               print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc,
+                   scripted, toplevel);
+               print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted,
+                   B_TRUE);
+               print_one_column(ZPOOL_PROP_FRAGMENTATION,
+                   vs->vs_fragmentation, scripted,
+                   (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel));
+               cap = (vs->vs_space == 0) ? 0 :
+                   (vs->vs_alloc * 100 / vs->vs_space);
+               print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel);
                (void) printf("\n");
        }
 
@@ -3049,7 +3232,8 @@ list_callback(zpool_handle_t *zhp, void *data)
  *     -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"
+ *             "name,size,allocated,free,expandsize,fragmentation,capacity,"
+ *             "dedupratio,health,altroot"
  *     -T      Display a timestamp in date(1) or Unix format
  *
  * List all pools in the system, whether or not they're healthy.  Output space
@@ -3062,8 +3246,8 @@ zpool_do_list(int argc, char **argv)
        int ret = 0;
        list_cbdata_t cb = { 0 };
        static char default_props[] =
-           "name,size,allocated,free,capacity,dedupratio,"
-           "health,altroot";
+           "name,size,allocated,free,expandsize,fragmentation,capacity,"
+           "dedupratio,health,altroot";
        char *props = default_props;
        unsigned long interval = 0, count = 0;
        zpool_list_t *list;
@@ -3104,17 +3288,10 @@ zpool_do_list(int argc, char **argv)
        if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
                usage(B_FALSE);
 
-       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 ((list = pool_list_get(argc, argv, &cb.cb_proplist,
+                   &ret)) == NULL)
+                       return (1);
 
                if (pool_list_count(list) == 0)
                        break;
@@ -3134,9 +3311,16 @@ zpool_do_list(int argc, char **argv)
                if (count != 0 && --count == 0)
                        break;
 
+               pool_list_free(list);
                (void) sleep(interval);
        }
 
+       if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
+               (void) printf(gettext("no pools available\n"));
+               ret = 0;
+       }
+
+       pool_list_free(list);
        zprop_free_list(cb.cb_proplist);
        return (ret);
 }
@@ -4098,13 +4282,14 @@ status_callback(zpool_handle_t *zhp, void *data)
        status_cbdata_t *cbp = data;
        nvlist_t *config, *nvroot;
        char *msgid;
-       int reason;
+       zpool_status_t reason;
+       zpool_errata_t errata;
        const char *health;
        uint_t c;
        vdev_stat_t *vs;
 
        config = zpool_get_config(zhp, NULL);
-       reason = zpool_get_status(zhp, &msgid);
+       reason = zpool_get_status(zhp, &msgid, &errata);
 
        cbp->cb_count++;
 
@@ -4322,6 +4507,39 @@ status_callback(zpool_handle_t *zhp, void *data)
                    "'zpool clear'.\n"));
                break;
 
+       case ZPOOL_STATUS_HOSTID_MISMATCH:
+               (void) printf(gettext("status: Mismatch between pool hostid "
+                   "and system hostid on imported pool.\n\tThis pool was "
+                   "previously imported into a system with a different "
+                   "hostid,\n\tand then was verbatim imported into this "
+                   "system.\n"));
+               (void) printf(gettext("action: Export this pool on all systems "
+                   "on which it is imported.\n"
+                   "\tThen import it to correct the mismatch.\n"));
+               break;
+
+       case ZPOOL_STATUS_ERRATA:
+               (void) printf(gettext("status: Errata #%d detected.\n"),
+                   errata);
+
+               switch (errata) {
+               case ZPOOL_ERRATA_NONE:
+                       break;
+
+               case ZPOOL_ERRATA_ZOL_2094_SCRUB:
+                       (void) printf(gettext("action: To correct the issue "
+                           "run 'zpool scrub'.\n"));
+                       break;
+
+               default:
+                       /*
+                        * All errata which allow the pool to be imported
+                        * must contain an action message.
+                        */
+                       assert(0);
+               }
+               break;
+
        default:
                /*
                 * The remaining errors can't actually be generated, yet.
@@ -4493,12 +4711,33 @@ typedef struct upgrade_cbdata {
        char    **cb_argv;
 } upgrade_cbdata_t;
 
+static int
+check_unsupp_fs(zfs_handle_t *zhp, void *unsupp_fs)
+{
+       int zfs_version = (int) zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+       int *count = (int *)unsupp_fs;
+
+       if (zfs_version > ZPL_VERSION) {
+               (void) printf(gettext("%s (v%d) is not supported by this "
+                   "implementation of ZFS.\n"),
+                   zfs_get_name(zhp), zfs_version);
+               (*count)++;
+       }
+
+       zfs_iter_filesystems(zhp, check_unsupp_fs, unsupp_fs);
+
+       zfs_close(zhp);
+
+       return (0);
+}
+
 static int
 upgrade_version(zpool_handle_t *zhp, uint64_t version)
 {
        int ret;
        nvlist_t *config;
        uint64_t oldversion;
+       int unsupp_fs = 0;
 
        config = zpool_get_config(zhp, NULL);
        verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
@@ -4507,6 +4746,17 @@ upgrade_version(zpool_handle_t *zhp, uint64_t version)
        assert(SPA_VERSION_IS_SUPPORTED(oldversion));
        assert(oldversion < version);
 
+       ret = zfs_iter_root(zpool_get_handle(zhp), check_unsupp_fs, &unsupp_fs);
+       if (ret != 0)
+               return (ret);
+
+       if (unsupp_fs) {
+               (void) fprintf(stderr, gettext("Upgrade not performed due "
+                   "to %d unsupported filesystems (max v%d).\n"),
+                   unsupp_fs, (int) ZPL_VERSION);
+               return (1);
+       }
+
        ret = zpool_upgrade(zhp, version);
        if (ret != 0)
                return (ret);
@@ -4585,13 +4835,6 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
                        return (ret);
                printnl = B_TRUE;
 
-#if 0
-               /*
-                * XXX: This code can be enabled when Illumos commit
-                * 4445fffbbb1ea25fd0e9ea68b9380dd7a6709025 is merged.
-                * It reworks the history logging among other things.
-                */
-
                /*
                 * If they did "zpool upgrade -a", then we could
                 * be doing ioctls to different pools.  We need
@@ -4600,7 +4843,6 @@ upgrade_cb(zpool_handle_t *zhp, void *arg)
                 */
                (void) zpool_log_history(g_zfs, history_str);
                log_history = B_FALSE;
-#endif
        }
 
        if (cbp->cb_version >= SPA_VERSION_FEATURES) {
@@ -4700,6 +4942,14 @@ upgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg)
 
                                (void) printf(gettext("      %s\n"), fname);
                        }
+                       /*
+                        * If they did "zpool upgrade -a", then we could
+                        * be doing ioctls to different pools.  We need
+                        * to log this history once to each pool, and bypass
+                        * the normal history logging that happens in main().
+                        */
+                       (void) zpool_log_history(g_zfs, history_str);
+                       log_history = B_FALSE;
                }
        }
 
@@ -4716,7 +4966,7 @@ upgrade_one(zpool_handle_t *zhp, void *data)
        int ret;
 
        if (strcmp("log", zpool_get_name(zhp)) == 0) {
-               (void) printf(gettext("'log' is now a reserved word\n"
+               (void) fprintf(stderr, gettext("'log' is now a reserved word\n"
                    "Pool 'log' must be renamed using export and import"
                    " to upgrade.\n"));
                return (1);
@@ -4955,8 +5205,8 @@ zpool_do_upgrade(int argc, char **argv)
 
 typedef struct hist_cbdata {
        boolean_t first;
-       int longfmt;
-       int internal;
+       boolean_t longfmt;
+       boolean_t internal;
 } hist_cbdata_t;
 
 /*
@@ -4968,21 +5218,8 @@ get_history_one(zpool_handle_t *zhp, void *data)
        nvlist_t *nvhis;
        nvlist_t **records;
        uint_t numrecords;
-       char *cmdstr;
-       char *pathstr;
-       uint64_t dst_time;
-       time_t tsec;
-       struct tm t;
-       char tbuf[30];
        int ret, i;
-       uint64_t who;
-       struct passwd *pwd;
-       char *hostname;
-       char *zonename;
-       char internalstr[MAXPATHLEN];
        hist_cbdata_t *cb = (hist_cbdata_t *)data;
-       uint64_t txg;
-       uint64_t ievent;
 
        cb->first = B_FALSE;
 
@@ -4994,62 +5231,95 @@ get_history_one(zpool_handle_t *zhp, void *data)
        verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
            &records, &numrecords) == 0);
        for (i = 0; i < numrecords; i++) {
-               if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
-                   &dst_time) != 0)
-                       continue;
+               nvlist_t *rec = records[i];
+               char tbuf[30] = "";
 
-               /* is it an internal event or a standard event? */
-               if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
-                   &cmdstr) != 0) {
-                       if (cb->internal == 0)
-                               continue;
+               if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
+                       time_t tsec;
+                       struct tm t;
+
+                       tsec = fnvlist_lookup_uint64(records[i],
+                           ZPOOL_HIST_TIME);
+                       (void) localtime_r(&tsec, &t);
+                       (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
+               }
 
-                       if (nvlist_lookup_uint64(records[i],
-                           ZPOOL_HIST_INT_EVENT, &ievent) != 0)
+               if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
+                       (void) printf("%s %s", tbuf,
+                           fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
+               } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
+                       int ievent =
+                           fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
+                       if (!cb->internal)
                                continue;
-                       verify(nvlist_lookup_uint64(records[i],
-                           ZPOOL_HIST_TXG, &txg) == 0);
-                       verify(nvlist_lookup_string(records[i],
-                           ZPOOL_HIST_INT_STR, &pathstr) == 0);
-                       if (ievent >= LOG_END)
+                       if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
+                               (void) printf("%s unrecognized record:\n",
+                                   tbuf);
+                               dump_nvlist(rec, 4);
+                               continue;
+                       }
+                       (void) printf("%s [internal %s txg:%lld] %s", tbuf,
+                           zfs_history_event_names[ievent],
+                           (longlong_t) fnvlist_lookup_uint64(
+                           rec, ZPOOL_HIST_TXG),
+                           fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
+               } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
+                       if (!cb->internal)
+                               continue;
+                       (void) printf("%s [txg:%lld] %s", tbuf,
+                           (longlong_t) fnvlist_lookup_uint64(
+                           rec, ZPOOL_HIST_TXG),
+                           fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
+                       if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
+                               (void) printf(" %s (%llu)",
+                                   fnvlist_lookup_string(rec,
+                                   ZPOOL_HIST_DSNAME),
+                                   (u_longlong_t)fnvlist_lookup_uint64(rec,
+                                   ZPOOL_HIST_DSID));
+                       }
+                       (void) printf(" %s", fnvlist_lookup_string(rec,
+                           ZPOOL_HIST_INT_STR));
+               } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
+                       if (!cb->internal)
                                continue;
-                       (void) snprintf(internalstr,
-                           sizeof (internalstr),
-                           "[internal %s txg:%llu] %s",
-                           zfs_history_event_names[ievent], (u_longlong_t)txg,
-                           pathstr);
-                       cmdstr = internalstr;
+                       (void) printf("%s ioctl %s\n", tbuf,
+                           fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
+                       if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
+                               (void) printf("    input:\n");
+                               dump_nvlist(fnvlist_lookup_nvlist(rec,
+                                   ZPOOL_HIST_INPUT_NVL), 8);
+                       }
+                       if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
+                               (void) printf("    output:\n");
+                               dump_nvlist(fnvlist_lookup_nvlist(rec,
+                                   ZPOOL_HIST_OUTPUT_NVL), 8);
+                       }
+               } else {
+                       if (!cb->internal)
+                               continue;
+                       (void) printf("%s unrecognized record:\n", tbuf);
+                       dump_nvlist(rec, 4);
                }
-               tsec = dst_time;
-               (void) localtime_r(&tsec, &t);
-               (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
-               (void) printf("%s %s", tbuf, cmdstr);
 
                if (!cb->longfmt) {
                        (void) printf("\n");
                        continue;
                }
                (void) printf(" [");
-               if (nvlist_lookup_uint64(records[i],
-                   ZPOOL_HIST_WHO, &who) == 0) {
-                       pwd = getpwuid((uid_t)who);
-                       if (pwd)
-                               (void) printf("user %s on",
-                                   pwd->pw_name);
-                       else
-                               (void) printf("user %d on",
-                                   (int)who);
-               } else {
-                       (void) printf(gettext("no info]\n"));
-                       continue;
+               if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
+                       uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
+                       struct passwd *pwd = getpwuid(who);
+                       (void) printf("user %d ", (int)who);
+                       if (pwd != NULL)
+                               (void) printf("(%s) ", pwd->pw_name);
                }
-               if (nvlist_lookup_string(records[i],
-                   ZPOOL_HIST_HOST, &hostname) == 0) {
-                       (void) printf(" %s", hostname);
+               if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
+                       (void) printf("on %s",
+                           fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
                }
-               if (nvlist_lookup_string(records[i],
-                   ZPOOL_HIST_ZONE, &zonename) == 0) {
-                       (void) printf(":%s", zonename);
+               if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
+                       (void) printf(":%s",
+                           fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
                }
 
                (void) printf("]");
@@ -5066,8 +5336,6 @@ get_history_one(zpool_handle_t *zhp, void *data)
  *
  * Displays the history of commands that modified pools.
  */
-
-
 int
 zpool_do_history(int argc, char **argv)
 {
@@ -5080,10 +5348,10 @@ zpool_do_history(int argc, char **argv)
        while ((c = getopt(argc, argv, "li")) != -1) {
                switch (c) {
                case 'l':
-                       cbdata.longfmt = 1;
+                       cbdata.longfmt = B_TRUE;
                        break;
                case 'i':
-                       cbdata.internal = 1;
+                       cbdata.internal = B_TRUE;
                        break;
                case '?':
                        (void) fprintf(stderr, gettext("invalid option '%c'\n"),
@@ -5122,10 +5390,10 @@ zpool_do_events_short(nvlist_t *nvl)
        verify(nvlist_lookup_int64_array(nvl, FM_EREPORT_TIME, &tv, &n) == 0);
        memset(str, ' ', 32);
        (void) ctime_r((const time_t *)&tv[0], ctime_str);
-       (void) strncpy(str,    ctime_str+4,  6);             /* 'Jun 30'     */
-       (void) strncpy(str+7,  ctime_str+20, 4);             /* '1993'       */
-       (void) strncpy(str+12, ctime_str+11, 8);             /* '21:49:08'   */
-       (void) sprintf(str+20, ".%09lld", (longlong_t)tv[1]);/* '.123456789' */
+       (void) strncpy(str, ctime_str+4,  6);           /* 'Jun 30' */
+       (void) strncpy(str+7, ctime_str+20, 4);         /* '1993' */
+       (void) strncpy(str+12, ctime_str+11, 8);        /* '21:49:08' */
+       (void) sprintf(str+20, ".%09lld", (longlong_t)tv[1]); /* '.123456789' */
        (void) printf(gettext("%s "), str);
 
        verify(nvlist_lookup_string(nvl, FM_CLASS, &ptr) == 0);
@@ -5233,10 +5501,10 @@ zpool_do_events_nvprint(nvlist_t *nvl, int depth)
                        printf(gettext("(%d embedded nvlists)\n"), nelem);
                        for (i = 0; i < nelem; i++) {
                                printf(gettext("%*s%s[%d] = %s\n"),
-                                      depth, "", name, i, "(embedded nvlist)");
+                                   depth, "", name, i, "(embedded nvlist)");
                                zpool_do_events_nvprint(val[i], depth + 8);
                                printf(gettext("%*s(end %s[%i])\n"),
-                                      depth, "", name, i);
+                                   depth, "", name, i);
                        }
                        printf(gettext("%*s(end %s)\n"), depth, "", name);
                        }
@@ -5314,7 +5582,8 @@ zpool_do_events_nvprint(nvlist_t *nvl, int depth)
 
                        (void) nvpair_value_int64_array(nvp, &val, &nelem);
                        for (i = 0; i < nelem; i++)
-                               printf(gettext("0x%llx "), (u_longlong_t)val[i]);
+                               printf(gettext("0x%llx "),
+                                   (u_longlong_t)val[i]);
 
                        break;
                        }
@@ -5325,12 +5594,24 @@ zpool_do_events_nvprint(nvlist_t *nvl, int depth)
 
                        (void) nvpair_value_uint64_array(nvp, &val, &nelem);
                        for (i = 0; i < nelem; i++)
-                               printf(gettext("0x%llx "), (u_longlong_t)val[i]);
+                               printf(gettext("0x%llx "),
+                                   (u_longlong_t)val[i]);
+
+                       break;
+                       }
+
+               case DATA_TYPE_STRING_ARRAY: {
+                       char **str;
+                       uint_t i, nelem;
+
+                       (void) nvpair_value_string_array(nvp, &str, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               printf(gettext("\"%s\" "),
+                                   str[i] ? str[i] : "<NULL>");
 
                        break;
                        }
 
-               case DATA_TYPE_STRING_ARRAY:
                case DATA_TYPE_BOOLEAN_ARRAY:
                case DATA_TYPE_BYTE_ARRAY:
                case DATA_TYPE_DOUBLE:
@@ -5347,17 +5628,17 @@ static int
 zpool_do_events_next(ev_opts_t *opts)
 {
        nvlist_t *nvl;
-       int cleanup_fd, ret, dropped;
+       int zevent_fd, ret, dropped;
 
-        cleanup_fd = open(ZFS_DEV, O_RDWR);
-        VERIFY(cleanup_fd >= 0);
+       zevent_fd = open(ZFS_DEV, O_RDWR);
+       VERIFY(zevent_fd >= 0);
 
        if (!opts->scripted)
                (void) printf(gettext("%-30s %s\n"), "TIME", "CLASS");
 
        while (1) {
                ret = zpool_events_next(g_zfs, &nvl, &dropped,
-                   !!opts->follow, cleanup_fd);
+                   (opts->follow ? ZEVENT_NONE : ZEVENT_NONBLOCK), zevent_fd);
                if (ret || nvl == NULL)
                        break;
 
@@ -5375,7 +5656,7 @@ zpool_do_events_next(ev_opts_t *opts)
                nvlist_free(nvl);
        }
 
-        VERIFY(0 == close(cleanup_fd));
+       VERIFY(0 == close(zevent_fd));
 
        return (ret);
 }
@@ -5433,7 +5714,7 @@ zpool_do_events(int argc, char **argv)
        else
                ret = zpool_do_events_next(&opts);
 
-       return ret;
+       return (ret);
 }
 
 static int
@@ -5466,8 +5747,8 @@ get_callback(zpool_handle_t *zhp, void *data)
                                    NULL, NULL);
                        }
                } else {
-                       if (zpool_get_prop(zhp, pl->pl_prop, value,
-                           sizeof (value), &srctype) != 0)
+                       if (zpool_get_prop_literal(zhp, pl->pl_prop, value,
+                           sizeof (value), &srctype, cbp->cb_literal) != 0)
                                continue;
 
                        zprop_print_one_property(zpool_get_name(zhp), cbp,
@@ -5483,9 +5764,30 @@ zpool_do_get(int argc, char **argv)
 {
        zprop_get_cbdata_t cb = { 0 };
        zprop_list_t fake_name = { 0 };
-       int ret;
+       int c, ret;
 
-       if (argc < 2) {
+       /* check options */
+       while ((c = getopt(argc, argv, "pH")) != -1) {
+               switch (c) {
+               case 'p':
+                       cb.cb_literal = B_TRUE;
+                       break;
+
+               case 'H':
+                       cb.cb_scripted = B_TRUE;
+                       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);
@@ -5499,10 +5801,12 @@ 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,
-           ZFS_TYPE_POOL) != 0)
+       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"));
@@ -5510,7 +5814,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)
@@ -5613,6 +5917,8 @@ main(int argc, char **argv)
        (void) setlocale(LC_ALL, "");
        (void) textdomain(TEXT_DOMAIN);
 
+       dprintf_setup(&argc, argv);
+
        opterr = 0;
 
        /*
@@ -5628,17 +5934,17 @@ main(int argc, char **argv)
        /*
         * Special case '-?'
         */
-       if ((strcmp(cmdname, "-?") == 0) ||
-            strcmp(cmdname, "--help") == 0)
+       if ((strcmp(cmdname, "-?") == 0) || strcmp(cmdname, "--help") == 0)
                usage(B_TRUE);
 
-       if ((g_zfs = libzfs_init()) == NULL)
+       if ((g_zfs = libzfs_init()) == NULL) {
+               (void) fprintf(stderr, "%s", libzfs_error_init(errno));
                return (1);
+       }
 
        libzfs_print_on_error(g_zfs, B_TRUE);
 
-       zpool_set_history_str("zpool", argc, argv, history_str);
-       verify(zpool_stage_history(g_zfs, history_str) == 0);
+       zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
 
        /*
         * Run the appropriate command.
@@ -5666,6 +5972,9 @@ main(int argc, char **argv)
                ret = 1;
        }
 
+       if (ret == 0 && log_history)
+               (void) zpool_log_history(g_zfs, history_str);
+
        libzfs_fini(g_zfs);
 
        /*