]> git.proxmox.com Git - mirror_zfs.git/blobdiff - cmd/zpool/zpool_main.c
Fix GCC 12 compilation errors
[mirror_zfs.git] / cmd / zpool / zpool_main.c
index d7cce73d3dffc43f5d6ebdcfee46a0e41a21d44f..0b55bf21f448d7f73a9519b65bce7ab5e253b3ee 100644 (file)
@@ -6,7 +6,7 @@
  * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
+ * or https://opensource.org/licenses/CDDL-1.0.
  * See the License for the specific language governing permissions
  * and limitations under the License.
  *
@@ -50,7 +50,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <strings.h>
 #include <time.h>
 #include <unistd.h>
 #include <pwd.h>
@@ -519,7 +518,7 @@ print_vdev_prop_cb(int prop, void *cb)
  * that command.  Otherwise, iterate over the entire command table and display
  * a complete usage message.
  */
-static void
+static __attribute__((noreturn)) void
 usage(boolean_t requested)
 {
        FILE *fp = requested ? stdout : stderr;
@@ -549,7 +548,7 @@ usage(boolean_t requested)
            (strcmp(current_command->name, "get") == 0) ||
            (strcmp(current_command->name, "list") == 0))) {
 
-               (void) fprintf(fp,
+               (void) fprintf(fp, "%s",
                    gettext("\nthe following properties are supported:\n"));
 
                (void) fprintf(fp, "\n\t%-19s  %s   %s\n\n",
@@ -712,7 +711,7 @@ print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
 
        for (c = 0; c < children; c++) {
                uint64_t is_log = B_FALSE, is_hole = B_FALSE;
-               char *class = "";
+               char *class = (char *)"";
 
                (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
                    &is_hole);
@@ -724,7 +723,7 @@ print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
                (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
                    &is_log);
                if (is_log)
-                       class = VDEV_ALLOC_BIAS_LOG;
+                       class = (char *)VDEV_ALLOC_BIAS_LOG;
                (void) nvlist_lookup_string(child[c],
                    ZPOOL_CONFIG_ALLOCATION_BIAS, &class);
                if (strcmp(match, class) != 0)
@@ -805,7 +804,7 @@ prop_list_contains_feature(nvlist_t *proplist)
  * Add a property pair (name, string-value) into a property nvlist.
  */
 static int
-add_prop_list(const char *propname, char *propval, nvlist_t **props,
+add_prop_list(const char *propname, const char *propval, nvlist_t **props,
     boolean_t poolprop)
 {
        zpool_prop_t prop = ZPOOL_PROP_INVAL;
@@ -906,7 +905,8 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props,
  * 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)
+add_prop_list_default(const char *propname, const char *propval,
+    nvlist_t **props)
 {
        char *pval;
 
@@ -1196,6 +1196,7 @@ zpool_do_remove(int argc, char **argv)
                return (1);
 
        if (stop && noop) {
+               zpool_close(zhp);
                (void) fprintf(stderr, gettext("stop request ignored\n"));
                return (0);
        }
@@ -1760,17 +1761,19 @@ zpool_do_create(int argc, char **argv)
                            "feature@%s", feat->fi_uname);
 
                        if (!nvlist_lookup_string(props, propname, &propval)) {
-                               if (strcmp(propval, ZFS_FEATURE_DISABLED) == 0)
+                               if (strcmp(propval,
+                                   ZFS_FEATURE_DISABLED) == 0) {
                                        (void) nvlist_remove_all(props,
                                            propname);
-                               if (strcmp(propval,
+                               } else if (strcmp(propval,
                                    ZFS_FEATURE_ENABLED) == 0 &&
-                                   !requested_features[i])
+                                   !requested_features[i]) {
                                        (void) fprintf(stderr, gettext(
                                            "Warning: feature \"%s\" enabled "
                                            "but is not in specified "
                                            "'compatibility' feature set.\n"),
                                            feat->fi_uname);
+                               }
                        } else if (
                            enable_pool_features &&
                            feat->fi_zfs_mod_supported &&
@@ -1789,8 +1792,8 @@ zpool_do_create(int argc, char **argv)
                            tname ? tname : poolname, ZFS_TYPE_FILESYSTEM);
                        if (pool != NULL) {
                                if (zfs_mount(pool, NULL, 0) == 0) {
-                                       ret = zfs_shareall(pool);
-                                       zfs_commit_all_shares();
+                                       ret = zfs_share(pool, NULL);
+                                       zfs_commit_shares(NULL);
                                }
                                zfs_close(pool);
                        }
@@ -1986,40 +1989,21 @@ static int
 max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max,
     int name_flags)
 {
-       char *name;
-       nvlist_t **child;
-       uint_t c, children;
-       int ret;
-
-       name = zpool_vdev_name(g_zfs, zhp, nv, name_flags);
-       if (strlen(name) + depth > max)
-               max = strlen(name) + depth;
+       static const char *const subtypes[] =
+           {ZPOOL_CONFIG_SPARES, ZPOOL_CONFIG_L2CACHE, ZPOOL_CONFIG_CHILDREN};
 
+       char *name = zpool_vdev_name(g_zfs, zhp, nv, name_flags);
+       max = MAX(strlen(name) + depth, max);
        free(name);
 
-       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
-           &child, &children) == 0) {
-               for (c = 0; c < children; c++)
-                       if ((ret = max_width(zhp, child[c], depth + 2,
-                           max, name_flags)) > max)
-                               max = ret;
-       }
-
-       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
-           &child, &children) == 0) {
-               for (c = 0; c < children; c++)
-                       if ((ret = max_width(zhp, child[c], depth + 2,
-                           max, name_flags)) > max)
-                               max = ret;
-       }
-
-       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
-           &child, &children) == 0) {
-               for (c = 0; c < children; c++)
-                       if ((ret = max_width(zhp, child[c], depth + 2,
-                           max, name_flags)) > max)
-                               max = ret;
-       }
+       nvlist_t **child;
+       uint_t children;
+       for (size_t i = 0; i < ARRAY_SIZE(subtypes); ++i)
+               if (nvlist_lookup_nvlist_array(nv, subtypes[i],
+                   &child, &children) == 0)
+                       for (uint_t c = 0; c < children; ++c)
+                               max = MAX(max_width(zhp, child[c], depth + 2,
+                                   max, name_flags), max);
 
        return (max);
 }
@@ -2087,15 +2071,13 @@ typedef struct status_cbdata {
 } status_cbdata_t;
 
 /* Return 1 if string is NULL, empty, or whitespace; return 0 otherwise. */
-static int
-is_blank_str(char *str)
+static boolean_t
+is_blank_str(const char *str)
 {
-       while (str != NULL && *str != '\0') {
+       for (; str != NULL && *str != '\0'; ++str)
                if (!isblank(*str))
-                       return (0);
-               str++;
-       }
-       return (1);
+                       return (B_FALSE);
+       return (B_TRUE);
 }
 
 /* Print command output lines for specific vdev in a specific pool */
@@ -2104,7 +2086,7 @@ zpool_print_cmd(vdev_cmd_data_list_t *vcdl, const char *pool, char *path)
 {
        vdev_cmd_data_t *data;
        int i, j;
-       char *val;
+       const char *val;
 
        for (i = 0; i < vcdl->count; i++) {
                if ((strcmp(vcdl->data[i].path, path) != 0) ||
@@ -2135,17 +2117,17 @@ zpool_print_cmd(vdev_cmd_data_list_t *vcdl, const char *pool, char *path)
 
                        printf("%*s", vcdl->uniq_cols_width[j], val);
                        if (j < vcdl->uniq_cols_cnt - 1)
-                               printf("  ");
+                               fputs("  ", stdout);
                }
 
                /* Print out any values that aren't in a column at the end */
                for (j = data->cols_cnt; j < data->lines_cnt; j++) {
                        /* Did we have any columns?  If so print a spacer. */
                        if (vcdl->uniq_cols_cnt > 0)
-                               printf("  ");
+                               fputs("  ", stdout);
 
                        val = data->lines[j];
-                       printf("%s", val ? val : "");
+                       fputs(val ?: "", stdout);
                }
                break;
        }
@@ -2258,7 +2240,7 @@ print_status_trim(vdev_stat_t *vs, boolean_t verbose)
  * Return the color associated with a health string.  This includes returning
  * NULL for no color change.
  */
-static char *
+static const char *
 health_str_to_color(const char *health)
 {
        if (strcmp(health, gettext("FAULTED")) == 0 ||
@@ -2294,7 +2276,7 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
        const char *state;
        char *type;
        char *path = NULL;
-       char *rcolor = NULL, *wcolor = NULL, *ccolor = NULL;
+       const char *rcolor = NULL, *wcolor = NULL, *ccolor = NULL;
 
        if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
            &child, &children) != 0)
@@ -2336,13 +2318,13 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
                        ccolor = ANSI_RED;
 
                if (cb->cb_literal) {
-                       printf(" ");
+                       fputc(' ', stdout);
                        printf_color(rcolor, "%5llu",
                            (u_longlong_t)vs->vs_read_errors);
-                       printf(" ");
+                       fputc(' ', stdout);
                        printf_color(wcolor, "%5llu",
                            (u_longlong_t)vs->vs_write_errors);
-                       printf(" ");
+                       fputc(' ', stdout);
                        printf_color(ccolor, "%5llu",
                            (u_longlong_t)vs->vs_checksum_errors);
                } else {
@@ -2350,11 +2332,11 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
                        zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
                        zfs_nicenum(vs->vs_checksum_errors, cbuf,
                            sizeof (cbuf));
-                       printf(" ");
+                       fputc(' ', stdout);
                        printf_color(rcolor, "%5s", rbuf);
-                       printf(" ");
+                       fputc(' ', stdout);
                        printf_color(wcolor, "%5s", wbuf);
-                       printf(" ");
+                       fputc(' ', stdout);
                        printf_color(ccolor, "%5s", cbuf);
                }
                if (cb->cb_print_slow_ios) {
@@ -2471,7 +2453,7 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
 
        if (vs->vs_scan_removing != 0) {
                (void) printf(gettext("  (removing)"));
-       } else if (vs->vs_noalloc != 0) {
+       } else if (VDEV_STAT_VALID(vs_noalloc, vsc) && vs->vs_noalloc != 0) {
                (void) printf(gettext("  (non-allocating)"));
        }
 
@@ -2481,7 +2463,14 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
        (void) nvlist_lookup_uint64_array(root, ZPOOL_CONFIG_SCAN_STATS,
            (uint64_t **)&ps, &c);
 
-       if (ps != NULL && ps->pss_state == DSS_SCANNING && children == 0) {
+       /*
+        * If you force fault a drive that's resilvering, its scan stats can
+        * get frozen in time, giving the false impression that it's
+        * being resilvered.  That's why we check the state to see if the vdev
+        * is healthy before reporting "resilvering" or "repairing".
+        */
+       if (ps != NULL && ps->pss_state == DSS_SCANNING && children == 0 &&
+           vs->vs_state == VDEV_STATE_HEALTHY) {
                if (vs->vs_scan_processed != 0) {
                        (void) printf(gettext("  (%s)"),
                            (ps->pss_func == POOL_SCAN_RESILVER) ?
@@ -2493,7 +2482,7 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
 
        /* The top-level vdevs have the rebuild stats */
        if (vrs != NULL && vrs->vrs_state == VDEV_REBUILD_ACTIVE &&
-           children == 0) {
+           children == 0 && vs->vs_state == VDEV_STATE_HEALTHY) {
                if (vs->vs_rebuild_processed != 0) {
                        (void) printf(gettext("  (resilvering)"));
                }
@@ -2689,7 +2678,7 @@ print_class_vdevs(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
                    &is_log);
 
                if (is_log) {
-                       bias = VDEV_ALLOC_CLASS_LOGS;
+                       bias = (char *)VDEV_ALLOC_CLASS_LOGS;
                } else {
                        (void) nvlist_lookup_string(child[c],
                            ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
@@ -2729,8 +2718,8 @@ show_import(nvlist_t *config, boolean_t report_error)
        char *name;
        uint64_t guid;
        uint64_t hostid = 0;
-       char *msgid;
-       char *hostname = "unknown";
+       const char *msgid;
+       const char *hostname = "unknown";
        nvlist_t *nvroot, *nvinfo;
        zpool_status_t reason;
        zpool_errata_t errata;
@@ -3039,9 +3028,8 @@ show_import(nvlist_t *config, boolean_t report_error)
                                    ZPOOL_CONFIG_MMP_HOSTID);
 
                        (void) printf(gettext(" action: The pool must be "
-                           "exported from %s (hostid=%lx)\n\tbefore it "
-                           "can be safely imported.\n"), hostname,
-                           (unsigned long) hostid);
+                           "exported from %s (hostid=%"PRIx64")\n\tbefore it "
+                           "can be safely imported.\n"), hostname, hostid);
                        break;
                case ZPOOL_STATUS_HOSTID_REQUIRED:
                        (void) printf(gettext(" action: Set a unique system "
@@ -3136,7 +3124,7 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
 {
        int ret = 0;
        zpool_handle_t *zhp;
-       char *name;
+       const char *name;
        uint64_t version;
 
        name = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME);
@@ -3157,7 +3145,7 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
                            ZPOOL_CONFIG_MMP_STATE);
 
                if (mmp_state == MMP_STATE_ACTIVE) {
-                       char *hostname = "<unknown>";
+                       const char *hostname = "<unknown>";
                        uint64_t hostid = 0;
 
                        if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTNAME))
@@ -3170,17 +3158,17 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
 
                        (void) fprintf(stderr, gettext("cannot import '%s': "
                            "pool is imported on %s (hostid: "
-                           "0x%lx)\nExport the pool on the other system, "
-                           "then run 'zpool import'.\n"),
-                           name, hostname, (unsigned long) hostid);
+                           "0x%"PRIx64")\nExport the pool on the other "
+                           "system, then run 'zpool import'.\n"),
+                           name, hostname, hostid);
                } else if (mmp_state == MMP_STATE_NO_HOSTID) {
                        (void) fprintf(stderr, gettext("Cannot import '%s': "
                            "pool has the multihost property on and the\n"
                            "system's hostid is not set. Set a unique hostid "
                            "with the zgenhostid(8) command.\n"), name);
                } else {
-                       char *hostname = "<unknown>";
-                       uint64_t timestamp = 0;
+                       const char *hostname = "<unknown>";
+                       time_t timestamp = 0;
                        uint64_t hostid = 0;
 
                        if (nvlist_exists(config, ZPOOL_CONFIG_HOSTNAME))
@@ -3197,10 +3185,10 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
 
                        (void) fprintf(stderr, gettext("cannot import '%s': "
                            "pool was previously in use from another system.\n"
-                           "Last accessed by %s (hostid=%lx) at %s"
+                           "Last accessed by %s (hostid=%"PRIx64") at %s"
                            "The pool can be imported, use 'zpool import -f' "
                            "to import the pool.\n"), name, hostname,
-                           (unsigned long)hostid, ctime((time_t *)&timestamp));
+                           hostid, ctime(&timestamp));
                }
 
                return (1);
@@ -3210,7 +3198,7 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
                return (1);
 
        if (newname != NULL)
-               name = (char *)newname;
+               name = newname;
 
        if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
                return (1);
@@ -3219,11 +3207,9 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
         * Loading keys is best effort. We don't want to return immediately
         * if it fails but we do want to give the error to the caller.
         */
-       if (flags & ZFS_IMPORT_LOAD_KEYS) {
-               ret = zfs_crypto_attempt_load_keys(g_zfs, name);
-               if (ret != 0)
+       if (flags & ZFS_IMPORT_LOAD_KEYS &&
+           zfs_crypto_attempt_load_keys(g_zfs, name) != 0)
                        ret = 1;
-       }
 
        if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
            !(flags & ZFS_IMPORT_ONLY) &&
@@ -3273,7 +3259,7 @@ import_pools(nvlist_t *pools, nvlist_t *props, char *mntopts, int flags,
                        if (first)
                                first = B_FALSE;
                        else if (!do_all)
-                               (void) printf("\n");
+                               (void) fputc('\n', stdout);
 
                        if (do_all) {
                                err |= do_import(config, NULL, mntopts,
@@ -3724,9 +3710,8 @@ zpool_do_import(int argc, char **argv)
        if (argc == 0 && geteuid() != 0) {
                (void) fprintf(stderr, gettext("cannot "
                    "discover pools: permission denied\n"));
-               if (searchdirs != NULL)
-                       free(searchdirs);
 
+               free(searchdirs);
                nvlist_free(props);
                nvlist_free(policy);
                return (1);
@@ -3788,7 +3773,12 @@ zpool_do_import(int argc, char **argv)
        idata.scan = do_scan;
        idata.policy = policy;
 
-       pools = zpool_search_import(g_zfs, &idata, &libzfs_config_ops);
+       libpc_handle_t lpch = {
+               .lpc_lib_handle = g_zfs,
+               .lpc_ops = &libzfs_config_ops,
+               .lpc_printerr = B_TRUE
+       };
+       pools = zpool_search_import(&lpch, &idata);
 
        if (pools != NULL && pool_exists &&
            (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
@@ -3844,7 +3834,7 @@ zpool_do_import(int argc, char **argv)
                 */
                idata.scan = B_TRUE;
                nvlist_free(pools);
-               pools = zpool_search_import(g_zfs, &idata, &libzfs_config_ops);
+               pools = zpool_search_import(&lpch, &idata);
 
                err = import_pools(pools, props, mntopts, flags,
                    argc >= 1 ? argv[0] : NULL,
@@ -4690,7 +4680,7 @@ print_iostat_default(vdev_stat_t *vs, iostat_cbdata_t *cb, double scale)
            format, column_width, cb->cb_scripted);
 }
 
-static const char *class_name[] = {
+static const char *const class_name[] = {
        VDEV_ALLOC_BIAS_DEDUP,
        VDEV_ALLOC_BIAS_SPECIAL,
        VDEV_ALLOC_CLASS_LOGS
@@ -4850,7 +4840,7 @@ children:
                        continue;
 
                vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
-                   cb->cb_vdevs.cb_name_flags);
+                   cb->cb_vdevs.cb_name_flags | VDEV_NAME_TYPE_ID);
                ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
                    newchild[c], cb, depth + 2);
                free(vname);
@@ -4859,7 +4849,7 @@ children:
        /*
         * print all other top-level devices
         */
-       for (uint_t n = 0; n < 3; n++) {
+       for (uint_t n = 0; n < ARRAY_SIZE(class_name); n++) {
                boolean_t printed = B_FALSE;
 
                for (c = 0; c < children; c++) {
@@ -4870,7 +4860,7 @@ children:
                        (void) nvlist_lookup_uint64(newchild[c],
                            ZPOOL_CONFIG_IS_LOG, &islog);
                        if (islog) {
-                               bias = VDEV_ALLOC_CLASS_LOGS;
+                               bias = (char *)VDEV_ALLOC_CLASS_LOGS;
                        } else {
                                (void) nvlist_lookup_string(newchild[c],
                                    ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
@@ -4894,7 +4884,7 @@ children:
                        }
 
                        vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
-                           cb->cb_vdevs.cb_name_flags);
+                           cb->cb_vdevs.cb_name_flags | VDEV_NAME_TYPE_ID);
                        ret += print_vdev_stats(zhp, vname, oldnv ?
                            oldchild[c] : NULL, newchild[c], cb, depth + 2);
                        free(vname);
@@ -5024,7 +5014,7 @@ get_namewidth(zpool_handle_t *zhp, int min_width, int flags, boolean_t verbose)
        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));
+               size_t poolname_len = strlen(zpool_get_name(zhp));
                if (verbose == B_FALSE) {
                        width = MAX(poolname_len, min_width);
                } else {
@@ -5404,7 +5394,7 @@ terminal_height(void)
 static void
 print_zpool_script_help(char *name, char *path)
 {
-       char *argv[] = {path, "-h", NULL};
+       char *argv[] = {path, (char *)"-h", NULL};
        char **lines = NULL;
        int lines_cnt = 0;
        int rc;
@@ -5456,7 +5446,7 @@ print_zpool_dir_scripts(char *dirpath)
  * Print out help text for all zpool status/iostat -c scripts.
  */
 static void
-print_zpool_script_list(char *subcommand)
+print_zpool_script_list(const char *subcommand)
 {
        char *dir, *sp, *tmp;
 
@@ -5489,8 +5479,8 @@ get_namewidth_iostat(zpool_handle_t *zhp, void *data)
         * get_namewidth() returns the maximum width of any name in that column
         * for any pool/vdev/device line that will be output.
         */
-       width = get_namewidth(zhp, cb->cb_namewidth, cb->cb_vdevs.cb_name_flags,
-           cb->cb_verbose);
+       width = get_namewidth(zhp, cb->cb_namewidth,
+           cb->cb_vdevs.cb_name_flags | VDEV_NAME_TYPE_ID, cb->cb_verbose);
 
        /*
         * The width we are calculating is the width of the header and also the
@@ -5963,12 +5953,12 @@ print_header(list_cbdata_t *cb)
                }
 
                if (!first)
-                       (void) printf("  ");
+                       (void) fputs("  ", stdout);
                else
                        first = B_FALSE;
 
                right_justify = B_FALSE;
-               if (pl->pl_prop != ZPROP_INVAL) {
+               if (pl->pl_prop != ZPROP_USERPROP) {
                        header = zpool_prop_column_name(pl->pl_prop);
                        right_justify = zpool_prop_align_right(pl->pl_prop);
                } else {
@@ -5981,14 +5971,14 @@ print_header(list_cbdata_t *cb)
                }
 
                if (pl->pl_next == NULL && !right_justify)
-                       (void) printf("%s", header);
+                       (void) fputs(header, stdout);
                else if (right_justify)
                        (void) printf("%*s", (int)width, header);
                else
                        (void) printf("%-*s", (int)width, header);
        }
 
-       (void) printf("\n");
+       (void) fputc('\n', stdout);
 }
 
 /*
@@ -6001,7 +5991,7 @@ 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;
+       const char *propstr;
        boolean_t right_justify;
        size_t width;
 
@@ -6018,15 +6008,15 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
 
                if (!first) {
                        if (cb->cb_scripted)
-                               (void) printf("\t");
+                               (void) fputc('\t', stdout);
                        else
-                               (void) printf("  ");
+                               (void) fputs("  ", stdout);
                } else {
                        first = B_FALSE;
                }
 
                right_justify = B_FALSE;
-               if (pl->pl_prop != ZPROP_INVAL) {
+               if (pl->pl_prop != ZPROP_USERPROP) {
                        if (zpool_get_prop(zhp, pl->pl_prop, property,
                            sizeof (property), NULL, cb->cb_literal) != 0)
                                propstr = "-";
@@ -6050,14 +6040,14 @@ print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
                 * format specifier.
                 */
                if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
-                       (void) printf("%s", propstr);
+                       (void) fputs(propstr, stdout);
                else if (right_justify)
                        (void) printf("%*s", (int)width, propstr);
                else
                        (void) printf("%-*s", (int)width, propstr);
        }
 
-       (void) printf("\n");
+       (void) fputc('\n', stdout);
 }
 
 static void
@@ -6069,6 +6059,7 @@ print_one_column(zpool_prop_t prop, uint64_t value, const char *str,
        size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
 
        switch (prop) {
+       case ZPOOL_PROP_SIZE:
        case ZPOOL_PROP_EXPANDSZ:
        case ZPOOL_PROP_CHECKPOINT:
        case ZPOOL_PROP_DEDUPRATIO:
@@ -6130,8 +6121,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";
+       const char *dashes = "%-*s      -      -      -        -         "
+           "-      -      -      -         -\n";
 
        verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
            (uint64_t **)&vs, &c) == 0);
@@ -6164,8 +6155,12 @@ 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, NULL, scripted,
-                   toplevel, format);
+               if (VDEV_STAT_VALID(vs_pspace, c) && vs->vs_pspace)
+                       print_one_column(ZPOOL_PROP_SIZE, vs->vs_pspace, NULL,
+                           scripted, B_TRUE, format);
+               else
+                       print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, NULL,
+                           scripted, toplevel, format);
                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,
@@ -6193,7 +6188,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
                }
                print_one_column(ZPOOL_PROP_HEALTH, 0, state, scripted,
                    B_TRUE, format);
-               (void) printf("\n");
+               (void) fputc('\n', stdout);
        }
 
        if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
@@ -6216,13 +6211,13 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
                        continue;
 
                vname = zpool_vdev_name(g_zfs, zhp, child[c],
-                   cb->cb_name_flags);
+                   cb->cb_name_flags | VDEV_NAME_TYPE_ID);
                print_list_stats(zhp, vname, child[c], cb, depth + 2, B_FALSE);
                free(vname);
        }
 
        /* list the classes: 'logs', 'dedup', and 'special' */
-       for (uint_t n = 0; n < 3; n++) {
+       for (uint_t n = 0; n < ARRAY_SIZE(class_name); n++) {
                boolean_t printed = B_FALSE;
 
                for (c = 0; c < children; c++) {
@@ -6231,7 +6226,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
 
                        if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
                            &islog) == 0 && islog) {
-                               bias = VDEV_ALLOC_CLASS_LOGS;
+                               bias = (char *)VDEV_ALLOC_CLASS_LOGS;
                        } else {
                                (void) nvlist_lookup_string(child[c],
                                    ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
@@ -6250,7 +6245,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
                                printed = B_TRUE;
                        }
                        vname = zpool_vdev_name(g_zfs, zhp, child[c],
-                           cb->cb_name_flags);
+                           cb->cb_name_flags | VDEV_NAME_TYPE_ID);
                        print_list_stats(zhp, vname, child[c], cb, depth + 2,
                            B_FALSE);
                        free(vname);
@@ -6316,8 +6311,8 @@ get_namewidth_list(zpool_handle_t *zhp, void *data)
        list_cbdata_t *cb = data;
        int width;
 
-       width = get_namewidth(zhp, cb->cb_namewidth, cb->cb_name_flags,
-           cb->cb_verbose);
+       width = get_namewidth(zhp, cb->cb_namewidth,
+           cb->cb_name_flags | VDEV_NAME_TYPE_ID, cb->cb_verbose);
 
        if (width < 9)
                width = 9;
@@ -8135,7 +8130,7 @@ status_callback(zpool_handle_t *zhp, void *data)
 {
        status_cbdata_t *cbp = data;
        nvlist_t *config, *nvroot;
-       char *msgid;
+       const char *msgid;
        zpool_status_t reason;
        zpool_errata_t errata;
        const char *health;
@@ -8180,12 +8175,12 @@ status_callback(zpool_handle_t *zhp, void *data)
        printf("  ");
        printf_color(ANSI_BOLD, gettext("pool:"));
        printf(" %s\n", zpool_get_name(zhp));
-       printf(" ");
+       fputc(' ', stdout);
        printf_color(ANSI_BOLD, gettext("state: "));
 
        printf_color(health_str_to_color(health), "%s", health);
 
-       printf("\n");
+       fputc('\n', stdout);
 
        switch (reason) {
        case ZPOOL_STATUS_MISSING_DEV_R:
@@ -9214,7 +9209,7 @@ zpool_do_upgrade(int argc, char **argv)
                }
        }
 
-       (void) printf(gettext("This system supports ZFS pool feature "
+       (void) printf("%s", gettext("This system supports ZFS pool feature "
            "flags.\n\n"));
        if (showversions) {
                int i;
@@ -10067,7 +10062,6 @@ zpool_do_get(int argc, char **argv)
        zprop_list_t fake_name = { 0 };
        int ret;
        int c, i;
-       char *value;
        char *propstr = NULL;
 
        cb.cb_first = B_TRUE;
@@ -10094,35 +10088,34 @@ zpool_do_get(int argc, char **argv)
                        cb.cb_scripted = B_TRUE;
                        break;
                case 'o':
-                       bzero(&cb.cb_columns, sizeof (cb.cb_columns));
+                       memset(&cb.cb_columns, 0, sizeof (cb.cb_columns));
                        i = 0;
-                       while (*optarg != '\0') {
-                               static char *col_subopts[] =
+
+                       for (char *tok; (tok = strsep(&optarg, ",")); ) {
+                               static const char *const col_opts[] =
                                { "name", "property", "value", "source",
-                               "all", NULL };
+                                   "all" };
+                               static const zfs_get_column_t col_cols[] =
+                               { GET_COL_NAME, GET_COL_PROPERTY, GET_COL_VALUE,
+                                   GET_COL_SOURCE };
 
-                               if (i == ZFS_GET_NCOLS) {
+                               if (i == ZFS_GET_NCOLS - 1) {
                                        (void) fprintf(stderr, gettext("too "
                                        "many fields given to -o "
                                        "option\n"));
                                        usage(B_FALSE);
                                }
 
-                               switch (getsubopt(&optarg, col_subopts,
-                                   &value)) {
-                               case 0:
-                                       cb.cb_columns[i++] = GET_COL_NAME;
-                                       break;
-                               case 1:
-                                       cb.cb_columns[i++] = GET_COL_PROPERTY;
-                                       break;
-                               case 2:
-                                       cb.cb_columns[i++] = GET_COL_VALUE;
-                                       break;
-                               case 3:
-                                       cb.cb_columns[i++] = GET_COL_SOURCE;
-                                       break;
-                               case 4:
+                               for (c = 0; c < ARRAY_SIZE(col_opts); ++c)
+                                       if (strcmp(tok, col_opts[c]) == 0)
+                                               goto found;
+
+                               (void) fprintf(stderr,
+                                   gettext("invalid column name '%s'\n"), tok);
+                               usage(B_FALSE);
+
+found:
+                               if (c >= 4) {
                                        if (i > 0) {
                                                (void) fprintf(stderr,
                                                    gettext("\"all\" conflicts "
@@ -10130,18 +10123,12 @@ zpool_do_get(int argc, char **argv)
                                                    "given to -o option\n"));
                                                usage(B_FALSE);
                                        }
-                                       cb.cb_columns[0] = GET_COL_NAME;
-                                       cb.cb_columns[1] = GET_COL_PROPERTY;
-                                       cb.cb_columns[2] = GET_COL_VALUE;
-                                       cb.cb_columns[3] = GET_COL_SOURCE;
-                                       i = ZFS_GET_NCOLS;
-                                       break;
-                               default:
-                                       (void) fprintf(stderr,
-                                           gettext("invalid column name "
-                                           "'%s'\n"), value);
-                                       usage(B_FALSE);
-                               }
+
+                                       memcpy(cb.cb_columns, col_cols,
+                                           sizeof (col_cols));
+                                       i = ZFS_GET_NCOLS - 1;
+                               } else
+                                       cb.cb_columns[i++] = col_cols[c];
                        }
                        break;
                case '?':
@@ -10510,8 +10497,8 @@ print_wait_status_row(wait_data_t *wd, zpool_handle_t *zhp, int row)
        pool_checkpoint_stat_t *pcs = NULL;
        pool_scan_stat_t *pss = NULL;
        pool_removal_stat_t *prs = NULL;
-       char *headers[] = {"DISCARD", "FREE", "INITIALIZE", "REPLACE",
-           "REMOVE", "RESILVER", "SCRUB", "TRIM"};
+       const char *const headers[] = {"DISCARD", "FREE", "INITIALIZE",
+           "REPLACE", "REMOVE", "RESILVER", "SCRUB", "TRIM"};
        int col_widths[ZPOOL_WAIT_NUM_ACTIVITIES];
 
        /* Calculate the width of each column */
@@ -10533,7 +10520,7 @@ print_wait_status_row(wait_data_t *wd, zpool_handle_t *zhp, int row)
                        if (wd->wd_enabled[i])
                                (void) printf("%*s", col_widths[i], headers[i]);
                }
-               (void) printf("\n");
+               (void) fputc('\n', stdout);
        }
 
        /* Bytes of work remaining in each activity */
@@ -10669,9 +10656,7 @@ int
 zpool_do_wait(int argc, char **argv)
 {
        boolean_t verbose = B_FALSE;
-       int c;
-       char *value;
-       int i;
+       int c, i;
        unsigned long count;
        pthread_t status_thr;
        int error = 0;
@@ -10705,28 +10690,26 @@ zpool_do_wait(int argc, char **argv)
                        get_timestamp_arg(*optarg);
                        break;
                case 't':
-               {
-                       static char *col_subopts[] = { "discard", "free",
-                           "initialize", "replace", "remove", "resilver",
-                           "scrub", "trim", NULL };
-
                        /* Reset activities array */
-                       bzero(&wd.wd_enabled, sizeof (wd.wd_enabled));
-                       while (*optarg != '\0') {
-                               int activity = getsubopt(&optarg, col_subopts,
-                                   &value);
-
-                               if (activity < 0) {
-                                       (void) fprintf(stderr,
-                                           gettext("invalid activity '%s'\n"),
-                                           value);
-                                       usage(B_FALSE);
-                               }
+                       memset(&wd.wd_enabled, 0, sizeof (wd.wd_enabled));
+
+                       for (char *tok; (tok = strsep(&optarg, ",")); ) {
+                               static const char *const col_opts[] = {
+                                   "discard", "free", "initialize", "replace",
+                                   "remove", "resilver", "scrub", "trim" };
+
+                               for (i = 0; i < ARRAY_SIZE(col_opts); ++i)
+                                       if (strcmp(tok, col_opts[i]) == 0) {
+                                               wd.wd_enabled[i] = B_TRUE;
+                                               goto found;
+                                       }
 
-                               wd.wd_enabled[activity] = B_TRUE;
+                               (void) fprintf(stderr,
+                                   gettext("invalid activity '%s'\n"), tok);
+                               usage(B_FALSE);
+found:;
                        }
                        break;
-               }
                case '?':
                        (void) fprintf(stderr, gettext("invalid option '%c'\n"),
                            optopt);
@@ -10824,11 +10807,9 @@ zpool_do_wait(int argc, char **argv)
 }
 
 static int
-find_command_idx(char *command, int *idx)
+find_command_idx(const char *command, int *idx)
 {
-       int i;
-
-       for (i = 0; i < NCOMMAND; i++) {
+       for (int i = 0; i < NCOMMAND; ++i) {
                if (command_table[i].name == NULL)
                        continue;
 
@@ -10847,11 +10828,7 @@ static int
 zpool_do_version(int argc, char **argv)
 {
        (void) argc, (void) argv;
-
-       if (zfs_version_print() == -1)
-               return (1);
-
-       return (0);
+       return (zfs_version_print() != 0);
 }
 
 /*
@@ -10934,7 +10911,7 @@ main(int argc, char **argv)
         * Many commands modify input strings for string parsing reasons.
         * We create a copy to protect the original argv.
         */
-       newargv = malloc((argc + 1) * sizeof (newargv[0]));
+       newargv = safe_malloc((argc + 1) * sizeof (newargv[0]));
        for (i = 0; i < argc; i++)
                newargv[i] = strdup(argv[i]);
        newargv[argc] = NULL;