xref: /illumos-gate/usr/src/cmd/zpool/zpool_main.c (revision 20f5062b9c5143e4b4bd21245fcebdb21d40c08c)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5441d80aaSlling  * Common Development and Distribution License (the "License").
6441d80aaSlling  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
2199653d4eSeschrock 
22fa9e4066Sahrens /*
233f9d6ad7SLin Ling  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
245cabbc6bSPrashanth Sreenivasa  * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
25e1d5e507SFrederik Wessels  * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
269edf9ebdSPrasad Joshi  * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
27b327cd3fSIgor Kozhukhov  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
286401734dSWill Andrews  * Copyright 2016 Nexenta Systems, Inc.
291702cce7SAlek Pinchuk  * Copyright (c) 2017 Datto Inc.
30663207adSDon Brady  * Copyright (c) 2017, Intel Corporation.
31084fd14fSBrian Behlendorf  * Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com>
32dd50e0ccSTony Hutter  * Copyright 2020 Joyent, Inc.
335711d393Sloli  * Copyright (c) 2012 by Cyril Plisko. All rights reserved.
34c4e4d410SAndy Fiddaman  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
35fa9e4066Sahrens  */
36fa9e4066Sahrens 
37fa9e4066Sahrens #include <assert.h>
38fa9e4066Sahrens #include <ctype.h>
39fa9e4066Sahrens #include <dirent.h>
40fa9e4066Sahrens #include <errno.h>
41fa9e4066Sahrens #include <fcntl.h>
4286714001SSerapheim Dimitropoulos #include <getopt.h>
43fa9e4066Sahrens #include <libgen.h>
44fa9e4066Sahrens #include <libintl.h>
45fa9e4066Sahrens #include <libuutil.h>
46fa9e4066Sahrens #include <locale.h>
47fa9e4066Sahrens #include <stdio.h>
48fa9e4066Sahrens #include <stdlib.h>
49fa9e4066Sahrens #include <string.h>
50fa9e4066Sahrens #include <strings.h>
51fa9e4066Sahrens #include <unistd.h>
52fa9e4066Sahrens #include <priv.h>
53ecd6cf80Smarks #include <pwd.h>
54ecd6cf80Smarks #include <zone.h>
554263d13fSGeorge Wilson #include <zfs_prop.h>
56b1b8ab34Slling #include <sys/fs/zfs.h>
57fa9e4066Sahrens #include <sys/stat.h>
58e0f1c0afSOlaf Faaland #include <sys/debug.h>
59dd50e0ccSTony Hutter #include <math.h>
60dd50e0ccSTony Hutter #include <sys/sysmacros.h>
61dd50e0ccSTony Hutter #include <sys/termios.h>
62fa9e4066Sahrens 
63fa9e4066Sahrens #include <libzfs.h>
64d8ab6e12SDon Brady #include <libzutil.h>
65fa9e4066Sahrens 
66fa9e4066Sahrens #include "zpool_util.h"
67b7b97454Sperrin #include "zfs_comutil.h"
68ad135b5dSChristopher Siden #include "zfeature_common.h"
69fa9e4066Sahrens 
7026fd7700SKrishnendu Sadhukhan - Sun Microsystems #include "statcommon.h"
7126fd7700SKrishnendu Sadhukhan - Sun Microsystems 
72fa9e4066Sahrens static int zpool_do_create(int, char **);
73fa9e4066Sahrens static int zpool_do_destroy(int, char **);
74fa9e4066Sahrens 
75fa9e4066Sahrens static int zpool_do_add(int, char **);
7699653d4eSeschrock static int zpool_do_remove(int, char **);
776401734dSWill Andrews static int zpool_do_labelclear(int, char **);
78fa9e4066Sahrens 
7986714001SSerapheim Dimitropoulos static int zpool_do_checkpoint(int, char **);
8086714001SSerapheim Dimitropoulos 
81fa9e4066Sahrens static int zpool_do_list(int, char **);
82fa9e4066Sahrens static int zpool_do_iostat(int, char **);
83fa9e4066Sahrens static int zpool_do_status(int, char **);
84fa9e4066Sahrens 
85fa9e4066Sahrens static int zpool_do_online(int, char **);
86fa9e4066Sahrens static int zpool_do_offline(int, char **);
87ea8dc4b6Seschrock static int zpool_do_clear(int, char **);
884263d13fSGeorge Wilson static int zpool_do_reopen(int, char **);
89fa9e4066Sahrens 
90e9103aaeSGarrett D'Amore static int zpool_do_reguid(int, char **);
91e9103aaeSGarrett D'Amore 
92fa9e4066Sahrens static int zpool_do_attach(int, char **);
93fa9e4066Sahrens static int zpool_do_detach(int, char **);
94fa9e4066Sahrens static int zpool_do_replace(int, char **);
951195e687SMark J Musante static int zpool_do_split(int, char **);
96fa9e4066Sahrens 
97094e47e9SGeorge Wilson static int zpool_do_initialize(int, char **);
98fa9e4066Sahrens static int zpool_do_scrub(int, char **);
99e4c795beSTom Caputi static int zpool_do_resilver(int, char **);
100084fd14fSBrian Behlendorf static int zpool_do_trim(int, char **);
101fa9e4066Sahrens 
102fa9e4066Sahrens static int zpool_do_import(int, char **);
103fa9e4066Sahrens static int zpool_do_export(int, char **);
104fa9e4066Sahrens 
105eaca9bbdSeschrock static int zpool_do_upgrade(int, char **);
106eaca9bbdSeschrock 
10706eeb2adSek static int zpool_do_history(int, char **);
10806eeb2adSek 
109b1b8ab34Slling static int zpool_do_get(int, char **);
110b1b8ab34Slling static int zpool_do_set(int, char **);
111b1b8ab34Slling 
1129c2acf00SAlek Pinchuk static int zpool_do_sync(int, char **);
1139c2acf00SAlek Pinchuk 
114fa9e4066Sahrens /*
115fa9e4066Sahrens  * These libumem hooks provide a reasonable set of defaults for the allocator's
116fa9e4066Sahrens  * debugging facilities.
117fa9e4066Sahrens  */
11829ab75c9Srm 
11929ab75c9Srm #ifdef DEBUG
120fa9e4066Sahrens const char *
12199653d4eSeschrock _umem_debug_init(void)
122fa9e4066Sahrens {
123fa9e4066Sahrens 	return ("default,verbose"); /* $UMEM_DEBUG setting */
124fa9e4066Sahrens }
125fa9e4066Sahrens 
126fa9e4066Sahrens const char *
127fa9e4066Sahrens _umem_logging_init(void)
128fa9e4066Sahrens {
129fa9e4066Sahrens 	return ("fail,contents"); /* $UMEM_LOGGING setting */
130fa9e4066Sahrens }
13129ab75c9Srm #endif
132fa9e4066Sahrens 
13365cd9f28Seschrock typedef enum {
13465cd9f28Seschrock 	HELP_ADD,
13565cd9f28Seschrock 	HELP_ATTACH,
136ea8dc4b6Seschrock 	HELP_CLEAR,
13765cd9f28Seschrock 	HELP_CREATE,
13886714001SSerapheim Dimitropoulos 	HELP_CHECKPOINT,
13965cd9f28Seschrock 	HELP_DESTROY,
14065cd9f28Seschrock 	HELP_DETACH,
14165cd9f28Seschrock 	HELP_EXPORT,
14206eeb2adSek 	HELP_HISTORY,
14365cd9f28Seschrock 	HELP_IMPORT,
14465cd9f28Seschrock 	HELP_IOSTAT,
1456401734dSWill Andrews 	HELP_LABELCLEAR,
14665cd9f28Seschrock 	HELP_LIST,
14765cd9f28Seschrock 	HELP_OFFLINE,
14865cd9f28Seschrock 	HELP_ONLINE,
14965cd9f28Seschrock 	HELP_REPLACE,
15099653d4eSeschrock 	HELP_REMOVE,
151094e47e9SGeorge Wilson 	HELP_INITIALIZE,
15265cd9f28Seschrock 	HELP_SCRUB,
153e4c795beSTom Caputi 	HELP_RESILVER,
154084fd14fSBrian Behlendorf 	HELP_TRIM,
155eaca9bbdSeschrock 	HELP_STATUS,
156b1b8ab34Slling 	HELP_UPGRADE,
157b1b8ab34Slling 	HELP_GET,
1581195e687SMark J Musante 	HELP_SET,
159e9103aaeSGarrett D'Amore 	HELP_SPLIT,
1609c2acf00SAlek Pinchuk 	HELP_SYNC,
1614263d13fSGeorge Wilson 	HELP_REGUID,
1624263d13fSGeorge Wilson 	HELP_REOPEN
16365cd9f28Seschrock } zpool_help_t;
16465cd9f28Seschrock 
16565cd9f28Seschrock 
166dd50e0ccSTony Hutter /*
167dd50e0ccSTony Hutter  * Flags for stats to display with "zpool iostats"
168dd50e0ccSTony Hutter  */
169dd50e0ccSTony Hutter enum iostat_type {
170dd50e0ccSTony Hutter 	IOS_DEFAULT = 0,
171dd50e0ccSTony Hutter 	IOS_LATENCY = 1,
172dd50e0ccSTony Hutter 	IOS_QUEUES = 2,
173dd50e0ccSTony Hutter 	IOS_L_HISTO = 3,
174dd50e0ccSTony Hutter 	IOS_RQ_HISTO = 4,
175dd50e0ccSTony Hutter 	IOS_COUNT,	/* always last element */
176dd50e0ccSTony Hutter };
177dd50e0ccSTony Hutter 
178dd50e0ccSTony Hutter /* iostat_type entries as bitmasks */
179dd50e0ccSTony Hutter #define	IOS_DEFAULT_M	(1ULL << IOS_DEFAULT)
180dd50e0ccSTony Hutter #define	IOS_LATENCY_M	(1ULL << IOS_LATENCY)
181dd50e0ccSTony Hutter #define	IOS_QUEUES_M	(1ULL << IOS_QUEUES)
182dd50e0ccSTony Hutter #define	IOS_L_HISTO_M	(1ULL << IOS_L_HISTO)
183dd50e0ccSTony Hutter #define	IOS_RQ_HISTO_M	(1ULL << IOS_RQ_HISTO)
184dd50e0ccSTony Hutter 
185dd50e0ccSTony Hutter /* Mask of all the histo bits */
186dd50e0ccSTony Hutter #define	IOS_ANYHISTO_M (IOS_L_HISTO_M | IOS_RQ_HISTO_M)
187dd50e0ccSTony Hutter 
188dd50e0ccSTony Hutter /*
189dd50e0ccSTony Hutter  * Lookup table for iostat flags to nvlist names.  Basically a list
190dd50e0ccSTony Hutter  * of all the nvlists a flag requires.  Also specifies the order in
191dd50e0ccSTony Hutter  * which data gets printed in zpool iostat.
192dd50e0ccSTony Hutter  */
193dd50e0ccSTony Hutter static const char *vsx_type_to_nvlist[IOS_COUNT][13] = {
194dd50e0ccSTony Hutter 	[IOS_L_HISTO] = {
195dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO,
196dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO,
197dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO,
198dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO,
199dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO,
200dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO,
201dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO,
202dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO,
203dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO,
204dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO,
205dd50e0ccSTony Hutter 	    NULL},
206dd50e0ccSTony Hutter 	[IOS_LATENCY] = {
207dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO,
208dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO,
209dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO,
210dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO,
211dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO,
212dd50e0ccSTony Hutter 	    NULL},
213dd50e0ccSTony Hutter 	[IOS_QUEUES] = {
214dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE,
215dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE,
216dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE,
217dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE,
218dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE,
219dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_TRIM_ACTIVE_QUEUE,
220dd50e0ccSTony Hutter 	    NULL},
221dd50e0ccSTony Hutter 	[IOS_RQ_HISTO] = {
222dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_SYNC_IND_R_HISTO,
223dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_SYNC_AGG_R_HISTO,
224dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_SYNC_IND_W_HISTO,
225dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_SYNC_AGG_W_HISTO,
226dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_ASYNC_IND_R_HISTO,
227dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_ASYNC_AGG_R_HISTO,
228dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_ASYNC_IND_W_HISTO,
229dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_ASYNC_AGG_W_HISTO,
230dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_IND_SCRUB_HISTO,
231dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_AGG_SCRUB_HISTO,
232dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_IND_TRIM_HISTO,
233dd50e0ccSTony Hutter 	    ZPOOL_CONFIG_VDEV_AGG_TRIM_HISTO,
234dd50e0ccSTony Hutter 	    NULL},
235dd50e0ccSTony Hutter };
236dd50e0ccSTony Hutter 
237dd50e0ccSTony Hutter 
238dd50e0ccSTony Hutter /*
239dd50e0ccSTony Hutter  * Given a cb->cb_flags with a histogram bit set, return the iostat_type.
240dd50e0ccSTony Hutter  * Right now, only one histo bit is ever set at one time, so we can
241dd50e0ccSTony Hutter  * just do a highbit64(a)
242dd50e0ccSTony Hutter  */
243dd50e0ccSTony Hutter #define	IOS_HISTO_IDX(a)	(highbit64(a & IOS_ANYHISTO_M) - 1)
244dd50e0ccSTony Hutter 
245fa9e4066Sahrens typedef struct zpool_command {
246fa9e4066Sahrens 	const char	*name;
247fa9e4066Sahrens 	int		(*func)(int, char **);
24865cd9f28Seschrock 	zpool_help_t	usage;
249fa9e4066Sahrens } zpool_command_t;
250fa9e4066Sahrens 
251fa9e4066Sahrens /*
252fa9e4066Sahrens  * Master command table.  Each ZFS command has a name, associated function, and
253ea8dc4b6Seschrock  * usage message.  The usage messages need to be internationalized, so we have
254ea8dc4b6Seschrock  * to have a function to return the usage message based on a command index.
25565cd9f28Seschrock  *
25665cd9f28Seschrock  * These commands are organized according to how they are displayed in the usage
25765cd9f28Seschrock  * message.  An empty command (one with a NULL name) indicates an empty line in
25865cd9f28Seschrock  * the generic usage message.
259fa9e4066Sahrens  */
260fa9e4066Sahrens static zpool_command_t command_table[] = {
26165cd9f28Seschrock 	{ "create",	zpool_do_create,	HELP_CREATE		},
26265cd9f28Seschrock 	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
263fa9e4066Sahrens 	{ NULL },
26465cd9f28Seschrock 	{ "add",	zpool_do_add,		HELP_ADD		},
26599653d4eSeschrock 	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
266fa9e4066Sahrens 	{ NULL },
2676401734dSWill Andrews 	{ "labelclear",	zpool_do_labelclear,	HELP_LABELCLEAR		},
2686401734dSWill Andrews 	{ NULL },
26986714001SSerapheim Dimitropoulos 	{ "checkpoint",	zpool_do_checkpoint,	HELP_CHECKPOINT		},
27086714001SSerapheim Dimitropoulos 	{ NULL },
27165cd9f28Seschrock 	{ "list",	zpool_do_list,		HELP_LIST		},
27265cd9f28Seschrock 	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
27365cd9f28Seschrock 	{ "status",	zpool_do_status,	HELP_STATUS		},
274fa9e4066Sahrens 	{ NULL },
27565cd9f28Seschrock 	{ "online",	zpool_do_online,	HELP_ONLINE		},
27665cd9f28Seschrock 	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
277ea8dc4b6Seschrock 	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
2784263d13fSGeorge Wilson 	{ "reopen",	zpool_do_reopen,	HELP_REOPEN		},
279fa9e4066Sahrens 	{ NULL },
28065cd9f28Seschrock 	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
28165cd9f28Seschrock 	{ "detach",	zpool_do_detach,	HELP_DETACH		},
28265cd9f28Seschrock 	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
2831195e687SMark J Musante 	{ "split",	zpool_do_split,		HELP_SPLIT		},
284fa9e4066Sahrens 	{ NULL },
285094e47e9SGeorge Wilson 	{ "initialize",	zpool_do_initialize,	HELP_INITIALIZE		},
286e4c795beSTom Caputi 	{ "resilver",	zpool_do_resilver,	HELP_RESILVER		},
28765cd9f28Seschrock 	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
288084fd14fSBrian Behlendorf 	{ "trim",	zpool_do_trim,		HELP_TRIM		},
289fa9e4066Sahrens 	{ NULL },
29065cd9f28Seschrock 	{ "import",	zpool_do_import,	HELP_IMPORT		},
29165cd9f28Seschrock 	{ "export",	zpool_do_export,	HELP_EXPORT		},
29206eeb2adSek 	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
293e9103aaeSGarrett D'Amore 	{ "reguid",	zpool_do_reguid,	HELP_REGUID		},
29406eeb2adSek 	{ NULL },
295b1b8ab34Slling 	{ "history",	zpool_do_history,	HELP_HISTORY		},
296b1b8ab34Slling 	{ "get",	zpool_do_get,		HELP_GET		},
297b1b8ab34Slling 	{ "set",	zpool_do_set,		HELP_SET		},
2989c2acf00SAlek Pinchuk 	{ "sync",	zpool_do_sync,		HELP_SYNC		},
299fa9e4066Sahrens };
300fa9e4066Sahrens 
301dd50e0ccSTony Hutter #define	NCOMMAND	(ARRAY_SIZE(command_table))
302fa9e4066Sahrens 
303663207adSDon Brady #define	VDEV_ALLOC_CLASS_LOGS	"logs"
304663207adSDon Brady 
3054445fffbSMatthew Ahrens static zpool_command_t *current_command;
3062a6b87f0Sek static char history_str[HIS_MAX_RECORD_LEN];
3074445fffbSMatthew Ahrens static boolean_t log_history = B_TRUE;
30826fd7700SKrishnendu Sadhukhan - Sun Microsystems static uint_t timestamp_fmt = NODATE;
30926fd7700SKrishnendu Sadhukhan - Sun Microsystems 
31065cd9f28Seschrock static const char *
3119a686fbcSPaul Dagnelie get_usage(zpool_help_t idx)
3129a686fbcSPaul Dagnelie {
31365cd9f28Seschrock 	switch (idx) {
31465cd9f28Seschrock 	case HELP_ADD:
3155711d393Sloli 		return (gettext("\tadd [-fgLnP] [-o property=value] "
3165711d393Sloli 		    "<pool> <vdev> ...\n"));
31765cd9f28Seschrock 	case HELP_ATTACH:
3185711d393Sloli 		return (gettext("\tattach [-f] [-o property=value] "
3195711d393Sloli 		    "<pool> <device> <new-device>\n"));
320ea8dc4b6Seschrock 	case HELP_CLEAR:
321468c413aSTim Haley 		return (gettext("\tclear [-nF] <pool> [device]\n"));
32265cd9f28Seschrock 	case HELP_CREATE:
3237855d95bSToomas Soome 		return (gettext("\tcreate [-fnd] [-B] "
3247855d95bSToomas Soome 		    "[-o property=value] ... \n"
32504e56356SAndriy Gapon 		    "\t    [-O file-system-property=value] ...\n"
32604e56356SAndriy Gapon 		    "\t    [-m mountpoint] [-R root] [-t tempname] "
32704e56356SAndriy Gapon 		    "<pool> <vdev> ...\n"));
32886714001SSerapheim Dimitropoulos 	case HELP_CHECKPOINT:
32986714001SSerapheim Dimitropoulos 		return (gettext("\tcheckpoint [--discard] <pool> ...\n"));
33065cd9f28Seschrock 	case HELP_DESTROY:
33165cd9f28Seschrock 		return (gettext("\tdestroy [-f] <pool>\n"));
33265cd9f28Seschrock 	case HELP_DETACH:
33365cd9f28Seschrock 		return (gettext("\tdetach <pool> <device>\n"));
33465cd9f28Seschrock 	case HELP_EXPORT:
33565cd9f28Seschrock 		return (gettext("\texport [-f] <pool> ...\n"));
33606eeb2adSek 	case HELP_HISTORY:
337ecd6cf80Smarks 		return (gettext("\thistory [-il] [<pool>] ...\n"));
33865cd9f28Seschrock 	case HELP_IMPORT:
3394c58d714Sdarrenm 		return (gettext("\timport [-d dir] [-D]\n"
340eb633035STom Caputi 		    "\timport [-d dir | -c cachefile] [-F [-n]] [-l] "
341eb633035STom Caputi 		    "<pool | id>\n"
3422f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
343eb633035STom Caputi 		    "\t    [-d dir | -c cachefile] [-D] [-l] [-f] [-m] [-N] "
344f9af39baSGeorge Wilson 		    "[-R root] [-F [-n]] -a\n"
3452f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
346eb633035STom Caputi 		    "\t    [-d dir | -c cachefile] [-D] [-l] [-f] [-m] [-N] "
34704e56356SAndriy Gapon 		    "[-R root] [-F [-n]] [-t]\n"
34886714001SSerapheim Dimitropoulos 		    "\t    [--rewind-to-checkpoint] <pool | id> [newpool]\n"));
34965cd9f28Seschrock 	case HELP_IOSTAT:
350dd50e0ccSTony Hutter 		return (gettext("\tiostat "
351dd50e0ccSTony Hutter 		    "[[-lq]|[-rw]] [-T d | u] [-ghHLpPvy]\n"
352*20f5062bSJerry Jelinek 		    "\t    [[pool] ...]|[pool vdev ...]|[vdev ...]]"
353dd50e0ccSTony Hutter 		    " [[-n] interval [count]]\n"));
3546401734dSWill Andrews 	case HELP_LABELCLEAR:
3556401734dSWill Andrews 		return (gettext("\tlabelclear [-f] <vdev>\n"));
35665cd9f28Seschrock 	case HELP_LIST:
357663207adSDon Brady 		return (gettext("\tlist [-gHLpPv] [-o property[,...]] "
3583f9d6ad7SLin Ling 		    "[-T d|u] [pool] ... [interval [count]]\n"));
35965cd9f28Seschrock 	case HELP_OFFLINE:
360441d80aaSlling 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
36165cd9f28Seschrock 	case HELP_ONLINE:
362441d80aaSlling 		return (gettext("\tonline <pool> <device> ...\n"));
36365cd9f28Seschrock 	case HELP_REPLACE:
36465cd9f28Seschrock 		return (gettext("\treplace [-f] <pool> <device> "
365e45ce728Sahrens 		    "[new-device]\n"));
36699653d4eSeschrock 	case HELP_REMOVE:
3675cabbc6bSPrashanth Sreenivasa 		return (gettext("\tremove [-nps] <pool> <device> ...\n"));
3684263d13fSGeorge Wilson 	case HELP_REOPEN:
36931d7e8faSGeorge Wilson 		return (gettext("\treopen <pool>\n"));
370094e47e9SGeorge Wilson 	case HELP_INITIALIZE:
371084fd14fSBrian Behlendorf 		return (gettext("\tinitialize [-c | -s] <pool> "
372084fd14fSBrian Behlendorf 		    "[<device> ...]\n"));
37365cd9f28Seschrock 	case HELP_SCRUB:
3741702cce7SAlek Pinchuk 		return (gettext("\tscrub [-s | -p] <pool> ...\n"));
375e4c795beSTom Caputi 	case HELP_RESILVER:
376e4c795beSTom Caputi 		return (gettext("\tresilver <pool> ...\n"));
377084fd14fSBrian Behlendorf 	case HELP_TRIM:
378084fd14fSBrian Behlendorf 		return (gettext("\ttrim [-d] [-r <rate>] [-c | -s] <pool> "
379084fd14fSBrian Behlendorf 		    "[<device> ...]\n"));
38065cd9f28Seschrock 	case HELP_STATUS:
381dd50e0ccSTony Hutter 		return (gettext("\tstatus "
382dd50e0ccSTony Hutter 		    "[-igLpPsvxD] [-T d|u] [pool] ... "
383663207adSDon Brady 		    "[interval [count]]\n"));
384eaca9bbdSeschrock 	case HELP_UPGRADE:
385eaca9bbdSeschrock 		return (gettext("\tupgrade\n"
386eaca9bbdSeschrock 		    "\tupgrade -v\n"
387990b4856Slling 		    "\tupgrade [-V version] <-a | pool ...>\n"));
388b1b8ab34Slling 	case HELP_GET:
389c58b3526SAdam Stevko 		return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] "
390c58b3526SAdam Stevko 		    "<\"all\" | property[,...]> <pool> ...\n"));
391b1b8ab34Slling 	case HELP_SET:
392b1b8ab34Slling 		return (gettext("\tset <property=value> <pool> \n"));
3931195e687SMark J Musante 	case HELP_SPLIT:
394eb633035STom Caputi 		return (gettext("\tsplit [-gLlnP] [-R altroot] [-o mntopts]\n"
3951195e687SMark J Musante 		    "\t    [-o property=value] <pool> <newpool> "
3961195e687SMark J Musante 		    "[<device> ...]\n"));
397e9103aaeSGarrett D'Amore 	case HELP_REGUID:
398e9103aaeSGarrett D'Amore 		return (gettext("\treguid <pool>\n"));
3999c2acf00SAlek Pinchuk 	case HELP_SYNC:
4009c2acf00SAlek Pinchuk 		return (gettext("\tsync [pool] ...\n"));
40165cd9f28Seschrock 	}
40265cd9f28Seschrock 
40365cd9f28Seschrock 	abort();
40465cd9f28Seschrock 	/* NOTREACHED */
40565cd9f28Seschrock }
40665cd9f28Seschrock 
407084fd14fSBrian Behlendorf static void
408084fd14fSBrian Behlendorf zpool_collect_leaves(zpool_handle_t *zhp, nvlist_t *nvroot, nvlist_t *res)
409084fd14fSBrian Behlendorf {
410084fd14fSBrian Behlendorf 	uint_t children = 0;
411084fd14fSBrian Behlendorf 	nvlist_t **child;
412084fd14fSBrian Behlendorf 	uint_t i;
413084fd14fSBrian Behlendorf 
414084fd14fSBrian Behlendorf 	(void) nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
415084fd14fSBrian Behlendorf 	    &child, &children);
416084fd14fSBrian Behlendorf 
417084fd14fSBrian Behlendorf 	if (children == 0) {
418084fd14fSBrian Behlendorf 		char *path = zpool_vdev_name(g_zfs, zhp, nvroot, 0);
419084fd14fSBrian Behlendorf 
420084fd14fSBrian Behlendorf 		if (strcmp(path, VDEV_TYPE_INDIRECT) != 0)
421084fd14fSBrian Behlendorf 			fnvlist_add_boolean(res, path);
422084fd14fSBrian Behlendorf 
423084fd14fSBrian Behlendorf 		free(path);
424084fd14fSBrian Behlendorf 		return;
425084fd14fSBrian Behlendorf 	}
426084fd14fSBrian Behlendorf 
427084fd14fSBrian Behlendorf 	for (i = 0; i < children; i++) {
428084fd14fSBrian Behlendorf 		zpool_collect_leaves(zhp, child[i], res);
429084fd14fSBrian Behlendorf 	}
430084fd14fSBrian Behlendorf }
431fa9e4066Sahrens 
432b1b8ab34Slling /*
433b1b8ab34Slling  * Callback routine that will print out a pool property value.
434b1b8ab34Slling  */
435990b4856Slling static int
436990b4856Slling print_prop_cb(int prop, void *cb)
437b1b8ab34Slling {
438b1b8ab34Slling 	FILE *fp = cb;
439b1b8ab34Slling 
440663207adSDon Brady 	(void) fprintf(fp, "\t%-19s  ", zpool_prop_to_name(prop));
441b1b8ab34Slling 
442990b4856Slling 	if (zpool_prop_readonly(prop))
443990b4856Slling 		(void) fprintf(fp, "  NO   ");
444990b4856Slling 	else
445b24ab676SJeff Bonwick 		(void) fprintf(fp, " YES   ");
446990b4856Slling 
447b1b8ab34Slling 	if (zpool_prop_values(prop) == NULL)
448b1b8ab34Slling 		(void) fprintf(fp, "-\n");
449b1b8ab34Slling 	else
450b1b8ab34Slling 		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
451b1b8ab34Slling 
452990b4856Slling 	return (ZPROP_CONT);
453b1b8ab34Slling }
454b1b8ab34Slling 
455fa9e4066Sahrens /*
456fa9e4066Sahrens  * Display usage message.  If we're inside a command, display only the usage for
457fa9e4066Sahrens  * that command.  Otherwise, iterate over the entire command table and display
458fa9e4066Sahrens  * a complete usage message.
459fa9e4066Sahrens  */
460fa9e4066Sahrens void
46199653d4eSeschrock usage(boolean_t requested)
462fa9e4066Sahrens {
463fa9e4066Sahrens 	FILE *fp = requested ? stdout : stderr;
464fa9e4066Sahrens 
465fa9e4066Sahrens 	if (current_command == NULL) {
466fa9e4066Sahrens 		int i;
467fa9e4066Sahrens 
468fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
469fa9e4066Sahrens 		(void) fprintf(fp,
470fa9e4066Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
471fa9e4066Sahrens 
472fa9e4066Sahrens 		for (i = 0; i < NCOMMAND; i++) {
473fa9e4066Sahrens 			if (command_table[i].name == NULL)
474fa9e4066Sahrens 				(void) fprintf(fp, "\n");
475fa9e4066Sahrens 			else
476fa9e4066Sahrens 				(void) fprintf(fp, "%s",
47765cd9f28Seschrock 				    get_usage(command_table[i].usage));
478fa9e4066Sahrens 		}
479fa9e4066Sahrens 	} else {
480fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
48165cd9f28Seschrock 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
482fa9e4066Sahrens 	}
483fa9e4066Sahrens 
484b1b8ab34Slling 	if (current_command != NULL &&
485b1b8ab34Slling 	    ((strcmp(current_command->name, "set") == 0) ||
486990b4856Slling 	    (strcmp(current_command->name, "get") == 0) ||
487990b4856Slling 	    (strcmp(current_command->name, "list") == 0))) {
488b1b8ab34Slling 
489b1b8ab34Slling 		(void) fprintf(fp,
490b1b8ab34Slling 		    gettext("\nthe following properties are supported:\n"));
491b1b8ab34Slling 
492663207adSDon Brady 		(void) fprintf(fp, "\n\t%-19s  %s   %s\n\n",
493990b4856Slling 		    "PROPERTY", "EDIT", "VALUES");
494b1b8ab34Slling 
495b1b8ab34Slling 		/* Iterate over all properties */
496990b4856Slling 		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
497990b4856Slling 		    ZFS_TYPE_POOL);
498ad135b5dSChristopher Siden 
499663207adSDon Brady 		(void) fprintf(fp, "\t%-19s   ", "feature@...");
500ad135b5dSChristopher Siden 		(void) fprintf(fp, "YES   disabled | enabled | active\n");
501ad135b5dSChristopher Siden 
502ad135b5dSChristopher Siden 		(void) fprintf(fp, gettext("\nThe feature@ properties must be "
503ad135b5dSChristopher Siden 		    "appended with a feature name.\nSee zpool-features(5).\n"));
504b1b8ab34Slling 	}
505b1b8ab34Slling 
506e9dbad6fSeschrock 	/*
507e9dbad6fSeschrock 	 * See comments at end of main().
508e9dbad6fSeschrock 	 */
509e9dbad6fSeschrock 	if (getenv("ZFS_ABORT") != NULL) {
510e9dbad6fSeschrock 		(void) printf("dumping core by request\n");
511e9dbad6fSeschrock 		abort();
512e9dbad6fSeschrock 	}
513e9dbad6fSeschrock 
514fa9e4066Sahrens 	exit(requested ? 0 : 2);
515fa9e4066Sahrens }
516fa9e4066Sahrens 
517663207adSDon Brady /*
518663207adSDon Brady  * print a pool vdev config for dry runs
519663207adSDon Brady  */
520663207adSDon Brady static void
5218654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
522663207adSDon Brady     const char *match, int name_flags)
523fa9e4066Sahrens {
524fa9e4066Sahrens 	nvlist_t **child;
525fa9e4066Sahrens 	uint_t c, children;
526afefbcddSeschrock 	char *vname;
527663207adSDon Brady 	boolean_t printed = B_FALSE;
528fa9e4066Sahrens 
529fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
530663207adSDon Brady 	    &child, &children) != 0) {
531663207adSDon Brady 		if (name != NULL)
532663207adSDon Brady 			(void) printf("\t%*s%s\n", indent, "", name);
533fa9e4066Sahrens 		return;
534663207adSDon Brady 	}
535fa9e4066Sahrens 
536afefbcddSeschrock 	for (c = 0; c < children; c++) {
5378654d025Sperrin 		uint64_t is_log = B_FALSE;
538663207adSDon Brady 		char *class = "";
5398654d025Sperrin 
5408654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
5418654d025Sperrin 		    &is_log);
542663207adSDon Brady 		if (is_log)
543663207adSDon Brady 			class = VDEV_ALLOC_BIAS_LOG;
544663207adSDon Brady 		(void) nvlist_lookup_string(child[c],
545663207adSDon Brady 		    ZPOOL_CONFIG_ALLOCATION_BIAS, &class);
546663207adSDon Brady 		if (strcmp(match, class) != 0)
5478654d025Sperrin 			continue;
5488654d025Sperrin 
549663207adSDon Brady 		if (!printed && name != NULL) {
550663207adSDon Brady 			(void) printf("\t%*s%s\n", indent, "", name);
551663207adSDon Brady 			printed = B_TRUE;
552663207adSDon Brady 		}
553663207adSDon Brady 		vname = zpool_vdev_name(g_zfs, zhp, child[c], name_flags);
554663207adSDon Brady 		print_vdev_tree(zhp, vname, child[c], indent + 2, "",
555663207adSDon Brady 		    name_flags);
556afefbcddSeschrock 		free(vname);
557afefbcddSeschrock 	}
558fa9e4066Sahrens }
559fa9e4066Sahrens 
56057221772SChristopher Siden static boolean_t
56157221772SChristopher Siden prop_list_contains_feature(nvlist_t *proplist)
56257221772SChristopher Siden {
56357221772SChristopher Siden 	nvpair_t *nvp;
56457221772SChristopher Siden 	for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp;
56557221772SChristopher Siden 	    nvp = nvlist_next_nvpair(proplist, nvp)) {
56657221772SChristopher Siden 		if (zpool_prop_feature(nvpair_name(nvp)))
56757221772SChristopher Siden 			return (B_TRUE);
56857221772SChristopher Siden 	}
56957221772SChristopher Siden 	return (B_FALSE);
57057221772SChristopher Siden }
57157221772SChristopher Siden 
572990b4856Slling /*
573990b4856Slling  * Add a property pair (name, string-value) into a property nvlist.
574990b4856Slling  */
575990b4856Slling static int
5760a48a24eStimh add_prop_list(const char *propname, char *propval, nvlist_t **props,
5770a48a24eStimh     boolean_t poolprop)
578990b4856Slling {
579d2aa06e8SAndrew Stormont 	zpool_prop_t prop = ZPOOL_PROP_INVAL;
5800a48a24eStimh 	zfs_prop_t fprop;
581990b4856Slling 	nvlist_t *proplist;
5820a48a24eStimh 	const char *normnm;
5830a48a24eStimh 	char *strval;
584990b4856Slling 
585990b4856Slling 	if (*props == NULL &&
586990b4856Slling 	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
587990b4856Slling 		(void) fprintf(stderr,
588990b4856Slling 		    gettext("internal error: out of memory\n"));
589990b4856Slling 		return (1);
590990b4856Slling 	}
591990b4856Slling 
592990b4856Slling 	proplist = *props;
593990b4856Slling 
5940a48a24eStimh 	if (poolprop) {
59557221772SChristopher Siden 		const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
59657221772SChristopher Siden 
597d2aa06e8SAndrew Stormont 		if ((prop = zpool_name_to_prop(propname)) == ZPOOL_PROP_INVAL &&
598ad135b5dSChristopher Siden 		    !zpool_prop_feature(propname)) {
5990a48a24eStimh 			(void) fprintf(stderr, gettext("property '%s' is "
6000a48a24eStimh 			    "not a valid pool property\n"), propname);
6010a48a24eStimh 			return (2);
6020a48a24eStimh 		}
60357221772SChristopher Siden 
60457221772SChristopher Siden 		/*
60557221772SChristopher Siden 		 * feature@ properties and version should not be specified
60657221772SChristopher Siden 		 * at the same time.
60757221772SChristopher Siden 		 */
6084ae5f5f0SAlan Somers 		if ((prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname) &&
60957221772SChristopher Siden 		    nvlist_exists(proplist, vname)) ||
61057221772SChristopher Siden 		    (prop == ZPOOL_PROP_VERSION &&
61157221772SChristopher Siden 		    prop_list_contains_feature(proplist))) {
61257221772SChristopher Siden 			(void) fprintf(stderr, gettext("'feature@' and "
61357221772SChristopher Siden 			    "'version' properties cannot be specified "
61457221772SChristopher Siden 			    "together\n"));
61557221772SChristopher Siden 			return (2);
61657221772SChristopher Siden 		}
61757221772SChristopher Siden 
61857221772SChristopher Siden 
619ad135b5dSChristopher Siden 		if (zpool_prop_feature(propname))
620ad135b5dSChristopher Siden 			normnm = propname;
621ad135b5dSChristopher Siden 		else
622ad135b5dSChristopher Siden 			normnm = zpool_prop_to_name(prop);
6230a48a24eStimh 	} else {
62414843421SMatthew Ahrens 		if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
62514843421SMatthew Ahrens 			normnm = zfs_prop_to_name(fprop);
62614843421SMatthew Ahrens 		} else {
62714843421SMatthew Ahrens 			normnm = propname;
6280a48a24eStimh 		}
629990b4856Slling 	}
630990b4856Slling 
6310a48a24eStimh 	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
6320a48a24eStimh 	    prop != ZPOOL_PROP_CACHEFILE) {
633990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' "
634990b4856Slling 		    "specified multiple times\n"), propname);
635990b4856Slling 		return (2);
636990b4856Slling 	}
637990b4856Slling 
6380a48a24eStimh 	if (nvlist_add_string(proplist, normnm, propval) != 0) {
639990b4856Slling 		(void) fprintf(stderr, gettext("internal "
640990b4856Slling 		    "error: out of memory\n"));
641990b4856Slling 		return (1);
642990b4856Slling 	}
643990b4856Slling 
644990b4856Slling 	return (0);
645990b4856Slling }
646990b4856Slling 
64704e56356SAndriy Gapon /*
64804e56356SAndriy Gapon  * Set a default property pair (name, string-value) in a property nvlist
64904e56356SAndriy Gapon  */
65004e56356SAndriy Gapon static int
65104e56356SAndriy Gapon add_prop_list_default(const char *propname, char *propval, nvlist_t **props,
65204e56356SAndriy Gapon     boolean_t poolprop)
65304e56356SAndriy Gapon {
65404e56356SAndriy Gapon 	char *pval;
65504e56356SAndriy Gapon 
65604e56356SAndriy Gapon 	if (nvlist_lookup_string(*props, propname, &pval) == 0)
65704e56356SAndriy Gapon 		return (0);
65804e56356SAndriy Gapon 
65904e56356SAndriy Gapon 	return (add_prop_list(propname, propval, props, poolprop));
66004e56356SAndriy Gapon }
66104e56356SAndriy Gapon 
662fa9e4066Sahrens /*
663663207adSDon Brady  * zpool add [-fgLnP] [-o property=value] <pool> <vdev> ...
664fa9e4066Sahrens  *
665fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
666663207adSDon Brady  *	-g	Display guid for individual vdev name.
667663207adSDon Brady  *	-L	Follow links when resolving vdev path name.
668fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
669fa9e4066Sahrens  *		they were to be added.
670663207adSDon Brady  *	-P	Display full path for vdev name.
6715711d393Sloli  *	-o	Set property=value.
672fa9e4066Sahrens  *
673fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
674fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
675fa9e4066Sahrens  * libzfs.
676fa9e4066Sahrens  */
677fa9e4066Sahrens int
678fa9e4066Sahrens zpool_do_add(int argc, char **argv)
679fa9e4066Sahrens {
68099653d4eSeschrock 	boolean_t force = B_FALSE;
68199653d4eSeschrock 	boolean_t dryrun = B_FALSE;
682663207adSDon Brady 	int name_flags = 0;
683fa9e4066Sahrens 	int c;
684fa9e4066Sahrens 	nvlist_t *nvroot;
685fa9e4066Sahrens 	char *poolname;
6867855d95bSToomas Soome 	zpool_boot_label_t boot_type;
6877855d95bSToomas Soome 	uint64_t boot_size;
688fa9e4066Sahrens 	int ret;
689fa9e4066Sahrens 	zpool_handle_t *zhp;
690fa9e4066Sahrens 	nvlist_t *config;
6915711d393Sloli 	nvlist_t *props = NULL;
6925711d393Sloli 	char *propval;
693fa9e4066Sahrens 
694fa9e4066Sahrens 	/* check options */
6955711d393Sloli 	while ((c = getopt(argc, argv, "fgLnPo:")) != -1) {
696fa9e4066Sahrens 		switch (c) {
697fa9e4066Sahrens 		case 'f':
69899653d4eSeschrock 			force = B_TRUE;
699fa9e4066Sahrens 			break;
700663207adSDon Brady 		case 'g':
701663207adSDon Brady 			name_flags |= VDEV_NAME_GUID;
702663207adSDon Brady 			break;
703663207adSDon Brady 		case 'L':
704663207adSDon Brady 			name_flags |= VDEV_NAME_FOLLOW_LINKS;
705663207adSDon Brady 			break;
706fa9e4066Sahrens 		case 'n':
70799653d4eSeschrock 			dryrun = B_TRUE;
708fa9e4066Sahrens 			break;
709663207adSDon Brady 		case 'P':
710663207adSDon Brady 			name_flags |= VDEV_NAME_PATH;
711663207adSDon Brady 			break;
7125711d393Sloli 		case 'o':
7135711d393Sloli 			if ((propval = strchr(optarg, '=')) == NULL) {
7145711d393Sloli 				(void) fprintf(stderr, gettext("missing "
7155711d393Sloli 				    "'=' for -o option\n"));
7165711d393Sloli 				usage(B_FALSE);
7175711d393Sloli 			}
7185711d393Sloli 			*propval = '\0';
7195711d393Sloli 			propval++;
7205711d393Sloli 
7215711d393Sloli 			if ((strcmp(optarg, ZPOOL_CONFIG_ASHIFT) != 0) ||
7225711d393Sloli 			    (add_prop_list(optarg, propval, &props, B_TRUE)))
7235711d393Sloli 				usage(B_FALSE);
7245711d393Sloli 			break;
725fa9e4066Sahrens 		case '?':
726fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
727fa9e4066Sahrens 			    optopt);
72899653d4eSeschrock 			usage(B_FALSE);
729fa9e4066Sahrens 		}
730fa9e4066Sahrens 	}
731fa9e4066Sahrens 
732fa9e4066Sahrens 	argc -= optind;
733fa9e4066Sahrens 	argv += optind;
734fa9e4066Sahrens 
735fa9e4066Sahrens 	/* get pool name and check number of arguments */
736fa9e4066Sahrens 	if (argc < 1) {
737fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
73899653d4eSeschrock 		usage(B_FALSE);
739fa9e4066Sahrens 	}
740fa9e4066Sahrens 	if (argc < 2) {
741fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
74299653d4eSeschrock 		usage(B_FALSE);
743fa9e4066Sahrens 	}
744fa9e4066Sahrens 
745fa9e4066Sahrens 	poolname = argv[0];
746fa9e4066Sahrens 
747fa9e4066Sahrens 	argc--;
748fa9e4066Sahrens 	argv++;
749fa9e4066Sahrens 
75099653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
751fa9e4066Sahrens 		return (1);
752fa9e4066Sahrens 
753088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
754fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
755fa9e4066Sahrens 		    poolname);
756fa9e4066Sahrens 		zpool_close(zhp);
757fa9e4066Sahrens 		return (1);
758fa9e4066Sahrens 	}
759fa9e4066Sahrens 
7607855d95bSToomas Soome 	if (zpool_is_bootable(zhp))
7617855d95bSToomas Soome 		boot_type = ZPOOL_COPY_BOOT_LABEL;
7627855d95bSToomas Soome 	else
7637855d95bSToomas Soome 		boot_type = ZPOOL_NO_BOOT_LABEL;
7647855d95bSToomas Soome 
7655711d393Sloli 	/* unless manually specified use "ashift" pool property (if set) */
7665711d393Sloli 	if (!nvlist_exists(props, ZPOOL_CONFIG_ASHIFT)) {
7675711d393Sloli 		int intval;
7685711d393Sloli 		zprop_source_t src;
7695711d393Sloli 		char strval[ZPOOL_MAXPROPLEN];
7705711d393Sloli 
7715711d393Sloli 		intval = zpool_get_prop_int(zhp, ZPOOL_PROP_ASHIFT, &src);
7725711d393Sloli 		if (src != ZPROP_SRC_DEFAULT) {
7735711d393Sloli 			(void) sprintf(strval, "%" PRId32, intval);
7745711d393Sloli 			verify(add_prop_list(ZPOOL_CONFIG_ASHIFT, strval,
7755711d393Sloli 			    &props, B_TRUE) == 0);
7765711d393Sloli 		}
7775711d393Sloli 	}
7785711d393Sloli 
779fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
7807855d95bSToomas Soome 	boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
7815711d393Sloli 	nvroot = make_root_vdev(zhp, props, force, !force, B_FALSE, dryrun,
7827855d95bSToomas Soome 	    boot_type, boot_size, argc, argv);
783fa9e4066Sahrens 	if (nvroot == NULL) {
784fa9e4066Sahrens 		zpool_close(zhp);
785fa9e4066Sahrens 		return (1);
786fa9e4066Sahrens 	}
787fa9e4066Sahrens 
788fa9e4066Sahrens 	if (dryrun) {
789fa9e4066Sahrens 		nvlist_t *poolnvroot;
790fa9e4066Sahrens 
791fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
792fa9e4066Sahrens 		    &poolnvroot) == 0);
793fa9e4066Sahrens 
794fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
795fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
796fa9e4066Sahrens 
7978654d025Sperrin 		/* print original main pool and new tree */
798663207adSDon Brady 		print_vdev_tree(zhp, poolname, poolnvroot, 0, "",
799663207adSDon Brady 		    name_flags | VDEV_NAME_TYPE_ID);
800663207adSDon Brady 		print_vdev_tree(zhp, NULL, nvroot, 0, "", name_flags);
801663207adSDon Brady 
802663207adSDon Brady 		/* print other classes: 'dedup', 'special', and 'log' */
803663207adSDon Brady 		print_vdev_tree(zhp, "dedup", poolnvroot, 0,
804663207adSDon Brady 		    VDEV_ALLOC_BIAS_DEDUP, name_flags);
805663207adSDon Brady 		print_vdev_tree(zhp, NULL, nvroot, 0, VDEV_ALLOC_BIAS_DEDUP,
806663207adSDon Brady 		    name_flags);
807663207adSDon Brady 
808663207adSDon Brady 		print_vdev_tree(zhp, "special", poolnvroot, 0,
809663207adSDon Brady 		    VDEV_ALLOC_BIAS_SPECIAL, name_flags);
810663207adSDon Brady 		print_vdev_tree(zhp, NULL, nvroot, 0, VDEV_ALLOC_BIAS_SPECIAL,
811663207adSDon Brady 		    name_flags);
812663207adSDon Brady 
813663207adSDon Brady 		print_vdev_tree(zhp, "logs", poolnvroot, 0, VDEV_ALLOC_BIAS_LOG,
814663207adSDon Brady 		    name_flags);
815663207adSDon Brady 		print_vdev_tree(zhp, NULL, nvroot, 0, VDEV_ALLOC_BIAS_LOG,
816663207adSDon Brady 		    name_flags);
817fa9e4066Sahrens 
818fa9e4066Sahrens 		ret = 0;
819fa9e4066Sahrens 	} else {
820fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
821fa9e4066Sahrens 	}
822fa9e4066Sahrens 
8235711d393Sloli 	nvlist_free(props);
82499653d4eSeschrock 	nvlist_free(nvroot);
82599653d4eSeschrock 	zpool_close(zhp);
82699653d4eSeschrock 
82799653d4eSeschrock 	return (ret);
82899653d4eSeschrock }
82999653d4eSeschrock 
83099653d4eSeschrock /*
8313f9d6ad7SLin Ling  * zpool remove  <pool> <vdev> ...
83299653d4eSeschrock  *
8335cabbc6bSPrashanth Sreenivasa  * Removes the given vdev from the pool.
83499653d4eSeschrock  */
83599653d4eSeschrock int
83699653d4eSeschrock zpool_do_remove(int argc, char **argv)
83799653d4eSeschrock {
83899653d4eSeschrock 	char *poolname;
839fa94a07fSbrendan 	int i, ret = 0;
84099653d4eSeschrock 	zpool_handle_t *zhp;
8415cabbc6bSPrashanth Sreenivasa 	boolean_t stop = B_FALSE;
8425cabbc6bSPrashanth Sreenivasa 	boolean_t noop = B_FALSE;
8435cabbc6bSPrashanth Sreenivasa 	boolean_t parsable = B_FALSE;
8445cabbc6bSPrashanth Sreenivasa 	char c;
84599653d4eSeschrock 
8465cabbc6bSPrashanth Sreenivasa 	/* check options */
8475cabbc6bSPrashanth Sreenivasa 	while ((c = getopt(argc, argv, "nps")) != -1) {
8485cabbc6bSPrashanth Sreenivasa 		switch (c) {
8495cabbc6bSPrashanth Sreenivasa 		case 'n':
8505cabbc6bSPrashanth Sreenivasa 			noop = B_TRUE;
8515cabbc6bSPrashanth Sreenivasa 			break;
8525cabbc6bSPrashanth Sreenivasa 		case 'p':
8535cabbc6bSPrashanth Sreenivasa 			parsable = B_TRUE;
8545cabbc6bSPrashanth Sreenivasa 			break;
8555cabbc6bSPrashanth Sreenivasa 		case 's':
8565cabbc6bSPrashanth Sreenivasa 			stop = B_TRUE;
8575cabbc6bSPrashanth Sreenivasa 			break;
8585cabbc6bSPrashanth Sreenivasa 		case '?':
8595cabbc6bSPrashanth Sreenivasa 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
8605cabbc6bSPrashanth Sreenivasa 			    optopt);
8615cabbc6bSPrashanth Sreenivasa 			usage(B_FALSE);
8625cabbc6bSPrashanth Sreenivasa 		}
8635cabbc6bSPrashanth Sreenivasa 	}
8645cabbc6bSPrashanth Sreenivasa 
8655cabbc6bSPrashanth Sreenivasa 	argc -= optind;
8665cabbc6bSPrashanth Sreenivasa 	argv += optind;
86799653d4eSeschrock 
86899653d4eSeschrock 	/* get pool name and check number of arguments */
86999653d4eSeschrock 	if (argc < 1) {
87099653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
87199653d4eSeschrock 		usage(B_FALSE);
87299653d4eSeschrock 	}
87399653d4eSeschrock 
87499653d4eSeschrock 	poolname = argv[0];
87599653d4eSeschrock 
87699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
87799653d4eSeschrock 		return (1);
87899653d4eSeschrock 
8795cabbc6bSPrashanth Sreenivasa 	if (stop && noop) {
8805cabbc6bSPrashanth Sreenivasa 		(void) fprintf(stderr, gettext("stop request ignored\n"));
8815cabbc6bSPrashanth Sreenivasa 		return (0);
8825cabbc6bSPrashanth Sreenivasa 	}
8835cabbc6bSPrashanth Sreenivasa 
8845cabbc6bSPrashanth Sreenivasa 	if (stop) {
8855cabbc6bSPrashanth Sreenivasa 		if (argc > 1) {
8865cabbc6bSPrashanth Sreenivasa 			(void) fprintf(stderr, gettext("too many arguments\n"));
8875cabbc6bSPrashanth Sreenivasa 			usage(B_FALSE);
8885cabbc6bSPrashanth Sreenivasa 		}
8895cabbc6bSPrashanth Sreenivasa 		if (zpool_vdev_remove_cancel(zhp) != 0)
890fa94a07fSbrendan 			ret = 1;
8915cabbc6bSPrashanth Sreenivasa 	} else {
8925cabbc6bSPrashanth Sreenivasa 		if (argc < 2) {
8935cabbc6bSPrashanth Sreenivasa 			(void) fprintf(stderr, gettext("missing device\n"));
8945cabbc6bSPrashanth Sreenivasa 			usage(B_FALSE);
8955cabbc6bSPrashanth Sreenivasa 		}
8965cabbc6bSPrashanth Sreenivasa 
8975cabbc6bSPrashanth Sreenivasa 		for (i = 1; i < argc; i++) {
8985cabbc6bSPrashanth Sreenivasa 			if (noop) {
8995cabbc6bSPrashanth Sreenivasa 				uint64_t size;
9005cabbc6bSPrashanth Sreenivasa 
9015cabbc6bSPrashanth Sreenivasa 				if (zpool_vdev_indirect_size(zhp, argv[i],
9025cabbc6bSPrashanth Sreenivasa 				    &size) != 0) {
9035cabbc6bSPrashanth Sreenivasa 					ret = 1;
9045cabbc6bSPrashanth Sreenivasa 					break;
9055cabbc6bSPrashanth Sreenivasa 				}
9065cabbc6bSPrashanth Sreenivasa 				if (parsable) {
9075cabbc6bSPrashanth Sreenivasa 					(void) printf("%s %llu\n",
9085cabbc6bSPrashanth Sreenivasa 					    argv[i], size);
9095cabbc6bSPrashanth Sreenivasa 				} else {
9105cabbc6bSPrashanth Sreenivasa 					char valstr[32];
9115cabbc6bSPrashanth Sreenivasa 					zfs_nicenum(size, valstr,
9125cabbc6bSPrashanth Sreenivasa 					    sizeof (valstr));
9135cabbc6bSPrashanth Sreenivasa 					(void) printf("Memory that will be "
9145cabbc6bSPrashanth Sreenivasa 					    "used after removing %s: %s\n",
9155cabbc6bSPrashanth Sreenivasa 					    argv[i], valstr);
9165cabbc6bSPrashanth Sreenivasa 				}
9175cabbc6bSPrashanth Sreenivasa 			} else {
9185cabbc6bSPrashanth Sreenivasa 				if (zpool_vdev_remove(zhp, argv[i]) != 0)
9195cabbc6bSPrashanth Sreenivasa 					ret = 1;
9205cabbc6bSPrashanth Sreenivasa 			}
9215cabbc6bSPrashanth Sreenivasa 		}
922fa94a07fSbrendan 	}
92399653d4eSeschrock 
924fa9e4066Sahrens 	return (ret);
925fa9e4066Sahrens }
926fa9e4066Sahrens 
9276401734dSWill Andrews /*
9286401734dSWill Andrews  * zpool labelclear [-f] <vdev>
9296401734dSWill Andrews  *
9306401734dSWill Andrews  *	-f	Force clearing the label for the vdevs which are members of
9316401734dSWill Andrews  *		the exported or foreign pools.
9326401734dSWill Andrews  *
9336401734dSWill Andrews  * Verifies that the vdev is not active and zeros out the label information
9346401734dSWill Andrews  * on the device.
9356401734dSWill Andrews  */
9366401734dSWill Andrews int
9376401734dSWill Andrews zpool_do_labelclear(int argc, char **argv)
9386401734dSWill Andrews {
9396401734dSWill Andrews 	char vdev[MAXPATHLEN];
9406401734dSWill Andrews 	char *name = NULL;
9416401734dSWill Andrews 	struct stat st;
9426401734dSWill Andrews 	int c, fd, ret = 0;
9436401734dSWill Andrews 	nvlist_t *config;
9446401734dSWill Andrews 	pool_state_t state;
9456401734dSWill Andrews 	boolean_t inuse = B_FALSE;
9466401734dSWill Andrews 	boolean_t force = B_FALSE;
9476401734dSWill Andrews 
9486401734dSWill Andrews 	/* check options */
9496401734dSWill Andrews 	while ((c = getopt(argc, argv, "f")) != -1) {
9506401734dSWill Andrews 		switch (c) {
9516401734dSWill Andrews 		case 'f':
9526401734dSWill Andrews 			force = B_TRUE;
9536401734dSWill Andrews 			break;
9546401734dSWill Andrews 		default:
9556401734dSWill Andrews 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
9566401734dSWill Andrews 			    optopt);
9576401734dSWill Andrews 			usage(B_FALSE);
9586401734dSWill Andrews 		}
9596401734dSWill Andrews 	}
9606401734dSWill Andrews 
9616401734dSWill Andrews 	argc -= optind;
9626401734dSWill Andrews 	argv += optind;
9636401734dSWill Andrews 
9646401734dSWill Andrews 	/* get vdev name */
9656401734dSWill Andrews 	if (argc < 1) {
9666401734dSWill Andrews 		(void) fprintf(stderr, gettext("missing vdev name\n"));
9676401734dSWill Andrews 		usage(B_FALSE);
9686401734dSWill Andrews 	}
9696401734dSWill Andrews 	if (argc > 1) {
9706401734dSWill Andrews 		(void) fprintf(stderr, gettext("too many arguments\n"));
9716401734dSWill Andrews 		usage(B_FALSE);
9726401734dSWill Andrews 	}
9736401734dSWill Andrews 
9746401734dSWill Andrews 	/*
9756401734dSWill Andrews 	 * Check if we were given absolute path and use it as is.
9766401734dSWill Andrews 	 * Otherwise if the provided vdev name doesn't point to a file,
9776401734dSWill Andrews 	 * try prepending dsk path and appending s0.
9786401734dSWill Andrews 	 */
9796401734dSWill Andrews 	(void) strlcpy(vdev, argv[0], sizeof (vdev));
9806401734dSWill Andrews 	if (vdev[0] != '/' && stat(vdev, &st) != 0) {
9816401734dSWill Andrews 		char *s;
9826401734dSWill Andrews 
9836401734dSWill Andrews 		(void) snprintf(vdev, sizeof (vdev), "%s/%s",
9846401734dSWill Andrews 		    ZFS_DISK_ROOT, argv[0]);
9856401734dSWill Andrews 		if ((s = strrchr(argv[0], 's')) == NULL ||
9866401734dSWill Andrews 		    !isdigit(*(s + 1)))
9876401734dSWill Andrews 			(void) strlcat(vdev, "s0", sizeof (vdev));
9886401734dSWill Andrews 		if (stat(vdev, &st) != 0) {
9896401734dSWill Andrews 			(void) fprintf(stderr, gettext(
9906401734dSWill Andrews 			    "failed to find device %s, try specifying absolute "
9916401734dSWill Andrews 			    "path instead\n"), argv[0]);
9926401734dSWill Andrews 			return (1);
9936401734dSWill Andrews 		}
9946401734dSWill Andrews 	}
9956401734dSWill Andrews 
9966401734dSWill Andrews 	if ((fd = open(vdev, O_RDWR)) < 0) {
9976401734dSWill Andrews 		(void) fprintf(stderr, gettext("failed to open %s: %s\n"),
9986401734dSWill Andrews 		    vdev, strerror(errno));
9996401734dSWill Andrews 		return (1);
10006401734dSWill Andrews 	}
10016401734dSWill Andrews 
1002d8ab6e12SDon Brady 	if (zpool_read_label(fd, &config, NULL) != 0) {
10036401734dSWill Andrews 		(void) fprintf(stderr,
10046401734dSWill Andrews 		    gettext("failed to read label from %s\n"), vdev);
10056401734dSWill Andrews 		return (1);
10066401734dSWill Andrews 	}
10076401734dSWill Andrews 	nvlist_free(config);
10086401734dSWill Andrews 
10096401734dSWill Andrews 	ret = zpool_in_use(g_zfs, fd, &state, &name, &inuse);
10106401734dSWill Andrews 	if (ret != 0) {
10116401734dSWill Andrews 		(void) fprintf(stderr,
10126401734dSWill Andrews 		    gettext("failed to check state for %s\n"), vdev);
10136401734dSWill Andrews 		return (1);
10146401734dSWill Andrews 	}
10156401734dSWill Andrews 
10166401734dSWill Andrews 	if (!inuse)
10176401734dSWill Andrews 		goto wipe_label;
10186401734dSWill Andrews 
10196401734dSWill Andrews 	switch (state) {
10206401734dSWill Andrews 	default:
10216401734dSWill Andrews 	case POOL_STATE_ACTIVE:
10226401734dSWill Andrews 	case POOL_STATE_SPARE:
10236401734dSWill Andrews 	case POOL_STATE_L2CACHE:
10246401734dSWill Andrews 		(void) fprintf(stderr, gettext(
10256401734dSWill Andrews 		    "%s is a member (%s) of pool \"%s\"\n"),
10266401734dSWill Andrews 		    vdev, zpool_pool_state_to_name(state), name);
10276401734dSWill Andrews 		ret = 1;
10286401734dSWill Andrews 		goto errout;
10296401734dSWill Andrews 
10306401734dSWill Andrews 	case POOL_STATE_EXPORTED:
10316401734dSWill Andrews 		if (force)
10326401734dSWill Andrews 			break;
10336401734dSWill Andrews 		(void) fprintf(stderr, gettext(
10346401734dSWill Andrews 		    "use '-f' to override the following error:\n"
10356401734dSWill Andrews 		    "%s is a member of exported pool \"%s\"\n"),
10366401734dSWill Andrews 		    vdev, name);
10376401734dSWill Andrews 		ret = 1;
10386401734dSWill Andrews 		goto errout;
10396401734dSWill Andrews 
10406401734dSWill Andrews 	case POOL_STATE_POTENTIALLY_ACTIVE:
10416401734dSWill Andrews 		if (force)
10426401734dSWill Andrews 			break;
10436401734dSWill Andrews 		(void) fprintf(stderr, gettext(
10446401734dSWill Andrews 		    "use '-f' to override the following error:\n"
10456401734dSWill Andrews 		    "%s is a member of potentially active pool \"%s\"\n"),
10466401734dSWill Andrews 		    vdev, name);
10476401734dSWill Andrews 		ret = 1;
10486401734dSWill Andrews 		goto errout;
10496401734dSWill Andrews 
10506401734dSWill Andrews 	case POOL_STATE_DESTROYED:
10516401734dSWill Andrews 		/* inuse should never be set for a destroyed pool */
10526401734dSWill Andrews 		assert(0);
10536401734dSWill Andrews 		break;
10546401734dSWill Andrews 	}
10556401734dSWill Andrews 
10566401734dSWill Andrews wipe_label:
10576401734dSWill Andrews 	ret = zpool_clear_label(fd);
10586401734dSWill Andrews 	if (ret != 0) {
10596401734dSWill Andrews 		(void) fprintf(stderr,
10606401734dSWill Andrews 		    gettext("failed to clear label for %s\n"), vdev);
10616401734dSWill Andrews 	}
10626401734dSWill Andrews 
10636401734dSWill Andrews errout:
10646401734dSWill Andrews 	free(name);
10656401734dSWill Andrews 	(void) close(fd);
10666401734dSWill Andrews 
10676401734dSWill Andrews 	return (ret);
10686401734dSWill Andrews }
10696401734dSWill Andrews 
1070fa9e4066Sahrens /*
10717855d95bSToomas Soome  * zpool create [-fnd] [-B] [-o property=value] ...
10720a48a24eStimh  *		[-O file-system-property=value] ...
107304e56356SAndriy Gapon  *		[-R root] [-m mountpoint] [-t tempname] <pool> <dev> ...
1074fa9e4066Sahrens  *
10757855d95bSToomas Soome  *	-B	Create boot partition.
1076fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
1077fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
1078fa9e4066Sahrens  *		were to be created.
107904e56356SAndriy Gapon  *	-R	Create a pool under an alternate root
108004e56356SAndriy Gapon  *	-m	Set default mountpoint for the root dataset.  By default it's
1081ad135b5dSChristopher Siden  *		'/<pool>'
108204e56356SAndriy Gapon  *	-t	Use the temporary name until the pool is exported.
1083990b4856Slling  *	-o	Set property=value.
1084ad135b5dSChristopher Siden  *	-d	Don't automatically enable all supported pool features
1085ad135b5dSChristopher Siden  *		(individual features can be enabled with -o).
10860a48a24eStimh  *	-O	Set fsproperty=value in the pool's root file system
1087fa9e4066Sahrens  *
1088b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
1089fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
1090fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
1091fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
1092fa9e4066Sahrens  */
10937855d95bSToomas Soome 
10947855d95bSToomas Soome #define	SYSTEM256	(256 * 1024 * 1024)
1095fa9e4066Sahrens int
1096fa9e4066Sahrens zpool_do_create(int argc, char **argv)
1097fa9e4066Sahrens {
109899653d4eSeschrock 	boolean_t force = B_FALSE;
109999653d4eSeschrock 	boolean_t dryrun = B_FALSE;
1100ad135b5dSChristopher Siden 	boolean_t enable_all_pool_feat = B_TRUE;
11017855d95bSToomas Soome 	zpool_boot_label_t boot_type = ZPOOL_NO_BOOT_LABEL;
11027855d95bSToomas Soome 	uint64_t boot_size = 0;
1103fa9e4066Sahrens 	int c;
1104990b4856Slling 	nvlist_t *nvroot = NULL;
1105fa9e4066Sahrens 	char *poolname;
110604e56356SAndriy Gapon 	char *tname = NULL;
1107990b4856Slling 	int ret = 1;
1108fa9e4066Sahrens 	char *altroot = NULL;
1109fa9e4066Sahrens 	char *mountpoint = NULL;
11100a48a24eStimh 	nvlist_t *fsprops = NULL;
1111990b4856Slling 	nvlist_t *props = NULL;
11122f8aaab3Seschrock 	char *propval;
1113fa9e4066Sahrens 
1114fa9e4066Sahrens 	/* check options */
111504e56356SAndriy Gapon 	while ((c = getopt(argc, argv, ":fndBR:m:o:O:t:")) != -1) {
1116fa9e4066Sahrens 		switch (c) {
1117fa9e4066Sahrens 		case 'f':
111899653d4eSeschrock 			force = B_TRUE;
1119fa9e4066Sahrens 			break;
1120fa9e4066Sahrens 		case 'n':
112199653d4eSeschrock 			dryrun = B_TRUE;
1122fa9e4066Sahrens 			break;
1123ad135b5dSChristopher Siden 		case 'd':
1124ad135b5dSChristopher Siden 			enable_all_pool_feat = B_FALSE;
1125ad135b5dSChristopher Siden 			break;
11267855d95bSToomas Soome 		case 'B':
11277855d95bSToomas Soome 			/*
11287855d95bSToomas Soome 			 * We should create the system partition.
11297855d95bSToomas Soome 			 * Also make sure the size is set.
11307855d95bSToomas Soome 			 */
11317855d95bSToomas Soome 			boot_type = ZPOOL_CREATE_BOOT_LABEL;
11327855d95bSToomas Soome 			if (boot_size == 0)
11337855d95bSToomas Soome 				boot_size = SYSTEM256;
11347855d95bSToomas Soome 			break;
1135fa9e4066Sahrens 		case 'R':
1136fa9e4066Sahrens 			altroot = optarg;
1137990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
11380a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1139990b4856Slling 				goto errout;
114004e56356SAndriy Gapon 			if (add_prop_list_default(zpool_prop_to_name(
11410a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1142990b4856Slling 				goto errout;
1143fa9e4066Sahrens 			break;
1144fa9e4066Sahrens 		case 'm':
11458b713775SWill Andrews 			/* Equivalent to -O mountpoint=optarg */
1146fa9e4066Sahrens 			mountpoint = optarg;
1147fa9e4066Sahrens 			break;
1148990b4856Slling 		case 'o':
1149990b4856Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
1150990b4856Slling 				(void) fprintf(stderr, gettext("missing "
1151990b4856Slling 				    "'=' for -o option\n"));
1152990b4856Slling 				goto errout;
1153990b4856Slling 			}
1154990b4856Slling 			*propval = '\0';
1155990b4856Slling 			propval++;
1156990b4856Slling 
11570a48a24eStimh 			if (add_prop_list(optarg, propval, &props, B_TRUE))
11580a48a24eStimh 				goto errout;
1159ad135b5dSChristopher Siden 
11607855d95bSToomas Soome 			/*
11617855d95bSToomas Soome 			 * Get bootsize value for make_root_vdev().
11627855d95bSToomas Soome 			 */
11637855d95bSToomas Soome 			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_BOOTSIZE) {
11647855d95bSToomas Soome 				if (zfs_nicestrtonum(g_zfs, propval,
11657855d95bSToomas Soome 				    &boot_size) < 0 || boot_size == 0) {
11667855d95bSToomas Soome 					(void) fprintf(stderr,
11677855d95bSToomas Soome 					    gettext("bad boot partition size "
11687855d95bSToomas Soome 					    "'%s': %s\n"),  propval,
11697855d95bSToomas Soome 					    libzfs_error_description(g_zfs));
11707855d95bSToomas Soome 					goto errout;
11717855d95bSToomas Soome 				}
11727855d95bSToomas Soome 			}
11737855d95bSToomas Soome 
1174ad135b5dSChristopher Siden 			/*
1175ad135b5dSChristopher Siden 			 * If the user is creating a pool that doesn't support
1176ad135b5dSChristopher Siden 			 * feature flags, don't enable any features.
1177ad135b5dSChristopher Siden 			 */
1178ad135b5dSChristopher Siden 			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) {
1179ad135b5dSChristopher Siden 				char *end;
1180ad135b5dSChristopher Siden 				u_longlong_t ver;
1181ad135b5dSChristopher Siden 
1182ad135b5dSChristopher Siden 				ver = strtoull(propval, &end, 10);
1183ad135b5dSChristopher Siden 				if (*end == '\0' &&
1184ad135b5dSChristopher Siden 				    ver < SPA_VERSION_FEATURES) {
1185ad135b5dSChristopher Siden 					enable_all_pool_feat = B_FALSE;
1186ad135b5dSChristopher Siden 				}
1187ad135b5dSChristopher Siden 			}
1188c423721fSXin Li 			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT)
1189c423721fSXin Li 				altroot = propval;
11900a48a24eStimh 			break;
11910a48a24eStimh 		case 'O':
11920a48a24eStimh 			if ((propval = strchr(optarg, '=')) == NULL) {
11930a48a24eStimh 				(void) fprintf(stderr, gettext("missing "
11940a48a24eStimh 				    "'=' for -O option\n"));
11950a48a24eStimh 				goto errout;
11960a48a24eStimh 			}
11970a48a24eStimh 			*propval = '\0';
11980a48a24eStimh 			propval++;
11990a48a24eStimh 
12008b713775SWill Andrews 			/*
12018b713775SWill Andrews 			 * Mountpoints are checked and then added later.
12028b713775SWill Andrews 			 * Uniquely among properties, they can be specified
12038b713775SWill Andrews 			 * more than once, to avoid conflict with -m.
12048b713775SWill Andrews 			 */
12058b713775SWill Andrews 			if (0 == strcmp(optarg,
12068b713775SWill Andrews 			    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) {
12078b713775SWill Andrews 				mountpoint = propval;
12088b713775SWill Andrews 			} else if (add_prop_list(optarg, propval, &fsprops,
12098b713775SWill Andrews 			    B_FALSE)) {
1210990b4856Slling 				goto errout;
12118b713775SWill Andrews 			}
1212990b4856Slling 			break;
121304e56356SAndriy Gapon 		case 't':
121404e56356SAndriy Gapon 			/*
121504e56356SAndriy Gapon 			 * Sanity check temporary pool name.
121604e56356SAndriy Gapon 			 */
121704e56356SAndriy Gapon 			if (strchr(optarg, '/') != NULL) {
121804e56356SAndriy Gapon 				(void) fprintf(stderr, gettext("cannot create "
121904e56356SAndriy Gapon 				    "'%s': invalid character '/' in temporary "
122004e56356SAndriy Gapon 				    "name\n"), optarg);
122104e56356SAndriy Gapon 				(void) fprintf(stderr, gettext("use 'zfs "
122204e56356SAndriy Gapon 				    "create' to create a dataset\n"));
122304e56356SAndriy Gapon 				goto errout;
122404e56356SAndriy Gapon 			}
122504e56356SAndriy Gapon 
122604e56356SAndriy Gapon 			if (add_prop_list(zpool_prop_to_name(
122704e56356SAndriy Gapon 			    ZPOOL_PROP_TNAME), optarg, &props, B_TRUE))
122804e56356SAndriy Gapon 				goto errout;
122904e56356SAndriy Gapon 			if (add_prop_list_default(zpool_prop_to_name(
123004e56356SAndriy Gapon 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
123104e56356SAndriy Gapon 				goto errout;
123204e56356SAndriy Gapon 			tname = optarg;
123304e56356SAndriy Gapon 			break;
1234fa9e4066Sahrens 		case ':':
1235fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1236fa9e4066Sahrens 			    "'%c' option\n"), optopt);
1237990b4856Slling 			goto badusage;
1238fa9e4066Sahrens 		case '?':
1239fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1240fa9e4066Sahrens 			    optopt);
1241990b4856Slling 			goto badusage;
1242fa9e4066Sahrens 		}
1243fa9e4066Sahrens 	}
1244fa9e4066Sahrens 
1245fa9e4066Sahrens 	argc -= optind;
1246fa9e4066Sahrens 	argv += optind;
1247fa9e4066Sahrens 
1248fa9e4066Sahrens 	/* get pool name and check number of arguments */
1249fa9e4066Sahrens 	if (argc < 1) {
1250fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
1251990b4856Slling 		goto badusage;
1252fa9e4066Sahrens 	}
1253fa9e4066Sahrens 	if (argc < 2) {
1254fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
1255990b4856Slling 		goto badusage;
1256fa9e4066Sahrens 	}
1257fa9e4066Sahrens 
1258fa9e4066Sahrens 	poolname = argv[0];
1259fa9e4066Sahrens 
1260fa9e4066Sahrens 	/*
1261fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
1262fa9e4066Sahrens 	 * user to use 'zfs create' instead.
1263fa9e4066Sahrens 	 */
1264fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
1265fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
1266fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
1267fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
1268fa9e4066Sahrens 		    "create a dataset\n"));
1269990b4856Slling 		goto errout;
1270fa9e4066Sahrens 	}
1271fa9e4066Sahrens 
12727855d95bSToomas Soome 	/*
12737855d95bSToomas Soome 	 * Make sure the bootsize is set when ZPOOL_CREATE_BOOT_LABEL is used,
12747855d95bSToomas Soome 	 * and not set otherwise.
12757855d95bSToomas Soome 	 */
12767855d95bSToomas Soome 	if (boot_type == ZPOOL_CREATE_BOOT_LABEL) {
12777855d95bSToomas Soome 		const char *propname;
12787855d95bSToomas Soome 		char *strptr, *buf = NULL;
12797855d95bSToomas Soome 		int rv;
12807855d95bSToomas Soome 
12817855d95bSToomas Soome 		propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE);
12827855d95bSToomas Soome 		if (nvlist_lookup_string(props, propname, &strptr) != 0) {
12837855d95bSToomas Soome 			(void) asprintf(&buf, "%" PRIu64, boot_size);
12847855d95bSToomas Soome 			if (buf == NULL) {
12857855d95bSToomas Soome 				(void) fprintf(stderr,
12867855d95bSToomas Soome 				    gettext("internal error: out of memory\n"));
12877855d95bSToomas Soome 				goto errout;
12887855d95bSToomas Soome 			}
12897855d95bSToomas Soome 			rv = add_prop_list(propname, buf, &props, B_TRUE);
12907855d95bSToomas Soome 			free(buf);
12917855d95bSToomas Soome 			if (rv != 0)
12927855d95bSToomas Soome 				goto errout;
12937855d95bSToomas Soome 		}
12947855d95bSToomas Soome 	} else {
12957855d95bSToomas Soome 		const char *propname;
12967855d95bSToomas Soome 		char *strptr;
12977855d95bSToomas Soome 
12987855d95bSToomas Soome 		propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE);
12997855d95bSToomas Soome 		if (nvlist_lookup_string(props, propname, &strptr) == 0) {
13007855d95bSToomas Soome 			(void) fprintf(stderr, gettext("error: setting boot "
13017855d95bSToomas Soome 			    "partition size requires option '-B'\n"));
13027855d95bSToomas Soome 			goto errout;
13037855d95bSToomas Soome 		}
13047855d95bSToomas Soome 	}
13057855d95bSToomas Soome 
1306fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
13075711d393Sloli 	nvroot = make_root_vdev(NULL, props, force, !force, B_FALSE, dryrun,
13087855d95bSToomas Soome 	    boot_type, boot_size, argc - 1, argv + 1);
1309fa9e4066Sahrens 	if (nvroot == NULL)
13100a48a24eStimh 		goto errout;
1311fa9e4066Sahrens 
131299653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
1313b7b97454Sperrin 	if (!zfs_allocatable_devs(nvroot)) {
131499653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
131599653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
131699653d4eSeschrock 		    "specified\n"));
1317990b4856Slling 		goto errout;
131899653d4eSeschrock 	}
131999653d4eSeschrock 
1320fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
1321fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
1322e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
1323990b4856Slling 		goto errout;
1324fa9e4066Sahrens 	}
1325fa9e4066Sahrens 
1326fa9e4066Sahrens 	/*
1327fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
1328fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
1329fa9e4066Sahrens 	 */
1330fa9e4066Sahrens 	if (mountpoint == NULL ||
1331fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
1332fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
1333fa9e4066Sahrens 		char buf[MAXPATHLEN];
133411022c7cStimh 		DIR *dirp;
1335fa9e4066Sahrens 
1336fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
1337fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
1338fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
1339fa9e4066Sahrens 			    "'none'\n"), mountpoint);
1340990b4856Slling 			goto errout;
1341fa9e4066Sahrens 		}
1342fa9e4066Sahrens 
1343fa9e4066Sahrens 		if (mountpoint == NULL) {
1344fa9e4066Sahrens 			if (altroot != NULL)
1345fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
1346fa9e4066Sahrens 				    altroot, poolname);
1347fa9e4066Sahrens 			else
1348fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
1349fa9e4066Sahrens 				    poolname);
1350fa9e4066Sahrens 		} else {
1351fa9e4066Sahrens 			if (altroot != NULL)
1352fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
1353fa9e4066Sahrens 				    altroot, mountpoint);
1354fa9e4066Sahrens 			else
1355fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
1356fa9e4066Sahrens 				    mountpoint);
1357fa9e4066Sahrens 		}
1358fa9e4066Sahrens 
135911022c7cStimh 		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
136011022c7cStimh 			(void) fprintf(stderr, gettext("mountpoint '%s' : "
136111022c7cStimh 			    "%s\n"), buf, strerror(errno));
1362fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
1363fa9e4066Sahrens 			    "option to provide a different default\n"));
1364990b4856Slling 			goto errout;
136511022c7cStimh 		} else if (dirp) {
136611022c7cStimh 			int count = 0;
136711022c7cStimh 
136811022c7cStimh 			while (count < 3 && readdir(dirp) != NULL)
136911022c7cStimh 				count++;
137011022c7cStimh 			(void) closedir(dirp);
137111022c7cStimh 
137211022c7cStimh 			if (count > 2) {
137311022c7cStimh 				(void) fprintf(stderr, gettext("mountpoint "
137411022c7cStimh 				    "'%s' exists and is not empty\n"), buf);
137511022c7cStimh 				(void) fprintf(stderr, gettext("use '-m' "
137611022c7cStimh 				    "option to provide a "
137711022c7cStimh 				    "different default\n"));
137811022c7cStimh 				goto errout;
137911022c7cStimh 			}
1380fa9e4066Sahrens 		}
1381fa9e4066Sahrens 	}
1382fa9e4066Sahrens 
13838b713775SWill Andrews 	/*
13848b713775SWill Andrews 	 * Now that the mountpoint's validity has been checked, ensure that
13858b713775SWill Andrews 	 * the property is set appropriately prior to creating the pool.
13868b713775SWill Andrews 	 */
13878b713775SWill Andrews 	if (mountpoint != NULL) {
13888b713775SWill Andrews 		ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
13898b713775SWill Andrews 		    mountpoint, &fsprops, B_FALSE);
13908b713775SWill Andrews 		if (ret != 0)
13918b713775SWill Andrews 			goto errout;
13928b713775SWill Andrews 	}
13938b713775SWill Andrews 
13948b713775SWill Andrews 	ret = 1;
1395fa9e4066Sahrens 	if (dryrun) {
1396fa9e4066Sahrens 		/*
1397fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
1398fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
1399fa9e4066Sahrens 		 * appropriate hierarchy.
1400fa9e4066Sahrens 		 */
1401fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
1402fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
1403fa9e4066Sahrens 
1404663207adSDon Brady 		print_vdev_tree(NULL, poolname, nvroot, 0, "", 0);
1405663207adSDon Brady 		print_vdev_tree(NULL, "dedup", nvroot, 0,
1406663207adSDon Brady 		    VDEV_ALLOC_BIAS_DEDUP, 0);
1407663207adSDon Brady 		print_vdev_tree(NULL, "special", nvroot, 0,
1408663207adSDon Brady 		    VDEV_ALLOC_BIAS_SPECIAL, 0);
1409663207adSDon Brady 		print_vdev_tree(NULL, "logs", nvroot, 0,
1410663207adSDon Brady 		    VDEV_ALLOC_BIAS_LOG, 0);
1411fa9e4066Sahrens 
1412fa9e4066Sahrens 		ret = 0;
1413fa9e4066Sahrens 	} else {
1414fa9e4066Sahrens 		/*
1415fa9e4066Sahrens 		 * Hand off to libzfs.
1416fa9e4066Sahrens 		 */
1417ad135b5dSChristopher Siden 		if (enable_all_pool_feat) {
14182acef22dSMatthew Ahrens 			spa_feature_t i;
1419ad135b5dSChristopher Siden 			for (i = 0; i < SPA_FEATURES; i++) {
1420ad135b5dSChristopher Siden 				char propname[MAXPATHLEN];
1421ad135b5dSChristopher Siden 				zfeature_info_t *feat = &spa_feature_table[i];
1422ad135b5dSChristopher Siden 
1423ad135b5dSChristopher Siden 				(void) snprintf(propname, sizeof (propname),
1424ad135b5dSChristopher Siden 				    "feature@%s", feat->fi_uname);
1425ad135b5dSChristopher Siden 
1426ad135b5dSChristopher Siden 				/*
1427ad135b5dSChristopher Siden 				 * Skip feature if user specified it manually
1428ad135b5dSChristopher Siden 				 * on the command line.
1429ad135b5dSChristopher Siden 				 */
1430ad135b5dSChristopher Siden 				if (nvlist_exists(props, propname))
1431ad135b5dSChristopher Siden 					continue;
1432ad135b5dSChristopher Siden 
14338b713775SWill Andrews 				ret = add_prop_list(propname,
14348b713775SWill Andrews 				    ZFS_FEATURE_ENABLED, &props, B_TRUE);
14358b713775SWill Andrews 				if (ret != 0)
1436ad135b5dSChristopher Siden 					goto errout;
1437ad135b5dSChristopher Siden 			}
1438ad135b5dSChristopher Siden 		}
14398b713775SWill Andrews 
14408b713775SWill Andrews 		ret = 1;
14410a48a24eStimh 		if (zpool_create(g_zfs, poolname,
14420a48a24eStimh 		    nvroot, props, fsprops) == 0) {
144304e56356SAndriy Gapon 			zfs_handle_t *pool = zfs_open(g_zfs,
144404e56356SAndriy Gapon 			    tname ? tname : poolname, ZFS_TYPE_FILESYSTEM);
1445fa9e4066Sahrens 			if (pool != NULL) {
1446fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
1447da6c28aaSamw 					ret = zfs_shareall(pool);
1448fa9e4066Sahrens 				zfs_close(pool);
1449fa9e4066Sahrens 			}
145099653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
145199653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
145299653d4eSeschrock 			    "been omitted\n"));
1453fa9e4066Sahrens 		}
1454fa9e4066Sahrens 	}
1455fa9e4066Sahrens 
1456990b4856Slling errout:
14572f8aaab3Seschrock 	nvlist_free(nvroot);
14580a48a24eStimh 	nvlist_free(fsprops);
14592f8aaab3Seschrock 	nvlist_free(props);
1460fa9e4066Sahrens 	return (ret);
1461990b4856Slling badusage:
14620a48a24eStimh 	nvlist_free(fsprops);
1463990b4856Slling 	nvlist_free(props);
1464990b4856Slling 	usage(B_FALSE);
1465990b4856Slling 	return (2);
1466fa9e4066Sahrens }
1467fa9e4066Sahrens 
1468fa9e4066Sahrens /*
1469fa9e4066Sahrens  * zpool destroy <pool>
1470fa9e4066Sahrens  *
147104e56356SAndriy Gapon  *	-f	Forcefully unmount any datasets
1472fa9e4066Sahrens  *
1473fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
1474fa9e4066Sahrens  */
1475fa9e4066Sahrens int
1476fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
1477fa9e4066Sahrens {
147899653d4eSeschrock 	boolean_t force = B_FALSE;
1479fa9e4066Sahrens 	int c;
1480fa9e4066Sahrens 	char *pool;
1481fa9e4066Sahrens 	zpool_handle_t *zhp;
1482fa9e4066Sahrens 	int ret;
1483fa9e4066Sahrens 
1484fa9e4066Sahrens 	/* check options */
1485fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
1486fa9e4066Sahrens 		switch (c) {
1487fa9e4066Sahrens 		case 'f':
148899653d4eSeschrock 			force = B_TRUE;
1489fa9e4066Sahrens 			break;
1490fa9e4066Sahrens 		case '?':
1491fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1492fa9e4066Sahrens 			    optopt);
149399653d4eSeschrock 			usage(B_FALSE);
1494fa9e4066Sahrens 		}
1495fa9e4066Sahrens 	}
1496fa9e4066Sahrens 
1497fa9e4066Sahrens 	argc -= optind;
1498fa9e4066Sahrens 	argv += optind;
1499fa9e4066Sahrens 
1500fa9e4066Sahrens 	/* check arguments */
1501fa9e4066Sahrens 	if (argc < 1) {
1502fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
150399653d4eSeschrock 		usage(B_FALSE);
1504fa9e4066Sahrens 	}
1505fa9e4066Sahrens 	if (argc > 1) {
1506fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
150799653d4eSeschrock 		usage(B_FALSE);
1508fa9e4066Sahrens 	}
1509fa9e4066Sahrens 
1510fa9e4066Sahrens 	pool = argv[0];
1511fa9e4066Sahrens 
151299653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
1513fa9e4066Sahrens 		/*
1514fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
1515fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
1516fa9e4066Sahrens 		 */
1517fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
1518fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
1519fa9e4066Sahrens 			    "destroy a dataset\n"));
1520fa9e4066Sahrens 		return (1);
1521fa9e4066Sahrens 	}
1522fa9e4066Sahrens 
1523f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
1524fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
1525fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
1526fa9e4066Sahrens 		return (1);
1527fa9e4066Sahrens 	}
1528fa9e4066Sahrens 
15294445fffbSMatthew Ahrens 	/* The history must be logged as part of the export */
15304445fffbSMatthew Ahrens 	log_history = B_FALSE;
15314445fffbSMatthew Ahrens 
15324445fffbSMatthew Ahrens 	ret = (zpool_destroy(zhp, history_str) != 0);
1533fa9e4066Sahrens 
1534fa9e4066Sahrens 	zpool_close(zhp);
1535fa9e4066Sahrens 
1536fa9e4066Sahrens 	return (ret);
1537fa9e4066Sahrens }
1538fa9e4066Sahrens 
1539fa9e4066Sahrens /*
1540fa9e4066Sahrens  * zpool export [-f] <pool> ...
1541fa9e4066Sahrens  *
1542fa9e4066Sahrens  *	-f	Forcefully unmount datasets
1543fa9e4066Sahrens  *
1544b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
1545fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
1546fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
1547fa9e4066Sahrens  */
1548fa9e4066Sahrens int
1549fa9e4066Sahrens zpool_do_export(int argc, char **argv)
1550fa9e4066Sahrens {
155199653d4eSeschrock 	boolean_t force = B_FALSE;
1552394ab0cbSGeorge Wilson 	boolean_t hardforce = B_FALSE;
1553fa9e4066Sahrens 	int c;
1554fa9e4066Sahrens 	zpool_handle_t *zhp;
1555fa9e4066Sahrens 	int ret;
1556fa9e4066Sahrens 	int i;
1557fa9e4066Sahrens 
1558fa9e4066Sahrens 	/* check options */
1559394ab0cbSGeorge Wilson 	while ((c = getopt(argc, argv, "fF")) != -1) {
1560fa9e4066Sahrens 		switch (c) {
1561fa9e4066Sahrens 		case 'f':
156299653d4eSeschrock 			force = B_TRUE;
1563fa9e4066Sahrens 			break;
1564394ab0cbSGeorge Wilson 		case 'F':
1565394ab0cbSGeorge Wilson 			hardforce = B_TRUE;
1566394ab0cbSGeorge Wilson 			break;
1567fa9e4066Sahrens 		case '?':
1568fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1569fa9e4066Sahrens 			    optopt);
157099653d4eSeschrock 			usage(B_FALSE);
1571fa9e4066Sahrens 		}
1572fa9e4066Sahrens 	}
1573fa9e4066Sahrens 
1574fa9e4066Sahrens 	argc -= optind;
1575fa9e4066Sahrens 	argv += optind;
1576fa9e4066Sahrens 
1577fa9e4066Sahrens 	/* check arguments */
1578fa9e4066Sahrens 	if (argc < 1) {
1579fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
158099653d4eSeschrock 		usage(B_FALSE);
1581fa9e4066Sahrens 	}
1582fa9e4066Sahrens 
1583fa9e4066Sahrens 	ret = 0;
1584fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
158599653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
1586fa9e4066Sahrens 			ret = 1;
1587fa9e4066Sahrens 			continue;
1588fa9e4066Sahrens 		}
1589fa9e4066Sahrens 
1590f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
1591fa9e4066Sahrens 			ret = 1;
1592fa9e4066Sahrens 			zpool_close(zhp);
1593fa9e4066Sahrens 			continue;
1594fa9e4066Sahrens 		}
1595fa9e4066Sahrens 
15964445fffbSMatthew Ahrens 		/* The history must be logged as part of the export */
15974445fffbSMatthew Ahrens 		log_history = B_FALSE;
15984445fffbSMatthew Ahrens 
1599394ab0cbSGeorge Wilson 		if (hardforce) {
16004445fffbSMatthew Ahrens 			if (zpool_export_force(zhp, history_str) != 0)
1601394ab0cbSGeorge Wilson 				ret = 1;
16024445fffbSMatthew Ahrens 		} else if (zpool_export(zhp, force, history_str) != 0) {
1603fa9e4066Sahrens 			ret = 1;
1604394ab0cbSGeorge Wilson 		}
1605fa9e4066Sahrens 
1606fa9e4066Sahrens 		zpool_close(zhp);
1607fa9e4066Sahrens 	}
1608fa9e4066Sahrens 
1609fa9e4066Sahrens 	return (ret);
1610fa9e4066Sahrens }
1611fa9e4066Sahrens 
1612fa9e4066Sahrens /*
1613fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
1614fa9e4066Sahrens  * name column.
1615fa9e4066Sahrens  */
1616fa9e4066Sahrens static int
1617663207adSDon Brady max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max,
1618663207adSDon Brady     int name_flags)
1619fa9e4066Sahrens {
1620663207adSDon Brady 	char *name;
1621fa9e4066Sahrens 	nvlist_t **child;
1622fa9e4066Sahrens 	uint_t c, children;
1623fa9e4066Sahrens 	int ret;
1624fa9e4066Sahrens 
1625663207adSDon Brady 	name = zpool_vdev_name(g_zfs, zhp, nv, name_flags | VDEV_NAME_TYPE_ID);
1626fa9e4066Sahrens 	if (strlen(name) + depth > max)
1627fa9e4066Sahrens 		max = strlen(name) + depth;
1628fa9e4066Sahrens 
1629afefbcddSeschrock 	free(name);
1630afefbcddSeschrock 
163199653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
163299653d4eSeschrock 	    &child, &children) == 0) {
163399653d4eSeschrock 		for (c = 0; c < children; c++)
163499653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
1635663207adSDon Brady 			    max, name_flags)) > max)
163699653d4eSeschrock 				max = ret;
163799653d4eSeschrock 	}
163899653d4eSeschrock 
1639fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1640fa94a07fSbrendan 	    &child, &children) == 0) {
1641fa94a07fSbrendan 		for (c = 0; c < children; c++)
1642fa94a07fSbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
1643663207adSDon Brady 			    max, name_flags)) > max)
1644fa94a07fSbrendan 				max = ret;
1645fa94a07fSbrendan 	}
1646fa94a07fSbrendan 
1647fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
164899653d4eSeschrock 	    &child, &children) == 0) {
164999653d4eSeschrock 		for (c = 0; c < children; c++)
165099653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
1651663207adSDon Brady 			    max, name_flags)) > max)
165299653d4eSeschrock 				max = ret;
165399653d4eSeschrock 	}
1654fa9e4066Sahrens 
1655fa9e4066Sahrens 	return (max);
1656fa9e4066Sahrens }
1657fa9e4066Sahrens 
1658e6ca193dSGeorge Wilson typedef struct spare_cbdata {
1659e6ca193dSGeorge Wilson 	uint64_t	cb_guid;
1660e6ca193dSGeorge Wilson 	zpool_handle_t	*cb_zhp;
1661e6ca193dSGeorge Wilson } spare_cbdata_t;
1662e6ca193dSGeorge Wilson 
1663e6ca193dSGeorge Wilson static boolean_t
1664e6ca193dSGeorge Wilson find_vdev(nvlist_t *nv, uint64_t search)
1665e6ca193dSGeorge Wilson {
1666e6ca193dSGeorge Wilson 	uint64_t guid;
1667e6ca193dSGeorge Wilson 	nvlist_t **child;
1668e6ca193dSGeorge Wilson 	uint_t c, children;
1669e6ca193dSGeorge Wilson 
1670e6ca193dSGeorge Wilson 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
1671e6ca193dSGeorge Wilson 	    search == guid)
1672e6ca193dSGeorge Wilson 		return (B_TRUE);
1673e6ca193dSGeorge Wilson 
1674e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1675e6ca193dSGeorge Wilson 	    &child, &children) == 0) {
1676e6ca193dSGeorge Wilson 		for (c = 0; c < children; c++)
1677e6ca193dSGeorge Wilson 			if (find_vdev(child[c], search))
1678e6ca193dSGeorge Wilson 				return (B_TRUE);
1679e6ca193dSGeorge Wilson 	}
1680e6ca193dSGeorge Wilson 
1681e6ca193dSGeorge Wilson 	return (B_FALSE);
1682e6ca193dSGeorge Wilson }
1683e6ca193dSGeorge Wilson 
1684e6ca193dSGeorge Wilson static int
1685e6ca193dSGeorge Wilson find_spare(zpool_handle_t *zhp, void *data)
1686e6ca193dSGeorge Wilson {
1687e6ca193dSGeorge Wilson 	spare_cbdata_t *cbp = data;
1688e6ca193dSGeorge Wilson 	nvlist_t *config, *nvroot;
1689e6ca193dSGeorge Wilson 
1690e6ca193dSGeorge Wilson 	config = zpool_get_config(zhp, NULL);
1691e6ca193dSGeorge Wilson 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1692e6ca193dSGeorge Wilson 	    &nvroot) == 0);
1693e6ca193dSGeorge Wilson 
1694e6ca193dSGeorge Wilson 	if (find_vdev(nvroot, cbp->cb_guid)) {
1695e6ca193dSGeorge Wilson 		cbp->cb_zhp = zhp;
1696e6ca193dSGeorge Wilson 		return (1);
1697e6ca193dSGeorge Wilson 	}
1698e6ca193dSGeorge Wilson 
1699e6ca193dSGeorge Wilson 	zpool_close(zhp);
1700e6ca193dSGeorge Wilson 	return (0);
1701e6ca193dSGeorge Wilson }
1702e6ca193dSGeorge Wilson 
1703663207adSDon Brady typedef struct status_cbdata {
1704663207adSDon Brady 	int		cb_count;
1705663207adSDon Brady 	int		cb_name_flags;
1706663207adSDon Brady 	int		cb_namewidth;
1707663207adSDon Brady 	boolean_t	cb_allpools;
1708663207adSDon Brady 	boolean_t	cb_verbose;
1709dd50e0ccSTony Hutter 	boolean_t	cb_literal;
1710663207adSDon Brady 	boolean_t	cb_explain;
1711663207adSDon Brady 	boolean_t	cb_first;
1712663207adSDon Brady 	boolean_t	cb_dedup_stats;
1713663207adSDon Brady 	boolean_t	cb_print_status;
1714dd50e0ccSTony Hutter 	boolean_t	cb_print_slow_ios;
1715084fd14fSBrian Behlendorf 	boolean_t	cb_print_vdev_init;
1716084fd14fSBrian Behlendorf 	boolean_t	cb_print_vdev_trim;
1717663207adSDon Brady } status_cbdata_t;
1718663207adSDon Brady 
1719084fd14fSBrian Behlendorf /*
1720084fd14fSBrian Behlendorf  * Print vdev initialization status for leaves
1721084fd14fSBrian Behlendorf  */
1722084fd14fSBrian Behlendorf static void
1723084fd14fSBrian Behlendorf print_status_initialize(vdev_stat_t *vs, boolean_t verbose)
1724084fd14fSBrian Behlendorf {
1725084fd14fSBrian Behlendorf 	if (verbose) {
1726084fd14fSBrian Behlendorf 		if ((vs->vs_initialize_state == VDEV_INITIALIZE_ACTIVE ||
1727084fd14fSBrian Behlendorf 		    vs->vs_initialize_state == VDEV_INITIALIZE_SUSPENDED ||
1728084fd14fSBrian Behlendorf 		    vs->vs_initialize_state == VDEV_INITIALIZE_COMPLETE) &&
1729084fd14fSBrian Behlendorf 		    !vs->vs_scan_removing) {
1730084fd14fSBrian Behlendorf 			char zbuf[1024];
1731084fd14fSBrian Behlendorf 			char tbuf[256];
1732084fd14fSBrian Behlendorf 			struct tm zaction_ts;
1733084fd14fSBrian Behlendorf 
1734084fd14fSBrian Behlendorf 			time_t t = vs->vs_initialize_action_time;
1735084fd14fSBrian Behlendorf 			int initialize_pct = 100;
1736084fd14fSBrian Behlendorf 			if (vs->vs_initialize_state !=
1737084fd14fSBrian Behlendorf 			    VDEV_INITIALIZE_COMPLETE) {
1738084fd14fSBrian Behlendorf 				initialize_pct = (vs->vs_initialize_bytes_done *
1739084fd14fSBrian Behlendorf 				    100 / (vs->vs_initialize_bytes_est + 1));
1740084fd14fSBrian Behlendorf 			}
1741084fd14fSBrian Behlendorf 
1742084fd14fSBrian Behlendorf 			(void) localtime_r(&t, &zaction_ts);
1743084fd14fSBrian Behlendorf 			(void) strftime(tbuf, sizeof (tbuf), "%c", &zaction_ts);
1744084fd14fSBrian Behlendorf 
1745084fd14fSBrian Behlendorf 			switch (vs->vs_initialize_state) {
1746084fd14fSBrian Behlendorf 			case VDEV_INITIALIZE_SUSPENDED:
1747084fd14fSBrian Behlendorf 				(void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
1748084fd14fSBrian Behlendorf 				    gettext("suspended, started at"), tbuf);
1749084fd14fSBrian Behlendorf 				break;
1750084fd14fSBrian Behlendorf 			case VDEV_INITIALIZE_ACTIVE:
1751084fd14fSBrian Behlendorf 				(void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
1752084fd14fSBrian Behlendorf 				    gettext("started at"), tbuf);
1753084fd14fSBrian Behlendorf 				break;
1754084fd14fSBrian Behlendorf 			case VDEV_INITIALIZE_COMPLETE:
1755084fd14fSBrian Behlendorf 				(void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
1756084fd14fSBrian Behlendorf 				    gettext("completed at"), tbuf);
1757084fd14fSBrian Behlendorf 				break;
1758084fd14fSBrian Behlendorf 			}
1759084fd14fSBrian Behlendorf 
1760084fd14fSBrian Behlendorf 			(void) printf(gettext("  (%d%% initialized%s)"),
1761084fd14fSBrian Behlendorf 			    initialize_pct, zbuf);
1762084fd14fSBrian Behlendorf 		} else {
1763084fd14fSBrian Behlendorf 			(void) printf(gettext("  (uninitialized)"));
1764084fd14fSBrian Behlendorf 		}
1765084fd14fSBrian Behlendorf 	} else if (vs->vs_initialize_state == VDEV_INITIALIZE_ACTIVE) {
1766084fd14fSBrian Behlendorf 		(void) printf(gettext("  (initializing)"));
1767084fd14fSBrian Behlendorf 	}
1768084fd14fSBrian Behlendorf }
1769084fd14fSBrian Behlendorf 
1770084fd14fSBrian Behlendorf /*
1771084fd14fSBrian Behlendorf  * Print vdev TRIM status for leaves
1772084fd14fSBrian Behlendorf  */
1773084fd14fSBrian Behlendorf static void
1774084fd14fSBrian Behlendorf print_status_trim(vdev_stat_t *vs, boolean_t verbose)
1775084fd14fSBrian Behlendorf {
1776084fd14fSBrian Behlendorf 	if (verbose) {
1777084fd14fSBrian Behlendorf 		if ((vs->vs_trim_state == VDEV_TRIM_ACTIVE ||
1778084fd14fSBrian Behlendorf 		    vs->vs_trim_state == VDEV_TRIM_SUSPENDED ||
1779084fd14fSBrian Behlendorf 		    vs->vs_trim_state == VDEV_TRIM_COMPLETE) &&
1780084fd14fSBrian Behlendorf 		    !vs->vs_scan_removing) {
1781084fd14fSBrian Behlendorf 			char zbuf[1024];
1782084fd14fSBrian Behlendorf 			char tbuf[256];
1783084fd14fSBrian Behlendorf 			struct tm zaction_ts;
1784084fd14fSBrian Behlendorf 
1785084fd14fSBrian Behlendorf 			time_t t = vs->vs_trim_action_time;
1786084fd14fSBrian Behlendorf 			int trim_pct = 100;
1787084fd14fSBrian Behlendorf 			if (vs->vs_trim_state != VDEV_TRIM_COMPLETE) {
1788084fd14fSBrian Behlendorf 				trim_pct = (vs->vs_trim_bytes_done *
1789084fd14fSBrian Behlendorf 				    100 / (vs->vs_trim_bytes_est + 1));
1790084fd14fSBrian Behlendorf 			}
1791084fd14fSBrian Behlendorf 
1792084fd14fSBrian Behlendorf 			(void) localtime_r(&t, &zaction_ts);
1793084fd14fSBrian Behlendorf 			(void) strftime(tbuf, sizeof (tbuf), "%c", &zaction_ts);
1794084fd14fSBrian Behlendorf 
1795084fd14fSBrian Behlendorf 			switch (vs->vs_trim_state) {
1796084fd14fSBrian Behlendorf 			case VDEV_TRIM_SUSPENDED:
1797084fd14fSBrian Behlendorf 				(void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
1798084fd14fSBrian Behlendorf 				    gettext("suspended, started at"), tbuf);
1799084fd14fSBrian Behlendorf 				break;
1800084fd14fSBrian Behlendorf 			case VDEV_TRIM_ACTIVE:
1801084fd14fSBrian Behlendorf 				(void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
1802084fd14fSBrian Behlendorf 				    gettext("started at"), tbuf);
1803084fd14fSBrian Behlendorf 				break;
1804084fd14fSBrian Behlendorf 			case VDEV_TRIM_COMPLETE:
1805084fd14fSBrian Behlendorf 				(void) snprintf(zbuf, sizeof (zbuf), ", %s %s",
1806084fd14fSBrian Behlendorf 				    gettext("completed at"), tbuf);
1807084fd14fSBrian Behlendorf 				break;
1808084fd14fSBrian Behlendorf 			}
1809084fd14fSBrian Behlendorf 
1810084fd14fSBrian Behlendorf 			(void) printf(gettext("  (%d%% trimmed%s)"),
1811084fd14fSBrian Behlendorf 			    trim_pct, zbuf);
1812084fd14fSBrian Behlendorf 		} else if (vs->vs_trim_notsup) {
1813084fd14fSBrian Behlendorf 			(void) printf(gettext("  (trim unsupported)"));
1814084fd14fSBrian Behlendorf 		} else {
1815084fd14fSBrian Behlendorf 			(void) printf(gettext("  (untrimmed)"));
1816084fd14fSBrian Behlendorf 		}
1817084fd14fSBrian Behlendorf 	} else if (vs->vs_trim_state == VDEV_TRIM_ACTIVE) {
1818084fd14fSBrian Behlendorf 		(void) printf(gettext("  (trimming)"));
1819084fd14fSBrian Behlendorf 	}
1820084fd14fSBrian Behlendorf }
1821084fd14fSBrian Behlendorf 
1822e6ca193dSGeorge Wilson /*
1823e6ca193dSGeorge Wilson  * Print out configuration state as requested by status_callback.
1824e6ca193dSGeorge Wilson  */
1825663207adSDon Brady static void
1826663207adSDon Brady print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
1827663207adSDon Brady     nvlist_t *nv, int depth, boolean_t isspare)
1828e6ca193dSGeorge Wilson {
182964dee23eSTony Hutter 	nvlist_t **child, *root;
1830e6ca193dSGeorge Wilson 	uint_t c, children;
18313f9d6ad7SLin Ling 	pool_scan_stat_t *ps = NULL;
1832e6ca193dSGeorge Wilson 	vdev_stat_t *vs;
18333f9d6ad7SLin Ling 	char rbuf[6], wbuf[6], cbuf[6];
1834e6ca193dSGeorge Wilson 	char *vname;
1835e6ca193dSGeorge Wilson 	uint64_t notpresent;
1836663207adSDon Brady 	spare_cbdata_t spare_cb;
18376401734dSWill Andrews 	const char *state;
18385cabbc6bSPrashanth Sreenivasa 	char *type;
1839e6ca193dSGeorge Wilson 
1840e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1841e6ca193dSGeorge Wilson 	    &child, &children) != 0)
1842e6ca193dSGeorge Wilson 		children = 0;
1843e6ca193dSGeorge Wilson 
18443f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
18453f9d6ad7SLin Ling 	    (uint64_t **)&vs, &c) == 0);
18463f9d6ad7SLin Ling 
18475cabbc6bSPrashanth Sreenivasa 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
18485cabbc6bSPrashanth Sreenivasa 
18495cabbc6bSPrashanth Sreenivasa 	if (strcmp(type, VDEV_TYPE_INDIRECT) == 0)
18505cabbc6bSPrashanth Sreenivasa 		return;
18515cabbc6bSPrashanth Sreenivasa 
1852e6ca193dSGeorge Wilson 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1853e6ca193dSGeorge Wilson 	if (isspare) {
1854e6ca193dSGeorge Wilson 		/*
1855e6ca193dSGeorge Wilson 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
1856e6ca193dSGeorge Wilson 		 * online drives.
1857e6ca193dSGeorge Wilson 		 */
1858e6ca193dSGeorge Wilson 		if (vs->vs_aux == VDEV_AUX_SPARED)
1859e6ca193dSGeorge Wilson 			state = "INUSE";
1860e6ca193dSGeorge Wilson 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
1861e6ca193dSGeorge Wilson 			state = "AVAIL";
1862e6ca193dSGeorge Wilson 	}
1863e6ca193dSGeorge Wilson 
1864663207adSDon Brady 	(void) printf("\t%*s%-*s  %-8s", depth, "", cb->cb_namewidth - depth,
1865e6ca193dSGeorge Wilson 	    name, state);
1866e6ca193dSGeorge Wilson 
1867e6ca193dSGeorge Wilson 	if (!isspare) {
1868dd50e0ccSTony Hutter 		if (cb->cb_literal) {
1869dd50e0ccSTony Hutter 			printf(" %5llu %5llu %5llu",
1870dd50e0ccSTony Hutter 			    (u_longlong_t)vs->vs_read_errors,
1871dd50e0ccSTony Hutter 			    (u_longlong_t)vs->vs_write_errors,
1872dd50e0ccSTony Hutter 			    (u_longlong_t)vs->vs_checksum_errors);
1873dd50e0ccSTony Hutter 		} else {
1874dd50e0ccSTony Hutter 			zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
1875dd50e0ccSTony Hutter 			zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
1876dd50e0ccSTony Hutter 			zfs_nicenum(vs->vs_checksum_errors, cbuf,
1877dd50e0ccSTony Hutter 			    sizeof (cbuf));
1878dd50e0ccSTony Hutter 			printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
1879dd50e0ccSTony Hutter 		}
1880dd50e0ccSTony Hutter 
1881dd50e0ccSTony Hutter 		if (cb->cb_print_slow_ios) {
1882dd50e0ccSTony Hutter 			if (children == 0)  {
1883dd50e0ccSTony Hutter 				/* Only leafs vdevs have slow IOs */
1884dd50e0ccSTony Hutter 				zfs_nicenum(vs->vs_slow_ios, rbuf,
1885dd50e0ccSTony Hutter 				    sizeof (rbuf));
1886dd50e0ccSTony Hutter 			} else {
1887dd50e0ccSTony Hutter 				(void) snprintf(rbuf, sizeof (rbuf), "-");
1888dd50e0ccSTony Hutter 			}
1889dd50e0ccSTony Hutter 
1890dd50e0ccSTony Hutter 			if (cb->cb_literal)
1891dd50e0ccSTony Hutter 				printf(" %5llu", (u_longlong_t)vs->vs_slow_ios);
1892dd50e0ccSTony Hutter 			else
1893dd50e0ccSTony Hutter 				printf(" %5s", rbuf);
1894dd50e0ccSTony Hutter 		}
1895dd50e0ccSTony Hutter 
1896e6ca193dSGeorge Wilson 	}
1897e6ca193dSGeorge Wilson 
1898e6ca193dSGeorge Wilson 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1899e6ca193dSGeorge Wilson 	    &notpresent) == 0) {
1900e6ca193dSGeorge Wilson 		char *path;
1901e6ca193dSGeorge Wilson 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
1902e6ca193dSGeorge Wilson 		(void) printf("  was %s", path);
1903e6ca193dSGeorge Wilson 	} else if (vs->vs_aux != 0) {
1904e6ca193dSGeorge Wilson 		(void) printf("  ");
1905e6ca193dSGeorge Wilson 
1906e6ca193dSGeorge Wilson 		switch (vs->vs_aux) {
1907e6ca193dSGeorge Wilson 		case VDEV_AUX_OPEN_FAILED:
1908e6ca193dSGeorge Wilson 			(void) printf(gettext("cannot open"));
1909e6ca193dSGeorge Wilson 			break;
1910e6ca193dSGeorge Wilson 
1911e6ca193dSGeorge Wilson 		case VDEV_AUX_BAD_GUID_SUM:
1912e6ca193dSGeorge Wilson 			(void) printf(gettext("missing device"));
1913e6ca193dSGeorge Wilson 			break;
1914e6ca193dSGeorge Wilson 
1915e6ca193dSGeorge Wilson 		case VDEV_AUX_NO_REPLICAS:
1916e6ca193dSGeorge Wilson 			(void) printf(gettext("insufficient replicas"));
1917e6ca193dSGeorge Wilson 			break;
1918e6ca193dSGeorge Wilson 
1919e6ca193dSGeorge Wilson 		case VDEV_AUX_VERSION_NEWER:
1920e6ca193dSGeorge Wilson 			(void) printf(gettext("newer version"));
1921e6ca193dSGeorge Wilson 			break;
1922e6ca193dSGeorge Wilson 
1923ad135b5dSChristopher Siden 		case VDEV_AUX_UNSUP_FEAT:
1924ad135b5dSChristopher Siden 			(void) printf(gettext("unsupported feature(s)"));
1925ad135b5dSChristopher Siden 			break;
1926ad135b5dSChristopher Siden 
1927e6ca193dSGeorge Wilson 		case VDEV_AUX_SPARED:
1928e6ca193dSGeorge Wilson 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1929663207adSDon Brady 			    &spare_cb.cb_guid) == 0);
1930663207adSDon Brady 			if (zpool_iter(g_zfs, find_spare, &spare_cb) == 1) {
1931663207adSDon Brady 				if (strcmp(zpool_get_name(spare_cb.cb_zhp),
1932e6ca193dSGeorge Wilson 				    zpool_get_name(zhp)) == 0)
1933e6ca193dSGeorge Wilson 					(void) printf(gettext("currently in "
1934e6ca193dSGeorge Wilson 					    "use"));
1935e6ca193dSGeorge Wilson 				else
1936e6ca193dSGeorge Wilson 					(void) printf(gettext("in use by "
1937e6ca193dSGeorge Wilson 					    "pool '%s'"),
1938663207adSDon Brady 					    zpool_get_name(spare_cb.cb_zhp));
1939663207adSDon Brady 				zpool_close(spare_cb.cb_zhp);
1940e6ca193dSGeorge Wilson 			} else {
1941e6ca193dSGeorge Wilson 				(void) printf(gettext("currently in use"));
1942e6ca193dSGeorge Wilson 			}
1943e6ca193dSGeorge Wilson 			break;
1944e6ca193dSGeorge Wilson 
1945e6ca193dSGeorge Wilson 		case VDEV_AUX_ERR_EXCEEDED:
1946e6ca193dSGeorge Wilson 			(void) printf(gettext("too many errors"));
1947e6ca193dSGeorge Wilson 			break;
1948e6ca193dSGeorge Wilson 
1949e6ca193dSGeorge Wilson 		case VDEV_AUX_IO_FAILURE:
1950e6ca193dSGeorge Wilson 			(void) printf(gettext("experienced I/O failures"));
1951e6ca193dSGeorge Wilson 			break;
1952e6ca193dSGeorge Wilson 
1953e6ca193dSGeorge Wilson 		case VDEV_AUX_BAD_LOG:
1954e6ca193dSGeorge Wilson 			(void) printf(gettext("bad intent log"));
1955e6ca193dSGeorge Wilson 			break;
1956e6ca193dSGeorge Wilson 
1957069f55e2SEric Schrock 		case VDEV_AUX_EXTERNAL:
1958069f55e2SEric Schrock 			(void) printf(gettext("external device fault"));
1959069f55e2SEric Schrock 			break;
1960069f55e2SEric Schrock 
19611195e687SMark J Musante 		case VDEV_AUX_SPLIT_POOL:
19621195e687SMark J Musante 			(void) printf(gettext("split into new pool"));
19631195e687SMark J Musante 			break;
19641195e687SMark J Musante 
1965e0f1c0afSOlaf Faaland 		case VDEV_AUX_ACTIVE:
1966e0f1c0afSOlaf Faaland 			(void) printf(gettext("currently in use"));
1967e0f1c0afSOlaf Faaland 			break;
1968e0f1c0afSOlaf Faaland 
19696f793812SPavel Zakharov 		case VDEV_AUX_CHILDREN_OFFLINE:
19706f793812SPavel Zakharov 			(void) printf(gettext("all children offline"));
19716f793812SPavel Zakharov 			break;
19726f793812SPavel Zakharov 
1973e6ca193dSGeorge Wilson 		default:
1974e6ca193dSGeorge Wilson 			(void) printf(gettext("corrupted data"));
1975e6ca193dSGeorge Wilson 			break;
1976e6ca193dSGeorge Wilson 		}
19773f9d6ad7SLin Ling 	}
19783f9d6ad7SLin Ling 
197964dee23eSTony Hutter 	/* The root vdev has the scrub/resilver stats */
198064dee23eSTony Hutter 	root = fnvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
198164dee23eSTony Hutter 	    ZPOOL_CONFIG_VDEV_TREE);
198264dee23eSTony Hutter 	(void) nvlist_lookup_uint64_array(root, ZPOOL_CONFIG_SCAN_STATS,
19833f9d6ad7SLin Ling 	    (uint64_t **)&ps, &c);
19843f9d6ad7SLin Ling 
1985e4c795beSTom Caputi 	if (ps != NULL && ps->pss_state == DSS_SCANNING && children == 0) {
1986e4c795beSTom Caputi 		if (vs->vs_scan_processed != 0) {
1987e4c795beSTom Caputi 			(void) printf(gettext("  (%s)"),
1988e4c795beSTom Caputi 			    (ps->pss_func == POOL_SCAN_RESILVER) ?
1989e4c795beSTom Caputi 			    "resilvering" : "repairing");
1990e4c795beSTom Caputi 		} else if (vs->vs_resilver_deferred) {
1991e4c795beSTom Caputi 			(void) printf(gettext("  (awaiting resilver)"));
1992e4c795beSTom Caputi 		}
1993e6ca193dSGeorge Wilson 	}
1994e6ca193dSGeorge Wilson 
1995084fd14fSBrian Behlendorf 	/* Display vdev initialization and trim status for leaves */
1996084fd14fSBrian Behlendorf 	if (children == 0) {
1997084fd14fSBrian Behlendorf 		print_status_initialize(vs, cb->cb_print_vdev_init);
1998084fd14fSBrian Behlendorf 		print_status_trim(vs, cb->cb_print_vdev_trim);
1999094e47e9SGeorge Wilson 	}
2000094e47e9SGeorge Wilson 
2001e6ca193dSGeorge Wilson 	(void) printf("\n");
2002e6ca193dSGeorge Wilson 
2003e6ca193dSGeorge Wilson 	for (c = 0; c < children; c++) {
200488ecc943SGeorge Wilson 		uint64_t islog = B_FALSE, ishole = B_FALSE;
2005e6ca193dSGeorge Wilson 
200688ecc943SGeorge Wilson 		/* Don't print logs or holes here */
2007e6ca193dSGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
200888ecc943SGeorge Wilson 		    &islog);
200988ecc943SGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
201088ecc943SGeorge Wilson 		    &ishole);
201188ecc943SGeorge Wilson 		if (islog || ishole)
2012e6ca193dSGeorge Wilson 			continue;
2013663207adSDon Brady 		/* Only print normal classes here */
2014663207adSDon Brady 		if (nvlist_exists(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
2015663207adSDon Brady 			continue;
2016663207adSDon Brady 
2017663207adSDon Brady 		vname = zpool_vdev_name(g_zfs, zhp, child[c],
2018663207adSDon Brady 		    cb->cb_name_flags | VDEV_NAME_TYPE_ID);
201964dee23eSTony Hutter 
2020663207adSDon Brady 		print_status_config(zhp, cb, vname, child[c], depth + 2,
2021663207adSDon Brady 		    isspare);
2022e6ca193dSGeorge Wilson 		free(vname);
2023e6ca193dSGeorge Wilson 	}
2024e6ca193dSGeorge Wilson }
2025e6ca193dSGeorge Wilson 
2026fa9e4066Sahrens /*
2027fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
2028fa9e4066Sahrens  * pool, printing out the name and status for each one.
2029fa9e4066Sahrens  */
2030663207adSDon Brady static void
2031663207adSDon Brady print_import_config(status_cbdata_t *cb, const char *name, nvlist_t *nv,
2032663207adSDon Brady     int depth)
2033fa9e4066Sahrens {
2034fa9e4066Sahrens 	nvlist_t **child;
2035fa9e4066Sahrens 	uint_t c, children;
2036fa9e4066Sahrens 	vdev_stat_t *vs;
2037afefbcddSeschrock 	char *type, *vname;
2038fa9e4066Sahrens 
2039fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
204088ecc943SGeorge Wilson 	if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
204188ecc943SGeorge Wilson 	    strcmp(type, VDEV_TYPE_HOLE) == 0)
2042fa9e4066Sahrens 		return;
2043fa9e4066Sahrens 
20443f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
2045fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2046fa9e4066Sahrens 
2047663207adSDon Brady 	(void) printf("\t%*s%-*s", depth, "", cb->cb_namewidth - depth, name);
2048990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
2049fa9e4066Sahrens 
2050fa9e4066Sahrens 	if (vs->vs_aux != 0) {
20513d7072f8Seschrock 		(void) printf("  ");
2052fa9e4066Sahrens 
2053fa9e4066Sahrens 		switch (vs->vs_aux) {
2054fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2055fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2056fa9e4066Sahrens 			break;
2057fa9e4066Sahrens 
2058fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2059fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2060fa9e4066Sahrens 			break;
2061fa9e4066Sahrens 
2062fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2063fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2064fa9e4066Sahrens 			break;
2065fa9e4066Sahrens 
2066eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
2067eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
2068eaca9bbdSeschrock 			break;
2069eaca9bbdSeschrock 
2070ad135b5dSChristopher Siden 		case VDEV_AUX_UNSUP_FEAT:
2071ad135b5dSChristopher Siden 			(void) printf(gettext("unsupported feature(s)"));
2072ad135b5dSChristopher Siden 			break;
2073ad135b5dSChristopher Siden 
20743d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
20753d7072f8Seschrock 			(void) printf(gettext("too many errors"));
20763d7072f8Seschrock 			break;
20773d7072f8Seschrock 
2078e0f1c0afSOlaf Faaland 		case VDEV_AUX_ACTIVE:
2079e0f1c0afSOlaf Faaland 			(void) printf(gettext("currently in use"));
2080e0f1c0afSOlaf Faaland 			break;
2081e0f1c0afSOlaf Faaland 
20826f793812SPavel Zakharov 		case VDEV_AUX_CHILDREN_OFFLINE:
20836f793812SPavel Zakharov 			(void) printf(gettext("all children offline"));
20846f793812SPavel Zakharov 			break;
20856f793812SPavel Zakharov 
2086fa9e4066Sahrens 		default:
2087fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2088fa9e4066Sahrens 			break;
2089fa9e4066Sahrens 		}
2090fa9e4066Sahrens 	}
2091fa9e4066Sahrens 	(void) printf("\n");
2092fa9e4066Sahrens 
2093fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2094fa9e4066Sahrens 	    &child, &children) != 0)
2095fa9e4066Sahrens 		return;
2096fa9e4066Sahrens 
2097afefbcddSeschrock 	for (c = 0; c < children; c++) {
20988654d025Sperrin 		uint64_t is_log = B_FALSE;
20998654d025Sperrin 
21008654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
21018654d025Sperrin 		    &is_log);
2102e6ca193dSGeorge Wilson 		if (is_log)
21038654d025Sperrin 			continue;
2104663207adSDon Brady 		if (nvlist_exists(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
2105663207adSDon Brady 			continue;
21068654d025Sperrin 
2107663207adSDon Brady 		vname = zpool_vdev_name(g_zfs, NULL, child[c],
2108663207adSDon Brady 		    cb->cb_name_flags | VDEV_NAME_TYPE_ID);
2109663207adSDon Brady 		print_import_config(cb, vname, child[c], depth + 2);
2110afefbcddSeschrock 		free(vname);
2111afefbcddSeschrock 	}
211299653d4eSeschrock 
2113fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
2114fa94a07fSbrendan 	    &child, &children) == 0) {
2115fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
2116fa94a07fSbrendan 		for (c = 0; c < children; c++) {
2117663207adSDon Brady 			vname = zpool_vdev_name(g_zfs, NULL, child[c],
2118663207adSDon Brady 			    cb->cb_name_flags);
2119fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
2120fa94a07fSbrendan 			free(vname);
2121fa94a07fSbrendan 		}
2122fa94a07fSbrendan 	}
212399653d4eSeschrock 
2124fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
2125fa94a07fSbrendan 	    &child, &children) == 0) {
2126fa94a07fSbrendan 		(void) printf(gettext("\tspares\n"));
2127fa94a07fSbrendan 		for (c = 0; c < children; c++) {
2128663207adSDon Brady 			vname = zpool_vdev_name(g_zfs, NULL, child[c],
2129663207adSDon Brady 			    cb->cb_name_flags);
2130fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
2131fa94a07fSbrendan 			free(vname);
2132fa94a07fSbrendan 		}
213399653d4eSeschrock 	}
2134fa9e4066Sahrens }
2135fa9e4066Sahrens 
2136e6ca193dSGeorge Wilson /*
2137663207adSDon Brady  * Print specialized class vdevs.
2138663207adSDon Brady  *
2139663207adSDon Brady  * These are recorded as top level vdevs in the main pool child array
2140663207adSDon Brady  * but with "is_log" set to 1 or an "alloc_bias" string. We use either
2141663207adSDon Brady  * print_status_config() or print_import_config() to print the top level
2142663207adSDon Brady  * class vdevs then any of their children (eg mirrored slogs) are printed
2143663207adSDon Brady  * recursively - which works because only the top level vdev is marked.
2144e6ca193dSGeorge Wilson  */
2145e6ca193dSGeorge Wilson static void
2146663207adSDon Brady print_class_vdevs(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
2147663207adSDon Brady     const char *class)
2148e6ca193dSGeorge Wilson {
2149e6ca193dSGeorge Wilson 	uint_t c, children;
2150e6ca193dSGeorge Wilson 	nvlist_t **child;
2151663207adSDon Brady 	boolean_t printed = B_FALSE;
2152663207adSDon Brady 
2153663207adSDon Brady 	assert(zhp != NULL || !cb->cb_verbose);
2154e6ca193dSGeorge Wilson 
2155e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
2156e6ca193dSGeorge Wilson 	    &children) != 0)
2157e6ca193dSGeorge Wilson 		return;
2158e6ca193dSGeorge Wilson 
2159e6ca193dSGeorge Wilson 	for (c = 0; c < children; c++) {
2160e6ca193dSGeorge Wilson 		uint64_t is_log = B_FALSE;
2161663207adSDon Brady 		char *bias = NULL;
2162663207adSDon Brady 		char *type = NULL;
2163e6ca193dSGeorge Wilson 
2164e6ca193dSGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
2165e6ca193dSGeorge Wilson 		    &is_log);
2166663207adSDon Brady 
2167663207adSDon Brady 		if (is_log) {
2168663207adSDon Brady 			bias = VDEV_ALLOC_CLASS_LOGS;
2169663207adSDon Brady 		} else {
2170663207adSDon Brady 			(void) nvlist_lookup_string(child[c],
2171663207adSDon Brady 			    ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
2172663207adSDon Brady 			(void) nvlist_lookup_string(child[c],
2173663207adSDon Brady 			    ZPOOL_CONFIG_TYPE, &type);
2174663207adSDon Brady 		}
2175663207adSDon Brady 
2176663207adSDon Brady 		if (bias == NULL || strcmp(bias, class) != 0)
2177e6ca193dSGeorge Wilson 			continue;
2178663207adSDon Brady 		if (!is_log && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
2179663207adSDon Brady 			continue;
2180663207adSDon Brady 
2181663207adSDon Brady 		if (!printed) {
2182663207adSDon Brady 			(void) printf("\t%s\t\n", gettext(class));
2183663207adSDon Brady 			printed = B_TRUE;
2184663207adSDon Brady 		}
2185663207adSDon Brady 
2186663207adSDon Brady 		char *name = zpool_vdev_name(g_zfs, zhp, child[c],
2187663207adSDon Brady 		    cb->cb_name_flags | VDEV_NAME_TYPE_ID);
2188663207adSDon Brady 		if (cb->cb_print_status)
2189663207adSDon Brady 			print_status_config(zhp, cb, name, child[c], 2,
2190663207adSDon Brady 			    B_FALSE);
2191e6ca193dSGeorge Wilson 		else
2192663207adSDon Brady 			print_import_config(cb, name, child[c], 2);
2193e6ca193dSGeorge Wilson 		free(name);
2194e6ca193dSGeorge Wilson 	}
2195e6ca193dSGeorge Wilson }
2196468c413aSTim Haley 
2197fa9e4066Sahrens /*
2198fa9e4066Sahrens  * Display the status for the given pool.
2199fa9e4066Sahrens  */
2200fa9e4066Sahrens static void
2201fa9e4066Sahrens show_import(nvlist_t *config)
2202fa9e4066Sahrens {
2203fa9e4066Sahrens 	uint64_t pool_state;
2204fa9e4066Sahrens 	vdev_stat_t *vs;
2205fa9e4066Sahrens 	char *name;
2206fa9e4066Sahrens 	uint64_t guid;
2207e0f1c0afSOlaf Faaland 	uint64_t hostid = 0;
2208fa9e4066Sahrens 	char *msgid;
2209e0f1c0afSOlaf Faaland 	char *hostname = "unknown";
2210e0f1c0afSOlaf Faaland 	nvlist_t *nvroot, *nvinfo;
2211fa9e4066Sahrens 	int reason;
2212eb633035STom Caputi 	zpool_errata_t errata;
221346657f8dSmmusante 	const char *health;
2214fa9e4066Sahrens 	uint_t vsc;
22158704186eSDan McDonald 	char *comment;
2216663207adSDon Brady 	status_cbdata_t cb = { 0 };
2217fa9e4066Sahrens 
2218fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
2219fa9e4066Sahrens 	    &name) == 0);
2220fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
2221fa9e4066Sahrens 	    &guid) == 0);
2222fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
2223fa9e4066Sahrens 	    &pool_state) == 0);
2224fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2225fa9e4066Sahrens 	    &nvroot) == 0);
2226fa9e4066Sahrens 
22273f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
2228fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2229990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
2230fa9e4066Sahrens 
2231eb633035STom Caputi 	reason = zpool_import_status(config, &msgid, &errata);
2232fa9e4066Sahrens 
22338704186eSDan McDonald 	(void) printf(gettext("   pool: %s\n"), name);
22348704186eSDan McDonald 	(void) printf(gettext("     id: %llu\n"), (u_longlong_t)guid);
22358704186eSDan McDonald 	(void) printf(gettext("  state: %s"), health);
22364c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
2237b1b8ab34Slling 		(void) printf(gettext(" (DESTROYED)"));
22384c58d714Sdarrenm 	(void) printf("\n");
2239fa9e4066Sahrens 
2240fa9e4066Sahrens 	switch (reason) {
2241fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
2242fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
2243fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
22448704186eSDan McDonald 		(void) printf(gettext(" status: One or more devices are "
22458704186eSDan McDonald 		    "missing from the system.\n"));
2246fa9e4066Sahrens 		break;
2247fa9e4066Sahrens 
2248fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
2249fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
22508704186eSDan McDonald 		(void) printf(gettext(" status: One or more devices contains "
2251fa9e4066Sahrens 		    "corrupted data.\n"));
2252fa9e4066Sahrens 		break;
2253fa9e4066Sahrens 
2254fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
22558704186eSDan McDonald 		(void) printf(
22568704186eSDan McDonald 		    gettext(" status: The pool data is corrupted.\n"));
2257fa9e4066Sahrens 		break;
2258fa9e4066Sahrens 
2259441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
22608704186eSDan McDonald 		(void) printf(gettext(" status: One or more devices "
2261441d80aaSlling 		    "are offlined.\n"));
2262441d80aaSlling 		break;
2263441d80aaSlling 
2264ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
22658704186eSDan McDonald 		(void) printf(gettext(" status: The pool metadata is "
2266ea8dc4b6Seschrock 		    "corrupted.\n"));
2267ea8dc4b6Seschrock 		break;
2268ea8dc4b6Seschrock 
2269eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
227057221772SChristopher Siden 		(void) printf(gettext(" status: The pool is formatted using a "
227157221772SChristopher Siden 		    "legacy on-disk version.\n"));
2272eaca9bbdSeschrock 		break;
2273eaca9bbdSeschrock 
2274eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
22758704186eSDan McDonald 		(void) printf(gettext(" status: The pool is formatted using an "
2276eaca9bbdSeschrock 		    "incompatible version.\n"));
2277eaca9bbdSeschrock 		break;
2278b87f3af3Sperrin 
227957221772SChristopher Siden 	case ZPOOL_STATUS_FEAT_DISABLED:
228057221772SChristopher Siden 		(void) printf(gettext(" status: Some supported features are "
228157221772SChristopher Siden 		    "not enabled on the pool.\n"));
228257221772SChristopher Siden 		break;
228357221772SChristopher Siden 
2284ad135b5dSChristopher Siden 	case ZPOOL_STATUS_UNSUP_FEAT_READ:
2285ad135b5dSChristopher Siden 		(void) printf(gettext("status: The pool uses the following "
2286edc8ef7dSToomas Soome 		    "feature(s) not supported on this system:\n"));
2287ad135b5dSChristopher Siden 		zpool_print_unsup_feat(config);
2288ad135b5dSChristopher Siden 		break;
2289ad135b5dSChristopher Siden 
2290ad135b5dSChristopher Siden 	case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
2291ad135b5dSChristopher Siden 		(void) printf(gettext("status: The pool can only be accessed "
2292ad135b5dSChristopher Siden 		    "in read-only mode on this system. It\n\tcannot be "
2293ad135b5dSChristopher Siden 		    "accessed in read-write mode because it uses the "
2294ad135b5dSChristopher Siden 		    "following\n\tfeature(s) not supported on this system:\n"));
2295ad135b5dSChristopher Siden 		zpool_print_unsup_feat(config);
2296ad135b5dSChristopher Siden 		break;
2297ad135b5dSChristopher Siden 
2298e0f1c0afSOlaf Faaland 	case ZPOOL_STATUS_HOSTID_ACTIVE:
2299e0f1c0afSOlaf Faaland 		(void) printf(gettext(" status: The pool is currently "
2300e0f1c0afSOlaf Faaland 		    "imported by another system.\n"));
2301e0f1c0afSOlaf Faaland 		break;
2302e0f1c0afSOlaf Faaland 
2303e0f1c0afSOlaf Faaland 	case ZPOOL_STATUS_HOSTID_REQUIRED:
2304e0f1c0afSOlaf Faaland 		(void) printf(gettext(" status: The pool has the "
2305e0f1c0afSOlaf Faaland 		    "multihost property on.  It cannot\n\tbe safely imported "
2306e0f1c0afSOlaf Faaland 		    "when the system hostid is not set.\n"));
2307e0f1c0afSOlaf Faaland 		break;
2308e0f1c0afSOlaf Faaland 
230995173954Sek 	case ZPOOL_STATUS_HOSTID_MISMATCH:
23108704186eSDan McDonald 		(void) printf(gettext(" status: The pool was last accessed by "
231195173954Sek 		    "another system.\n"));
231295173954Sek 		break;
2313b87f3af3Sperrin 
23143d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
23153d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
23168704186eSDan McDonald 		(void) printf(gettext(" status: One or more devices are "
23173d7072f8Seschrock 		    "faulted.\n"));
23183d7072f8Seschrock 		break;
23193d7072f8Seschrock 
2320b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
23218704186eSDan McDonald 		(void) printf(gettext(" status: An intent log record cannot be "
2322b87f3af3Sperrin 		    "read.\n"));
2323b87f3af3Sperrin 		break;
2324b87f3af3Sperrin 
23253f9d6ad7SLin Ling 	case ZPOOL_STATUS_RESILVERING:
23268704186eSDan McDonald 		(void) printf(gettext(" status: One or more devices were being "
23273f9d6ad7SLin Ling 		    "resilvered.\n"));
23283f9d6ad7SLin Ling 		break;
23293f9d6ad7SLin Ling 
2330eb633035STom Caputi 	case ZPOOL_STATUS_ERRATA:
2331eb633035STom Caputi 		(void) printf(gettext(" status: Errata #%d detected.\n"),
2332eb633035STom Caputi 		    errata);
2333eb633035STom Caputi 		break;
2334eb633035STom Caputi 
2335fa9e4066Sahrens 	default:
2336fa9e4066Sahrens 		/*
2337fa9e4066Sahrens 		 * No other status can be seen when importing pools.
2338fa9e4066Sahrens 		 */
2339fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
2340fa9e4066Sahrens 	}
2341fa9e4066Sahrens 
2342fa9e4066Sahrens 	/*
2343fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
2344fa9e4066Sahrens 	 */
234546657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
234657221772SChristopher Siden 		if (reason == ZPOOL_STATUS_VERSION_OLDER ||
234757221772SChristopher Siden 		    reason == ZPOOL_STATUS_FEAT_DISABLED) {
23488704186eSDan McDonald 			(void) printf(gettext(" action: The pool can be "
2349eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
2350eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
2351eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
235257221772SChristopher Siden 		} else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) {
23538704186eSDan McDonald 			(void) printf(gettext(" action: The pool can be "
235495173954Sek 			    "imported using its name or numeric "
235595173954Sek 			    "identifier and\n\tthe '-f' flag.\n"));
2356eb633035STom Caputi 		} else if (reason == ZPOOL_STATUS_ERRATA) {
2357eb633035STom Caputi 			switch (errata) {
2358eb633035STom Caputi 			case ZPOOL_ERRATA_NONE:
2359eb633035STom Caputi 				break;
2360eb633035STom Caputi 
2361eb633035STom Caputi 			case ZPOOL_ERRATA_ZOL_2094_SCRUB:
2362eb633035STom Caputi 				(void) printf(gettext(" action: The pool can "
2363eb633035STom Caputi 				    "be imported using its name or numeric "
2364eb633035STom Caputi 				    "identifier,\n\thowever there is a compat"
2365eb633035STom Caputi 				    "ibility issue which should be corrected"
2366eb633035STom Caputi 				    "\n\tby running 'zpool scrub'\n"));
2367eb633035STom Caputi 				break;
2368eb633035STom Caputi 
2369eb633035STom Caputi 			case ZPOOL_ERRATA_ZOL_2094_ASYNC_DESTROY:
2370eb633035STom Caputi 				(void) printf(gettext(" action: The pool can"
2371eb633035STom Caputi 				    "not be imported with this version of ZFS "
2372eb633035STom Caputi 				    "due to\n\tan active asynchronous destroy. "
2373eb633035STom Caputi 				    "Revert to an earlier version\n\tand "
2374eb633035STom Caputi 				    "allow the destroy to complete before "
2375eb633035STom Caputi 				    "updating.\n"));
2376eb633035STom Caputi 				break;
2377eb633035STom Caputi 
2378eb633035STom Caputi 			case ZPOOL_ERRATA_ZOL_6845_ENCRYPTION:
2379eb633035STom Caputi 				(void) printf(gettext(" action: Existing "
2380eb633035STom Caputi 				    "encrypted datasets contain an on-disk "
2381eb633035STom Caputi 				    "incompatibility, which\n\tneeds to be "
2382eb633035STom Caputi 				    "corrected. Backup these datasets to new "
2383eb633035STom Caputi 				    "encrypted datasets\n\tand destroy the "
2384eb633035STom Caputi 				    "old ones.\n"));
2385eb633035STom Caputi 				break;
2386eb633035STom Caputi 			case ZPOOL_ERRATA_ZOL_8308_ENCRYPTION:
2387eb633035STom Caputi 				(void) printf(gettext(" action: Any existing "
2388eb633035STom Caputi 				    "encrypted datasets contain an on-disk "
2389eb633035STom Caputi 				    "incompatibility which\n\tmay cause "
2390eb633035STom Caputi 				    "on-disk corruption with 'zfs recv' and "
2391eb633035STom Caputi 				    "which needs to be\n\tcorrected. Enable "
2392eb633035STom Caputi 				    "the bookmark_v2 feature and backup "
2393eb633035STom Caputi 				    "these datasets to new encrypted "
2394eb633035STom Caputi 				    "datasets and\n\tdestroy the old ones. "
2395eb633035STom Caputi 				    "If this pool does not contain any "
2396eb633035STom Caputi 				    "encrypted datasets, simply enable\n\t"
2397eb633035STom Caputi 				    "the bookmark_v2 feature.\n"));
2398eb633035STom Caputi 				break;
2399eb633035STom Caputi 			default:
2400eb633035STom Caputi 				/*
2401eb633035STom Caputi 				 * All errata must contain an action message.
2402eb633035STom Caputi 				 */
2403eb633035STom Caputi 				assert(0);
2404eb633035STom Caputi 			}
240557221772SChristopher Siden 		} else {
24068704186eSDan McDonald 			(void) printf(gettext(" action: The pool can be "
2407eaca9bbdSeschrock 			    "imported using its name or numeric "
2408eaca9bbdSeschrock 			    "identifier.\n"));
240957221772SChristopher Siden 		}
241046657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
24118704186eSDan McDonald 		(void) printf(gettext(" action: The pool can be imported "
2412fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
2413eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
2414fa9e4066Sahrens 	} else {
2415eaca9bbdSeschrock 		switch (reason) {
2416eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
24178704186eSDan McDonald 			(void) printf(gettext(" action: The pool cannot be "
2418eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
2419eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
2420eaca9bbdSeschrock 			    "backup.\n"));
2421eaca9bbdSeschrock 			break;
2422ad135b5dSChristopher Siden 		case ZPOOL_STATUS_UNSUP_FEAT_READ:
2423ad135b5dSChristopher Siden 			(void) printf(gettext("action: The pool cannot be "
2424ad135b5dSChristopher Siden 			    "imported. Access the pool on a system that "
2425ad135b5dSChristopher Siden 			    "supports\n\tthe required feature(s), or recreate "
2426ad135b5dSChristopher Siden 			    "the pool from backup.\n"));
2427ad135b5dSChristopher Siden 			break;
2428ad135b5dSChristopher Siden 		case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
2429ad135b5dSChristopher Siden 			(void) printf(gettext("action: The pool cannot be "
2430ad135b5dSChristopher Siden 			    "imported in read-write mode. Import the pool "
2431ad135b5dSChristopher Siden 			    "with\n"
2432ad135b5dSChristopher Siden 			    "\t\"-o readonly=on\", access the pool on a system "
2433ad135b5dSChristopher Siden 			    "that supports the\n\trequired feature(s), or "
2434ad135b5dSChristopher Siden 			    "recreate the pool from backup.\n"));
2435ad135b5dSChristopher Siden 			break;
2436eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
2437eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
2438eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
24398704186eSDan McDonald 			(void) printf(gettext(" action: The pool cannot be "
2440fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
2441fa9e4066Sahrens 			    "again.\n"));
2442eaca9bbdSeschrock 			break;
2443e0f1c0afSOlaf Faaland 		case ZPOOL_STATUS_HOSTID_ACTIVE:
2444e0f1c0afSOlaf Faaland 			VERIFY0(nvlist_lookup_nvlist(config,
2445e0f1c0afSOlaf Faaland 			    ZPOOL_CONFIG_LOAD_INFO, &nvinfo));
2446e0f1c0afSOlaf Faaland 
2447e0f1c0afSOlaf Faaland 			if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTNAME))
2448e0f1c0afSOlaf Faaland 				hostname = fnvlist_lookup_string(nvinfo,
2449e0f1c0afSOlaf Faaland 				    ZPOOL_CONFIG_MMP_HOSTNAME);
2450e0f1c0afSOlaf Faaland 
2451e0f1c0afSOlaf Faaland 			if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTID))
2452e0f1c0afSOlaf Faaland 				hostid = fnvlist_lookup_uint64(nvinfo,
2453e0f1c0afSOlaf Faaland 				    ZPOOL_CONFIG_MMP_HOSTID);
2454e0f1c0afSOlaf Faaland 
2455e0f1c0afSOlaf Faaland 			(void) printf(gettext(" action: The pool must be "
2456e0f1c0afSOlaf Faaland 			    "exported from %s (hostid=%lx)\n\tbefore it "
2457e0f1c0afSOlaf Faaland 			    "can be safely imported.\n"), hostname,
2458e0f1c0afSOlaf Faaland 			    (unsigned long) hostid);
2459e0f1c0afSOlaf Faaland 			break;
2460e0f1c0afSOlaf Faaland 		case ZPOOL_STATUS_HOSTID_REQUIRED:
2461e0f1c0afSOlaf Faaland 			(void) printf(gettext(" action: Check the SMF "
2462e0f1c0afSOlaf Faaland 			    "svc:/system/hostid service.\n"));
2463e0f1c0afSOlaf Faaland 			break;
2464eaca9bbdSeschrock 		default:
24658704186eSDan McDonald 			(void) printf(gettext(" action: The pool cannot be "
2466fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
2467eaca9bbdSeschrock 		}
2468eaca9bbdSeschrock 	}
2469eaca9bbdSeschrock 
24708704186eSDan McDonald 	/* Print the comment attached to the pool. */
24718704186eSDan McDonald 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
24728704186eSDan McDonald 		(void) printf(gettext("comment: %s\n"), comment);
24738704186eSDan McDonald 
247446657f8dSmmusante 	/*
247546657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
247646657f8dSmmusante 	 * is "corrupt data":
247746657f8dSmmusante 	 */
247846657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
247946657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
248046657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
2481eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
2482eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
2483eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
2484eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
2485eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
248618ce54dfSek 			    "another system, but can be imported using\n\t"
2487eaca9bbdSeschrock 			    "the '-f' flag.\n"));
2488fa9e4066Sahrens 	}
2489fa9e4066Sahrens 
2490fa9e4066Sahrens 	if (msgid != NULL)
2491654b400cSJoshua M. Clulow 		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
2492fa9e4066Sahrens 		    msgid);
2493fa9e4066Sahrens 
24948704186eSDan McDonald 	(void) printf(gettext(" config:\n\n"));
2495fa9e4066Sahrens 
2496dd50e0ccSTony Hutter 	cb.cb_namewidth = max_width(NULL, nvroot, 0, strlen(name),
2497dd50e0ccSTony Hutter 	    VDEV_NAME_TYPE_ID);
2498663207adSDon Brady 	if (cb.cb_namewidth < 10)
2499663207adSDon Brady 		cb.cb_namewidth = 10;
25008654d025Sperrin 
2501663207adSDon Brady 	print_import_config(&cb, name, nvroot, 0);
2502663207adSDon Brady 
2503663207adSDon Brady 	print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_BIAS_DEDUP);
2504663207adSDon Brady 	print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_BIAS_SPECIAL);
2505663207adSDon Brady 	print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_CLASS_LOGS);
2506fa9e4066Sahrens 
2507fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
250846657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
2509fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
251046657f8dSmmusante 		    "configuration cannot be determined.\n"));
2511fa9e4066Sahrens 	}
2512fa9e4066Sahrens }
2513fa9e4066Sahrens 
2514e0f1c0afSOlaf Faaland static boolean_t
2515e0f1c0afSOlaf Faaland zfs_force_import_required(nvlist_t *config)
2516e0f1c0afSOlaf Faaland {
2517e0f1c0afSOlaf Faaland 	uint64_t state;
2518e0f1c0afSOlaf Faaland 	uint64_t hostid = 0;
2519e0f1c0afSOlaf Faaland 	nvlist_t *nvinfo;
2520e0f1c0afSOlaf Faaland 
2521e0f1c0afSOlaf Faaland 	state = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE);
2522e0f1c0afSOlaf Faaland 	(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
2523e0f1c0afSOlaf Faaland 
2524e0f1c0afSOlaf Faaland 	if (state != POOL_STATE_EXPORTED && hostid != get_system_hostid())
2525e0f1c0afSOlaf Faaland 		return (B_TRUE);
2526e0f1c0afSOlaf Faaland 
2527e0f1c0afSOlaf Faaland 	nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
2528e0f1c0afSOlaf Faaland 	if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_STATE)) {
2529e0f1c0afSOlaf Faaland 		mmp_state_t mmp_state = fnvlist_lookup_uint64(nvinfo,
2530e0f1c0afSOlaf Faaland 		    ZPOOL_CONFIG_MMP_STATE);
2531e0f1c0afSOlaf Faaland 
2532e0f1c0afSOlaf Faaland 		if (mmp_state != MMP_STATE_INACTIVE)
2533e0f1c0afSOlaf Faaland 			return (B_TRUE);
2534e0f1c0afSOlaf Faaland 	}
2535e0f1c0afSOlaf Faaland 
2536e0f1c0afSOlaf Faaland 	return (B_FALSE);
2537e0f1c0afSOlaf Faaland }
2538e0f1c0afSOlaf Faaland 
2539fa9e4066Sahrens /*
2540fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
2541990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
2542990b4856Slling  * within the pool.
2543fa9e4066Sahrens  */
2544fa9e4066Sahrens static int
2545fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
25464b964adaSGeorge Wilson     nvlist_t *props, int flags)
2547fa9e4066Sahrens {
2548eb633035STom Caputi 	int ret = 0;
2549fa9e4066Sahrens 	zpool_handle_t *zhp;
2550fa9e4066Sahrens 	char *name;
2551eaca9bbdSeschrock 	uint64_t version;
2552fa9e4066Sahrens 
2553e0f1c0afSOlaf Faaland 	name = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME);
2554e0f1c0afSOlaf Faaland 	version = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION);
2555fa9e4066Sahrens 
2556ad135b5dSChristopher Siden 	if (!SPA_VERSION_IS_SUPPORTED(version)) {
2557eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
2558ad135b5dSChristopher Siden 		    "is formatted using an unsupported ZFS version\n"), name);
2559eaca9bbdSeschrock 		return (1);
2560e0f1c0afSOlaf Faaland 	} else if (zfs_force_import_required(config) &&
25614b964adaSGeorge Wilson 	    !(flags & ZFS_IMPORT_ANY_HOST)) {
2562e0f1c0afSOlaf Faaland 		mmp_state_t mmp_state = MMP_STATE_INACTIVE;
2563e0f1c0afSOlaf Faaland 		nvlist_t *nvinfo;
2564e0f1c0afSOlaf Faaland 
2565e0f1c0afSOlaf Faaland 		nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
2566e0f1c0afSOlaf Faaland 		if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_STATE))
2567e0f1c0afSOlaf Faaland 			mmp_state = fnvlist_lookup_uint64(nvinfo,
2568e0f1c0afSOlaf Faaland 			    ZPOOL_CONFIG_MMP_STATE);
2569e0f1c0afSOlaf Faaland 
2570e0f1c0afSOlaf Faaland 		if (mmp_state == MMP_STATE_ACTIVE) {
2571e0f1c0afSOlaf Faaland 			char *hostname = "<unknown>";
2572e0f1c0afSOlaf Faaland 			uint64_t hostid = 0;
2573e0f1c0afSOlaf Faaland 
2574e0f1c0afSOlaf Faaland 			if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTNAME))
2575e0f1c0afSOlaf Faaland 				hostname = fnvlist_lookup_string(nvinfo,
2576e0f1c0afSOlaf Faaland 				    ZPOOL_CONFIG_MMP_HOSTNAME);
2577e0f1c0afSOlaf Faaland 
2578e0f1c0afSOlaf Faaland 			if (nvlist_exists(nvinfo, ZPOOL_CONFIG_MMP_HOSTID))
2579e0f1c0afSOlaf Faaland 				hostid = fnvlist_lookup_uint64(nvinfo,
2580e0f1c0afSOlaf Faaland 				    ZPOOL_CONFIG_MMP_HOSTID);
2581e0f1c0afSOlaf Faaland 
2582e0f1c0afSOlaf Faaland 			(void) fprintf(stderr, gettext("cannot import '%s': "
2583e0f1c0afSOlaf Faaland 			    "pool is imported on %s (hostid: "
2584e0f1c0afSOlaf Faaland 			    "0x%lx)\nExport the pool on the other system, "
2585e0f1c0afSOlaf Faaland 			    "then run 'zpool import'.\n"),
2586e0f1c0afSOlaf Faaland 			    name, hostname, (unsigned long) hostid);
2587e0f1c0afSOlaf Faaland 		} else if (mmp_state == MMP_STATE_NO_HOSTID) {
2588e0f1c0afSOlaf Faaland 			(void) fprintf(stderr, gettext("Cannot import '%s': "
2589e0f1c0afSOlaf Faaland 			    "pool has the multihost property on and the\n"
2590e0f1c0afSOlaf Faaland 			    "system's hostid is not set.\n"), name);
259195173954Sek 		} else {
2592e0f1c0afSOlaf Faaland 			char *hostname = "<unknown>";
2593e0f1c0afSOlaf Faaland 			uint64_t timestamp = 0;
2594e0f1c0afSOlaf Faaland 			uint64_t hostid = 0;
2595e0f1c0afSOlaf Faaland 
2596e0f1c0afSOlaf Faaland 			if (nvlist_exists(config, ZPOOL_CONFIG_HOSTNAME))
2597e0f1c0afSOlaf Faaland 				hostname = fnvlist_lookup_string(config,
2598e0f1c0afSOlaf Faaland 				    ZPOOL_CONFIG_HOSTNAME);
2599e0f1c0afSOlaf Faaland 
2600e0f1c0afSOlaf Faaland 			if (nvlist_exists(config, ZPOOL_CONFIG_TIMESTAMP))
2601e0f1c0afSOlaf Faaland 				timestamp = fnvlist_lookup_uint64(config,
2602e0f1c0afSOlaf Faaland 				    ZPOOL_CONFIG_TIMESTAMP);
2603e0f1c0afSOlaf Faaland 
2604e0f1c0afSOlaf Faaland 			if (nvlist_exists(config, ZPOOL_CONFIG_HOSTID))
2605e0f1c0afSOlaf Faaland 				hostid = fnvlist_lookup_uint64(config,
2606e0f1c0afSOlaf Faaland 				    ZPOOL_CONFIG_HOSTID);
2607e0f1c0afSOlaf Faaland 
260895173954Sek 			(void) fprintf(stderr, gettext("cannot import '%s': "
2609e0f1c0afSOlaf Faaland 			    "pool was previously in use from another system.\n"
2610e0f1c0afSOlaf Faaland 			    "Last accessed by %s (hostid=%lx) at %s"
2611e0f1c0afSOlaf Faaland 			    "The pool can be imported, use 'zpool import -f' "
2612e0f1c0afSOlaf Faaland 			    "to import the pool.\n"), name, hostname,
2613e0f1c0afSOlaf Faaland 			    (unsigned long)hostid, ctime((time_t *)&timestamp));
2614e0f1c0afSOlaf Faaland 
261595173954Sek 		}
2616e0f1c0afSOlaf Faaland 
2617e0f1c0afSOlaf Faaland 		return (1);
2618fa9e4066Sahrens 	}
2619fa9e4066Sahrens 
26204b964adaSGeorge Wilson 	if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
2621fa9e4066Sahrens 		return (1);
2622fa9e4066Sahrens 
2623fa9e4066Sahrens 	if (newname != NULL)
2624fa9e4066Sahrens 		name = (char *)newname;
2625fa9e4066Sahrens 
26264f0f5e5bSVictor Latushkin 	if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
26274f0f5e5bSVictor Latushkin 		return (1);
2628fa9e4066Sahrens 
2629eb633035STom Caputi 	/*
2630eb633035STom Caputi 	 * Loading keys is best effort. We don't want to return immediately
2631eb633035STom Caputi 	 * if it fails but we do want to give the error to the caller.
2632eb633035STom Caputi 	 */
2633eb633035STom Caputi 	if (flags & ZFS_IMPORT_LOAD_KEYS) {
2634eb633035STom Caputi 		ret = zfs_crypto_attempt_load_keys(g_zfs, name);
2635eb633035STom Caputi 		if (ret != 0)
2636eb633035STom Caputi 			ret = 1;
2637eb633035STom Caputi 	}
2638eb633035STom Caputi 
2639379c004dSEric Schrock 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
2640f9af39baSGeorge Wilson 	    !(flags & ZFS_IMPORT_ONLY) &&
2641379c004dSEric Schrock 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
2642fa9e4066Sahrens 		zpool_close(zhp);
2643fa9e4066Sahrens 		return (1);
2644fa9e4066Sahrens 	}
2645fa9e4066Sahrens 
2646fa9e4066Sahrens 	zpool_close(zhp);
2647eb633035STom Caputi 	return (ret);
2648fa9e4066Sahrens }
2649fa9e4066Sahrens 
2650d8ab6e12SDon Brady typedef struct target_exists_args {
2651d8ab6e12SDon Brady 	const char	*poolname;
2652d8ab6e12SDon Brady 	uint64_t	poolguid;
2653d8ab6e12SDon Brady } target_exists_args_t;
2654d8ab6e12SDon Brady 
2655d8ab6e12SDon Brady static int
2656d8ab6e12SDon Brady name_or_guid_exists(zpool_handle_t *zhp, void *data)
2657d8ab6e12SDon Brady {
2658d8ab6e12SDon Brady 	target_exists_args_t *args = data;
2659d8ab6e12SDon Brady 	nvlist_t *config = zpool_get_config(zhp, NULL);
2660d8ab6e12SDon Brady 	int found = 0;
2661d8ab6e12SDon Brady 
2662d8ab6e12SDon Brady 	if (config == NULL)
2663d8ab6e12SDon Brady 		return (0);
2664d8ab6e12SDon Brady 
2665d8ab6e12SDon Brady 	if (args->poolname != NULL) {
2666d8ab6e12SDon Brady 		char *pool_name;
2667d8ab6e12SDon Brady 
2668d8ab6e12SDon Brady 		verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
2669d8ab6e12SDon Brady 		    &pool_name) == 0);
2670d8ab6e12SDon Brady 		if (strcmp(pool_name, args->poolname) == 0)
2671d8ab6e12SDon Brady 			found = 1;
2672d8ab6e12SDon Brady 	} else {
2673d8ab6e12SDon Brady 		uint64_t pool_guid;
2674d8ab6e12SDon Brady 
2675d8ab6e12SDon Brady 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
2676d8ab6e12SDon Brady 		    &pool_guid) == 0);
2677d8ab6e12SDon Brady 		if (pool_guid == args->poolguid)
2678d8ab6e12SDon Brady 			found = 1;
2679d8ab6e12SDon Brady 	}
2680d8ab6e12SDon Brady 	zpool_close(zhp);
2681d8ab6e12SDon Brady 
2682d8ab6e12SDon Brady 	return (found);
2683d8ab6e12SDon Brady }
268486714001SSerapheim Dimitropoulos /*
268586714001SSerapheim Dimitropoulos  * zpool checkpoint <pool>
268686714001SSerapheim Dimitropoulos  *       checkpoint --discard <pool>
268786714001SSerapheim Dimitropoulos  *
268804e56356SAndriy Gapon  *	-d	Discard the checkpoint from a checkpointed
268904e56356SAndriy Gapon  *	--discard  pool.
269086714001SSerapheim Dimitropoulos  *
269186714001SSerapheim Dimitropoulos  * Checkpoints the specified pool, by taking a "snapshot" of its
269286714001SSerapheim Dimitropoulos  * current state. A pool can only have one checkpoint at a time.
269386714001SSerapheim Dimitropoulos  */
269486714001SSerapheim Dimitropoulos int
269586714001SSerapheim Dimitropoulos zpool_do_checkpoint(int argc, char **argv)
269686714001SSerapheim Dimitropoulos {
269786714001SSerapheim Dimitropoulos 	boolean_t discard;
269886714001SSerapheim Dimitropoulos 	char *pool;
269986714001SSerapheim Dimitropoulos 	zpool_handle_t *zhp;
270086714001SSerapheim Dimitropoulos 	int c, err;
270186714001SSerapheim Dimitropoulos 
270286714001SSerapheim Dimitropoulos 	struct option long_options[] = {
270386714001SSerapheim Dimitropoulos 		{"discard", no_argument, NULL, 'd'},
270486714001SSerapheim Dimitropoulos 		{0, 0, 0, 0}
270586714001SSerapheim Dimitropoulos 	};
270686714001SSerapheim Dimitropoulos 
270786714001SSerapheim Dimitropoulos 	discard = B_FALSE;
270886714001SSerapheim Dimitropoulos 	while ((c = getopt_long(argc, argv, ":d", long_options, NULL)) != -1) {
270986714001SSerapheim Dimitropoulos 		switch (c) {
271086714001SSerapheim Dimitropoulos 		case 'd':
271186714001SSerapheim Dimitropoulos 			discard = B_TRUE;
271286714001SSerapheim Dimitropoulos 			break;
271386714001SSerapheim Dimitropoulos 		case '?':
271486714001SSerapheim Dimitropoulos 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
271586714001SSerapheim Dimitropoulos 			    optopt);
271686714001SSerapheim Dimitropoulos 			usage(B_FALSE);
271786714001SSerapheim Dimitropoulos 		}
271886714001SSerapheim Dimitropoulos 	}
271986714001SSerapheim Dimitropoulos 
272086714001SSerapheim Dimitropoulos 	argc -= optind;
272186714001SSerapheim Dimitropoulos 	argv += optind;
272286714001SSerapheim Dimitropoulos 
272386714001SSerapheim Dimitropoulos 	if (argc < 1) {
272486714001SSerapheim Dimitropoulos 		(void) fprintf(stderr, gettext("missing pool argument\n"));
272586714001SSerapheim Dimitropoulos 		usage(B_FALSE);
272686714001SSerapheim Dimitropoulos 	}
272786714001SSerapheim Dimitropoulos 
272886714001SSerapheim Dimitropoulos 	if (argc > 1) {
272986714001SSerapheim Dimitropoulos 		(void) fprintf(stderr, gettext("too many arguments\n"));
273086714001SSerapheim Dimitropoulos 		usage(B_FALSE);
273186714001SSerapheim Dimitropoulos 	}
273286714001SSerapheim Dimitropoulos 
273386714001SSerapheim Dimitropoulos 	pool = argv[0];
273486714001SSerapheim Dimitropoulos 
273586714001SSerapheim Dimitropoulos 	if ((zhp = zpool_open(g_zfs, pool)) == NULL) {
273686714001SSerapheim Dimitropoulos 		/* As a special case, check for use of '/' in the name */
273786714001SSerapheim Dimitropoulos 		if (strchr(pool, '/') != NULL)
273886714001SSerapheim Dimitropoulos 			(void) fprintf(stderr, gettext("'zpool checkpoint' "
273986714001SSerapheim Dimitropoulos 			    "doesn't work on datasets. To save the state "
274086714001SSerapheim Dimitropoulos 			    "of a dataset from a specific point in time "
274186714001SSerapheim Dimitropoulos 			    "please use 'zfs snapshot'\n"));
274286714001SSerapheim Dimitropoulos 		return (1);
274386714001SSerapheim Dimitropoulos 	}
274486714001SSerapheim Dimitropoulos 
274586714001SSerapheim Dimitropoulos 	if (discard)
274686714001SSerapheim Dimitropoulos 		err = (zpool_discard_checkpoint(zhp) != 0);
274786714001SSerapheim Dimitropoulos 	else
274886714001SSerapheim Dimitropoulos 		err = (zpool_checkpoint(zhp) != 0);
274986714001SSerapheim Dimitropoulos 
275086714001SSerapheim Dimitropoulos 	zpool_close(zhp);
275186714001SSerapheim Dimitropoulos 
275286714001SSerapheim Dimitropoulos 	return (err);
275386714001SSerapheim Dimitropoulos }
275486714001SSerapheim Dimitropoulos 
275586714001SSerapheim Dimitropoulos #define	CHECKPOINT_OPT	1024
275686714001SSerapheim Dimitropoulos 
2757fa9e4066Sahrens /*
27584c58d714Sdarrenm  * zpool import [-d dir] [-D]
2759eb633035STom Caputi  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-l]
27602f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
2761eb633035STom Caputi  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-l]
276204e56356SAndriy Gapon  *              [-d dir | -c cachefile] [-f] [-n] [-F] [-t]
276304e56356SAndriy Gapon  *              <pool | id> [newpool]
27642f8aaab3Seschrock  *
276504e56356SAndriy Gapon  *	-c	Read pool information from a cachefile instead of searching
27662f8aaab3Seschrock  *		devices.
2767fa9e4066Sahrens  *
276804e56356SAndriy Gapon  *	-d	Scan in a specific directory, other than /dev/dsk.  More than
2769fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
2770fa9e4066Sahrens  *
277104e56356SAndriy Gapon  *	-D	Scan for previously destroyed pools or import all or only
277204e56356SAndriy Gapon  *		specified destroyed pools.
27734c58d714Sdarrenm  *
277404e56356SAndriy Gapon  *	-R	Temporarily import the pool, with all mountpoints relative to
2775fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
2776fa9e4066Sahrens  *		is rebooted.
2777fa9e4066Sahrens  *
277804e56356SAndriy Gapon  *	-V	Import even in the presence of faulted vdevs.  This is an
277904e56356SAndriy Gapon  *		intentionally undocumented option for testing purposes, and
278004e56356SAndriy Gapon  *		treats the pool configuration as complete, leaving any bad
27814f0f5e5bSVictor Latushkin  *		vdevs in the FAULTED state. In other words, it does verbatim
27824f0f5e5bSVictor Latushkin  *		import.
2783c5904d13Seschrock  *
278404e56356SAndriy Gapon  *	-f	Force import, even if it appears that the pool is active.
278504e56356SAndriy Gapon  *
278604e56356SAndriy Gapon  *	-F	Attempt rewind if necessary.
2787468c413aSTim Haley  *
278804e56356SAndriy Gapon  *	-n	See if rewind would work, but don't actually rewind.
2789468c413aSTim Haley  *
279004e56356SAndriy Gapon  *	-N	Import the pool but don't mount datasets.
2791468c413aSTim Haley  *
279204e56356SAndriy Gapon  *	-t	Use newpool as a temporary pool name instead of renaming
279304e56356SAndriy Gapon  *		the pool.
2794f9af39baSGeorge Wilson  *
279504e56356SAndriy Gapon  *	-T	Specify a starting txg to use for import. This option is
279604e56356SAndriy Gapon  *		intentionally undocumented option for testing purposes.
2797f9af39baSGeorge Wilson  *
279804e56356SAndriy Gapon  *	-a	Import all pools found.
2799fa9e4066Sahrens  *
280004e56356SAndriy Gapon  *	-o	Set property=value and/or temporary mount options (without '=').
2801eb633035STom Caputi  *  -l	Load encryption keys while importing.
2802ecd6cf80Smarks  *
280304e56356SAndriy Gapon  *	--rewind-to-checkpoint
280404e56356SAndriy Gapon  *		Import the pool and revert back to the checkpoint.
280586714001SSerapheim Dimitropoulos  *
2806fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
2807fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
2808fa9e4066Sahrens  */
2809fa9e4066Sahrens int
2810fa9e4066Sahrens zpool_do_import(int argc, char **argv)
2811fa9e4066Sahrens {
2812fa9e4066Sahrens 	char **searchdirs = NULL;
2813fa9e4066Sahrens 	int nsearch = 0;
2814fa9e4066Sahrens 	int c;
2815d41c4376SMark J Musante 	int err = 0;
28162f8aaab3Seschrock 	nvlist_t *pools = NULL;
281799653d4eSeschrock 	boolean_t do_all = B_FALSE;
281899653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
2819fa9e4066Sahrens 	char *mntopts = NULL;
2820fa9e4066Sahrens 	nvpair_t *elem;
2821fa9e4066Sahrens 	nvlist_t *config;
282224e697d4Sck 	uint64_t searchguid = 0;
282324e697d4Sck 	char *searchname = NULL;
2824990b4856Slling 	char *propval;
2825fa9e4066Sahrens 	nvlist_t *found_config;
2826468c413aSTim Haley 	nvlist_t *policy = NULL;
2827ecd6cf80Smarks 	nvlist_t *props = NULL;
282899653d4eSeschrock 	boolean_t first;
28294b964adaSGeorge Wilson 	int flags = ZFS_IMPORT_NORMAL;
2830468c413aSTim Haley 	uint32_t rewind_policy = ZPOOL_NO_REWIND;
2831468c413aSTim Haley 	boolean_t dryrun = B_FALSE;
2832468c413aSTim Haley 	boolean_t do_rewind = B_FALSE;
2833468c413aSTim Haley 	boolean_t xtreme_rewind = B_FALSE;
2834d8ab6e12SDon Brady 	boolean_t pool_exists = B_FALSE;
2835f9af39baSGeorge Wilson 	uint64_t pool_state, txg = -1ULL;
28362f8aaab3Seschrock 	char *cachefile = NULL;
2837d41c4376SMark J Musante 	importargs_t idata = { 0 };
2838f9af39baSGeorge Wilson 	char *endptr;
2839fa9e4066Sahrens 
284086714001SSerapheim Dimitropoulos 
284186714001SSerapheim Dimitropoulos 	struct option long_options[] = {
284286714001SSerapheim Dimitropoulos 		{"rewind-to-checkpoint", no_argument, NULL, CHECKPOINT_OPT},
284386714001SSerapheim Dimitropoulos 		{0, 0, 0, 0}
284486714001SSerapheim Dimitropoulos 	};
284586714001SSerapheim Dimitropoulos 
2846fa9e4066Sahrens 	/* check options */
2847eb633035STom Caputi 	while ((c = getopt_long(argc, argv, ":aCc:d:DEfFlmnNo:rR:tT:VX",
284886714001SSerapheim Dimitropoulos 	    long_options, NULL)) != -1) {
2849fa9e4066Sahrens 		switch (c) {
2850fa9e4066Sahrens 		case 'a':
285199653d4eSeschrock 			do_all = B_TRUE;
2852fa9e4066Sahrens 			break;
28532f8aaab3Seschrock 		case 'c':
28542f8aaab3Seschrock 			cachefile = optarg;
28552f8aaab3Seschrock 			break;
2856fa9e4066Sahrens 		case 'd':
2857fa9e4066Sahrens 			if (searchdirs == NULL) {
2858fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
2859fa9e4066Sahrens 			} else {
2860fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
2861fa9e4066Sahrens 				    sizeof (char *));
2862fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
2863fa9e4066Sahrens 				    sizeof (char *));
2864fa9e4066Sahrens 				free(searchdirs);
2865fa9e4066Sahrens 				searchdirs = tmp;
2866fa9e4066Sahrens 			}
2867fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
2868fa9e4066Sahrens 			break;
28694c58d714Sdarrenm 		case 'D':
287099653d4eSeschrock 			do_destroyed = B_TRUE;
28714c58d714Sdarrenm 			break;
2872fa9e4066Sahrens 		case 'f':
28734b964adaSGeorge Wilson 			flags |= ZFS_IMPORT_ANY_HOST;
2874fa9e4066Sahrens 			break;
2875c5904d13Seschrock 		case 'F':
2876468c413aSTim Haley 			do_rewind = B_TRUE;
2877468c413aSTim Haley 			break;
2878eb633035STom Caputi 		case 'l':
2879eb633035STom Caputi 			flags |= ZFS_IMPORT_LOAD_KEYS;
2880eb633035STom Caputi 			break;
28814b964adaSGeorge Wilson 		case 'm':
28824b964adaSGeorge Wilson 			flags |= ZFS_IMPORT_MISSING_LOG;
28834b964adaSGeorge Wilson 			break;
2884468c413aSTim Haley 		case 'n':
2885468c413aSTim Haley 			dryrun = B_TRUE;
2886c5904d13Seschrock 			break;
2887f9af39baSGeorge Wilson 		case 'N':
2888f9af39baSGeorge Wilson 			flags |= ZFS_IMPORT_ONLY;
2889f9af39baSGeorge Wilson 			break;
2890fa9e4066Sahrens 		case 'o':
2891990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
2892990b4856Slling 				*propval = '\0';
2893990b4856Slling 				propval++;
28940a48a24eStimh 				if (add_prop_list(optarg, propval,
28950a48a24eStimh 				    &props, B_TRUE))
2896990b4856Slling 					goto error;
2897990b4856Slling 			} else {
2898990b4856Slling 				mntopts = optarg;
2899990b4856Slling 			}
2900fa9e4066Sahrens 			break;
2901fa9e4066Sahrens 		case 'R':
2902990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
29030a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
2904990b4856Slling 				goto error;
290504e56356SAndriy Gapon 			if (add_prop_list_default(zpool_prop_to_name(
290604e56356SAndriy Gapon 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
290704e56356SAndriy Gapon 				goto error;
290804e56356SAndriy Gapon 			break;
290904e56356SAndriy Gapon 		case 't':
291004e56356SAndriy Gapon 			flags |= ZFS_IMPORT_TEMP_NAME;
291104e56356SAndriy Gapon 			if (add_prop_list_default(zpool_prop_to_name(
29120a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
2913990b4856Slling 				goto error;
2914fa9e4066Sahrens 			break;
2915f9af39baSGeorge Wilson 		case 'T':
2916f9af39baSGeorge Wilson 			errno = 0;
2917e42d2059SMatthew Ahrens 			txg = strtoull(optarg, &endptr, 0);
2918f9af39baSGeorge Wilson 			if (errno != 0 || *endptr != '\0') {
2919f9af39baSGeorge Wilson 				(void) fprintf(stderr,
2920f9af39baSGeorge Wilson 				    gettext("invalid txg value\n"));
2921f9af39baSGeorge Wilson 				usage(B_FALSE);
2922f9af39baSGeorge Wilson 			}
2923f9af39baSGeorge Wilson 			rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
2924f9af39baSGeorge Wilson 			break;
2925468c413aSTim Haley 		case 'V':
29264b964adaSGeorge Wilson 			flags |= ZFS_IMPORT_VERBATIM;
2927468c413aSTim Haley 			break;
2928468c413aSTim Haley 		case 'X':
2929468c413aSTim Haley 			xtreme_rewind = B_TRUE;
2930468c413aSTim Haley 			break;
293186714001SSerapheim Dimitropoulos 		case CHECKPOINT_OPT:
293286714001SSerapheim Dimitropoulos 			flags |= ZFS_IMPORT_CHECKPOINT;
293386714001SSerapheim Dimitropoulos 			break;
2934fa9e4066Sahrens 		case ':':
2935fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2936fa9e4066Sahrens 			    "'%c' option\n"), optopt);
293799653d4eSeschrock 			usage(B_FALSE);
2938fa9e4066Sahrens 			break;
2939fa9e4066Sahrens 		case '?':
2940fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2941fa9e4066Sahrens 			    optopt);
294299653d4eSeschrock 			usage(B_FALSE);
2943fa9e4066Sahrens 		}
2944fa9e4066Sahrens 	}
2945fa9e4066Sahrens 
2946fa9e4066Sahrens 	argc -= optind;
2947fa9e4066Sahrens 	argv += optind;
2948fa9e4066Sahrens 
29492f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
29502f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
29512f8aaab3Seschrock 		usage(B_FALSE);
29522f8aaab3Seschrock 	}
29532f8aaab3Seschrock 
2954eb633035STom Caputi 	if ((flags & ZFS_IMPORT_LOAD_KEYS) && (flags & ZFS_IMPORT_ONLY)) {
2955eb633035STom Caputi 		(void) fprintf(stderr, gettext("-l is incompatible with -N\n"));
2956eb633035STom Caputi 		usage(B_FALSE);
2957eb633035STom Caputi 	}
2958eb633035STom Caputi 
2959eb633035STom Caputi 	if ((flags & ZFS_IMPORT_LOAD_KEYS) && !do_all && argc == 0) {
2960eb633035STom Caputi 		(void) fprintf(stderr, gettext("-l is only meaningful during "
2961eb633035STom Caputi 		    "an import\n"));
2962eb633035STom Caputi 		usage(B_FALSE);
2963eb633035STom Caputi 	}
2964eb633035STom Caputi 
2965468c413aSTim Haley 	if ((dryrun || xtreme_rewind) && !do_rewind) {
2966468c413aSTim Haley 		(void) fprintf(stderr,
2967468c413aSTim Haley 		    gettext("-n or -X only meaningful with -F\n"));
2968468c413aSTim Haley 		usage(B_FALSE);
2969468c413aSTim Haley 	}
2970468c413aSTim Haley 	if (dryrun)
2971468c413aSTim Haley 		rewind_policy = ZPOOL_TRY_REWIND;
2972468c413aSTim Haley 	else if (do_rewind)
2973468c413aSTim Haley 		rewind_policy = ZPOOL_DO_REWIND;
2974468c413aSTim Haley 	if (xtreme_rewind)
2975468c413aSTim Haley 		rewind_policy |= ZPOOL_EXTREME_REWIND;
2976468c413aSTim Haley 
2977468c413aSTim Haley 	/* In the future, we can capture further policy and include it here */
2978468c413aSTim Haley 	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
29795dafeea3SPavel Zakharov 	    nvlist_add_uint64(policy, ZPOOL_LOAD_REQUEST_TXG, txg) != 0 ||
29805dafeea3SPavel Zakharov 	    nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY,
29815dafeea3SPavel Zakharov 	    rewind_policy) != 0)
2982468c413aSTim Haley 		goto error;
2983468c413aSTim Haley 
2984fa9e4066Sahrens 	if (searchdirs == NULL) {
2985fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
29866401734dSWill Andrews 		searchdirs[0] = ZFS_DISK_ROOT;
2987fa9e4066Sahrens 		nsearch = 1;
2988fa9e4066Sahrens 	}
2989fa9e4066Sahrens 
2990fa9e4066Sahrens 	/* check argument count */
2991fa9e4066Sahrens 	if (do_all) {
2992fa9e4066Sahrens 		if (argc != 0) {
2993fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
299499653d4eSeschrock 			usage(B_FALSE);
2995fa9e4066Sahrens 		}
2996fa9e4066Sahrens 	} else {
2997fa9e4066Sahrens 		if (argc > 2) {
2998fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
299999653d4eSeschrock 			usage(B_FALSE);
3000fa9e4066Sahrens 		}
3001fa9e4066Sahrens 
3002fa9e4066Sahrens 		/*
3003fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
3004fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
3005fa9e4066Sahrens 		 * silently fail.
3006fa9e4066Sahrens 		 */
3007fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
3008fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
3009fa9e4066Sahrens 			    "discover pools: permission denied\n"));
301099653d4eSeschrock 			free(searchdirs);
3011468c413aSTim Haley 			nvlist_free(policy);
3012fa9e4066Sahrens 			return (1);
3013fa9e4066Sahrens 		}
3014fa9e4066Sahrens 	}
3015fa9e4066Sahrens 
3016fa9e4066Sahrens 	/*
3017fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
3018fa9e4066Sahrens 	 *
3019fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
3020fa9e4066Sahrens 	 *		each one.
3021fa9e4066Sahrens 	 *
3022fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
3023fa9e4066Sahrens 	 *
3024fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
3025fa9e4066Sahrens 	 *		name and import that one.
30264c58d714Sdarrenm 	 *
30274c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
3028fa9e4066Sahrens 	 */
3029fa9e4066Sahrens 	if (argc != 0) {
3030fa9e4066Sahrens 		char *endptr;
3031fa9e4066Sahrens 
3032fa9e4066Sahrens 		errno = 0;
3033fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
30349edf9ebdSPrasad Joshi 		if (errno != 0 || *endptr != '\0') {
3035fa9e4066Sahrens 			searchname = argv[0];
30369edf9ebdSPrasad Joshi 			searchguid = 0;
30379edf9ebdSPrasad Joshi 		}
3038fa9e4066Sahrens 		found_config = NULL;
3039fa9e4066Sahrens 
304024e697d4Sck 		/*
3041d41c4376SMark J Musante 		 * User specified a name or guid.  Ensure it's unique.
304224e697d4Sck 		 */
3043d8ab6e12SDon Brady 		target_exists_args_t search = {searchname, searchguid};
3044d8ab6e12SDon Brady 		pool_exists = zpool_iter(g_zfs, name_or_guid_exists, &search);
304524e697d4Sck 	}
304624e697d4Sck 
3047d41c4376SMark J Musante 	idata.path = searchdirs;
3048d41c4376SMark J Musante 	idata.paths = nsearch;
3049d41c4376SMark J Musante 	idata.poolname = searchname;
3050d41c4376SMark J Musante 	idata.guid = searchguid;
3051d41c4376SMark J Musante 	idata.cachefile = cachefile;
30526f793812SPavel Zakharov 	idata.policy = policy;
3053d41c4376SMark J Musante 
3054d8ab6e12SDon Brady 	pools = zpool_search_import(g_zfs, &idata, &libzfs_config_ops);
3055d41c4376SMark J Musante 
3056d8ab6e12SDon Brady 	if (pools != NULL && pool_exists &&
3057d41c4376SMark J Musante 	    (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
3058d41c4376SMark J Musante 		(void) fprintf(stderr, gettext("cannot import '%s': "
3059d41c4376SMark J Musante 		    "a pool with that name already exists\n"),
3060d41c4376SMark J Musante 		    argv[0]);
306104e56356SAndriy Gapon 		(void) fprintf(stderr, gettext("use the form 'zpool import "
306204e56356SAndriy Gapon 		    "[-t] <pool | id> <newpool>' to give it a new temporary "
306304e56356SAndriy Gapon 		    "or permanent name\n"));
3064d41c4376SMark J Musante 		err = 1;
3065d8ab6e12SDon Brady 	} else if (pools == NULL && pool_exists) {
3066d41c4376SMark J Musante 		(void) fprintf(stderr, gettext("cannot import '%s': "
3067d41c4376SMark J Musante 		    "a pool with that name is already created/imported,\n"),
3068d41c4376SMark J Musante 		    argv[0]);
3069d41c4376SMark J Musante 		(void) fprintf(stderr, gettext("and no additional pools "
3070d41c4376SMark J Musante 		    "with that name were found\n"));
3071d41c4376SMark J Musante 		err = 1;
3072d41c4376SMark J Musante 	} else if (pools == NULL) {
307324e697d4Sck 		if (argc != 0) {
307424e697d4Sck 			(void) fprintf(stderr, gettext("cannot import '%s': "
307524e697d4Sck 			    "no such pool available\n"), argv[0]);
307624e697d4Sck 		}
3077d41c4376SMark J Musante 		err = 1;
3078d41c4376SMark J Musante 	}
3079d41c4376SMark J Musante 
3080d41c4376SMark J Musante 	if (err == 1) {
308124e697d4Sck 		free(searchdirs);
3082468c413aSTim Haley 		nvlist_free(policy);
308324e697d4Sck 		return (1);
308424e697d4Sck 	}
308524e697d4Sck 
308624e697d4Sck 	/*
308724e697d4Sck 	 * At this point we have a list of import candidate configs. Even if
308824e697d4Sck 	 * we were searching by pool name or guid, we still need to
308924e697d4Sck 	 * post-process the list to deal with pool state and possible
309024e697d4Sck 	 * duplicate names.
309124e697d4Sck 	 */
3092fa9e4066Sahrens 	err = 0;
3093fa9e4066Sahrens 	elem = NULL;
309499653d4eSeschrock 	first = B_TRUE;
3095fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
3096fa9e4066Sahrens 
3097fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
3098fa9e4066Sahrens 
30994c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
31004c58d714Sdarrenm 		    &pool_state) == 0);
31014c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
31024c58d714Sdarrenm 			continue;
31034c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
31044c58d714Sdarrenm 			continue;
31054c58d714Sdarrenm 
31065dafeea3SPavel Zakharov 		verify(nvlist_add_nvlist(config, ZPOOL_LOAD_POLICY,
3107468c413aSTim Haley 		    policy) == 0);
3108468c413aSTim Haley 
3109fa9e4066Sahrens 		if (argc == 0) {
3110fa9e4066Sahrens 			if (first)
311199653d4eSeschrock 				first = B_FALSE;
31123bb79becSeschrock 			else if (!do_all)
3113fa9e4066Sahrens 				(void) printf("\n");
3114fa9e4066Sahrens 
3115468c413aSTim Haley 			if (do_all) {
3116fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
31174b964adaSGeorge Wilson 				    props, flags);
3118468c413aSTim Haley 			} else {
3119fa9e4066Sahrens 				show_import(config);
3120468c413aSTim Haley 			}
3121fa9e4066Sahrens 		} else if (searchname != NULL) {
3122fa9e4066Sahrens 			char *name;
3123fa9e4066Sahrens 
3124fa9e4066Sahrens 			/*
3125fa9e4066Sahrens 			 * We are searching for a pool based on name.
3126fa9e4066Sahrens 			 */
3127fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
3128fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
3129fa9e4066Sahrens 
3130fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
3131fa9e4066Sahrens 				if (found_config != NULL) {
3132fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
3133fa9e4066Sahrens 					    "cannot import '%s': more than "
3134fa9e4066Sahrens 					    "one matching pool\n"), searchname);
3135fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
3136fa9e4066Sahrens 					    "import by numeric ID instead\n"));
313799653d4eSeschrock 					err = B_TRUE;
3138fa9e4066Sahrens 				}
3139fa9e4066Sahrens 				found_config = config;
3140fa9e4066Sahrens 			}
3141fa9e4066Sahrens 		} else {
3142fa9e4066Sahrens 			uint64_t guid;
3143fa9e4066Sahrens 
3144fa9e4066Sahrens 			/*
3145fa9e4066Sahrens 			 * Search for a pool by guid.
3146fa9e4066Sahrens 			 */
3147fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
3148fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
3149fa9e4066Sahrens 
3150fa9e4066Sahrens 			if (guid == searchguid)
3151fa9e4066Sahrens 				found_config = config;
3152fa9e4066Sahrens 		}
3153fa9e4066Sahrens 	}
3154fa9e4066Sahrens 
3155fa9e4066Sahrens 	/*
3156fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
3157fa9e4066Sahrens 	 * pool, and then do the import.
3158fa9e4066Sahrens 	 */
3159fa9e4066Sahrens 	if (argc != 0 && err == 0) {
3160fa9e4066Sahrens 		if (found_config == NULL) {
3161fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
3162fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
316399653d4eSeschrock 			err = B_TRUE;
3164fa9e4066Sahrens 		} else {
3165fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
31664b964adaSGeorge Wilson 			    argv[1], mntopts, props, flags);
3167fa9e4066Sahrens 		}
3168fa9e4066Sahrens 	}
3169fa9e4066Sahrens 
3170fa9e4066Sahrens 	/*
3171fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
3172fa9e4066Sahrens 	 * found.
3173fa9e4066Sahrens 	 */
3174fa9e4066Sahrens 	if (argc == 0 && first)
3175fa9e4066Sahrens 		(void) fprintf(stderr,
3176fa9e4066Sahrens 		    gettext("no pools available to import\n"));
3177fa9e4066Sahrens 
3178ecd6cf80Smarks error:
31792f8aaab3Seschrock 	nvlist_free(props);
3180fa9e4066Sahrens 	nvlist_free(pools);
3181468c413aSTim Haley 	nvlist_free(policy);
318299653d4eSeschrock 	free(searchdirs);
3183fa9e4066Sahrens 
3184fa9e4066Sahrens 	return (err ? 1 : 0);
3185fa9e4066Sahrens }
3186fa9e4066Sahrens 
31879c2acf00SAlek Pinchuk /*
31889c2acf00SAlek Pinchuk  * zpool sync [-f] [pool] ...
31899c2acf00SAlek Pinchuk  *
31909c2acf00SAlek Pinchuk  * -f (undocumented) force uberblock (and config including zpool cache file)
31919c2acf00SAlek Pinchuk  *    update.
31929c2acf00SAlek Pinchuk  *
31939c2acf00SAlek Pinchuk  * Sync the specified pool(s).
31949c2acf00SAlek Pinchuk  * Without arguments "zpool sync" will sync all pools.
31959c2acf00SAlek Pinchuk  * This command initiates TXG sync(s) and will return after the TXG(s) commit.
31969c2acf00SAlek Pinchuk  *
31979c2acf00SAlek Pinchuk  */
31989c2acf00SAlek Pinchuk static int
31999c2acf00SAlek Pinchuk zpool_do_sync(int argc, char **argv)
32009c2acf00SAlek Pinchuk {
32019c2acf00SAlek Pinchuk 	int ret;
32029c2acf00SAlek Pinchuk 	boolean_t force = B_FALSE;
32039c2acf00SAlek Pinchuk 
32049c2acf00SAlek Pinchuk 	/* check options */
32059c2acf00SAlek Pinchuk 	while ((ret  = getopt(argc, argv, "f")) != -1) {
32069c2acf00SAlek Pinchuk 		switch (ret) {
32079c2acf00SAlek Pinchuk 		case 'f':
32089c2acf00SAlek Pinchuk 			force = B_TRUE;
32099c2acf00SAlek Pinchuk 			break;
32109c2acf00SAlek Pinchuk 		case '?':
32119c2acf00SAlek Pinchuk 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
32129c2acf00SAlek Pinchuk 			    optopt);
32139c2acf00SAlek Pinchuk 			usage(B_FALSE);
32149c2acf00SAlek Pinchuk 		}
32159c2acf00SAlek Pinchuk 	}
32169c2acf00SAlek Pinchuk 
32179c2acf00SAlek Pinchuk 	argc -= optind;
32189c2acf00SAlek Pinchuk 	argv += optind;
32199c2acf00SAlek Pinchuk 
32209c2acf00SAlek Pinchuk 	/* if argc == 0 we will execute zpool_sync_one on all pools */
32219c2acf00SAlek Pinchuk 	ret = for_each_pool(argc, argv, B_FALSE, NULL, zpool_sync_one, &force);
32229c2acf00SAlek Pinchuk 
32239c2acf00SAlek Pinchuk 	return (ret);
32249c2acf00SAlek Pinchuk }
32259c2acf00SAlek Pinchuk 
3226fa9e4066Sahrens typedef struct iostat_cbdata {
3227dd50e0ccSTony Hutter 	uint64_t cb_flags;
3228663207adSDon Brady 	int cb_name_flags;
3229fa9e4066Sahrens 	int cb_namewidth;
32304263d13fSGeorge Wilson 	int cb_iteration;
3231dd50e0ccSTony Hutter 	char **cb_vdev_names; /* Only show these vdevs */
3232dd50e0ccSTony Hutter 	unsigned int cb_vdev_names_count;
3233dd50e0ccSTony Hutter 	boolean_t cb_verbose;
3234dd50e0ccSTony Hutter 	boolean_t cb_literal;
3235663207adSDon Brady 	boolean_t cb_scripted;
32364263d13fSGeorge Wilson 	zpool_list_t *cb_list;
3237fa9e4066Sahrens } iostat_cbdata_t;
3238fa9e4066Sahrens 
3239dd50e0ccSTony Hutter /*  iostat labels */
3240dd50e0ccSTony Hutter typedef struct name_and_columns {
3241dd50e0ccSTony Hutter 	const char *name;	/* Column name */
3242dd50e0ccSTony Hutter 	unsigned int columns;	/* Center name to this number of columns */
3243dd50e0ccSTony Hutter } name_and_columns_t;
3244dd50e0ccSTony Hutter 
3245dd50e0ccSTony Hutter #define	IOSTAT_MAX_LABELS	13	/* Max number of labels on one line */
3246dd50e0ccSTony Hutter 
3247dd50e0ccSTony Hutter static const name_and_columns_t iostat_top_labels[][IOSTAT_MAX_LABELS] =
3248dd50e0ccSTony Hutter {
3249dd50e0ccSTony Hutter 	[IOS_DEFAULT] = {{"capacity", 2}, {"operations", 2}, {"bandwidth", 2},
3250dd50e0ccSTony Hutter 	    {NULL}},
3251dd50e0ccSTony Hutter 	[IOS_LATENCY] = {{"total_wait", 2}, {"disk_wait", 2}, {"syncq_wait", 2},
3252dd50e0ccSTony Hutter 	    {"asyncq_wait", 2}, {"scrub"}, {"trim", 1}, {NULL}},
3253dd50e0ccSTony Hutter 	[IOS_QUEUES] = {{"syncq_read", 2}, {"syncq_write", 2},
3254dd50e0ccSTony Hutter 	    {"asyncq_read", 2}, {"asyncq_write", 2}, {"scrubq_read", 2},
3255dd50e0ccSTony Hutter 	    {"trimq_write", 2}, {NULL}},
3256dd50e0ccSTony Hutter 	[IOS_L_HISTO] = {{"total_wait", 2}, {"disk_wait", 2}, {"syncq_wait", 2},
3257dd50e0ccSTony Hutter 	    {"asyncq_wait", 2}, {NULL}},
3258dd50e0ccSTony Hutter 	[IOS_RQ_HISTO] = {{"sync_read", 2}, {"sync_write", 2},
3259dd50e0ccSTony Hutter 	    {"async_read", 2}, {"async_write", 2}, {"scrub", 2},
3260dd50e0ccSTony Hutter 	    {"trim", 2}, {NULL}},
3261dd50e0ccSTony Hutter 
3262dd50e0ccSTony Hutter };
3263dd50e0ccSTony Hutter 
3264dd50e0ccSTony Hutter /* Shorthand - if "columns" field not set, default to 1 column */
3265dd50e0ccSTony Hutter static const name_and_columns_t iostat_bottom_labels[][IOSTAT_MAX_LABELS] =
3266dd50e0ccSTony Hutter {
3267dd50e0ccSTony Hutter 	[IOS_DEFAULT] = {{"alloc"}, {"free"}, {"read"}, {"write"}, {"read"},
3268dd50e0ccSTony Hutter 	    {"write"}, {NULL}},
3269dd50e0ccSTony Hutter 	[IOS_LATENCY] = {{"read"}, {"write"}, {"read"}, {"write"}, {"read"},
3270dd50e0ccSTony Hutter 	    {"write"}, {"read"}, {"write"}, {"wait"}, {"wait"}, {NULL}},
3271dd50e0ccSTony Hutter 	[IOS_QUEUES] = {{"pend"}, {"activ"}, {"pend"}, {"activ"}, {"pend"},
3272dd50e0ccSTony Hutter 	    {"activ"}, {"pend"}, {"activ"}, {"pend"}, {"activ"},
3273dd50e0ccSTony Hutter 	    {"pend"}, {"activ"}, {NULL}},
3274dd50e0ccSTony Hutter 	[IOS_L_HISTO] = {{"read"}, {"write"}, {"read"}, {"write"}, {"read"},
3275dd50e0ccSTony Hutter 	    {"write"}, {"read"}, {"write"}, {"scrub"}, {"trim"}, {NULL}},
3276dd50e0ccSTony Hutter 	[IOS_RQ_HISTO] = {{"ind"}, {"agg"}, {"ind"}, {"agg"}, {"ind"}, {"agg"},
3277dd50e0ccSTony Hutter 	    {"ind"}, {"agg"}, {"ind"}, {"agg"}, {"ind"}, {"agg"}, {NULL}},
3278dd50e0ccSTony Hutter };
3279dd50e0ccSTony Hutter 
3280dd50e0ccSTony Hutter static const char *histo_to_title[] = {
3281dd50e0ccSTony Hutter 	[IOS_L_HISTO] = "latency",
3282dd50e0ccSTony Hutter 	[IOS_RQ_HISTO] = "req_size",
3283dd50e0ccSTony Hutter };
3284dd50e0ccSTony Hutter 
3285dd50e0ccSTony Hutter /*
3286dd50e0ccSTony Hutter  * Return the number of labels in a null-terminated name_and_columns_t
3287dd50e0ccSTony Hutter  * array.
3288dd50e0ccSTony Hutter  *
3289dd50e0ccSTony Hutter  */
3290dd50e0ccSTony Hutter static unsigned int
3291dd50e0ccSTony Hutter label_array_len(const name_and_columns_t *labels)
3292fa9e4066Sahrens {
3293fa9e4066Sahrens 	int i = 0;
3294fa9e4066Sahrens 
3295dd50e0ccSTony Hutter 	while (labels[i].name)
3296dd50e0ccSTony Hutter 		i++;
3297dd50e0ccSTony Hutter 
3298dd50e0ccSTony Hutter 	return (i);
3299fa9e4066Sahrens }
3300fa9e4066Sahrens 
3301dd50e0ccSTony Hutter /*
3302dd50e0ccSTony Hutter  * Return the number of strings in a null-terminated string array.
3303dd50e0ccSTony Hutter  * For example:
3304dd50e0ccSTony Hutter  *
3305dd50e0ccSTony Hutter  *     const char foo[] = {"bar", "baz", NULL}
3306dd50e0ccSTony Hutter  *
3307dd50e0ccSTony Hutter  * returns 2
3308dd50e0ccSTony Hutter  */
3309dd50e0ccSTony Hutter static uint64_t
3310dd50e0ccSTony Hutter str_array_len(const char *array[])
3311fa9e4066Sahrens {
3312dd50e0ccSTony Hutter 	uint64_t i = 0;
3313dd50e0ccSTony Hutter 	while (array[i])
3314dd50e0ccSTony Hutter 		i++;
3315dd50e0ccSTony Hutter 
3316dd50e0ccSTony Hutter 	return (i);
3317fa9e4066Sahrens }
3318fa9e4066Sahrens 
3319dd50e0ccSTony Hutter 
3320fa9e4066Sahrens /*
3321dd50e0ccSTony Hutter  * Return a default column width for default/latency/queue columns. This does
3322dd50e0ccSTony Hutter  * not include histograms, which have their columns autosized.
3323fa9e4066Sahrens  */
3324dd50e0ccSTony Hutter static unsigned int
3325dd50e0ccSTony Hutter default_column_width(iostat_cbdata_t *cb, enum iostat_type type)
3326fa9e4066Sahrens {
3327dd50e0ccSTony Hutter 	unsigned long column_width = 5; /* Normal niceprint */
3328dd50e0ccSTony Hutter 	static unsigned long widths[] = {
3329dd50e0ccSTony Hutter 		/*
3330dd50e0ccSTony Hutter 		 * Choose some sane default column sizes for printing the
3331dd50e0ccSTony Hutter 		 * raw numbers.
3332dd50e0ccSTony Hutter 		 */
3333dd50e0ccSTony Hutter 		[IOS_DEFAULT] = 15, /* 1PB capacity */
3334dd50e0ccSTony Hutter 		[IOS_LATENCY] = 10, /* 1B ns = 10sec */
3335dd50e0ccSTony Hutter 		[IOS_QUEUES] = 6,   /* 1M queue entries */
3336dd50e0ccSTony Hutter 		[IOS_L_HISTO] = 10, /* 1B ns = 10sec */
3337dd50e0ccSTony Hutter 		[IOS_RQ_HISTO] = 6, /* 1M queue entries */
3338dd50e0ccSTony Hutter 	};
3339fa9e4066Sahrens 
3340dd50e0ccSTony Hutter 	if (cb->cb_literal)
3341dd50e0ccSTony Hutter 		column_width = widths[type];
3342fa9e4066Sahrens 
3343dd50e0ccSTony Hutter 	return (column_width);
3344dd50e0ccSTony Hutter }
3345663207adSDon Brady 
3346fa9e4066Sahrens /*
3347dd50e0ccSTony Hutter  * Print the column labels, i.e:
3348dd50e0ccSTony Hutter  *
3349dd50e0ccSTony Hutter  *   capacity     operations     bandwidth
3350dd50e0ccSTony Hutter  * alloc   free   read  write   read  write  ...
3351dd50e0ccSTony Hutter  *
3352dd50e0ccSTony Hutter  * If force_column_width is set, use it for the column width.  If not set, use
3353dd50e0ccSTony Hutter  * the default column width.
3354fa9e4066Sahrens  */
3355dd50e0ccSTony Hutter void
3356dd50e0ccSTony Hutter print_iostat_labels(iostat_cbdata_t *cb, unsigned int force_column_width,
3357dd50e0ccSTony Hutter     const name_and_columns_t labels[][IOSTAT_MAX_LABELS])
3358fa9e4066Sahrens {
3359dd50e0ccSTony Hutter 	int i, idx, s;
3360dd50e0ccSTony Hutter 	int text_start, rw_column_width, spaces_to_end;
3361dd50e0ccSTony Hutter 	uint64_t flags = cb->cb_flags;
3362dd50e0ccSTony Hutter 	uint64_t f;
3363dd50e0ccSTony Hutter 	unsigned int column_width = force_column_width;
3364dd50e0ccSTony Hutter 
3365dd50e0ccSTony Hutter 	/* For each bit set in flags */
3366dd50e0ccSTony Hutter 	for (f = flags; f; f &= ~(1ULL << idx)) {
3367dd50e0ccSTony Hutter 		idx = lowbit64(f) - 1;
3368dd50e0ccSTony Hutter 		if (!force_column_width)
3369dd50e0ccSTony Hutter 			column_width = default_column_width(cb, idx);
3370dd50e0ccSTony Hutter 		/* Print our top labels centered over "read  write" label. */
3371dd50e0ccSTony Hutter 		for (i = 0; i < label_array_len(labels[idx]); i++) {
3372dd50e0ccSTony Hutter 			const char *name = labels[idx][i].name;
3373dd50e0ccSTony Hutter 			/*
3374dd50e0ccSTony Hutter 			 * We treat labels[][].columns == 0 as shorthand
3375dd50e0ccSTony Hutter 			 * for one column.  It makes writing out the label
3376dd50e0ccSTony Hutter 			 * tables more concise.
3377dd50e0ccSTony Hutter 			 */
3378dd50e0ccSTony Hutter 			unsigned int columns = MAX(1, labels[idx][i].columns);
3379dd50e0ccSTony Hutter 			unsigned int slen = strlen(name);
3380fa9e4066Sahrens 
3381dd50e0ccSTony Hutter 			rw_column_width = (column_width * columns) +
3382dd50e0ccSTony Hutter 			    (2 * (columns - 1));
33835cabbc6bSPrashanth Sreenivasa 
3384dd50e0ccSTony Hutter 			text_start = (int)((rw_column_width) / columns -
3385dd50e0ccSTony Hutter 			    slen / columns);
3386dd50e0ccSTony Hutter 			if (text_start < 0)
3387dd50e0ccSTony Hutter 				text_start = 0;
3388fa9e4066Sahrens 
3389dd50e0ccSTony Hutter 			printf("  ");	/* Two spaces between columns */
3390fa9e4066Sahrens 
3391dd50e0ccSTony Hutter 			/* Space from beginning of column to label */
3392dd50e0ccSTony Hutter 			for (s = 0; s < text_start; s++)
3393dd50e0ccSTony Hutter 				printf(" ");
3394fa9e4066Sahrens 
3395dd50e0ccSTony Hutter 			printf("%s", name);
3396fa9e4066Sahrens 
3397dd50e0ccSTony Hutter 			/* Print space after label to end of column */
3398dd50e0ccSTony Hutter 			spaces_to_end = rw_column_width - text_start - slen;
3399dd50e0ccSTony Hutter 			if (spaces_to_end < 0)
3400dd50e0ccSTony Hutter 				spaces_to_end = 0;
3401fa9e4066Sahrens 
3402dd50e0ccSTony Hutter 			for (s = 0; s < spaces_to_end; s++)
3403dd50e0ccSTony Hutter 				printf(" ");
3404dd50e0ccSTony Hutter 		}
3405fa9e4066Sahrens 	}
3406dd50e0ccSTony Hutter }
3407fa9e4066Sahrens 
3408dd50e0ccSTony Hutter /*
3409dd50e0ccSTony Hutter  * Utility function to print out a line of dashes like:
3410dd50e0ccSTony Hutter  *
3411dd50e0ccSTony Hutter  * 	--------------------------------  -----  -----  -----  -----  -----
3412dd50e0ccSTony Hutter  *
3413dd50e0ccSTony Hutter  * ...or a dashed named-row line like:
3414dd50e0ccSTony Hutter  *
3415dd50e0ccSTony Hutter  * 	logs                                  -      -      -      -      -
3416dd50e0ccSTony Hutter  *
3417dd50e0ccSTony Hutter  * @cb:				iostat data
3418dd50e0ccSTony Hutter  *
3419dd50e0ccSTony Hutter  * @force_column_width		If non-zero, use the value as the column width.
3420dd50e0ccSTony Hutter  * 				Otherwise use the default column widths.
3421dd50e0ccSTony Hutter  *
3422dd50e0ccSTony Hutter  * @name:			Print a dashed named-row line starting
3423dd50e0ccSTony Hutter  * 				with @name.  Otherwise, print a regular
3424dd50e0ccSTony Hutter  * 				dashed line.
3425dd50e0ccSTony Hutter  */
3426dd50e0ccSTony Hutter static void
3427dd50e0ccSTony Hutter print_iostat_dashes(iostat_cbdata_t *cb, unsigned int force_column_width,
3428dd50e0ccSTony Hutter     const char *name)
3429dd50e0ccSTony Hutter {
3430dd50e0ccSTony Hutter 	int i;
3431dd50e0ccSTony Hutter 	unsigned int namewidth;
3432dd50e0ccSTony Hutter 	uint64_t flags = cb->cb_flags;
3433dd50e0ccSTony Hutter 	uint64_t f;
3434dd50e0ccSTony Hutter 	int idx;
3435dd50e0ccSTony Hutter 	const name_and_columns_t *labels;
3436dd50e0ccSTony Hutter 	const char *title;
3437fa9e4066Sahrens 
3438fa9e4066Sahrens 
3439dd50e0ccSTony Hutter 	if (cb->cb_flags & IOS_ANYHISTO_M) {
3440dd50e0ccSTony Hutter 		title = histo_to_title[IOS_HISTO_IDX(cb->cb_flags)];
3441dd50e0ccSTony Hutter 	} else if (cb->cb_vdev_names_count) {
3442dd50e0ccSTony Hutter 		title = "vdev";
3443dd50e0ccSTony Hutter 	} else  {
3444dd50e0ccSTony Hutter 		title = "pool";
3445dd50e0ccSTony Hutter 	}
3446fa9e4066Sahrens 
3447dd50e0ccSTony Hutter 	namewidth = MAX(MAX(strlen(title), cb->cb_namewidth),
3448dd50e0ccSTony Hutter 	    name ? strlen(name) : 0);
3449fa9e4066Sahrens 
3450fa9e4066Sahrens 
3451dd50e0ccSTony Hutter 	if (name) {
3452dd50e0ccSTony Hutter 		printf("%-*s", namewidth, name);
3453dd50e0ccSTony Hutter 	} else {
3454dd50e0ccSTony Hutter 		for (i = 0; i < namewidth; i++)
3455dd50e0ccSTony Hutter 			(void) printf("-");
3456dd50e0ccSTony Hutter 	}
3457fa9e4066Sahrens 
3458dd50e0ccSTony Hutter 	/* For each bit in flags */
3459dd50e0ccSTony Hutter 	for (f = flags; f; f &= ~(1ULL << idx)) {
3460dd50e0ccSTony Hutter 		unsigned int column_width;
3461dd50e0ccSTony Hutter 		idx = lowbit64(f) - 1;
3462dd50e0ccSTony Hutter 		if (force_column_width)
3463dd50e0ccSTony Hutter 			column_width = force_column_width;
3464dd50e0ccSTony Hutter 		else
3465dd50e0ccSTony Hutter 			column_width = default_column_width(cb, idx);
3466fa9e4066Sahrens 
3467dd50e0ccSTony Hutter 		labels = iostat_bottom_labels[idx];
3468dd50e0ccSTony Hutter 		for (i = 0; i < label_array_len(labels); i++) {
3469dd50e0ccSTony Hutter 			if (name)
3470dd50e0ccSTony Hutter 				printf("  %*s-", column_width - 1, " ");
3471dd50e0ccSTony Hutter 			else
3472dd50e0ccSTony Hutter 				printf("  %.*s", column_width,
3473dd50e0ccSTony Hutter 				    "--------------------");
3474dd50e0ccSTony Hutter 		}
3475dd50e0ccSTony Hutter 	}
3476dd50e0ccSTony Hutter }
34773f9d6ad7SLin Ling 
34789d439f90SMike Harsch 
3479dd50e0ccSTony Hutter static void
3480dd50e0ccSTony Hutter print_iostat_separator_impl(iostat_cbdata_t *cb,
3481dd50e0ccSTony Hutter     unsigned int force_column_width)
3482dd50e0ccSTony Hutter {
3483dd50e0ccSTony Hutter 	print_iostat_dashes(cb, force_column_width, NULL);
3484dd50e0ccSTony Hutter }
34859d439f90SMike Harsch 
3486dd50e0ccSTony Hutter static void
3487dd50e0ccSTony Hutter print_iostat_separator(iostat_cbdata_t *cb)
3488dd50e0ccSTony Hutter {
3489dd50e0ccSTony Hutter 	print_iostat_separator_impl(cb, 0);
3490dd50e0ccSTony Hutter }
34913f9d6ad7SLin Ling 
3492dd50e0ccSTony Hutter static void
3493dd50e0ccSTony Hutter print_iostat_header_impl(iostat_cbdata_t *cb, unsigned int force_column_width,
3494dd50e0ccSTony Hutter     const char *histo_vdev_name)
3495dd50e0ccSTony Hutter {
3496dd50e0ccSTony Hutter 	unsigned int namewidth;
3497dd50e0ccSTony Hutter 	const char *title;
3498663207adSDon Brady 
3499dd50e0ccSTony Hutter 	if (cb->cb_flags & IOS_ANYHISTO_M) {
3500dd50e0ccSTony Hutter 		title = histo_to_title[IOS_HISTO_IDX(cb->cb_flags)];
3501dd50e0ccSTony Hutter 	} else if (cb->cb_vdev_names_count) {
3502dd50e0ccSTony Hutter 		title = "vdev";
3503dd50e0ccSTony Hutter 	} else  {
3504dd50e0ccSTony Hutter 		title = "pool";
3505afefbcddSeschrock 	}
3506fa94a07fSbrendan 
3507dd50e0ccSTony Hutter 	namewidth = MAX(MAX(strlen(title), cb->cb_namewidth),
3508dd50e0ccSTony Hutter 	    histo_vdev_name ? strlen(histo_vdev_name) : 0);
3509663207adSDon Brady 
3510dd50e0ccSTony Hutter 	if (histo_vdev_name)
3511dd50e0ccSTony Hutter 		printf("%-*s", namewidth, histo_vdev_name);
3512dd50e0ccSTony Hutter 	else
3513dd50e0ccSTony Hutter 		printf("%*s", namewidth, "");
3514663207adSDon Brady 
3515c4e4d410SAndy Fiddaman 
3516dd50e0ccSTony Hutter 	print_iostat_labels(cb, force_column_width, iostat_top_labels);
3517dd50e0ccSTony Hutter 	printf("\n");
35189d439f90SMike Harsch 
3519dd50e0ccSTony Hutter 	printf("%-*s", namewidth, title);
35209d439f90SMike Harsch 
3521dd50e0ccSTony Hutter 	print_iostat_labels(cb, force_column_width, iostat_bottom_labels);
3522fa94a07fSbrendan 
3523dd50e0ccSTony Hutter 	printf("\n");
3524fa94a07fSbrendan 
3525dd50e0ccSTony Hutter 	print_iostat_separator_impl(cb, force_column_width);
3526dd50e0ccSTony Hutter 
3527dd50e0ccSTony Hutter 	printf("\n");
3528fa9e4066Sahrens }
3529fa9e4066Sahrens 
3530dd50e0ccSTony Hutter static void
3531dd50e0ccSTony Hutter print_iostat_header(iostat_cbdata_t *cb)
3532088e9d47Seschrock {
3533dd50e0ccSTony Hutter 	print_iostat_header_impl(cb, 0, NULL);
3534dd50e0ccSTony Hutter }
3535088e9d47Seschrock 
3536dd50e0ccSTony Hutter /*
3537dd50e0ccSTony Hutter  * Display a single statistic.
3538dd50e0ccSTony Hutter  */
3539dd50e0ccSTony Hutter static void
3540dd50e0ccSTony Hutter print_one_stat(uint64_t value, enum zfs_nicenum_format format,
3541dd50e0ccSTony Hutter     unsigned int column_size, boolean_t scripted)
3542dd50e0ccSTony Hutter {
3543dd50e0ccSTony Hutter 	char buf[64];
354494de1d4cSeschrock 
3545dd50e0ccSTony Hutter 	zfs_nicenum_format(value, buf, sizeof (buf), format);
3546088e9d47Seschrock 
3547dd50e0ccSTony Hutter 	if (scripted)
3548dd50e0ccSTony Hutter 		printf("\t%s", buf);
3549dd50e0ccSTony Hutter 	else
3550dd50e0ccSTony Hutter 		printf("  %*s", column_size, buf);
3551088e9d47Seschrock }
3552088e9d47Seschrock 
3553fa9e4066Sahrens /*
3554dd50e0ccSTony Hutter  * Calculate the default vdev stats
3555dd50e0ccSTony Hutter  *
3556dd50e0ccSTony Hutter  * Subtract oldvs from newvs, apply a scaling factor, and save the resulting
3557dd50e0ccSTony Hutter  * stats into calcvs.
3558fa9e4066Sahrens  */
3559dd50e0ccSTony Hutter static void
3560dd50e0ccSTony Hutter calc_default_iostats(vdev_stat_t *oldvs, vdev_stat_t *newvs,
3561dd50e0ccSTony Hutter     vdev_stat_t *calcvs)
3562fa9e4066Sahrens {
3563dd50e0ccSTony Hutter 	int i;
3564fa9e4066Sahrens 
3565dd50e0ccSTony Hutter 	memcpy(calcvs, newvs, sizeof (*calcvs));
3566dd50e0ccSTony Hutter 	for (i = 0; i < ARRAY_SIZE(calcvs->vs_ops); i++)
3567dd50e0ccSTony Hutter 		calcvs->vs_ops[i] = (newvs->vs_ops[i] - oldvs->vs_ops[i]);
3568fa9e4066Sahrens 
3569dd50e0ccSTony Hutter 	for (i = 0; i < ARRAY_SIZE(calcvs->vs_bytes); i++)
3570dd50e0ccSTony Hutter 		calcvs->vs_bytes[i] = (newvs->vs_bytes[i] - oldvs->vs_bytes[i]);
3571dd50e0ccSTony Hutter }
3572fa9e4066Sahrens 
3573dd50e0ccSTony Hutter /*
3574dd50e0ccSTony Hutter  * Internal representation of the extended iostats data.
3575dd50e0ccSTony Hutter  *
3576dd50e0ccSTony Hutter  * The extended iostat stats are exported in nvlists as either uint64_t arrays
3577dd50e0ccSTony Hutter  * or single uint64_t's.  We make both look like arrays to make them easier
3578dd50e0ccSTony Hutter  * to process.  In order to make single uint64_t's look like arrays, we set
3579dd50e0ccSTony Hutter  * __data to the stat data, and then set *data = &__data with count = 1.  Then,
3580dd50e0ccSTony Hutter  * we can just use *data and count.
3581dd50e0ccSTony Hutter  */
3582dd50e0ccSTony Hutter struct stat_array {
3583dd50e0ccSTony Hutter 	uint64_t *data;
3584dd50e0ccSTony Hutter 	uint_t count;	/* Number of entries in data[] */
3585dd50e0ccSTony Hutter 	uint64_t __data; /* Only used when data is a single uint64_t */
3586dd50e0ccSTony Hutter };
3587fa9e4066Sahrens 
3588dd50e0ccSTony Hutter static uint64_t
3589dd50e0ccSTony Hutter stat_histo_max(struct stat_array *nva, unsigned int len)
3590dd50e0ccSTony Hutter {
3591dd50e0ccSTony Hutter 	uint64_t max = 0;
3592dd50e0ccSTony Hutter 	int i;
3593dd50e0ccSTony Hutter 	for (i = 0; i < len; i++)
3594dd50e0ccSTony Hutter 		max = MAX(max, array64_max(nva[i].data, nva[i].count));
3595fa9e4066Sahrens 
3596dd50e0ccSTony Hutter 	return (max);
3597dd50e0ccSTony Hutter }
3598fa9e4066Sahrens 
3599dd50e0ccSTony Hutter /*
3600dd50e0ccSTony Hutter  * Helper function to lookup a uint64_t array or uint64_t value and store its
3601dd50e0ccSTony Hutter  * data as a stat_array.  If the nvpair is a single uint64_t value, then we make
3602dd50e0ccSTony Hutter  * it look like a one element array to make it easier to process.
3603dd50e0ccSTony Hutter  */
3604dd50e0ccSTony Hutter static int
3605dd50e0ccSTony Hutter nvpair64_to_stat_array(nvlist_t *nvl, const char *name,
3606dd50e0ccSTony Hutter     struct stat_array *nva)
3607dd50e0ccSTony Hutter {
3608dd50e0ccSTony Hutter 	nvpair_t *tmp;
3609dd50e0ccSTony Hutter 	int ret;
3610dd50e0ccSTony Hutter 
3611dd50e0ccSTony Hutter 	verify(nvlist_lookup_nvpair(nvl, name, &tmp) == 0);
3612dd50e0ccSTony Hutter 	switch (nvpair_type(tmp)) {
3613dd50e0ccSTony Hutter 	case DATA_TYPE_UINT64_ARRAY:
3614dd50e0ccSTony Hutter 		ret = nvpair_value_uint64_array(tmp, &nva->data, &nva->count);
3615dd50e0ccSTony Hutter 		break;
3616dd50e0ccSTony Hutter 	case DATA_TYPE_UINT64:
3617dd50e0ccSTony Hutter 		ret = nvpair_value_uint64(tmp, &nva->__data);
3618dd50e0ccSTony Hutter 		nva->data = &nva->__data;
3619dd50e0ccSTony Hutter 		nva->count = 1;
3620dd50e0ccSTony Hutter 		break;
3621dd50e0ccSTony Hutter 	default:
3622dd50e0ccSTony Hutter 		/* Not a uint64_t */
3623dd50e0ccSTony Hutter 		ret = EINVAL;
3624dd50e0ccSTony Hutter 		break;
3625dd50e0ccSTony Hutter 	}
3626dd50e0ccSTony Hutter 
3627dd50e0ccSTony Hutter 	return (ret);
3628dd50e0ccSTony Hutter }
3629dd50e0ccSTony Hutter 
3630dd50e0ccSTony Hutter /*
3631dd50e0ccSTony Hutter  * Given a list of nvlist names, look up the extended stats in newnv and oldnv,
3632dd50e0ccSTony Hutter  * subtract them, and return the results in a newly allocated stat_array.
3633dd50e0ccSTony Hutter  * You must free the returned array after you are done with it with
3634dd50e0ccSTony Hutter  * free_calc_stats().
3635dd50e0ccSTony Hutter  *
3636dd50e0ccSTony Hutter  * Additionally, you can set "oldnv" to NULL if you simply want the newnv
3637dd50e0ccSTony Hutter  * values.
3638dd50e0ccSTony Hutter  */
3639dd50e0ccSTony Hutter static struct stat_array *
3640dd50e0ccSTony Hutter calc_and_alloc_stats_ex(const char **names, unsigned int len, nvlist_t *oldnv,
3641dd50e0ccSTony Hutter     nvlist_t *newnv)
3642dd50e0ccSTony Hutter {
3643dd50e0ccSTony Hutter 	nvlist_t *oldnvx = NULL, *newnvx;
3644dd50e0ccSTony Hutter 	struct stat_array *oldnva, *newnva, *calcnva;
3645dd50e0ccSTony Hutter 	int i, j;
3646dd50e0ccSTony Hutter 	unsigned int alloc_size = (sizeof (struct stat_array)) * len;
3647dd50e0ccSTony Hutter 
3648dd50e0ccSTony Hutter 	/* Extract our extended stats nvlist from the main list */
3649dd50e0ccSTony Hutter 	verify(nvlist_lookup_nvlist(newnv, ZPOOL_CONFIG_VDEV_STATS_EX,
3650dd50e0ccSTony Hutter 	    &newnvx) == 0);
3651dd50e0ccSTony Hutter 	if (oldnv) {
3652dd50e0ccSTony Hutter 		verify(nvlist_lookup_nvlist(oldnv, ZPOOL_CONFIG_VDEV_STATS_EX,
3653dd50e0ccSTony Hutter 		    &oldnvx) == 0);
3654dd50e0ccSTony Hutter 	}
3655dd50e0ccSTony Hutter 
3656dd50e0ccSTony Hutter 	newnva = safe_malloc(alloc_size);
3657dd50e0ccSTony Hutter 	oldnva = safe_malloc(alloc_size);
3658dd50e0ccSTony Hutter 	calcnva = safe_malloc(alloc_size);
3659dd50e0ccSTony Hutter 
3660dd50e0ccSTony Hutter 	for (j = 0; j < len; j++) {
3661dd50e0ccSTony Hutter 		verify(nvpair64_to_stat_array(newnvx, names[j],
3662dd50e0ccSTony Hutter 		    &newnva[j]) == 0);
3663dd50e0ccSTony Hutter 		calcnva[j].count = newnva[j].count;
3664dd50e0ccSTony Hutter 		alloc_size = calcnva[j].count * sizeof (calcnva[j].data[0]);
3665dd50e0ccSTony Hutter 		calcnva[j].data = safe_malloc(alloc_size);
3666dd50e0ccSTony Hutter 		memcpy(calcnva[j].data, newnva[j].data, alloc_size);
3667dd50e0ccSTony Hutter 
3668dd50e0ccSTony Hutter 		if (oldnvx) {
3669dd50e0ccSTony Hutter 			verify(nvpair64_to_stat_array(oldnvx, names[j],
3670dd50e0ccSTony Hutter 			    &oldnva[j]) == 0);
3671dd50e0ccSTony Hutter 			for (i = 0; i < oldnva[j].count; i++)
3672dd50e0ccSTony Hutter 				calcnva[j].data[i] -= oldnva[j].data[i];
3673dd50e0ccSTony Hutter 		}
3674dd50e0ccSTony Hutter 	}
3675dd50e0ccSTony Hutter 	free(newnva);
3676dd50e0ccSTony Hutter 	free(oldnva);
3677dd50e0ccSTony Hutter 	return (calcnva);
3678dd50e0ccSTony Hutter }
3679dd50e0ccSTony Hutter 
3680dd50e0ccSTony Hutter static void
3681dd50e0ccSTony Hutter free_calc_stats(struct stat_array *nva, unsigned int len)
3682dd50e0ccSTony Hutter {
3683dd50e0ccSTony Hutter 	int i;
3684dd50e0ccSTony Hutter 	for (i = 0; i < len; i++)
3685dd50e0ccSTony Hutter 		free(nva[i].data);
3686dd50e0ccSTony Hutter 
3687dd50e0ccSTony Hutter 	free(nva);
3688dd50e0ccSTony Hutter }
3689dd50e0ccSTony Hutter 
3690dd50e0ccSTony Hutter static void
3691dd50e0ccSTony Hutter print_iostat_histo(struct stat_array *nva, unsigned int len,
3692dd50e0ccSTony Hutter     iostat_cbdata_t *cb, unsigned int column_width, unsigned int namewidth,
3693dd50e0ccSTony Hutter     double scale)
3694dd50e0ccSTony Hutter {
3695dd50e0ccSTony Hutter 	int i, j;
3696dd50e0ccSTony Hutter 	char buf[6];
3697dd50e0ccSTony Hutter 	uint64_t val;
3698dd50e0ccSTony Hutter 	enum zfs_nicenum_format format;
3699dd50e0ccSTony Hutter 	unsigned int buckets;
3700dd50e0ccSTony Hutter 	unsigned int start_bucket;
3701dd50e0ccSTony Hutter 
3702dd50e0ccSTony Hutter 	if (cb->cb_literal)
3703dd50e0ccSTony Hutter 		format = ZFS_NICENUM_RAW;
3704dd50e0ccSTony Hutter 	else
3705dd50e0ccSTony Hutter 		format = ZFS_NICENUM_1024;
3706dd50e0ccSTony Hutter 
3707dd50e0ccSTony Hutter 	/* All these histos are the same size, so just use nva[0].count */
3708dd50e0ccSTony Hutter 	buckets = nva[0].count;
3709dd50e0ccSTony Hutter 
3710dd50e0ccSTony Hutter 	if (cb->cb_flags & IOS_RQ_HISTO_M) {
3711dd50e0ccSTony Hutter 		/* Start at 512 - req size should never be lower than this */
3712dd50e0ccSTony Hutter 		start_bucket = 9;
3713dd50e0ccSTony Hutter 	} else {
3714dd50e0ccSTony Hutter 		start_bucket = 0;
3715dd50e0ccSTony Hutter 	}
3716dd50e0ccSTony Hutter 
3717dd50e0ccSTony Hutter 	for (j = start_bucket; j < buckets; j++) {
3718dd50e0ccSTony Hutter 		/* Print histogram bucket label */
3719dd50e0ccSTony Hutter 		if (cb->cb_flags & IOS_L_HISTO_M) {
3720dd50e0ccSTony Hutter 			/* Ending range of this bucket */
3721dd50e0ccSTony Hutter 			val = (1ULL << (j + 1)) - 1;
3722dd50e0ccSTony Hutter 			zfs_nicetime(val, buf, sizeof (buf));
3723dd50e0ccSTony Hutter 		} else {
3724dd50e0ccSTony Hutter 			/* Request size (starting range of bucket) */
3725dd50e0ccSTony Hutter 			val = (1UL << j);
3726dd50e0ccSTony Hutter 			zfs_nicenum(val, buf, sizeof (buf));
3727dd50e0ccSTony Hutter 		}
3728dd50e0ccSTony Hutter 
3729dd50e0ccSTony Hutter 		if (cb->cb_scripted)
3730dd50e0ccSTony Hutter 			printf("%llu", (u_longlong_t)val);
3731dd50e0ccSTony Hutter 		else
3732dd50e0ccSTony Hutter 			printf("%-*s", namewidth, buf);
3733dd50e0ccSTony Hutter 
3734dd50e0ccSTony Hutter 		/* Print the values on the line */
3735dd50e0ccSTony Hutter 		for (i = 0; i < len; i++) {
3736dd50e0ccSTony Hutter 			print_one_stat(nva[i].data[j] * scale, format,
3737dd50e0ccSTony Hutter 			    column_width, cb->cb_scripted);
3738dd50e0ccSTony Hutter 		}
3739dd50e0ccSTony Hutter 		printf("\n");
3740dd50e0ccSTony Hutter 	}
3741dd50e0ccSTony Hutter }
3742dd50e0ccSTony Hutter 
3743dd50e0ccSTony Hutter static void
3744dd50e0ccSTony Hutter print_solid_separator(unsigned int length)
3745dd50e0ccSTony Hutter {
3746dd50e0ccSTony Hutter 	while (length--)
3747dd50e0ccSTony Hutter 		printf("-");
3748dd50e0ccSTony Hutter 	printf("\n");
3749dd50e0ccSTony Hutter }
3750dd50e0ccSTony Hutter 
3751dd50e0ccSTony Hutter static void
3752dd50e0ccSTony Hutter print_iostat_histos(iostat_cbdata_t *cb, nvlist_t *oldnv,
3753dd50e0ccSTony Hutter     nvlist_t *newnv, double scale, const char *name)
3754dd50e0ccSTony Hutter {
3755dd50e0ccSTony Hutter 	unsigned int column_width;
3756dd50e0ccSTony Hutter 	unsigned int namewidth;
3757dd50e0ccSTony Hutter 	unsigned int entire_width;
3758dd50e0ccSTony Hutter 	enum iostat_type type;
3759dd50e0ccSTony Hutter 	struct stat_array *nva;
3760dd50e0ccSTony Hutter 	const char **names;
3761dd50e0ccSTony Hutter 	unsigned int names_len;
3762dd50e0ccSTony Hutter 
3763dd50e0ccSTony Hutter 	/* What type of histo are we? */
3764dd50e0ccSTony Hutter 	type = IOS_HISTO_IDX(cb->cb_flags);
3765dd50e0ccSTony Hutter 
3766dd50e0ccSTony Hutter 	/* Get NULL-terminated array of nvlist names for our histo */
3767dd50e0ccSTony Hutter 	names = vsx_type_to_nvlist[type];
3768dd50e0ccSTony Hutter 	names_len = str_array_len(names); /* num of names */
3769dd50e0ccSTony Hutter 
3770dd50e0ccSTony Hutter 	nva = calc_and_alloc_stats_ex(names, names_len, oldnv, newnv);
3771dd50e0ccSTony Hutter 
3772dd50e0ccSTony Hutter 	if (cb->cb_literal) {
3773dd50e0ccSTony Hutter 		column_width = MAX(5,
3774dd50e0ccSTony Hutter 		    (unsigned int) log10(stat_histo_max(nva, names_len)) + 1);
3775dd50e0ccSTony Hutter 	} else {
3776dd50e0ccSTony Hutter 		column_width = 5;
3777dd50e0ccSTony Hutter 	}
3778dd50e0ccSTony Hutter 
3779dd50e0ccSTony Hutter 	namewidth = MAX(cb->cb_namewidth,
3780dd50e0ccSTony Hutter 	    strlen(histo_to_title[IOS_HISTO_IDX(cb->cb_flags)]));
3781dd50e0ccSTony Hutter 
3782dd50e0ccSTony Hutter 	/*
3783dd50e0ccSTony Hutter 	 * Calculate the entire line width of what we're printing.  The
3784dd50e0ccSTony Hutter 	 * +2 is for the two spaces between columns:
3785dd50e0ccSTony Hutter 	 */
3786dd50e0ccSTony Hutter 	/*	 read  write				*/
3787dd50e0ccSTony Hutter 	/*	-----  -----				*/
3788dd50e0ccSTony Hutter 	/*	|___|  <---------- column_width		*/
3789dd50e0ccSTony Hutter 	/*						*/
3790dd50e0ccSTony Hutter 	/*	|__________|  <--- entire_width		*/
3791dd50e0ccSTony Hutter 	/*						*/
3792dd50e0ccSTony Hutter 	entire_width = namewidth + (column_width + 2) *
3793dd50e0ccSTony Hutter 	    label_array_len(iostat_bottom_labels[type]);
3794dd50e0ccSTony Hutter 
3795dd50e0ccSTony Hutter 	if (cb->cb_scripted)
3796dd50e0ccSTony Hutter 		printf("%s\n", name);
3797dd50e0ccSTony Hutter 	else
3798dd50e0ccSTony Hutter 		print_iostat_header_impl(cb, column_width, name);
3799dd50e0ccSTony Hutter 
3800dd50e0ccSTony Hutter 	print_iostat_histo(nva, names_len, cb, column_width,
3801dd50e0ccSTony Hutter 	    namewidth, scale);
3802dd50e0ccSTony Hutter 
3803dd50e0ccSTony Hutter 	free_calc_stats(nva, names_len);
3804dd50e0ccSTony Hutter 	if (!cb->cb_scripted)
3805dd50e0ccSTony Hutter 		print_solid_separator(entire_width);
3806dd50e0ccSTony Hutter }
3807dd50e0ccSTony Hutter 
3808dd50e0ccSTony Hutter /*
3809dd50e0ccSTony Hutter  * Calculate the average latency of a power-of-two latency histogram
3810dd50e0ccSTony Hutter  */
3811dd50e0ccSTony Hutter static uint64_t
3812dd50e0ccSTony Hutter single_histo_average(uint64_t *histo, unsigned int buckets)
3813dd50e0ccSTony Hutter {
3814dd50e0ccSTony Hutter 	int i;
3815dd50e0ccSTony Hutter 	uint64_t count = 0, total = 0;
3816dd50e0ccSTony Hutter 
3817dd50e0ccSTony Hutter 	for (i = 0; i < buckets; i++) {
3818dd50e0ccSTony Hutter 		/*
3819dd50e0ccSTony Hutter 		 * Our buckets are power-of-two latency ranges.  Use the
3820dd50e0ccSTony Hutter 		 * midpoint latency of each bucket to calculate the average.
3821dd50e0ccSTony Hutter 		 * For example:
3822dd50e0ccSTony Hutter 		 *
3823dd50e0ccSTony Hutter 		 * Bucket	Midpoint
3824dd50e0ccSTony Hutter 		 * 8ns-15ns:	12ns
3825dd50e0ccSTony Hutter 		 * 16ns-31ns:	24ns
3826dd50e0ccSTony Hutter 		 * ...
3827dd50e0ccSTony Hutter 		 */
3828dd50e0ccSTony Hutter 		if (histo[i] != 0) {
3829dd50e0ccSTony Hutter 			total += histo[i] * (((1UL << i) + ((1UL << i)/2)));
3830dd50e0ccSTony Hutter 			count += histo[i];
3831dd50e0ccSTony Hutter 		}
3832dd50e0ccSTony Hutter 	}
3833dd50e0ccSTony Hutter 
3834dd50e0ccSTony Hutter 	/* Prevent divide by zero */
3835dd50e0ccSTony Hutter 	return (count == 0 ? 0 : total / count);
3836dd50e0ccSTony Hutter }
3837dd50e0ccSTony Hutter 
3838dd50e0ccSTony Hutter static void
3839dd50e0ccSTony Hutter print_iostat_queues(iostat_cbdata_t *cb, nvlist_t *oldnv,
3840dd50e0ccSTony Hutter     nvlist_t *newnv)
3841dd50e0ccSTony Hutter {
3842dd50e0ccSTony Hutter 	int i;
3843dd50e0ccSTony Hutter 	uint64_t val;
3844dd50e0ccSTony Hutter 	const char *names[] = {
3845dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_SYNC_R_PEND_QUEUE,
3846dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE,
3847dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_SYNC_W_PEND_QUEUE,
3848dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE,
3849dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_ASYNC_R_PEND_QUEUE,
3850dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE,
3851dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_ASYNC_W_PEND_QUEUE,
3852dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE,
3853dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_SCRUB_PEND_QUEUE,
3854dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE,
3855dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_TRIM_PEND_QUEUE,
3856dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_TRIM_ACTIVE_QUEUE,
3857dd50e0ccSTony Hutter 	};
3858dd50e0ccSTony Hutter 
3859dd50e0ccSTony Hutter 	struct stat_array *nva;
3860dd50e0ccSTony Hutter 
3861dd50e0ccSTony Hutter 	unsigned int column_width = default_column_width(cb, IOS_QUEUES);
3862dd50e0ccSTony Hutter 	enum zfs_nicenum_format format;
3863dd50e0ccSTony Hutter 
3864dd50e0ccSTony Hutter 	nva = calc_and_alloc_stats_ex(names, ARRAY_SIZE(names), NULL, newnv);
3865dd50e0ccSTony Hutter 
3866dd50e0ccSTony Hutter 	if (cb->cb_literal)
3867dd50e0ccSTony Hutter 		format = ZFS_NICENUM_RAW;
3868dd50e0ccSTony Hutter 	else
3869dd50e0ccSTony Hutter 		format = ZFS_NICENUM_1024;
3870dd50e0ccSTony Hutter 
3871dd50e0ccSTony Hutter 	for (i = 0; i < ARRAY_SIZE(names); i++) {
3872dd50e0ccSTony Hutter 		val = nva[i].data[0];
3873dd50e0ccSTony Hutter 		print_one_stat(val, format, column_width, cb->cb_scripted);
3874dd50e0ccSTony Hutter 	}
3875dd50e0ccSTony Hutter 
3876dd50e0ccSTony Hutter 	free_calc_stats(nva, ARRAY_SIZE(names));
3877dd50e0ccSTony Hutter }
3878dd50e0ccSTony Hutter 
3879dd50e0ccSTony Hutter static void
3880dd50e0ccSTony Hutter print_iostat_latency(iostat_cbdata_t *cb, nvlist_t *oldnv,
3881dd50e0ccSTony Hutter     nvlist_t *newnv)
3882dd50e0ccSTony Hutter {
3883dd50e0ccSTony Hutter 	int i;
3884dd50e0ccSTony Hutter 	uint64_t val;
3885dd50e0ccSTony Hutter 	const char *names[] = {
3886dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO,
3887dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO,
3888dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO,
3889dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO,
3890dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO,
3891dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO,
3892dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO,
3893dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO,
3894dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO,
3895dd50e0ccSTony Hutter 		ZPOOL_CONFIG_VDEV_TRIM_LAT_HISTO,
3896dd50e0ccSTony Hutter 	};
3897dd50e0ccSTony Hutter 	struct stat_array *nva;
3898dd50e0ccSTony Hutter 
3899dd50e0ccSTony Hutter 	unsigned int column_width = default_column_width(cb, IOS_LATENCY);
3900dd50e0ccSTony Hutter 	enum zfs_nicenum_format format;
3901dd50e0ccSTony Hutter 
3902dd50e0ccSTony Hutter 	nva = calc_and_alloc_stats_ex(names, ARRAY_SIZE(names), oldnv, newnv);
3903dd50e0ccSTony Hutter 
3904dd50e0ccSTony Hutter 	if (cb->cb_literal)
3905dd50e0ccSTony Hutter 		format = ZFS_NICENUM_RAWTIME;
3906dd50e0ccSTony Hutter 	else
3907dd50e0ccSTony Hutter 		format = ZFS_NICENUM_TIME;
3908dd50e0ccSTony Hutter 
3909dd50e0ccSTony Hutter 	/* Print our avg latencies on the line */
3910dd50e0ccSTony Hutter 	for (i = 0; i < ARRAY_SIZE(names); i++) {
3911dd50e0ccSTony Hutter 		/* Compute average latency for a latency histo */
3912dd50e0ccSTony Hutter 		val = single_histo_average(nva[i].data, nva[i].count);
3913dd50e0ccSTony Hutter 		print_one_stat(val, format, column_width, cb->cb_scripted);
3914dd50e0ccSTony Hutter 	}
3915dd50e0ccSTony Hutter 	free_calc_stats(nva, ARRAY_SIZE(names));
3916dd50e0ccSTony Hutter }
3917dd50e0ccSTony Hutter 
3918dd50e0ccSTony Hutter /*
3919dd50e0ccSTony Hutter  * Print default statistics (capacity/operations/bandwidth)
3920dd50e0ccSTony Hutter  */
3921dd50e0ccSTony Hutter static void
3922dd50e0ccSTony Hutter print_iostat_default(vdev_stat_t *vs, iostat_cbdata_t *cb, double scale)
3923dd50e0ccSTony Hutter {
3924dd50e0ccSTony Hutter 	unsigned int column_width = default_column_width(cb, IOS_DEFAULT);
3925dd50e0ccSTony Hutter 	enum zfs_nicenum_format format;
3926dd50e0ccSTony Hutter 	char na;	/* char to print for "not applicable" values */
3927dd50e0ccSTony Hutter 
3928dd50e0ccSTony Hutter 	if (cb->cb_literal) {
3929dd50e0ccSTony Hutter 		format = ZFS_NICENUM_RAW;
3930dd50e0ccSTony Hutter 		na = '0';
3931dd50e0ccSTony Hutter 	} else {
3932dd50e0ccSTony Hutter 		format = ZFS_NICENUM_1024;
3933dd50e0ccSTony Hutter 		na = '-';
3934dd50e0ccSTony Hutter 	}
3935dd50e0ccSTony Hutter 
3936dd50e0ccSTony Hutter 	/* only toplevel vdevs have capacity stats */
3937dd50e0ccSTony Hutter 	if (vs->vs_space == 0) {
3938dd50e0ccSTony Hutter 		if (cb->cb_scripted)
3939dd50e0ccSTony Hutter 			printf("\t%c\t%c", na, na);
3940dd50e0ccSTony Hutter 		else
3941dd50e0ccSTony Hutter 			printf("  %*c  %*c", column_width, na, column_width,
3942dd50e0ccSTony Hutter 			    na);
3943dd50e0ccSTony Hutter 	} else {
3944dd50e0ccSTony Hutter 		print_one_stat(vs->vs_alloc, format, column_width,
3945dd50e0ccSTony Hutter 		    cb->cb_scripted);
3946dd50e0ccSTony Hutter 		print_one_stat(vs->vs_space - vs->vs_alloc, format,
3947dd50e0ccSTony Hutter 		    column_width, cb->cb_scripted);
3948dd50e0ccSTony Hutter 	}
3949dd50e0ccSTony Hutter 
3950dd50e0ccSTony Hutter 	print_one_stat((uint64_t)(vs->vs_ops[ZIO_TYPE_READ] * scale),
3951dd50e0ccSTony Hutter 	    format, column_width, cb->cb_scripted);
3952dd50e0ccSTony Hutter 	print_one_stat((uint64_t)(vs->vs_ops[ZIO_TYPE_WRITE] * scale),
3953dd50e0ccSTony Hutter 	    format, column_width, cb->cb_scripted);
3954dd50e0ccSTony Hutter 	print_one_stat((uint64_t)(vs->vs_bytes[ZIO_TYPE_READ] * scale),
3955dd50e0ccSTony Hutter 	    format, column_width, cb->cb_scripted);
3956dd50e0ccSTony Hutter 	print_one_stat((uint64_t)(vs->vs_bytes[ZIO_TYPE_WRITE] * scale),
3957dd50e0ccSTony Hutter 	    format, column_width, cb->cb_scripted);
3958dd50e0ccSTony Hutter }
3959dd50e0ccSTony Hutter 
3960dd50e0ccSTony Hutter static const char *class_name[] = {
3961dd50e0ccSTony Hutter 	VDEV_ALLOC_BIAS_DEDUP,
3962dd50e0ccSTony Hutter 	VDEV_ALLOC_BIAS_SPECIAL,
3963dd50e0ccSTony Hutter 	VDEV_ALLOC_CLASS_LOGS
3964dd50e0ccSTony Hutter };
3965dd50e0ccSTony Hutter 
3966dd50e0ccSTony Hutter /*
3967dd50e0ccSTony Hutter  * Print out all the statistics for the given vdev.  This can either be the
3968dd50e0ccSTony Hutter  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
3969dd50e0ccSTony Hutter  * is a verbose output, and we don't want to display the toplevel pool stats.
3970dd50e0ccSTony Hutter  *
3971dd50e0ccSTony Hutter  * Returns the number of stat lines printed.
3972dd50e0ccSTony Hutter  */
3973dd50e0ccSTony Hutter unsigned int
3974dd50e0ccSTony Hutter print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
3975dd50e0ccSTony Hutter     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
3976dd50e0ccSTony Hutter {
3977dd50e0ccSTony Hutter 	nvlist_t **oldchild, **newchild;
3978dd50e0ccSTony Hutter 	uint_t c, children, oldchildren;
3979dd50e0ccSTony Hutter 	vdev_stat_t *oldvs, *newvs, *calcvs;
3980dd50e0ccSTony Hutter 	vdev_stat_t zerovs = { 0 };
3981dd50e0ccSTony Hutter 	char *vname;
3982dd50e0ccSTony Hutter 	int i;
3983dd50e0ccSTony Hutter 	int ret = 0;
3984dd50e0ccSTony Hutter 	uint64_t tdelta;
3985dd50e0ccSTony Hutter 	double scale;
3986dd50e0ccSTony Hutter 
3987dd50e0ccSTony Hutter 	if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
3988dd50e0ccSTony Hutter 		return (0);
3989dd50e0ccSTony Hutter 
3990dd50e0ccSTony Hutter 	calcvs = safe_malloc(sizeof (*calcvs));
3991dd50e0ccSTony Hutter 
3992dd50e0ccSTony Hutter 	if (oldnv != NULL) {
3993dd50e0ccSTony Hutter 		verify(nvlist_lookup_uint64_array(oldnv,
3994dd50e0ccSTony Hutter 		    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
3995dd50e0ccSTony Hutter 	} else {
3996dd50e0ccSTony Hutter 		oldvs = &zerovs;
3997dd50e0ccSTony Hutter 	}
3998dd50e0ccSTony Hutter 
3999dd50e0ccSTony Hutter 	/* Do we only want to see a specific vdev? */
4000dd50e0ccSTony Hutter 	for (i = 0; i < cb->cb_vdev_names_count; i++) {
4001dd50e0ccSTony Hutter 		/* Yes we do.  Is this the vdev? */
4002dd50e0ccSTony Hutter 		if (strcmp(name, cb->cb_vdev_names[i]) == 0) {
4003dd50e0ccSTony Hutter 			/*
4004dd50e0ccSTony Hutter 			 * This is our vdev.  Since it is the only vdev we
4005dd50e0ccSTony Hutter 			 * will be displaying, make depth = 0 so that it
4006dd50e0ccSTony Hutter 			 * doesn't get indented.
4007dd50e0ccSTony Hutter 			 */
4008dd50e0ccSTony Hutter 			depth = 0;
4009dd50e0ccSTony Hutter 			break;
4010dd50e0ccSTony Hutter 		}
4011dd50e0ccSTony Hutter 	}
4012dd50e0ccSTony Hutter 
4013dd50e0ccSTony Hutter 	if (cb->cb_vdev_names_count && (i == cb->cb_vdev_names_count)) {
4014dd50e0ccSTony Hutter 		/* Couldn't match the name */
4015dd50e0ccSTony Hutter 		goto children;
4016dd50e0ccSTony Hutter 	}
4017dd50e0ccSTony Hutter 
4018dd50e0ccSTony Hutter 
4019dd50e0ccSTony Hutter 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
4020dd50e0ccSTony Hutter 	    (uint64_t **)&newvs, &c) == 0);
4021dd50e0ccSTony Hutter 
4022dd50e0ccSTony Hutter 	/*
4023dd50e0ccSTony Hutter 	 * Print the vdev name unless it's is a histogram.  Histograms
4024dd50e0ccSTony Hutter 	 * display the vdev name in the header itself.
4025dd50e0ccSTony Hutter 	 */
4026dd50e0ccSTony Hutter 	if (!(cb->cb_flags & IOS_ANYHISTO_M)) {
4027dd50e0ccSTony Hutter 		if (cb->cb_scripted) {
4028dd50e0ccSTony Hutter 			printf("%s", name);
4029dd50e0ccSTony Hutter 		} else {
4030dd50e0ccSTony Hutter 			if (strlen(name) + depth > cb->cb_namewidth)
4031dd50e0ccSTony Hutter 				(void) printf("%*s%s", depth, "", name);
4032dd50e0ccSTony Hutter 			else
4033dd50e0ccSTony Hutter 				(void) printf("%*s%s%*s", depth, "", name,
4034dd50e0ccSTony Hutter 				    (int)(cb->cb_namewidth - strlen(name) -
4035dd50e0ccSTony Hutter 				    depth), "");
4036dd50e0ccSTony Hutter 		}
4037dd50e0ccSTony Hutter 	}
4038dd50e0ccSTony Hutter 
4039dd50e0ccSTony Hutter 	/* Calculate our scaling factor */
4040dd50e0ccSTony Hutter 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
4041dd50e0ccSTony Hutter 	if ((oldvs->vs_timestamp == 0) && (cb->cb_flags & IOS_ANYHISTO_M)) {
4042dd50e0ccSTony Hutter 		/*
4043dd50e0ccSTony Hutter 		 * If we specify printing histograms with no time interval, then
4044dd50e0ccSTony Hutter 		 * print the histogram numbers over the entire lifetime of the
4045dd50e0ccSTony Hutter 		 * vdev.
4046dd50e0ccSTony Hutter 		 */
4047dd50e0ccSTony Hutter 		scale = 1;
4048dd50e0ccSTony Hutter 	} else {
4049dd50e0ccSTony Hutter 		if (tdelta == 0)
4050dd50e0ccSTony Hutter 			scale = 1.0;
4051dd50e0ccSTony Hutter 		else
4052dd50e0ccSTony Hutter 			scale = (double)NANOSEC / tdelta;
4053dd50e0ccSTony Hutter 	}
4054dd50e0ccSTony Hutter 
4055dd50e0ccSTony Hutter 	if (cb->cb_flags & IOS_DEFAULT_M) {
4056dd50e0ccSTony Hutter 		calc_default_iostats(oldvs, newvs, calcvs);
4057dd50e0ccSTony Hutter 		print_iostat_default(calcvs, cb, scale);
4058dd50e0ccSTony Hutter 	}
4059dd50e0ccSTony Hutter 	if (cb->cb_flags & IOS_LATENCY_M)
4060dd50e0ccSTony Hutter 		print_iostat_latency(cb, oldnv, newnv);
4061dd50e0ccSTony Hutter 	if (cb->cb_flags & IOS_QUEUES_M)
4062dd50e0ccSTony Hutter 		print_iostat_queues(cb, oldnv, newnv);
4063dd50e0ccSTony Hutter 	if (cb->cb_flags & IOS_ANYHISTO_M) {
4064dd50e0ccSTony Hutter 		printf("\n");
4065dd50e0ccSTony Hutter 		print_iostat_histos(cb, oldnv, newnv, scale, name);
4066dd50e0ccSTony Hutter 	}
4067dd50e0ccSTony Hutter 
4068dd50e0ccSTony Hutter 	if (!(cb->cb_flags & IOS_ANYHISTO_M))
4069dd50e0ccSTony Hutter 		printf("\n");
4070dd50e0ccSTony Hutter 
4071dd50e0ccSTony Hutter 	ret++;
4072dd50e0ccSTony Hutter 
4073dd50e0ccSTony Hutter children:
4074dd50e0ccSTony Hutter 
4075dd50e0ccSTony Hutter 	free(calcvs);
4076dd50e0ccSTony Hutter 
4077dd50e0ccSTony Hutter 	if (!cb->cb_verbose)
4078dd50e0ccSTony Hutter 		return (ret);
4079dd50e0ccSTony Hutter 
4080dd50e0ccSTony Hutter 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
4081dd50e0ccSTony Hutter 	    &newchild, &children) != 0)
4082dd50e0ccSTony Hutter 		return (ret);
4083dd50e0ccSTony Hutter 
4084dd50e0ccSTony Hutter 	if (oldnv) {
4085dd50e0ccSTony Hutter 		if (nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
4086dd50e0ccSTony Hutter 		    &oldchild, &oldchildren) != 0)
4087dd50e0ccSTony Hutter 			return (ret);
4088dd50e0ccSTony Hutter 
4089dd50e0ccSTony Hutter 		children = MIN(oldchildren, children);
4090dd50e0ccSTony Hutter 	}
4091dd50e0ccSTony Hutter 
4092dd50e0ccSTony Hutter 	/*
4093dd50e0ccSTony Hutter 	 * print normal top-level devices
4094dd50e0ccSTony Hutter 	 */
4095dd50e0ccSTony Hutter 	for (c = 0; c < children; c++) {
4096dd50e0ccSTony Hutter 		uint64_t ishole = B_FALSE, islog = B_FALSE;
4097dd50e0ccSTony Hutter 
4098dd50e0ccSTony Hutter 		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
4099dd50e0ccSTony Hutter 		    &ishole);
4100dd50e0ccSTony Hutter 
4101dd50e0ccSTony Hutter 		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
4102dd50e0ccSTony Hutter 		    &islog);
4103dd50e0ccSTony Hutter 
4104dd50e0ccSTony Hutter 		if (ishole || islog)
4105dd50e0ccSTony Hutter 			continue;
4106dd50e0ccSTony Hutter 
4107dd50e0ccSTony Hutter 		if (nvlist_exists(newchild[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
4108dd50e0ccSTony Hutter 			continue;
4109dd50e0ccSTony Hutter 
4110dd50e0ccSTony Hutter 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
4111dd50e0ccSTony Hutter 		    cb->cb_name_flags);
4112dd50e0ccSTony Hutter 		ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
4113dd50e0ccSTony Hutter 		    newchild[c], cb, depth + 2);
4114dd50e0ccSTony Hutter 		free(vname);
4115dd50e0ccSTony Hutter 	}
4116dd50e0ccSTony Hutter 
4117dd50e0ccSTony Hutter 	/*
4118dd50e0ccSTony Hutter 	 * print all other top-level devices
4119dd50e0ccSTony Hutter 	 */
4120dd50e0ccSTony Hutter 	for (uint_t n = 0; n < 3; n++) {
4121dd50e0ccSTony Hutter 		boolean_t printed = B_FALSE;
4122dd50e0ccSTony Hutter 
4123dd50e0ccSTony Hutter 		for (c = 0; c < children; c++) {
4124dd50e0ccSTony Hutter 			uint64_t islog = B_FALSE;
4125dd50e0ccSTony Hutter 			char *bias = NULL;
4126dd50e0ccSTony Hutter 			char *type = NULL;
4127dd50e0ccSTony Hutter 
4128dd50e0ccSTony Hutter 			(void) nvlist_lookup_uint64(newchild[c],
4129dd50e0ccSTony Hutter 			    ZPOOL_CONFIG_IS_LOG, &islog);
4130dd50e0ccSTony Hutter 			if (islog) {
4131dd50e0ccSTony Hutter 				bias = VDEV_ALLOC_CLASS_LOGS;
4132dd50e0ccSTony Hutter 			} else {
4133dd50e0ccSTony Hutter 				(void) nvlist_lookup_string(newchild[c],
4134dd50e0ccSTony Hutter 				    ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
4135dd50e0ccSTony Hutter 				(void) nvlist_lookup_string(newchild[c],
4136dd50e0ccSTony Hutter 				    ZPOOL_CONFIG_TYPE, &type);
4137dd50e0ccSTony Hutter 			}
4138dd50e0ccSTony Hutter 			if (bias == NULL || strcmp(bias, class_name[n]) != 0)
4139dd50e0ccSTony Hutter 				continue;
4140dd50e0ccSTony Hutter 			if (!islog && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
4141dd50e0ccSTony Hutter 				continue;
4142dd50e0ccSTony Hutter 
4143dd50e0ccSTony Hutter 			if (!printed) {
4144dd50e0ccSTony Hutter 				if ((!(cb->cb_flags & IOS_ANYHISTO_M)) &&
4145dd50e0ccSTony Hutter 				    !cb->cb_scripted && !cb->cb_vdev_names) {
4146dd50e0ccSTony Hutter 					print_iostat_dashes(cb, 0,
4147dd50e0ccSTony Hutter 					    class_name[n]);
4148dd50e0ccSTony Hutter 				}
4149dd50e0ccSTony Hutter 				printf("\n");
4150dd50e0ccSTony Hutter 				printed = B_TRUE;
4151dd50e0ccSTony Hutter 			}
4152dd50e0ccSTony Hutter 
4153dd50e0ccSTony Hutter 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
4154dd50e0ccSTony Hutter 			    cb->cb_name_flags);
4155dd50e0ccSTony Hutter 			ret += print_vdev_stats(zhp, vname, oldnv ?
4156dd50e0ccSTony Hutter 			    oldchild[c] : NULL, newchild[c], cb, depth + 2);
4157dd50e0ccSTony Hutter 			free(vname);
4158dd50e0ccSTony Hutter 		}
4159dd50e0ccSTony Hutter 
4160dd50e0ccSTony Hutter 	}
4161dd50e0ccSTony Hutter 
4162dd50e0ccSTony Hutter 	/*
4163dd50e0ccSTony Hutter 	 * Include level 2 ARC devices in iostat output
4164dd50e0ccSTony Hutter 	 */
4165dd50e0ccSTony Hutter 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
4166dd50e0ccSTony Hutter 	    &newchild, &children) != 0)
4167dd50e0ccSTony Hutter 		return (ret);
4168dd50e0ccSTony Hutter 
4169dd50e0ccSTony Hutter 	if (oldnv) {
4170dd50e0ccSTony Hutter 		if (nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
4171dd50e0ccSTony Hutter 		    &oldchild, &oldchildren) != 0)
4172dd50e0ccSTony Hutter 			return (ret);
4173dd50e0ccSTony Hutter 
4174dd50e0ccSTony Hutter 		children = MIN(oldchildren, children);
4175dd50e0ccSTony Hutter 	}
4176dd50e0ccSTony Hutter 
4177dd50e0ccSTony Hutter 	if (children > 0) {
4178dd50e0ccSTony Hutter 		if ((!(cb->cb_flags & IOS_ANYHISTO_M)) && !cb->cb_scripted &&
4179dd50e0ccSTony Hutter 		    !cb->cb_vdev_names) {
4180dd50e0ccSTony Hutter 			print_iostat_dashes(cb, 0, "cache");
4181dd50e0ccSTony Hutter 		}
4182dd50e0ccSTony Hutter 		printf("\n");
4183dd50e0ccSTony Hutter 
4184dd50e0ccSTony Hutter 		for (c = 0; c < children; c++) {
4185dd50e0ccSTony Hutter 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
4186dd50e0ccSTony Hutter 			    cb->cb_name_flags);
4187dd50e0ccSTony Hutter 			ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c]
4188dd50e0ccSTony Hutter 			    : NULL, newchild[c], cb, depth + 2);
4189dd50e0ccSTony Hutter 			free(vname);
4190dd50e0ccSTony Hutter 		}
4191dd50e0ccSTony Hutter 	}
4192dd50e0ccSTony Hutter 
4193dd50e0ccSTony Hutter 	return (ret);
4194dd50e0ccSTony Hutter }
4195dd50e0ccSTony Hutter 
4196dd50e0ccSTony Hutter static int
4197dd50e0ccSTony Hutter refresh_iostat(zpool_handle_t *zhp, void *data)
4198dd50e0ccSTony Hutter {
4199dd50e0ccSTony Hutter 	iostat_cbdata_t *cb = data;
4200dd50e0ccSTony Hutter 	boolean_t missing;
4201dd50e0ccSTony Hutter 
4202dd50e0ccSTony Hutter 	/*
4203dd50e0ccSTony Hutter 	 * If the pool has disappeared, remove it from the list and continue.
4204dd50e0ccSTony Hutter 	 */
4205dd50e0ccSTony Hutter 	if (zpool_refresh_stats(zhp, &missing) != 0)
4206dd50e0ccSTony Hutter 		return (-1);
4207dd50e0ccSTony Hutter 
4208dd50e0ccSTony Hutter 	if (missing)
4209dd50e0ccSTony Hutter 		pool_list_remove(cb->cb_list, zhp);
4210dd50e0ccSTony Hutter 
4211dd50e0ccSTony Hutter 	return (0);
4212dd50e0ccSTony Hutter }
4213dd50e0ccSTony Hutter 
4214dd50e0ccSTony Hutter /*
4215dd50e0ccSTony Hutter  * Callback to print out the iostats for the given pool.
4216dd50e0ccSTony Hutter  */
4217dd50e0ccSTony Hutter int
4218dd50e0ccSTony Hutter print_iostat(zpool_handle_t *zhp, void *data)
4219dd50e0ccSTony Hutter {
4220dd50e0ccSTony Hutter 	iostat_cbdata_t *cb = data;
4221dd50e0ccSTony Hutter 	nvlist_t *oldconfig, *newconfig;
4222dd50e0ccSTony Hutter 	nvlist_t *oldnvroot, *newnvroot;
4223dd50e0ccSTony Hutter 	int ret;
4224dd50e0ccSTony Hutter 
4225dd50e0ccSTony Hutter 	newconfig = zpool_get_config(zhp, &oldconfig);
4226dd50e0ccSTony Hutter 
4227dd50e0ccSTony Hutter 	if (cb->cb_iteration == 1)
4228dd50e0ccSTony Hutter 		oldconfig = NULL;
4229dd50e0ccSTony Hutter 
4230dd50e0ccSTony Hutter 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
4231dd50e0ccSTony Hutter 	    &newnvroot) == 0);
4232dd50e0ccSTony Hutter 
4233dd50e0ccSTony Hutter 	if (oldconfig == NULL)
4234dd50e0ccSTony Hutter 		oldnvroot = NULL;
4235dd50e0ccSTony Hutter 	else
4236dd50e0ccSTony Hutter 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
4237dd50e0ccSTony Hutter 		    &oldnvroot) == 0);
4238dd50e0ccSTony Hutter 
4239dd50e0ccSTony Hutter 	ret = print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot,
4240dd50e0ccSTony Hutter 	    cb, 0);
4241dd50e0ccSTony Hutter 	if ((ret != 0) && !(cb->cb_flags & IOS_ANYHISTO_M) &&
4242dd50e0ccSTony Hutter 	    !cb->cb_scripted && cb->cb_verbose && !cb->cb_vdev_names_count) {
4243dd50e0ccSTony Hutter 		print_iostat_separator(cb);
4244dd50e0ccSTony Hutter 		printf("\n");
4245dd50e0ccSTony Hutter 	}
4246dd50e0ccSTony Hutter 
4247dd50e0ccSTony Hutter 	return (ret);
4248dd50e0ccSTony Hutter }
4249dd50e0ccSTony Hutter 
4250dd50e0ccSTony Hutter static int
4251dd50e0ccSTony Hutter get_columns(void)
4252dd50e0ccSTony Hutter {
4253dd50e0ccSTony Hutter 	struct winsize ws;
4254dd50e0ccSTony Hutter 	int columns = 80;
4255dd50e0ccSTony Hutter 	int error;
4256dd50e0ccSTony Hutter 
4257dd50e0ccSTony Hutter 	if (isatty(STDOUT_FILENO)) {
4258dd50e0ccSTony Hutter 		error = ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
4259dd50e0ccSTony Hutter 		if (error == 0)
4260dd50e0ccSTony Hutter 			columns = ws.ws_col;
4261dd50e0ccSTony Hutter 	} else {
4262dd50e0ccSTony Hutter 		columns = 999;
4263dd50e0ccSTony Hutter 	}
4264dd50e0ccSTony Hutter 
4265dd50e0ccSTony Hutter 	return (columns);
4266dd50e0ccSTony Hutter }
4267dd50e0ccSTony Hutter 
4268dd50e0ccSTony Hutter /*
4269dd50e0ccSTony Hutter  * Return the required length of the pool/vdev name column.  The minimum
4270dd50e0ccSTony Hutter  * allowed width and output formatting flags must be provided.
4271dd50e0ccSTony Hutter  */
4272dd50e0ccSTony Hutter static int
4273dd50e0ccSTony Hutter get_namewidth(zpool_handle_t *zhp, int min_width, int flags, boolean_t verbose)
4274dd50e0ccSTony Hutter {
4275dd50e0ccSTony Hutter 	nvlist_t *config, *nvroot;
4276dd50e0ccSTony Hutter 	int width = min_width;
4277dd50e0ccSTony Hutter 
4278dd50e0ccSTony Hutter 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
4279dd50e0ccSTony Hutter 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
4280dd50e0ccSTony Hutter 		    &nvroot) == 0);
4281dd50e0ccSTony Hutter 		unsigned int poolname_len = strlen(zpool_get_name(zhp));
4282dd50e0ccSTony Hutter 		if (verbose == B_FALSE) {
4283dd50e0ccSTony Hutter 			width = MAX(poolname_len, min_width);
4284dd50e0ccSTony Hutter 		} else {
4285dd50e0ccSTony Hutter 			width = MAX(poolname_len,
4286dd50e0ccSTony Hutter 			    max_width(zhp, nvroot, 0, min_width, flags));
4287dd50e0ccSTony Hutter 		}
4288dd50e0ccSTony Hutter 	}
4289dd50e0ccSTony Hutter 
4290dd50e0ccSTony Hutter 	return (width);
4291dd50e0ccSTony Hutter }
4292dd50e0ccSTony Hutter 
4293dd50e0ccSTony Hutter /*
4294dd50e0ccSTony Hutter  * Parse the input string, get the 'interval' and 'count' value if there is one.
4295dd50e0ccSTony Hutter  */
4296dd50e0ccSTony Hutter static void
4297dd50e0ccSTony Hutter get_interval_count(int *argcp, char **argv, float *iv,
4298dd50e0ccSTony Hutter     unsigned long *cnt)
4299dd50e0ccSTony Hutter {
4300dd50e0ccSTony Hutter 	float interval = 0;
4301dd50e0ccSTony Hutter 	unsigned long count = 0;
4302dd50e0ccSTony Hutter 	int argc = *argcp, errno;
4303dd50e0ccSTony Hutter 
4304dd50e0ccSTony Hutter 	/*
4305dd50e0ccSTony Hutter 	 * Determine if the last argument is an integer or a pool name
4306dd50e0ccSTony Hutter 	 */
4307dd50e0ccSTony Hutter 	if (argc > 0 && isnumber(argv[argc - 1])) {
4308dd50e0ccSTony Hutter 		char *end;
4309dd50e0ccSTony Hutter 
4310dd50e0ccSTony Hutter 		errno = 0;
4311dd50e0ccSTony Hutter 		interval = strtof(argv[argc - 1], &end);
4312dd50e0ccSTony Hutter 
4313dd50e0ccSTony Hutter 		if (*end == '\0' && errno == 0) {
4314dd50e0ccSTony Hutter 			if (interval == 0) {
4315dd50e0ccSTony Hutter 				(void) fprintf(stderr, gettext("interval "
4316dd50e0ccSTony Hutter 				    "cannot be zero\n"));
4317dd50e0ccSTony Hutter 				usage(B_FALSE);
4318dd50e0ccSTony Hutter 			}
4319dd50e0ccSTony Hutter 			/*
4320dd50e0ccSTony Hutter 			 * Ignore the last parameter
4321dd50e0ccSTony Hutter 			 */
4322dd50e0ccSTony Hutter 			argc--;
4323dd50e0ccSTony Hutter 		} else {
4324dd50e0ccSTony Hutter 			/*
4325dd50e0ccSTony Hutter 			 * If this is not a valid number, just plow on.  The
4326dd50e0ccSTony Hutter 			 * user will get a more informative error message later
4327dd50e0ccSTony Hutter 			 * on.
4328dd50e0ccSTony Hutter 			 */
4329dd50e0ccSTony Hutter 			interval = 0;
4330dd50e0ccSTony Hutter 		}
4331dd50e0ccSTony Hutter 	}
4332dd50e0ccSTony Hutter 
4333dd50e0ccSTony Hutter 	/*
4334dd50e0ccSTony Hutter 	 * If the last argument is also an integer, then we have both a count
4335dd50e0ccSTony Hutter 	 * and an interval.
4336dd50e0ccSTony Hutter 	 */
4337dd50e0ccSTony Hutter 	if (argc > 0 && isnumber(argv[argc - 1])) {
4338dd50e0ccSTony Hutter 		char *end;
4339dd50e0ccSTony Hutter 
4340dd50e0ccSTony Hutter 		errno = 0;
4341dd50e0ccSTony Hutter 		count = interval;
4342dd50e0ccSTony Hutter 		interval = strtof(argv[argc - 1], &end);
4343dd50e0ccSTony Hutter 
4344dd50e0ccSTony Hutter 		if (*end == '\0' && errno == 0) {
4345dd50e0ccSTony Hutter 			if (interval == 0) {
4346dd50e0ccSTony Hutter 				(void) fprintf(stderr, gettext("interval "
4347dd50e0ccSTony Hutter 				    "cannot be zero\n"));
4348dd50e0ccSTony Hutter 				usage(B_FALSE);
4349dd50e0ccSTony Hutter 			}
4350dd50e0ccSTony Hutter 
4351dd50e0ccSTony Hutter 			/*
4352dd50e0ccSTony Hutter 			 * Ignore the last parameter
4353dd50e0ccSTony Hutter 			 */
4354dd50e0ccSTony Hutter 			argc--;
4355dd50e0ccSTony Hutter 		} else {
4356dd50e0ccSTony Hutter 			interval = 0;
4357dd50e0ccSTony Hutter 		}
4358dd50e0ccSTony Hutter 	}
4359fa9e4066Sahrens 
4360dd50e0ccSTony Hutter 	*iv = interval;
4361dd50e0ccSTony Hutter 	*cnt = count;
4362dd50e0ccSTony Hutter 	*argcp = argc;
4363dd50e0ccSTony Hutter }
4364dd50e0ccSTony Hutter 
4365dd50e0ccSTony Hutter static void
4366dd50e0ccSTony Hutter get_timestamp_arg(char c)
4367dd50e0ccSTony Hutter {
4368dd50e0ccSTony Hutter 	if (c == 'u')
4369dd50e0ccSTony Hutter 		timestamp_fmt = UDATE;
4370dd50e0ccSTony Hutter 	else if (c == 'd')
4371dd50e0ccSTony Hutter 		timestamp_fmt = DDATE;
4372dd50e0ccSTony Hutter 	else
4373dd50e0ccSTony Hutter 		usage(B_FALSE);
4374dd50e0ccSTony Hutter }
4375dd50e0ccSTony Hutter 
4376dd50e0ccSTony Hutter /*
4377dd50e0ccSTony Hutter  * Return stat flags that are supported by all pools by both the module and
4378dd50e0ccSTony Hutter  * zpool iostat.  "*data" should be initialized to all 0xFFs before running.
4379dd50e0ccSTony Hutter  * It will get ANDed down until only the flags that are supported on all pools
4380dd50e0ccSTony Hutter  * remain.
4381dd50e0ccSTony Hutter  */
4382dd50e0ccSTony Hutter static int
4383dd50e0ccSTony Hutter get_stat_flags_cb(zpool_handle_t *zhp, void *data)
4384dd50e0ccSTony Hutter {
4385dd50e0ccSTony Hutter 	uint64_t *mask = data;
4386dd50e0ccSTony Hutter 	nvlist_t *config, *nvroot, *nvx;
4387dd50e0ccSTony Hutter 	uint64_t flags = 0;
4388dd50e0ccSTony Hutter 	int i, j;
4389dd50e0ccSTony Hutter 
4390dd50e0ccSTony Hutter 	config = zpool_get_config(zhp, NULL);
4391dd50e0ccSTony Hutter 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
4392dd50e0ccSTony Hutter 	    &nvroot) == 0);
4393dd50e0ccSTony Hutter 
4394dd50e0ccSTony Hutter 	/* Default stats are always supported, but for completeness.. */
4395dd50e0ccSTony Hutter 	if (nvlist_exists(nvroot, ZPOOL_CONFIG_VDEV_STATS))
4396dd50e0ccSTony Hutter 		flags |= IOS_DEFAULT_M;
4397dd50e0ccSTony Hutter 
4398dd50e0ccSTony Hutter 	/* Get our extended stats nvlist from the main list */
4399dd50e0ccSTony Hutter 	if (nvlist_lookup_nvlist(nvroot, ZPOOL_CONFIG_VDEV_STATS_EX,
4400dd50e0ccSTony Hutter 	    &nvx) != 0) {
4401dd50e0ccSTony Hutter 		/*
4402dd50e0ccSTony Hutter 		 * No extended stats; they're probably running an older
4403dd50e0ccSTony Hutter 		 * module.  No big deal, we support that too.
4404dd50e0ccSTony Hutter 		 */
4405dd50e0ccSTony Hutter 		goto end;
4406dd50e0ccSTony Hutter 	}
4407dd50e0ccSTony Hutter 
4408dd50e0ccSTony Hutter 	/* For each extended stat, make sure all its nvpairs are supported */
4409dd50e0ccSTony Hutter 	for (j = 0; j < ARRAY_SIZE(vsx_type_to_nvlist); j++) {
4410dd50e0ccSTony Hutter 		if (!vsx_type_to_nvlist[j][0])
4411dd50e0ccSTony Hutter 			continue;
4412dd50e0ccSTony Hutter 
4413dd50e0ccSTony Hutter 		/* Start off by assuming the flag is supported, then check */
4414dd50e0ccSTony Hutter 		flags |= (1ULL << j);
4415dd50e0ccSTony Hutter 		for (i = 0; vsx_type_to_nvlist[j][i]; i++) {
4416dd50e0ccSTony Hutter 			if (!nvlist_exists(nvx, vsx_type_to_nvlist[j][i])) {
4417dd50e0ccSTony Hutter 				/* flag isn't supported */
4418dd50e0ccSTony Hutter 				flags = flags & ~(1ULL  << j);
4419dd50e0ccSTony Hutter 				break;
4420dd50e0ccSTony Hutter 			}
4421dd50e0ccSTony Hutter 		}
4422dd50e0ccSTony Hutter 	}
4423dd50e0ccSTony Hutter end:
4424dd50e0ccSTony Hutter 	*mask = *mask & flags;
4425fa9e4066Sahrens 	return (0);
4426fa9e4066Sahrens }
4427fa9e4066Sahrens 
4428dd50e0ccSTony Hutter /*
4429dd50e0ccSTony Hutter  * Return a bitmask of stats that are supported on all pools by both the module
4430dd50e0ccSTony Hutter  * and zpool iostat.
4431dd50e0ccSTony Hutter  */
4432dd50e0ccSTony Hutter static uint64_t
4433dd50e0ccSTony Hutter get_stat_flags(zpool_list_t *list)
4434dd50e0ccSTony Hutter {
4435dd50e0ccSTony Hutter 	uint64_t mask = -1;
4436dd50e0ccSTony Hutter 
4437dd50e0ccSTony Hutter 	/*
4438dd50e0ccSTony Hutter 	 * get_stat_flags_cb() will lop off bits from "mask" until only the
4439dd50e0ccSTony Hutter 	 * flags that are supported on all pools remain.
4440dd50e0ccSTony Hutter 	 */
4441dd50e0ccSTony Hutter 	(void) pool_list_iter(list, B_FALSE, get_stat_flags_cb, &mask);
4442dd50e0ccSTony Hutter 	return (mask);
4443dd50e0ccSTony Hutter }
4444dd50e0ccSTony Hutter 
4445dd50e0ccSTony Hutter /*
4446dd50e0ccSTony Hutter  * Return 1 if cb_data->cb_vdev_names[0] is this vdev's name, 0 otherwise.
4447dd50e0ccSTony Hutter  */
4448dd50e0ccSTony Hutter static int
4449dd50e0ccSTony Hutter is_vdev_cb(zpool_handle_t *zhp, nvlist_t *nv, void *cb_data)
4450dd50e0ccSTony Hutter {
4451dd50e0ccSTony Hutter 	iostat_cbdata_t *cb = cb_data;
4452dd50e0ccSTony Hutter 	char *name;
4453dd50e0ccSTony Hutter 
4454dd50e0ccSTony Hutter 	name = zpool_vdev_name(g_zfs, zhp, nv, cb->cb_name_flags);
4455dd50e0ccSTony Hutter 
4456dd50e0ccSTony Hutter 	if (strcmp(name, cb->cb_vdev_names[0]) == 0)
4457dd50e0ccSTony Hutter 		return (1); /* match */
4458dd50e0ccSTony Hutter 
4459dd50e0ccSTony Hutter 	return (0);
4460dd50e0ccSTony Hutter }
4461dd50e0ccSTony Hutter 
4462dd50e0ccSTony Hutter /*
4463dd50e0ccSTony Hutter  * Returns 1 if cb_data->cb_vdev_names[0] is a vdev name, 0 otherwise.
4464dd50e0ccSTony Hutter  */
4465dd50e0ccSTony Hutter static int
4466dd50e0ccSTony Hutter is_vdev(zpool_handle_t *zhp, void *cb_data)
4467dd50e0ccSTony Hutter {
4468dd50e0ccSTony Hutter 	return (for_each_vdev(zhp, is_vdev_cb, cb_data));
4469dd50e0ccSTony Hutter }
4470dd50e0ccSTony Hutter 
4471dd50e0ccSTony Hutter /*
4472dd50e0ccSTony Hutter  * Check if vdevs are in a pool
4473dd50e0ccSTony Hutter  *
4474dd50e0ccSTony Hutter  * Return 1 if all argv[] strings are vdev names in pool "pool_name". Otherwise
4475dd50e0ccSTony Hutter  * return 0.  If pool_name is NULL, then search all pools.
4476dd50e0ccSTony Hutter  */
4477dd50e0ccSTony Hutter static int
4478dd50e0ccSTony Hutter are_vdevs_in_pool(int argc, char **argv, char *pool_name,
4479dd50e0ccSTony Hutter     iostat_cbdata_t *cb)
4480fa9e4066Sahrens {
4481dd50e0ccSTony Hutter 	char **tmp_name;
4482dd50e0ccSTony Hutter 	int ret = 0;
4483dd50e0ccSTony Hutter 	int i;
4484dd50e0ccSTony Hutter 	int pool_count = 0;
4485fa9e4066Sahrens 
4486dd50e0ccSTony Hutter 	if ((argc == 0) || !*argv)
4487dd50e0ccSTony Hutter 		return (0);
4488dd50e0ccSTony Hutter 
4489dd50e0ccSTony Hutter 	if (pool_name)
4490dd50e0ccSTony Hutter 		pool_count = 1;
4491dd50e0ccSTony Hutter 
4492dd50e0ccSTony Hutter 	/* Temporarily hijack cb_vdev_names for a second... */
4493dd50e0ccSTony Hutter 	tmp_name = cb->cb_vdev_names;
4494dd50e0ccSTony Hutter 
4495dd50e0ccSTony Hutter 	/* Go though our list of prospective vdev names */
4496dd50e0ccSTony Hutter 	for (i = 0; i < argc; i++) {
4497dd50e0ccSTony Hutter 		cb->cb_vdev_names = argv + i;
4498dd50e0ccSTony Hutter 
4499dd50e0ccSTony Hutter 		/* Is this name a vdev in our pools? */
4500dd50e0ccSTony Hutter 		ret = for_each_pool(pool_count, &pool_name, B_TRUE, NULL,
4501dd50e0ccSTony Hutter 		    is_vdev, cb);
4502dd50e0ccSTony Hutter 		if (!ret) {
4503dd50e0ccSTony Hutter 			/* No match */
4504dd50e0ccSTony Hutter 			break;
4505dd50e0ccSTony Hutter 		}
4506fa9e4066Sahrens 	}
4507fa9e4066Sahrens 
4508dd50e0ccSTony Hutter 	cb->cb_vdev_names = tmp_name;
4509dd50e0ccSTony Hutter 
4510dd50e0ccSTony Hutter 	return (ret);
4511dd50e0ccSTony Hutter }
4512dd50e0ccSTony Hutter 
4513dd50e0ccSTony Hutter static int
4514dd50e0ccSTony Hutter is_pool_cb(zpool_handle_t *zhp, void *data)
4515dd50e0ccSTony Hutter {
4516dd50e0ccSTony Hutter 	char *name = data;
4517dd50e0ccSTony Hutter 	if (strcmp(name, zpool_get_name(zhp)) == 0)
4518dd50e0ccSTony Hutter 		return (1);
4519fa9e4066Sahrens 
4520fa9e4066Sahrens 	return (0);
4521fa9e4066Sahrens }
4522fa9e4066Sahrens 
4523fa9e4066Sahrens /*
4524dd50e0ccSTony Hutter  * Do we have a pool named *name?  If so, return 1, otherwise 0.
4525fa9e4066Sahrens  */
4526dd50e0ccSTony Hutter static int
4527dd50e0ccSTony Hutter is_pool(char *name)
4528fa9e4066Sahrens {
4529dd50e0ccSTony Hutter 	return (for_each_pool(0, NULL, B_TRUE, NULL,  is_pool_cb, name));
4530dd50e0ccSTony Hutter }
4531fa9e4066Sahrens 
4532dd50e0ccSTony Hutter /* Are all our argv[] strings pool names?  If so return 1, 0 otherwise. */
4533dd50e0ccSTony Hutter static int
4534dd50e0ccSTony Hutter are_all_pools(int argc, char **argv)
4535dd50e0ccSTony Hutter {
4536dd50e0ccSTony Hutter 	if ((argc == 0) || !*argv)
4537dd50e0ccSTony Hutter 		return (0);
4538fa9e4066Sahrens 
4539dd50e0ccSTony Hutter 	while (--argc >= 0)
4540dd50e0ccSTony Hutter 		if (!is_pool(argv[argc]))
4541dd50e0ccSTony Hutter 			return (0);
4542fa9e4066Sahrens 
4543dd50e0ccSTony Hutter 	return (1);
4544dd50e0ccSTony Hutter }
4545fa9e4066Sahrens 
4546dd50e0ccSTony Hutter /*
4547dd50e0ccSTony Hutter  * Helper function to print out vdev/pool names we can't resolve.  Used for an
4548dd50e0ccSTony Hutter  * error message.
4549dd50e0ccSTony Hutter  */
4550dd50e0ccSTony Hutter static void
4551dd50e0ccSTony Hutter error_list_unresolved_vdevs(int argc, char **argv, char *pool_name,
4552dd50e0ccSTony Hutter     iostat_cbdata_t *cb)
4553dd50e0ccSTony Hutter {
4554dd50e0ccSTony Hutter 	int i;
4555dd50e0ccSTony Hutter 	char *name;
4556dd50e0ccSTony Hutter 	char *str;
4557dd50e0ccSTony Hutter 	for (i = 0; i < argc; i++) {
4558dd50e0ccSTony Hutter 		name = argv[i];
4559dd50e0ccSTony Hutter 
4560dd50e0ccSTony Hutter 		if (is_pool(name))
4561dd50e0ccSTony Hutter 			str = gettext("pool");
4562dd50e0ccSTony Hutter 		else if (are_vdevs_in_pool(1, &name, pool_name, cb))
4563dd50e0ccSTony Hutter 			str = gettext("vdev in this pool");
4564dd50e0ccSTony Hutter 		else if (are_vdevs_in_pool(1, &name, NULL, cb))
4565dd50e0ccSTony Hutter 			str = gettext("vdev in another pool");
4566dd50e0ccSTony Hutter 		else
4567dd50e0ccSTony Hutter 			str = gettext("unknown");
4568fa9e4066Sahrens 
4569dd50e0ccSTony Hutter 		fprintf(stderr, "\t%s (%s)\n", name, str);
4570dd50e0ccSTony Hutter 	}
4571dd50e0ccSTony Hutter }
4572fa9e4066Sahrens 
4573dd50e0ccSTony Hutter /*
4574dd50e0ccSTony Hutter  * Same as get_interval_count(), but with additional checks to not misinterpret
4575dd50e0ccSTony Hutter  * guids as interval/count values.  Assumes VDEV_NAME_GUID is set in
4576dd50e0ccSTony Hutter  * cb.cb_name_flags.
4577dd50e0ccSTony Hutter  */
4578dd50e0ccSTony Hutter static void
4579dd50e0ccSTony Hutter get_interval_count_filter_guids(int *argc, char **argv, float *interval,
4580dd50e0ccSTony Hutter     unsigned long *count, iostat_cbdata_t *cb)
4581dd50e0ccSTony Hutter {
4582dd50e0ccSTony Hutter 	char **tmpargv = argv;
4583dd50e0ccSTony Hutter 	int argc_for_interval = 0;
4584dd50e0ccSTony Hutter 
4585dd50e0ccSTony Hutter 	/* Is the last arg an interval value?  Or a guid? */
4586dd50e0ccSTony Hutter 	if (*argc >= 1 && !are_vdevs_in_pool(1, &argv[*argc - 1], NULL, cb)) {
4587dd50e0ccSTony Hutter 		/*
4588dd50e0ccSTony Hutter 		 * The last arg is not a guid, so it's probably an
4589dd50e0ccSTony Hutter 		 * interval value.
4590dd50e0ccSTony Hutter 		 */
4591dd50e0ccSTony Hutter 		argc_for_interval++;
4592fa9e4066Sahrens 
4593dd50e0ccSTony Hutter 		if (*argc >= 2 &&
4594dd50e0ccSTony Hutter 		    !are_vdevs_in_pool(1, &argv[*argc - 2], NULL, cb)) {
4595fa9e4066Sahrens 			/*
4596dd50e0ccSTony Hutter 			 * The 2nd to last arg is not a guid, so it's probably
4597dd50e0ccSTony Hutter 			 * an interval value.
4598fa9e4066Sahrens 			 */
4599dd50e0ccSTony Hutter 			argc_for_interval++;
4600fa9e4066Sahrens 		}
4601fa9e4066Sahrens 	}
4602fa9e4066Sahrens 
4603dd50e0ccSTony Hutter 	/* Point to our list of possible intervals */
4604dd50e0ccSTony Hutter 	tmpargv = &argv[*argc - argc_for_interval];
4605dd50e0ccSTony Hutter 
4606dd50e0ccSTony Hutter 	*argc = *argc - argc_for_interval;
4607dd50e0ccSTony Hutter 	get_interval_count(&argc_for_interval, tmpargv,
4608dd50e0ccSTony Hutter 	    interval, count);
46093f9d6ad7SLin Ling }
46103f9d6ad7SLin Ling 
4611dd50e0ccSTony Hutter /*
4612dd50e0ccSTony Hutter  * Floating point sleep().  Allows you to pass in a floating point value for
4613dd50e0ccSTony Hutter  * seconds.
4614dd50e0ccSTony Hutter  */
46153f9d6ad7SLin Ling static void
4616dd50e0ccSTony Hutter fsleep(float sec)
46173f9d6ad7SLin Ling {
4618dd50e0ccSTony Hutter 	struct timespec req;
4619dd50e0ccSTony Hutter 	req.tv_sec = floor(sec);
4620dd50e0ccSTony Hutter 	req.tv_nsec = (sec - (float)req.tv_sec) * NANOSEC;
4621dd50e0ccSTony Hutter 	(void) nanosleep(&req, NULL);
4622dd50e0ccSTony Hutter }
4623dd50e0ccSTony Hutter 
4624dd50e0ccSTony Hutter /*
4625dd50e0ccSTony Hutter  * Set the minimum pool/vdev name column width.  The width must be at least 10,
4626dd50e0ccSTony Hutter  * but may be as large as the column width - 42 so it still fits on one line.
4627dd50e0ccSTony Hutter  */
4628dd50e0ccSTony Hutter static int
4629dd50e0ccSTony Hutter get_namewidth_iostat(zpool_handle_t *zhp, void *data)
4630dd50e0ccSTony Hutter {
4631dd50e0ccSTony Hutter 	iostat_cbdata_t *cb = data;
4632dd50e0ccSTony Hutter 	int width, columns;
4633dd50e0ccSTony Hutter 
4634dd50e0ccSTony Hutter 	width = get_namewidth(zhp, cb->cb_namewidth, cb->cb_name_flags,
4635dd50e0ccSTony Hutter 	    cb->cb_verbose);
4636dd50e0ccSTony Hutter 	columns = get_columns();
4637dd50e0ccSTony Hutter 
4638dd50e0ccSTony Hutter 	if (width < 10)
4639dd50e0ccSTony Hutter 		width = 10;
4640dd50e0ccSTony Hutter 	if (width > columns - 42)
4641dd50e0ccSTony Hutter 		width = columns - 42;
4642dd50e0ccSTony Hutter 
4643dd50e0ccSTony Hutter 	cb->cb_namewidth = width;
4644dd50e0ccSTony Hutter 
4645dd50e0ccSTony Hutter 	return (0);
46463f9d6ad7SLin Ling }
46473f9d6ad7SLin Ling 
46483f9d6ad7SLin Ling /*
4649dd50e0ccSTony Hutter  * zpool iostat [-ghHLpPvy] [[-lq]|[-r|-w]] [-n name] [-T d|u]
4650dd50e0ccSTony Hutter  *		[[ pool ...]|[pool vdev ...]|[vdev ...]]
4651dd50e0ccSTony Hutter  *		[interval [count]]
46523f9d6ad7SLin Ling  *
4653663207adSDon Brady  *	-g	Display guid for individual vdev name.
4654663207adSDon Brady  *	-L	Follow links when resolving vdev path name.
4655663207adSDon Brady  *	-P	Display full path for vdev name.
46563f9d6ad7SLin Ling  *	-v	Display statistics for individual vdevs
4657dd50e0ccSTony Hutter  *	-h	Display help
4658dd50e0ccSTony Hutter  *	-p	Display values in parsable (exact) format.
4659dd50e0ccSTony Hutter  *	-H	Scripted mode.  Don't display headers, and separate properties
4660dd50e0ccSTony Hutter  *		by a single tab.
4661dd50e0ccSTony Hutter  *	-l	Display average latency
4662dd50e0ccSTony Hutter  *	-q	Display queue depths
4663dd50e0ccSTony Hutter  *	-w	Display latency histograms
4664dd50e0ccSTony Hutter  *	-r	Display request size histogram
46653f9d6ad7SLin Ling  *	-T	Display a timestamp in date(1) or Unix format
4666dd50e0ccSTony Hutter  *	-n	Only print headers once
46673f9d6ad7SLin Ling  *
46683f9d6ad7SLin Ling  * This command can be tricky because we want to be able to deal with pool
46693f9d6ad7SLin Ling  * creation/destruction as well as vdev configuration changes.  The bulk of this
46703f9d6ad7SLin Ling  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
46713f9d6ad7SLin Ling  * on pool_list_update() to detect the addition of new pools.  Configuration
46723f9d6ad7SLin Ling  * changes are all handled within libzfs.
46733f9d6ad7SLin Ling  */
46743f9d6ad7SLin Ling int
46753f9d6ad7SLin Ling zpool_do_iostat(int argc, char **argv)
46763f9d6ad7SLin Ling {
46773f9d6ad7SLin Ling 	int c;
46783f9d6ad7SLin Ling 	int ret;
46793f9d6ad7SLin Ling 	int npools;
4680dd50e0ccSTony Hutter 	float interval = 0;
4681dd50e0ccSTony Hutter 	unsigned long count = 0;
4682dd50e0ccSTony Hutter 	int winheight = 24;
4683dd50e0ccSTony Hutter 	struct winsize win;
46843f9d6ad7SLin Ling 	zpool_list_t *list;
46853f9d6ad7SLin Ling 	boolean_t verbose = B_FALSE;
4686dd50e0ccSTony Hutter 	boolean_t latency = B_FALSE, l_histo = B_FALSE, rq_histo = B_FALSE;
4687dd50e0ccSTony Hutter 	boolean_t queues = B_FALSE, parseable = B_FALSE, scripted = B_FALSE;
4688dd50e0ccSTony Hutter 	boolean_t omit_since_boot = B_FALSE;
4689663207adSDon Brady 	boolean_t guid = B_FALSE;
4690663207adSDon Brady 	boolean_t follow_links = B_FALSE;
4691663207adSDon Brady 	boolean_t full_name = B_FALSE;
4692dd50e0ccSTony Hutter 	boolean_t headers_once = B_FALSE;
4693663207adSDon Brady 	iostat_cbdata_t cb = { 0 };
46943f9d6ad7SLin Ling 
4695dd50e0ccSTony Hutter 	/* Used for printing error message */
4696dd50e0ccSTony Hutter 	const char flag_to_arg[] = {[IOS_LATENCY] = 'l', [IOS_QUEUES] = 'q',
4697dd50e0ccSTony Hutter 	    [IOS_L_HISTO] = 'w', [IOS_RQ_HISTO] = 'r'};
4698dd50e0ccSTony Hutter 
4699dd50e0ccSTony Hutter 	uint64_t unsupported_flags;
4700dd50e0ccSTony Hutter 
47013f9d6ad7SLin Ling 	/* check options */
4702dd50e0ccSTony Hutter 	while ((c = getopt(argc, argv, "gLPT:vyhplqrwnH")) != -1) {
47033f9d6ad7SLin Ling 		switch (c) {
4704663207adSDon Brady 		case 'g':
4705663207adSDon Brady 			guid = B_TRUE;
4706663207adSDon Brady 			break;
4707663207adSDon Brady 		case 'L':
4708663207adSDon Brady 			follow_links = B_TRUE;
4709663207adSDon Brady 			break;
4710663207adSDon Brady 		case 'P':
4711663207adSDon Brady 			full_name = B_TRUE;
4712663207adSDon Brady 			break;
47133f9d6ad7SLin Ling 		case 'T':
47143f9d6ad7SLin Ling 			get_timestamp_arg(*optarg);
47153f9d6ad7SLin Ling 			break;
47163f9d6ad7SLin Ling 		case 'v':
47173f9d6ad7SLin Ling 			verbose = B_TRUE;
47183f9d6ad7SLin Ling 			break;
4719dd50e0ccSTony Hutter 		case 'p':
4720dd50e0ccSTony Hutter 			parseable = B_TRUE;
4721dd50e0ccSTony Hutter 			break;
4722dd50e0ccSTony Hutter 		case 'l':
4723dd50e0ccSTony Hutter 			latency = B_TRUE;
4724dd50e0ccSTony Hutter 			break;
4725dd50e0ccSTony Hutter 		case 'q':
4726dd50e0ccSTony Hutter 			queues = B_TRUE;
4727dd50e0ccSTony Hutter 			break;
4728dd50e0ccSTony Hutter 		case 'H':
4729dd50e0ccSTony Hutter 			scripted = B_TRUE;
4730dd50e0ccSTony Hutter 			break;
4731dd50e0ccSTony Hutter 		case 'w':
4732dd50e0ccSTony Hutter 			l_histo = B_TRUE;
4733dd50e0ccSTony Hutter 			break;
4734dd50e0ccSTony Hutter 		case 'r':
4735dd50e0ccSTony Hutter 			rq_histo = B_TRUE;
4736dd50e0ccSTony Hutter 			break;
4737dd50e0ccSTony Hutter 		case 'y':
4738dd50e0ccSTony Hutter 			omit_since_boot = B_TRUE;
4739dd50e0ccSTony Hutter 			break;
4740dd50e0ccSTony Hutter 		case 'n':
4741dd50e0ccSTony Hutter 			headers_once = B_TRUE;
4742dd50e0ccSTony Hutter 			break;
4743dd50e0ccSTony Hutter 		case 'h':
4744dd50e0ccSTony Hutter 			usage(B_FALSE);
4745dd50e0ccSTony Hutter 			break;
47463f9d6ad7SLin Ling 		case '?':
47473f9d6ad7SLin Ling 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
47483f9d6ad7SLin Ling 			    optopt);
47493f9d6ad7SLin Ling 			usage(B_FALSE);
47503f9d6ad7SLin Ling 		}
47513f9d6ad7SLin Ling 	}
47523f9d6ad7SLin Ling 
47533f9d6ad7SLin Ling 	argc -= optind;
47543f9d6ad7SLin Ling 	argv += optind;
47553f9d6ad7SLin Ling 
4756dd50e0ccSTony Hutter 	cb.cb_literal = parseable;
4757dd50e0ccSTony Hutter 	cb.cb_scripted = scripted;
4758dd50e0ccSTony Hutter 
4759dd50e0ccSTony Hutter 	if (guid)
4760dd50e0ccSTony Hutter 		cb.cb_name_flags |= VDEV_NAME_GUID;
4761dd50e0ccSTony Hutter 	if (follow_links)
4762dd50e0ccSTony Hutter 		cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
4763dd50e0ccSTony Hutter 	if (full_name)
4764dd50e0ccSTony Hutter 		cb.cb_name_flags |= VDEV_NAME_PATH;
4765dd50e0ccSTony Hutter 	cb.cb_iteration = 0;
4766dd50e0ccSTony Hutter 	cb.cb_namewidth = 0;
4767dd50e0ccSTony Hutter 	cb.cb_verbose = verbose;
4768dd50e0ccSTony Hutter 
4769dd50e0ccSTony Hutter 	/* Get our interval and count values (if any) */
4770dd50e0ccSTony Hutter 	if (guid) {
4771dd50e0ccSTony Hutter 		get_interval_count_filter_guids(&argc, argv, &interval,
4772dd50e0ccSTony Hutter 		    &count, &cb);
4773dd50e0ccSTony Hutter 	} else {
4774dd50e0ccSTony Hutter 		get_interval_count(&argc, argv, &interval, &count);
4775dd50e0ccSTony Hutter 	}
4776dd50e0ccSTony Hutter 
4777dd50e0ccSTony Hutter 	if (argc == 0) {
4778dd50e0ccSTony Hutter 		/* No args, so just print the defaults. */
4779dd50e0ccSTony Hutter 	} else if (are_all_pools(argc, argv)) {
4780dd50e0ccSTony Hutter 		/* All the args are pool names */
4781dd50e0ccSTony Hutter 	} else if (are_vdevs_in_pool(argc, argv, NULL, &cb)) {
4782dd50e0ccSTony Hutter 		/* All the args are vdevs */
4783dd50e0ccSTony Hutter 		cb.cb_vdev_names = argv;
4784dd50e0ccSTony Hutter 		cb.cb_vdev_names_count = argc;
4785dd50e0ccSTony Hutter 		argc = 0; /* No pools to process */
4786dd50e0ccSTony Hutter 	} else if (are_all_pools(1, argv)) {
4787dd50e0ccSTony Hutter 		/* The first arg is a pool name */
4788dd50e0ccSTony Hutter 		if (are_vdevs_in_pool(argc - 1, argv + 1, argv[0], &cb)) {
4789dd50e0ccSTony Hutter 			/* ...and the rest are vdev names */
4790dd50e0ccSTony Hutter 			cb.cb_vdev_names = argv + 1;
4791dd50e0ccSTony Hutter 			cb.cb_vdev_names_count = argc - 1;
4792dd50e0ccSTony Hutter 			argc = 1; /* One pool to process */
4793dd50e0ccSTony Hutter 		} else {
4794dd50e0ccSTony Hutter 			fprintf(stderr, gettext("Expected either a list of "));
4795dd50e0ccSTony Hutter 			fprintf(stderr, gettext("pools, or list of vdevs in"));
4796dd50e0ccSTony Hutter 			fprintf(stderr, " \"%s\", ", argv[0]);
4797dd50e0ccSTony Hutter 			fprintf(stderr, gettext("but got:\n"));
4798dd50e0ccSTony Hutter 			error_list_unresolved_vdevs(argc - 1, argv + 1,
4799dd50e0ccSTony Hutter 			    argv[0], &cb);
4800dd50e0ccSTony Hutter 			fprintf(stderr, "\n");
4801dd50e0ccSTony Hutter 			usage(B_FALSE);
4802dd50e0ccSTony Hutter 			return (1);
4803dd50e0ccSTony Hutter 		}
4804dd50e0ccSTony Hutter 	} else {
4805dd50e0ccSTony Hutter 		/*
4806dd50e0ccSTony Hutter 		 * The args don't make sense. The first arg isn't a pool name,
4807dd50e0ccSTony Hutter 		 * nor are all the args vdevs.
4808dd50e0ccSTony Hutter 		 */
4809dd50e0ccSTony Hutter 		fprintf(stderr, gettext("Unable to parse pools/vdevs list.\n"));
4810dd50e0ccSTony Hutter 		fprintf(stderr, "\n");
4811dd50e0ccSTony Hutter 		return (1);
4812dd50e0ccSTony Hutter 	}
4813dd50e0ccSTony Hutter 
4814dd50e0ccSTony Hutter 	if (cb.cb_vdev_names_count != 0) {
4815dd50e0ccSTony Hutter 		/*
4816dd50e0ccSTony Hutter 		 * If user specified vdevs, it implies verbose.
4817dd50e0ccSTony Hutter 		 */
4818dd50e0ccSTony Hutter 		cb.cb_verbose = B_TRUE;
4819dd50e0ccSTony Hutter 	}
48203f9d6ad7SLin Ling 
4821fa9e4066Sahrens 	/*
4822fa9e4066Sahrens 	 * Construct the list of all interesting pools.
4823fa9e4066Sahrens 	 */
4824fa9e4066Sahrens 	ret = 0;
4825b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
4826fa9e4066Sahrens 		return (1);
4827fa9e4066Sahrens 
482899653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
482999653d4eSeschrock 		pool_list_free(list);
4830fa9e4066Sahrens 		return (1);
483199653d4eSeschrock 	}
4832fa9e4066Sahrens 
4833fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
483499653d4eSeschrock 		pool_list_free(list);
4835fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
4836fa9e4066Sahrens 		return (1);
4837fa9e4066Sahrens 	}
4838fa9e4066Sahrens 
4839dd50e0ccSTony Hutter 	if ((l_histo || rq_histo) && (queues || latency)) {
4840dd50e0ccSTony Hutter 		pool_list_free(list);
4841dd50e0ccSTony Hutter 		(void) fprintf(stderr,
4842dd50e0ccSTony Hutter 		    gettext("[-r|-w] isn't allowed with [-q|-l]\n"));
4843dd50e0ccSTony Hutter 		usage(B_FALSE);
4844dd50e0ccSTony Hutter 		return (1);
4845dd50e0ccSTony Hutter 	}
4846dd50e0ccSTony Hutter 
4847dd50e0ccSTony Hutter 	if (l_histo && rq_histo) {
4848dd50e0ccSTony Hutter 		pool_list_free(list);
4849dd50e0ccSTony Hutter 		(void) fprintf(stderr,
4850dd50e0ccSTony Hutter 		    gettext("Only one of [-r|-w] can be passed at a time\n"));
4851dd50e0ccSTony Hutter 		usage(B_FALSE);
4852dd50e0ccSTony Hutter 		return (1);
4853dd50e0ccSTony Hutter 	}
4854dd50e0ccSTony Hutter 
4855fa9e4066Sahrens 	/*
4856fa9e4066Sahrens 	 * Enter the main iostat loop.
4857fa9e4066Sahrens 	 */
4858fa9e4066Sahrens 	cb.cb_list = list;
4859fa9e4066Sahrens 
4860dd50e0ccSTony Hutter 	if (l_histo) {
4861dd50e0ccSTony Hutter 		/*
4862dd50e0ccSTony Hutter 		 * Histograms tables look out of place when you try to display
4863dd50e0ccSTony Hutter 		 * them with the other stats, so make a rule that you can only
4864dd50e0ccSTony Hutter 		 * print histograms by themselves.
4865dd50e0ccSTony Hutter 		 */
4866dd50e0ccSTony Hutter 		cb.cb_flags = IOS_L_HISTO_M;
4867dd50e0ccSTony Hutter 	} else if (rq_histo) {
4868dd50e0ccSTony Hutter 		cb.cb_flags = IOS_RQ_HISTO_M;
4869dd50e0ccSTony Hutter 	} else {
4870dd50e0ccSTony Hutter 		cb.cb_flags = IOS_DEFAULT_M;
4871dd50e0ccSTony Hutter 		if (latency)
4872dd50e0ccSTony Hutter 			cb.cb_flags |= IOS_LATENCY_M;
4873dd50e0ccSTony Hutter 		if (queues)
4874dd50e0ccSTony Hutter 			cb.cb_flags |= IOS_QUEUES_M;
4875dd50e0ccSTony Hutter 	}
4876dd50e0ccSTony Hutter 
4877dd50e0ccSTony Hutter 	/*
4878dd50e0ccSTony Hutter 	 * See if the module supports all the stats we want to display.
4879dd50e0ccSTony Hutter 	 */
4880dd50e0ccSTony Hutter 	unsupported_flags = cb.cb_flags & ~get_stat_flags(list);
4881dd50e0ccSTony Hutter 	if (unsupported_flags) {
4882dd50e0ccSTony Hutter 		uint64_t f;
4883dd50e0ccSTony Hutter 		int idx;
4884dd50e0ccSTony Hutter 		fprintf(stderr,
4885dd50e0ccSTony Hutter 		    gettext("The loaded zfs module doesn't support:"));
4886dd50e0ccSTony Hutter 
4887dd50e0ccSTony Hutter 		/* for each bit set in unsupported_flags */
4888dd50e0ccSTony Hutter 		for (f = unsupported_flags; f; f &= ~(1ULL << idx)) {
4889dd50e0ccSTony Hutter 			idx = lowbit64(f) - 1;
4890dd50e0ccSTony Hutter 			fprintf(stderr, " -%c", flag_to_arg[idx]);
4891dd50e0ccSTony Hutter 		}
4892dd50e0ccSTony Hutter 
4893dd50e0ccSTony Hutter 		fprintf(stderr, ".  Try running a newer module.\n"),
4894dd50e0ccSTony Hutter 		    pool_list_free(list);
4895dd50e0ccSTony Hutter 
4896dd50e0ccSTony Hutter 		return (1);
4897dd50e0ccSTony Hutter 	}
4898fa9e4066Sahrens 
4899dd50e0ccSTony Hutter 	for (;;) {
4900fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
4901dd50e0ccSTony Hutter 			(void) fprintf(stderr, gettext("no pools available\n"));
4902dd50e0ccSTony Hutter 		else {
4903dd50e0ccSTony Hutter 			/*
4904dd50e0ccSTony Hutter 			 * If this is the first iteration and -y was supplied
4905dd50e0ccSTony Hutter 			 * we skip any printing.
4906dd50e0ccSTony Hutter 			 */
4907dd50e0ccSTony Hutter 			boolean_t skip = (omit_since_boot &&
4908dd50e0ccSTony Hutter 			    cb.cb_iteration == 0);
4909fa9e4066Sahrens 
4910dd50e0ccSTony Hutter 			/*
4911dd50e0ccSTony Hutter 			 * Refresh all statistics.  This is done as an
4912dd50e0ccSTony Hutter 			 * explicit step before calculating the maximum name
4913dd50e0ccSTony Hutter 			 * width, so that any configuration changes are
4914dd50e0ccSTony Hutter 			 * properly accounted for.
4915dd50e0ccSTony Hutter 			 */
4916dd50e0ccSTony Hutter 			(void) pool_list_iter(list, B_FALSE, refresh_iostat,
4917dd50e0ccSTony Hutter 			    &cb);
4918088e9d47Seschrock 
4919dd50e0ccSTony Hutter 			/*
4920dd50e0ccSTony Hutter 			 * Iterate over all pools to determine the maximum width
4921dd50e0ccSTony Hutter 			 * for the pool / device name column across all pools.
4922dd50e0ccSTony Hutter 			 */
4923dd50e0ccSTony Hutter 			cb.cb_namewidth = 0;
4924dd50e0ccSTony Hutter 			(void) pool_list_iter(list, B_FALSE,
4925dd50e0ccSTony Hutter 			    get_namewidth_iostat, &cb);
4926fa9e4066Sahrens 
4927dd50e0ccSTony Hutter 			if (timestamp_fmt != NODATE)
4928dd50e0ccSTony Hutter 				print_timestamp(timestamp_fmt);
492926fd7700SKrishnendu Sadhukhan - Sun Microsystems 
4930dd50e0ccSTony Hutter 			/*
4931dd50e0ccSTony Hutter 			 * Check terminal size so we can print headers
4932dd50e0ccSTony Hutter 			 * even when terminal window has its height
4933dd50e0ccSTony Hutter 			 * changed.
4934dd50e0ccSTony Hutter 			 */
4935dd50e0ccSTony Hutter 			if (headers_once == B_FALSE) {
4936dd50e0ccSTony Hutter 				if (ioctl(1, TIOCGWINSZ, &win) != -1) {
4937dd50e0ccSTony Hutter 					if (win.ws_row <= 0) {
4938dd50e0ccSTony Hutter 						headers_once = B_TRUE;
4939dd50e0ccSTony Hutter 					} else {
4940dd50e0ccSTony Hutter 						winheight = win.ws_row;
4941dd50e0ccSTony Hutter 					}
4942dd50e0ccSTony Hutter 				}
4943dd50e0ccSTony Hutter 			}
4944dd50e0ccSTony Hutter 			/*
4945dd50e0ccSTony Hutter 			 * Are we connected to TTY? If not, headers_once
4946dd50e0ccSTony Hutter 			 * should be true, to avoid breaking scripts.
4947dd50e0ccSTony Hutter 			 */
4948dd50e0ccSTony Hutter 			if (isatty(fileno(stdout)) == 0)
4949dd50e0ccSTony Hutter 				headers_once = B_TRUE;
4950fa9e4066Sahrens 
4951dd50e0ccSTony Hutter 			/*
4952dd50e0ccSTony Hutter 			 * If it's the first time and we're not skipping it,
4953dd50e0ccSTony Hutter 			 * or either skip or verbose mode, print the header.
4954dd50e0ccSTony Hutter 			 *
4955dd50e0ccSTony Hutter 			 * The histogram code explicitly prints its header on
4956dd50e0ccSTony Hutter 			 * every vdev, so skip this for histograms.
4957dd50e0ccSTony Hutter 			 */
4958dd50e0ccSTony Hutter 			if (((++cb.cb_iteration == 1 && !skip) ||
4959dd50e0ccSTony Hutter 			    (skip != verbose) ||
4960dd50e0ccSTony Hutter 			    (!headers_once &&
4961dd50e0ccSTony Hutter 			    (cb.cb_iteration % winheight) == 0)) &&
4962dd50e0ccSTony Hutter 			    (!(cb.cb_flags & IOS_ANYHISTO_M)) &&
4963dd50e0ccSTony Hutter 			    !cb.cb_scripted)
4964dd50e0ccSTony Hutter 				print_iostat_header(&cb);
4965dd50e0ccSTony Hutter 
4966dd50e0ccSTony Hutter 			if (skip) {
4967dd50e0ccSTony Hutter 				(void) fsleep(interval);
4968dd50e0ccSTony Hutter 				continue;
4969dd50e0ccSTony Hutter 			}
4970fa9e4066Sahrens 
4971dd50e0ccSTony Hutter 			(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
4972fa9e4066Sahrens 
4973dd50e0ccSTony Hutter 			/*
4974dd50e0ccSTony Hutter 			 * If there's more than one pool, and we're not in
4975dd50e0ccSTony Hutter 			 * verbose mode (which prints a separator for us),
4976dd50e0ccSTony Hutter 			 * then print a separator.
4977dd50e0ccSTony Hutter 			 *
4978dd50e0ccSTony Hutter 			 * In addition, if we're printing specific vdevs then
4979dd50e0ccSTony Hutter 			 * we also want an ending separator.
4980dd50e0ccSTony Hutter 			 */
4981dd50e0ccSTony Hutter 			if (((npools > 1 && !verbose &&
4982dd50e0ccSTony Hutter 			    !(cb.cb_flags & IOS_ANYHISTO_M)) ||
4983dd50e0ccSTony Hutter 			    (!(cb.cb_flags & IOS_ANYHISTO_M) &&
4984dd50e0ccSTony Hutter 			    cb.cb_vdev_names_count)) &&
4985dd50e0ccSTony Hutter 			    !cb.cb_scripted) {
4986dd50e0ccSTony Hutter 				print_iostat_separator(&cb);
4987*20f5062bSJerry Jelinek 				printf("\n");
4988dd50e0ccSTony Hutter 			}
4989dd50e0ccSTony Hutter 		}
4990fa9e4066Sahrens 
499139c23413Seschrock 		/*
499239c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
499339c23413Seschrock 		 * indefinitely.
499439c23413Seschrock 		 */
499539c23413Seschrock 		(void) fflush(stdout);
499639c23413Seschrock 
4997fa9e4066Sahrens 		if (interval == 0)
4998fa9e4066Sahrens 			break;
4999fa9e4066Sahrens 
5000fa9e4066Sahrens 		if (count != 0 && --count == 0)
5001fa9e4066Sahrens 			break;
5002fa9e4066Sahrens 
5003dd50e0ccSTony Hutter 		(void) fsleep(interval);
5004fa9e4066Sahrens 	}
5005fa9e4066Sahrens 
5006fa9e4066Sahrens 	pool_list_free(list);
5007fa9e4066Sahrens 
5008fa9e4066Sahrens 	return (ret);
5009fa9e4066Sahrens }
5010fa9e4066Sahrens 
5011fa9e4066Sahrens typedef struct list_cbdata {
50124263d13fSGeorge Wilson 	boolean_t	cb_verbose;
5013663207adSDon Brady 	int		cb_name_flags;
50144263d13fSGeorge Wilson 	int		cb_namewidth;
501599653d4eSeschrock 	boolean_t	cb_scripted;
5016990b4856Slling 	zprop_list_t	*cb_proplist;
5017c58b3526SAdam Stevko 	boolean_t	cb_literal;
5018fa9e4066Sahrens } list_cbdata_t;
5019fa9e4066Sahrens 
5020663207adSDon Brady 
5021fa9e4066Sahrens /*
5022fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
5023fa9e4066Sahrens  */
5024990b4856Slling static void
50254263d13fSGeorge Wilson print_header(list_cbdata_t *cb)
5026fa9e4066Sahrens {
50274263d13fSGeorge Wilson 	zprop_list_t *pl = cb->cb_proplist;
5028ad135b5dSChristopher Siden 	char headerbuf[ZPOOL_MAXPROPLEN];
5029990b4856Slling 	const char *header;
5030990b4856Slling 	boolean_t first = B_TRUE;
5031990b4856Slling 	boolean_t right_justify;
50324263d13fSGeorge Wilson 	size_t width = 0;
5033990b4856Slling 
5034990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
50354263d13fSGeorge Wilson 		width = pl->pl_width;
50364263d13fSGeorge Wilson 		if (first && cb->cb_verbose) {
50374263d13fSGeorge Wilson 			/*
50384263d13fSGeorge Wilson 			 * Reset the width to accommodate the verbose listing
50394263d13fSGeorge Wilson 			 * of devices.
50404263d13fSGeorge Wilson 			 */
50414263d13fSGeorge Wilson 			width = cb->cb_namewidth;
50424263d13fSGeorge Wilson 		}
50434263d13fSGeorge Wilson 
5044990b4856Slling 		if (!first)
5045fa9e4066Sahrens 			(void) printf("  ");
5046fa9e4066Sahrens 		else
5047990b4856Slling 			first = B_FALSE;
5048990b4856Slling 
5049ad135b5dSChristopher Siden 		right_justify = B_FALSE;
5050ad135b5dSChristopher Siden 		if (pl->pl_prop != ZPROP_INVAL) {
5051ad135b5dSChristopher Siden 			header = zpool_prop_column_name(pl->pl_prop);
5052ad135b5dSChristopher Siden 			right_justify = zpool_prop_align_right(pl->pl_prop);
5053ad135b5dSChristopher Siden 		} else {
5054ad135b5dSChristopher Siden 			int i;
5055ad135b5dSChristopher Siden 
5056ad135b5dSChristopher Siden 			for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
5057ad135b5dSChristopher Siden 				headerbuf[i] = toupper(pl->pl_user_prop[i]);
5058ad135b5dSChristopher Siden 			headerbuf[i] = '\0';
5059ad135b5dSChristopher Siden 			header = headerbuf;
5060ad135b5dSChristopher Siden 		}
5061fa9e4066Sahrens 
5062990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
5063990b4856Slling 			(void) printf("%s", header);
5064990b4856Slling 		else if (right_justify)
50654263d13fSGeorge Wilson 			(void) printf("%*s", width, header);
5066990b4856Slling 		else
50674263d13fSGeorge Wilson 			(void) printf("%-*s", width, header);
50684263d13fSGeorge Wilson 
5069fa9e4066Sahrens 	}
5070fa9e4066Sahrens 
5071fa9e4066Sahrens 	(void) printf("\n");
5072fa9e4066Sahrens }
5073fa9e4066Sahrens 
5074990b4856Slling /*
5075990b4856Slling  * Given a pool and a list of properties, print out all the properties according
5076663207adSDon Brady  * to the described layout. Used by zpool_do_list().
5077990b4856Slling  */
5078990b4856Slling static void
50794263d13fSGeorge Wilson print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
5080fa9e4066Sahrens {
50814263d13fSGeorge Wilson 	zprop_list_t *pl = cb->cb_proplist;
5082990b4856Slling 	boolean_t first = B_TRUE;
5083990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
5084990b4856Slling 	char *propstr;
5085990b4856Slling 	boolean_t right_justify;
50864263d13fSGeorge Wilson 	size_t width;
5087990b4856Slling 
5088990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
50894263d13fSGeorge Wilson 
50904263d13fSGeorge Wilson 		width = pl->pl_width;
50914263d13fSGeorge Wilson 		if (first && cb->cb_verbose) {
50924263d13fSGeorge Wilson 			/*
50934263d13fSGeorge Wilson 			 * Reset the width to accommodate the verbose listing
50944263d13fSGeorge Wilson 			 * of devices.
50954263d13fSGeorge Wilson 			 */
50964263d13fSGeorge Wilson 			width = cb->cb_namewidth;
50974263d13fSGeorge Wilson 		}
50984263d13fSGeorge Wilson 
5099990b4856Slling 		if (!first) {
51004263d13fSGeorge Wilson 			if (cb->cb_scripted)
5101fa9e4066Sahrens 				(void) printf("\t");
5102fa9e4066Sahrens 			else
5103fa9e4066Sahrens 				(void) printf("  ");
5104990b4856Slling 		} else {
5105990b4856Slling 			first = B_FALSE;
5106fa9e4066Sahrens 		}
5107fa9e4066Sahrens 
5108990b4856Slling 		right_justify = B_FALSE;
5109990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
51107a09f97bSGeorge Wilson 			if (zpool_get_prop(zhp, pl->pl_prop, property,
5111c58b3526SAdam Stevko 			    sizeof (property), NULL, cb->cb_literal) != 0)
5112990b4856Slling 				propstr = "-";
5113fa9e4066Sahrens 			else
5114990b4856Slling 				propstr = property;
5115fa9e4066Sahrens 
5116990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
5117ad135b5dSChristopher Siden 		} else if ((zpool_prop_feature(pl->pl_user_prop) ||
5118ad135b5dSChristopher Siden 		    zpool_prop_unsupported(pl->pl_user_prop)) &&
5119ad135b5dSChristopher Siden 		    zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
5120ad135b5dSChristopher Siden 		    sizeof (property)) == 0) {
5121ad135b5dSChristopher Siden 			propstr = property;
5122990b4856Slling 		} else {
5123990b4856Slling 			propstr = "-";
5124990b4856Slling 		}
5125fa9e4066Sahrens 
5126fa9e4066Sahrens 
5127990b4856Slling 		/*
5128990b4856Slling 		 * If this is being called in scripted mode, or if this is the
5129990b4856Slling 		 * last column and it is left-justified, don't include a width
5130990b4856Slling 		 * format specifier.
5131990b4856Slling 		 */
51324263d13fSGeorge Wilson 		if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
5133990b4856Slling 			(void) printf("%s", propstr);
5134990b4856Slling 		else if (right_justify)
5135990b4856Slling 			(void) printf("%*s", width, propstr);
5136990b4856Slling 		else
5137990b4856Slling 			(void) printf("%-*s", width, propstr);
5138990b4856Slling 	}
5139fa9e4066Sahrens 
5140990b4856Slling 	(void) printf("\n");
5141990b4856Slling }
5142fa9e4066Sahrens 
51434263d13fSGeorge Wilson static void
51447a09f97bSGeorge Wilson print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted,
51457a09f97bSGeorge Wilson     boolean_t valid)
51464263d13fSGeorge Wilson {
51474263d13fSGeorge Wilson 	char propval[64];
51484263d13fSGeorge Wilson 	boolean_t fixed;
51494263d13fSGeorge Wilson 	size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
51504263d13fSGeorge Wilson 
51517a09f97bSGeorge Wilson 	switch (prop) {
51527a09f97bSGeorge Wilson 	case ZPOOL_PROP_EXPANDSZ:
515386714001SSerapheim Dimitropoulos 	case ZPOOL_PROP_CHECKPOINT:
51547a09f97bSGeorge Wilson 		if (value == 0)
51557a09f97bSGeorge Wilson 			(void) strlcpy(propval, "-", sizeof (propval));
51567a09f97bSGeorge Wilson 		else
51577a09f97bSGeorge Wilson 			zfs_nicenum(value, propval, sizeof (propval));
51587a09f97bSGeorge Wilson 		break;
51597a09f97bSGeorge Wilson 	case ZPOOL_PROP_FRAGMENTATION:
51607a09f97bSGeorge Wilson 		if (value == ZFS_FRAG_INVALID) {
51617a09f97bSGeorge Wilson 			(void) strlcpy(propval, "-", sizeof (propval));
51627a09f97bSGeorge Wilson 		} else {
51637a09f97bSGeorge Wilson 			(void) snprintf(propval, sizeof (propval), "%llu%%",
51647a09f97bSGeorge Wilson 			    value);
51657a09f97bSGeorge Wilson 		}
51667a09f97bSGeorge Wilson 		break;
51677a09f97bSGeorge Wilson 	case ZPOOL_PROP_CAPACITY:
5168663207adSDon Brady 		(void) snprintf(propval, sizeof (propval),
5169663207adSDon Brady 		    value < 1000 ? "%1.2f%%" : value < 10000 ?
5170663207adSDon Brady 		    "%2.1f%%" : "%3.0f%%", value / 100.0);
51717a09f97bSGeorge Wilson 		break;
51727a09f97bSGeorge Wilson 	default:
51732e4c9986SGeorge Wilson 		zfs_nicenum(value, propval, sizeof (propval));
51747a09f97bSGeorge Wilson 	}
51757a09f97bSGeorge Wilson 
51767a09f97bSGeorge Wilson 	if (!valid)
51777a09f97bSGeorge Wilson 		(void) strlcpy(propval, "-", sizeof (propval));
51784263d13fSGeorge Wilson 
51794263d13fSGeorge Wilson 	if (scripted)
51804263d13fSGeorge Wilson 		(void) printf("\t%s", propval);
51814263d13fSGeorge Wilson 	else
51824263d13fSGeorge Wilson 		(void) printf("  %*s", width, propval);
51834263d13fSGeorge Wilson }
51844263d13fSGeorge Wilson 
5185663207adSDon Brady /*
5186663207adSDon Brady  * print static default line per vdev
5187663207adSDon Brady  */
51884263d13fSGeorge Wilson void
51894263d13fSGeorge Wilson print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
51904263d13fSGeorge Wilson     list_cbdata_t *cb, int depth)
51914263d13fSGeorge Wilson {
51924263d13fSGeorge Wilson 	nvlist_t **child;
51934263d13fSGeorge Wilson 	vdev_stat_t *vs;
51944263d13fSGeorge Wilson 	uint_t c, children;
51954263d13fSGeorge Wilson 	char *vname;
51964263d13fSGeorge Wilson 	boolean_t scripted = cb->cb_scripted;
519752244c09SJohn Wren Kennedy 	uint64_t islog = B_FALSE;
519852244c09SJohn Wren Kennedy 	char *dashes = "%-*s      -      -      -         -      -      -\n";
51994263d13fSGeorge Wilson 
52004263d13fSGeorge Wilson 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
52014263d13fSGeorge Wilson 	    (uint64_t **)&vs, &c) == 0);
52024263d13fSGeorge Wilson 
52034263d13fSGeorge Wilson 	if (name != NULL) {
52047a09f97bSGeorge Wilson 		boolean_t toplevel = (vs->vs_space != 0);
52057a09f97bSGeorge Wilson 		uint64_t cap;
52067a09f97bSGeorge Wilson 
52075cabbc6bSPrashanth Sreenivasa 		if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
52085cabbc6bSPrashanth Sreenivasa 			return;
52095cabbc6bSPrashanth Sreenivasa 
52104263d13fSGeorge Wilson 		if (scripted)
52114263d13fSGeorge Wilson 			(void) printf("\t%s", name);
52124263d13fSGeorge Wilson 		else if (strlen(name) + depth > cb->cb_namewidth)
52134263d13fSGeorge Wilson 			(void) printf("%*s%s", depth, "", name);
52144263d13fSGeorge Wilson 		else
52154263d13fSGeorge Wilson 			(void) printf("%*s%s%*s", depth, "", name,
52164263d13fSGeorge Wilson 			    (int)(cb->cb_namewidth - strlen(name) - depth), "");
52174263d13fSGeorge Wilson 
52187a09f97bSGeorge Wilson 		/*
52197a09f97bSGeorge Wilson 		 * Print the properties for the individual vdevs. Some
52207a09f97bSGeorge Wilson 		 * properties are only applicable to toplevel vdevs. The
52217a09f97bSGeorge Wilson 		 * 'toplevel' boolean value is passed to the print_one_column()
52227a09f97bSGeorge Wilson 		 * to indicate that the value is valid.
52237a09f97bSGeorge Wilson 		 */
52247a09f97bSGeorge Wilson 		print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted,
52257a09f97bSGeorge Wilson 		    toplevel);
52267a09f97bSGeorge Wilson 		print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted,
52277a09f97bSGeorge Wilson 		    toplevel);
52287a09f97bSGeorge Wilson 		print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc,
52297a09f97bSGeorge Wilson 		    scripted, toplevel);
523086714001SSerapheim Dimitropoulos 		print_one_column(ZPOOL_PROP_CHECKPOINT,
523186714001SSerapheim Dimitropoulos 		    vs->vs_checkpoint_space, scripted, toplevel);
52327a09f97bSGeorge Wilson 		print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted,
52337a09f97bSGeorge Wilson 		    B_TRUE);
52347a09f97bSGeorge Wilson 		print_one_column(ZPOOL_PROP_FRAGMENTATION,
52357a09f97bSGeorge Wilson 		    vs->vs_fragmentation, scripted,
52367a09f97bSGeorge Wilson 		    (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel));
52377a09f97bSGeorge Wilson 		cap = (vs->vs_space == 0) ? 0 :
5238663207adSDon Brady 		    (vs->vs_alloc * 10000 / vs->vs_space);
52397a09f97bSGeorge Wilson 		print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel);
52404263d13fSGeorge Wilson 		(void) printf("\n");
52414263d13fSGeorge Wilson 	}
52424263d13fSGeorge Wilson 
52434263d13fSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
52444263d13fSGeorge Wilson 	    &child, &children) != 0)
52454263d13fSGeorge Wilson 		return;
52464263d13fSGeorge Wilson 
5247663207adSDon Brady 	/* list the normal vdevs first */
52484263d13fSGeorge Wilson 	for (c = 0; c < children; c++) {
52494263d13fSGeorge Wilson 		uint64_t ishole = B_FALSE;
52504263d13fSGeorge Wilson 
52514263d13fSGeorge Wilson 		if (nvlist_lookup_uint64(child[c],
52524263d13fSGeorge Wilson 		    ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
52534263d13fSGeorge Wilson 			continue;
52544263d13fSGeorge Wilson 
525552244c09SJohn Wren Kennedy 		if (nvlist_lookup_uint64(child[c],
5256663207adSDon Brady 		    ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog)
525752244c09SJohn Wren Kennedy 			continue;
525852244c09SJohn Wren Kennedy 
5259663207adSDon Brady 		if (nvlist_exists(child[c], ZPOOL_CONFIG_ALLOCATION_BIAS))
5260663207adSDon Brady 			continue;
5261663207adSDon Brady 
5262663207adSDon Brady 		vname = zpool_vdev_name(g_zfs, zhp, child[c],
5263663207adSDon Brady 		    cb->cb_name_flags);
52644263d13fSGeorge Wilson 		print_list_stats(zhp, vname, child[c], cb, depth + 2);
52654263d13fSGeorge Wilson 		free(vname);
52664263d13fSGeorge Wilson 	}
52674263d13fSGeorge Wilson 
5268663207adSDon Brady 	/* list the classes: 'logs', 'dedup', and 'special' */
5269663207adSDon Brady 	for (uint_t n = 0; n < 3; n++) {
5270663207adSDon Brady 		boolean_t printed = B_FALSE;
5271663207adSDon Brady 
527252244c09SJohn Wren Kennedy 		for (c = 0; c < children; c++) {
5273663207adSDon Brady 			char *bias = NULL;
5274663207adSDon Brady 			char *type = NULL;
5275663207adSDon Brady 
527652244c09SJohn Wren Kennedy 			if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
5277663207adSDon Brady 			    &islog) == 0 && islog) {
5278663207adSDon Brady 				bias = VDEV_ALLOC_CLASS_LOGS;
5279663207adSDon Brady 			} else {
5280663207adSDon Brady 				(void) nvlist_lookup_string(child[c],
5281663207adSDon Brady 				    ZPOOL_CONFIG_ALLOCATION_BIAS, &bias);
5282663207adSDon Brady 				(void) nvlist_lookup_string(child[c],
5283663207adSDon Brady 				    ZPOOL_CONFIG_TYPE, &type);
5284663207adSDon Brady 			}
5285663207adSDon Brady 			if (bias == NULL || strcmp(bias, class_name[n]) != 0)
5286663207adSDon Brady 				continue;
5287663207adSDon Brady 			if (!islog && strcmp(type, VDEV_TYPE_INDIRECT) == 0)
528852244c09SJohn Wren Kennedy 				continue;
5289663207adSDon Brady 
5290663207adSDon Brady 			if (!printed) {
5291663207adSDon Brady 				/* LINTED E_SEC_PRINTF_VAR_FMT */
5292663207adSDon Brady 				(void) printf(dashes, cb->cb_namewidth,
5293663207adSDon Brady 				    class_name[n]);
5294663207adSDon Brady 				printed = B_TRUE;
5295663207adSDon Brady 			}
5296663207adSDon Brady 			vname = zpool_vdev_name(g_zfs, zhp, child[c],
5297663207adSDon Brady 			    cb->cb_name_flags);
529852244c09SJohn Wren Kennedy 			print_list_stats(zhp, vname, child[c], cb, depth + 2);
529952244c09SJohn Wren Kennedy 			free(vname);
530052244c09SJohn Wren Kennedy 		}
530152244c09SJohn Wren Kennedy 	}
530252244c09SJohn Wren Kennedy 
53034263d13fSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
530452244c09SJohn Wren Kennedy 	    &child, &children) == 0 && children > 0) {
530552244c09SJohn Wren Kennedy 		/* LINTED E_SEC_PRINTF_VAR_FMT */
530652244c09SJohn Wren Kennedy 		(void) printf(dashes, cb->cb_namewidth, "cache");
530752244c09SJohn Wren Kennedy 		for (c = 0; c < children; c++) {
5308663207adSDon Brady 			vname = zpool_vdev_name(g_zfs, zhp, child[c],
5309663207adSDon Brady 			    cb->cb_name_flags);
531052244c09SJohn Wren Kennedy 			print_list_stats(zhp, vname, child[c], cb, depth + 2);
531152244c09SJohn Wren Kennedy 			free(vname);
531252244c09SJohn Wren Kennedy 		}
531352244c09SJohn Wren Kennedy 	}
53144263d13fSGeorge Wilson 
531552244c09SJohn Wren Kennedy 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child,
531652244c09SJohn Wren Kennedy 	    &children) == 0 && children > 0) {
531752244c09SJohn Wren Kennedy 		/* LINTED E_SEC_PRINTF_VAR_FMT */
531852244c09SJohn Wren Kennedy 		(void) printf(dashes, cb->cb_namewidth, "spare");
53194263d13fSGeorge Wilson 		for (c = 0; c < children; c++) {
5320663207adSDon Brady 			vname = zpool_vdev_name(g_zfs, zhp, child[c],
5321663207adSDon Brady 			    cb->cb_name_flags);
53224263d13fSGeorge Wilson 			print_list_stats(zhp, vname, child[c], cb, depth + 2);
53234263d13fSGeorge Wilson 			free(vname);
53244263d13fSGeorge Wilson 		}
53254263d13fSGeorge Wilson 	}
53264263d13fSGeorge Wilson }
53274263d13fSGeorge Wilson 
5328990b4856Slling /*
5329990b4856Slling  * Generic callback function to list a pool.
5330990b4856Slling  */
5331990b4856Slling int
5332990b4856Slling list_callback(zpool_handle_t *zhp, void *data)
5333990b4856Slling {
5334990b4856Slling 	list_cbdata_t *cbp = data;
53354263d13fSGeorge Wilson 	nvlist_t *config;
53364263d13fSGeorge Wilson 	nvlist_t *nvroot;
5337fa9e4066Sahrens 
53384263d13fSGeorge Wilson 	config = zpool_get_config(zhp, NULL);
5339fa9e4066Sahrens 
5340663207adSDon Brady 	if (cbp->cb_verbose) {
5341663207adSDon Brady 		config = zpool_get_config(zhp, NULL);
5342663207adSDon Brady 
5343663207adSDon Brady 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
5344663207adSDon Brady 		    &nvroot) == 0);
5345663207adSDon Brady 	}
5346663207adSDon Brady 
5347663207adSDon Brady 	if (cbp->cb_verbose)
5348663207adSDon Brady 		cbp->cb_namewidth = max_width(zhp, nvroot, 0, 0,
5349663207adSDon Brady 		    cbp->cb_name_flags);
5350663207adSDon Brady 
53514263d13fSGeorge Wilson 	print_pool(zhp, cbp);
53524263d13fSGeorge Wilson 
5353663207adSDon Brady 	if (cbp->cb_verbose)
5354663207adSDon Brady 		print_list_stats(zhp, NULL, nvroot, cbp, 0);
5355fa9e4066Sahrens 
5356fa9e4066Sahrens 	return (0);
5357fa9e4066Sahrens }
5358fa9e4066Sahrens 
5359dd50e0ccSTony Hutter /*
5360dd50e0ccSTony Hutter  * Set the minimum pool/vdev name column width.  The width must be at least 9,
5361dd50e0ccSTony Hutter  * but may be as large as needed.
5362dd50e0ccSTony Hutter  */
5363dd50e0ccSTony Hutter static int
5364dd50e0ccSTony Hutter get_namewidth_list(zpool_handle_t *zhp, void *data)
5365dd50e0ccSTony Hutter {
5366dd50e0ccSTony Hutter 	list_cbdata_t *cb = data;
5367dd50e0ccSTony Hutter 	int width;
5368dd50e0ccSTony Hutter 
5369dd50e0ccSTony Hutter 	width = get_namewidth(zhp, cb->cb_namewidth, cb->cb_name_flags,
5370dd50e0ccSTony Hutter 	    cb->cb_verbose);
5371dd50e0ccSTony Hutter 
5372dd50e0ccSTony Hutter 	if (width < 9)
5373dd50e0ccSTony Hutter 		width = 9;
5374dd50e0ccSTony Hutter 
5375dd50e0ccSTony Hutter 	cb->cb_namewidth = width;
5376dd50e0ccSTony Hutter 
5377dd50e0ccSTony Hutter 	return (0);
5378dd50e0ccSTony Hutter }
5379dd50e0ccSTony Hutter 
5380fa9e4066Sahrens /*
5381663207adSDon Brady  * zpool list [-gHLP] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
5382fa9e4066Sahrens  *
5383663207adSDon Brady  *	-g	Display guid for individual vdev name.
5384990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
5385990b4856Slling  *		by a single tab.
5386663207adSDon Brady  *	-L	Follow links when resolving vdev path name.
5387990b4856Slling  *	-o	List of properties to display.  Defaults to
53887a09f97bSGeorge Wilson  *		"name,size,allocated,free,expandsize,fragmentation,capacity,"
53897a09f97bSGeorge Wilson  *		"dedupratio,health,altroot"
539004e56356SAndriy Gapon  *	-p	Diplay values in parsable (exact) format.
5391663207adSDon Brady  *	-P	Display full path for vdev name.
53923f9d6ad7SLin Ling  *	-T	Display a timestamp in date(1) or Unix format
5393fa9e4066Sahrens  *
5394fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
5395fa9e4066Sahrens  * statistics for each one, as well as health status summary.
5396fa9e4066Sahrens  */
5397fa9e4066Sahrens int
5398fa9e4066Sahrens zpool_do_list(int argc, char **argv)
5399fa9e4066Sahrens {
5400fa9e4066Sahrens 	int c;
5401fa9e4066Sahrens 	int ret;
5402fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
5403990b4856Slling 	static char default_props[] =
540486714001SSerapheim Dimitropoulos 	    "name,size,allocated,free,checkpoint,expandsize,fragmentation,"
540586714001SSerapheim Dimitropoulos 	    "capacity,dedupratio,health,altroot";
5406990b4856Slling 	char *props = default_props;
5407dd50e0ccSTony Hutter 	float interval = 0;
5408dd50e0ccSTony Hutter 	unsigned long count = 0;
54094263d13fSGeorge Wilson 	zpool_list_t *list;
54104263d13fSGeorge Wilson 	boolean_t first = B_TRUE;
5411fa9e4066Sahrens 
5412fa9e4066Sahrens 	/* check options */
5413663207adSDon Brady 	while ((c = getopt(argc, argv, ":gHLo:pPT:v")) != -1) {
5414fa9e4066Sahrens 		switch (c) {
5415663207adSDon Brady 		case 'g':
5416663207adSDon Brady 			cb.cb_name_flags |= VDEV_NAME_GUID;
5417663207adSDon Brady 			break;
5418fa9e4066Sahrens 		case 'H':
541999653d4eSeschrock 			cb.cb_scripted = B_TRUE;
5420fa9e4066Sahrens 			break;
5421663207adSDon Brady 		case 'L':
5422663207adSDon Brady 			cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
5423663207adSDon Brady 			break;
5424fa9e4066Sahrens 		case 'o':
5425990b4856Slling 			props = optarg;
5426fa9e4066Sahrens 			break;
5427663207adSDon Brady 		case 'P':
5428663207adSDon Brady 			cb.cb_name_flags |= VDEV_NAME_PATH;
5429663207adSDon Brady 			break;
5430c58b3526SAdam Stevko 		case 'p':
5431c58b3526SAdam Stevko 			cb.cb_literal = B_TRUE;
5432c58b3526SAdam Stevko 			break;
54333f9d6ad7SLin Ling 		case 'T':
54343f9d6ad7SLin Ling 			get_timestamp_arg(*optarg);
54353f9d6ad7SLin Ling 			break;
54364263d13fSGeorge Wilson 		case 'v':
54374263d13fSGeorge Wilson 			cb.cb_verbose = B_TRUE;
5438663207adSDon Brady 			cb.cb_namewidth = 8;	/* 8 until precalc is avail */
54394263d13fSGeorge Wilson 			break;
5440fa9e4066Sahrens 		case ':':
5441fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
5442fa9e4066Sahrens 			    "'%c' option\n"), optopt);
544399653d4eSeschrock 			usage(B_FALSE);
5444fa9e4066Sahrens 			break;
5445fa9e4066Sahrens 		case '?':
5446fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5447fa9e4066Sahrens 			    optopt);
544899653d4eSeschrock 			usage(B_FALSE);
5449fa9e4066Sahrens 		}
5450fa9e4066Sahrens 	}
5451fa9e4066Sahrens 
5452fa9e4066Sahrens 	argc -= optind;
5453fa9e4066Sahrens 	argv += optind;
5454fa9e4066Sahrens 
54553f9d6ad7SLin Ling 	get_interval_count(&argc, argv, &interval, &count);
54563f9d6ad7SLin Ling 
5457990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
5458990b4856Slling 		usage(B_FALSE);
5459fa9e4066Sahrens 
54603f9d6ad7SLin Ling 	for (;;) {
5461cd67d23dSGeorge Wilson 		if ((list = pool_list_get(argc, argv, &cb.cb_proplist,
5462cd67d23dSGeorge Wilson 		    &ret)) == NULL)
5463cd67d23dSGeorge Wilson 			return (1);
54644263d13fSGeorge Wilson 
54654263d13fSGeorge Wilson 		if (pool_list_count(list) == 0)
54664263d13fSGeorge Wilson 			break;
54674263d13fSGeorge Wilson 
54684263d13fSGeorge Wilson 		cb.cb_namewidth = 0;
5469dd50e0ccSTony Hutter 		(void) pool_list_iter(list, B_FALSE, get_namewidth_list, &cb);
5470990b4856Slling 
54713f9d6ad7SLin Ling 		if (timestamp_fmt != NODATE)
54723f9d6ad7SLin Ling 			print_timestamp(timestamp_fmt);
5473fa9e4066Sahrens 
54744263d13fSGeorge Wilson 		if (!cb.cb_scripted && (first || cb.cb_verbose)) {
54754263d13fSGeorge Wilson 			print_header(&cb);
54764263d13fSGeorge Wilson 			first = B_FALSE;
54773f9d6ad7SLin Ling 		}
54784263d13fSGeorge Wilson 		ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
54793f9d6ad7SLin Ling 
54803f9d6ad7SLin Ling 		if (interval == 0)
54813f9d6ad7SLin Ling 			break;
54823f9d6ad7SLin Ling 
54833f9d6ad7SLin Ling 		if (count != 0 && --count == 0)
54843f9d6ad7SLin Ling 			break;
54853f9d6ad7SLin Ling 
5486cd67d23dSGeorge Wilson 		pool_list_free(list);
5487dd50e0ccSTony Hutter 		(void) fsleep(interval);
5488fa9e4066Sahrens 	}
5489fa9e4066Sahrens 
5490cd67d23dSGeorge Wilson 	if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
5491cd67d23dSGeorge Wilson 		(void) printf(gettext("no pools available\n"));
5492cd67d23dSGeorge Wilson 		ret = 0;
5493cd67d23dSGeorge Wilson 	}
5494cd67d23dSGeorge Wilson 
5495cd67d23dSGeorge Wilson 	pool_list_free(list);
54963f9d6ad7SLin Ling 	zprop_free_list(cb.cb_proplist);
5497fa9e4066Sahrens 	return (ret);
5498fa9e4066Sahrens }
5499fa9e4066Sahrens 
5500fa9e4066Sahrens static int
5501fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
5502fa9e4066Sahrens {
550399653d4eSeschrock 	boolean_t force = B_FALSE;
5504fa9e4066Sahrens 	int c;
5505fa9e4066Sahrens 	nvlist_t *nvroot;
5506fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
5507fa9e4066Sahrens 	zpool_handle_t *zhp;
55087855d95bSToomas Soome 	zpool_boot_label_t boot_type;
55097855d95bSToomas Soome 	uint64_t boot_size;
55105711d393Sloli 	nvlist_t *props = NULL;
55115711d393Sloli 	char *propval;
551299653d4eSeschrock 	int ret;
5513fa9e4066Sahrens 
5514fa9e4066Sahrens 	/* check options */
55155711d393Sloli 	while ((c = getopt(argc, argv, "fo:")) != -1) {
5516fa9e4066Sahrens 		switch (c) {
5517fa9e4066Sahrens 		case 'f':
551899653d4eSeschrock 			force = B_TRUE;
5519fa9e4066Sahrens 			break;
55205711d393Sloli 		case 'o':
55215711d393Sloli 			if ((propval = strchr(optarg, '=')) == NULL) {
55225711d393Sloli 				(void) fprintf(stderr, gettext("missing "
55235711d393Sloli 				    "'=' for -o option\n"));
55245711d393Sloli 				usage(B_FALSE);
55255711d393Sloli 			}
55265711d393Sloli 			*propval = '\0';
55275711d393Sloli 			propval++;
55285711d393Sloli 
55295711d393Sloli 			if ((strcmp(optarg, ZPOOL_CONFIG_ASHIFT) != 0) ||
55305711d393Sloli 			    (add_prop_list(optarg, propval, &props, B_TRUE)))
55315711d393Sloli 				usage(B_FALSE);
55325711d393Sloli 			break;
5533fa9e4066Sahrens 		case '?':
5534fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5535fa9e4066Sahrens 			    optopt);
553699653d4eSeschrock 			usage(B_FALSE);
5537fa9e4066Sahrens 		}
5538fa9e4066Sahrens 	}
5539fa9e4066Sahrens 
5540fa9e4066Sahrens 	argc -= optind;
5541fa9e4066Sahrens 	argv += optind;
5542fa9e4066Sahrens 
5543fa9e4066Sahrens 	/* get pool name and check number of arguments */
5544fa9e4066Sahrens 	if (argc < 1) {
5545fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
554699653d4eSeschrock 		usage(B_FALSE);
5547fa9e4066Sahrens 	}
5548fa9e4066Sahrens 
5549fa9e4066Sahrens 	poolname = argv[0];
5550fa9e4066Sahrens 
5551fa9e4066Sahrens 	if (argc < 2) {
5552fa9e4066Sahrens 		(void) fprintf(stderr,
5553fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
555499653d4eSeschrock 		usage(B_FALSE);
5555fa9e4066Sahrens 	}
5556fa9e4066Sahrens 
5557fa9e4066Sahrens 	old_disk = argv[1];
5558fa9e4066Sahrens 
5559fa9e4066Sahrens 	if (argc < 3) {
5560fa9e4066Sahrens 		if (!replacing) {
5561fa9e4066Sahrens 			(void) fprintf(stderr,
5562fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
556399653d4eSeschrock 			usage(B_FALSE);
5564fa9e4066Sahrens 		}
5565fa9e4066Sahrens 		new_disk = old_disk;
5566fa9e4066Sahrens 		argc -= 1;
5567fa9e4066Sahrens 		argv += 1;
5568fa9e4066Sahrens 	} else {
5569fa9e4066Sahrens 		new_disk = argv[2];
5570fa9e4066Sahrens 		argc -= 2;
5571fa9e4066Sahrens 		argv += 2;
5572fa9e4066Sahrens 	}
5573fa9e4066Sahrens 
5574fa9e4066Sahrens 	if (argc > 1) {
5575fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
557699653d4eSeschrock 		usage(B_FALSE);
5577fa9e4066Sahrens 	}
5578fa9e4066Sahrens 
557999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
5580fa9e4066Sahrens 		return (1);
5581fa9e4066Sahrens 
55828488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
5583fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
5584fa9e4066Sahrens 		    poolname);
5585fa9e4066Sahrens 		zpool_close(zhp);
5586fa9e4066Sahrens 		return (1);
5587fa9e4066Sahrens 	}
5588fa9e4066Sahrens 
55897855d95bSToomas Soome 	if (zpool_is_bootable(zhp))
55907855d95bSToomas Soome 		boot_type = ZPOOL_COPY_BOOT_LABEL;
55917855d95bSToomas Soome 	else
55927855d95bSToomas Soome 		boot_type = ZPOOL_NO_BOOT_LABEL;
55937855d95bSToomas Soome 
55947855d95bSToomas Soome 	boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
55955711d393Sloli 
55965711d393Sloli 	/* unless manually specified use "ashift" pool property (if set) */
55975711d393Sloli 	if (!nvlist_exists(props, ZPOOL_CONFIG_ASHIFT)) {
55985711d393Sloli 		int intval;
55995711d393Sloli 		zprop_source_t src;
56005711d393Sloli 		char strval[ZPOOL_MAXPROPLEN];
56015711d393Sloli 
56025711d393Sloli 		intval = zpool_get_prop_int(zhp, ZPOOL_PROP_ASHIFT, &src);
56035711d393Sloli 		if (src != ZPROP_SRC_DEFAULT) {
56045711d393Sloli 			(void) sprintf(strval, "%" PRId32, intval);
56055711d393Sloli 			verify(add_prop_list(ZPOOL_CONFIG_ASHIFT, strval,
56065711d393Sloli 			    &props, B_TRUE) == 0);
56075711d393Sloli 		}
56085711d393Sloli 	}
56095711d393Sloli 
56105711d393Sloli 	nvroot = make_root_vdev(zhp, props, force, B_FALSE, replacing, B_FALSE,
56117855d95bSToomas Soome 	    boot_type, boot_size, argc, argv);
5612fa9e4066Sahrens 	if (nvroot == NULL) {
5613fa9e4066Sahrens 		zpool_close(zhp);
5614fa9e4066Sahrens 		return (1);
5615fa9e4066Sahrens 	}
5616fa9e4066Sahrens 
561799653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
561899653d4eSeschrock 
561999653d4eSeschrock 	nvlist_free(nvroot);
562099653d4eSeschrock 	zpool_close(zhp);
562199653d4eSeschrock 
562299653d4eSeschrock 	return (ret);
5623fa9e4066Sahrens }
5624fa9e4066Sahrens 
5625fa9e4066Sahrens /*
5626fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
5627fa9e4066Sahrens  *
5628fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
5629fa9e4066Sahrens  *
5630fa9e4066Sahrens  * Replace <device> with <new_device>.
5631fa9e4066Sahrens  */
5632fa9e4066Sahrens /* ARGSUSED */
5633fa9e4066Sahrens int
5634fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
5635fa9e4066Sahrens {
5636fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
5637fa9e4066Sahrens }
5638fa9e4066Sahrens 
5639fa9e4066Sahrens /*
56405711d393Sloli  * zpool attach [-f] [-o property=value] <pool> <device> <new_device>
5641fa9e4066Sahrens  *
5642fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
56435711d393Sloli  *	-o	Set property=value.
5644fa9e4066Sahrens  *
5645fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
5646fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
5647fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
5648fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
5649fa9e4066Sahrens  */
5650fa9e4066Sahrens int
5651fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
5652fa9e4066Sahrens {
5653fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
5654fa9e4066Sahrens }
5655fa9e4066Sahrens 
5656fa9e4066Sahrens /*
5657fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
5658fa9e4066Sahrens  *
5659fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
5660fa9e4066Sahrens  *		(not supported yet)
5661fa9e4066Sahrens  *
5662fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
5663fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
5664fa9e4066Sahrens  * has the only valid copy of some data.
5665fa9e4066Sahrens  */
5666fa9e4066Sahrens /* ARGSUSED */
5667fa9e4066Sahrens int
5668fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
5669fa9e4066Sahrens {
5670fa9e4066Sahrens 	int c;
5671fa9e4066Sahrens 	char *poolname, *path;
5672fa9e4066Sahrens 	zpool_handle_t *zhp;
567399653d4eSeschrock 	int ret;
5674fa9e4066Sahrens 
5675fa9e4066Sahrens 	/* check options */
5676fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
5677fa9e4066Sahrens 		switch (c) {
5678fa9e4066Sahrens 		case 'f':
5679fa9e4066Sahrens 		case '?':
5680fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5681fa9e4066Sahrens 			    optopt);
568299653d4eSeschrock 			usage(B_FALSE);
5683fa9e4066Sahrens 		}
5684fa9e4066Sahrens 	}
5685fa9e4066Sahrens 
5686fa9e4066Sahrens 	argc -= optind;
5687fa9e4066Sahrens 	argv += optind;
5688fa9e4066Sahrens 
5689fa9e4066Sahrens 	/* get pool name and check number of arguments */
5690fa9e4066Sahrens 	if (argc < 1) {
5691fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
569299653d4eSeschrock 		usage(B_FALSE);
5693fa9e4066Sahrens 	}
5694fa9e4066Sahrens 
5695fa9e4066Sahrens 	if (argc < 2) {
5696fa9e4066Sahrens 		(void) fprintf(stderr,
5697fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
569899653d4eSeschrock 		usage(B_FALSE);
5699fa9e4066Sahrens 	}
5700fa9e4066Sahrens 
5701fa9e4066Sahrens 	poolname = argv[0];
5702fa9e4066Sahrens 	path = argv[1];
5703fa9e4066Sahrens 
570499653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
5705fa9e4066Sahrens 		return (1);
5706fa9e4066Sahrens 
570799653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
570899653d4eSeschrock 
570999653d4eSeschrock 	zpool_close(zhp);
571099653d4eSeschrock 
571199653d4eSeschrock 	return (ret);
5712fa9e4066Sahrens }
5713fa9e4066Sahrens 
57141195e687SMark J Musante /*
5715663207adSDon Brady  * zpool split [-gLnP] [-o prop=val] ...
57161195e687SMark J Musante  *		[-o mntopt] ...
57171195e687SMark J Musante  *		[-R altroot] <pool> <newpool> [<device> ...]
57181195e687SMark J Musante  *
5719663207adSDon Brady  *	-g      Display guid for individual vdev name.
5720663207adSDon Brady  *	-L	Follow links when resolving vdev path name.
57211195e687SMark J Musante  *	-n	Do not split the pool, but display the resulting layout if
57221195e687SMark J Musante  *		it were to be split.
57231195e687SMark J Musante  *	-o	Set property=value, or set mount options.
5724663207adSDon Brady  *	-P	Display full path for vdev name.
57251195e687SMark J Musante  *	-R	Mount the split-off pool under an alternate root.
5726eb633035STom Caputi  *	-l	Load encryption keys while importing.
57271195e687SMark J Musante  *
57281195e687SMark J Musante  * Splits the named pool and gives it the new pool name.  Devices to be split
57291195e687SMark J Musante  * off may be listed, provided that no more than one device is specified
57301195e687SMark J Musante  * per top-level vdev mirror.  The newly split pool is left in an exported
57311195e687SMark J Musante  * state unless -R is specified.
57321195e687SMark J Musante  *
57331195e687SMark J Musante  * Restrictions: the top-level of the pool pool must only be made up of
57341195e687SMark J Musante  * mirrors; all devices in the pool must be healthy; no device may be
57351195e687SMark J Musante  * undergoing a resilvering operation.
57361195e687SMark J Musante  */
57371195e687SMark J Musante int
57381195e687SMark J Musante zpool_do_split(int argc, char **argv)
57391195e687SMark J Musante {
57401195e687SMark J Musante 	char *srcpool, *newpool, *propval;
57411195e687SMark J Musante 	char *mntopts = NULL;
57421195e687SMark J Musante 	splitflags_t flags;
57431195e687SMark J Musante 	int c, ret = 0;
5744eb633035STom Caputi 	boolean_t loadkeys = B_FALSE;
57451195e687SMark J Musante 	zpool_handle_t *zhp;
57461195e687SMark J Musante 	nvlist_t *config, *props = NULL;
57471195e687SMark J Musante 
57481195e687SMark J Musante 	flags.dryrun = B_FALSE;
57491195e687SMark J Musante 	flags.import = B_FALSE;
5750663207adSDon Brady 	flags.name_flags = 0;
57511195e687SMark J Musante 
57521195e687SMark J Musante 	/* check options */
5753eb633035STom Caputi 	while ((c = getopt(argc, argv, ":gLR:lno:P")) != -1) {
57541195e687SMark J Musante 		switch (c) {
5755663207adSDon Brady 		case 'g':
5756663207adSDon Brady 			flags.name_flags |= VDEV_NAME_GUID;
5757663207adSDon Brady 			break;
5758663207adSDon Brady 		case 'L':
5759663207adSDon Brady 			flags.name_flags |= VDEV_NAME_FOLLOW_LINKS;
5760663207adSDon Brady 			break;
57611195e687SMark J Musante 		case 'R':
57621195e687SMark J Musante 			flags.import = B_TRUE;
57631195e687SMark J Musante 			if (add_prop_list(
57641195e687SMark J Musante 			    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
57651195e687SMark J Musante 			    &props, B_TRUE) != 0) {
5766aab83bb8SJosef 'Jeff' Sipek 				nvlist_free(props);
57671195e687SMark J Musante 				usage(B_FALSE);
57681195e687SMark J Musante 			}
57691195e687SMark J Musante 			break;
5770eb633035STom Caputi 		case 'l':
5771eb633035STom Caputi 			loadkeys = B_TRUE;
5772eb633035STom Caputi 			break;
57731195e687SMark J Musante 		case 'n':
57741195e687SMark J Musante 			flags.dryrun = B_TRUE;
57751195e687SMark J Musante 			break;
57761195e687SMark J Musante 		case 'o':
57771195e687SMark J Musante 			if ((propval = strchr(optarg, '=')) != NULL) {
57781195e687SMark J Musante 				*propval = '\0';
57791195e687SMark J Musante 				propval++;
57801195e687SMark J Musante 				if (add_prop_list(optarg, propval,
57811195e687SMark J Musante 				    &props, B_TRUE) != 0) {
5782aab83bb8SJosef 'Jeff' Sipek 					nvlist_free(props);
57831195e687SMark J Musante 					usage(B_FALSE);
57841195e687SMark J Musante 				}
57851195e687SMark J Musante 			} else {
57861195e687SMark J Musante 				mntopts = optarg;
57871195e687SMark J Musante 			}
57881195e687SMark J Musante 			break;
5789663207adSDon Brady 		case 'P':
5790663207adSDon Brady 			flags.name_flags |= VDEV_NAME_PATH;
5791663207adSDon Brady 			break;
57921195e687SMark J Musante 		case ':':
57931195e687SMark J Musante 			(void) fprintf(stderr, gettext("missing argument for "
57941195e687SMark J Musante 			    "'%c' option\n"), optopt);
57951195e687SMark J Musante 			usage(B_FALSE);
57961195e687SMark J Musante 			break;
57971195e687SMark J Musante 		case '?':
57981195e687SMark J Musante 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
57991195e687SMark J Musante 			    optopt);
58001195e687SMark J Musante 			usage(B_FALSE);
58011195e687SMark J Musante 			break;
58021195e687SMark J Musante 		}
58031195e687SMark J Musante 	}
58041195e687SMark J Musante 
58051195e687SMark J Musante 	if (!flags.import && mntopts != NULL) {
58061195e687SMark J Musante 		(void) fprintf(stderr, gettext("setting mntopts is only "
58071195e687SMark J Musante 		    "valid when importing the pool\n"));
58081195e687SMark J Musante 		usage(B_FALSE);
58091195e687SMark J Musante 	}
58101195e687SMark J Musante 
5811eb633035STom Caputi 	if (!flags.import && loadkeys) {
5812eb633035STom Caputi 		(void) fprintf(stderr, gettext("loading keys is only "
5813eb633035STom Caputi 		    "valid when importing the pool\n"));
5814eb633035STom Caputi 		usage(B_FALSE);
5815eb633035STom Caputi 	}
5816eb633035STom Caputi 
58171195e687SMark J Musante 	argc -= optind;
58181195e687SMark J Musante 	argv += optind;
58191195e687SMark J Musante 
58201195e687SMark J Musante 	if (argc < 1) {
58211195e687SMark J Musante 		(void) fprintf(stderr, gettext("Missing pool name\n"));
58221195e687SMark J Musante 		usage(B_FALSE);
58231195e687SMark J Musante 	}
58241195e687SMark J Musante 	if (argc < 2) {
58251195e687SMark J Musante 		(void) fprintf(stderr, gettext("Missing new pool name\n"));
58261195e687SMark J Musante 		usage(B_FALSE);
58271195e687SMark J Musante 	}
58281195e687SMark J Musante 
58291195e687SMark J Musante 	srcpool = argv[0];
58301195e687SMark J Musante 	newpool = argv[1];
58311195e687SMark J Musante 
58321195e687SMark J Musante 	argc -= 2;
58331195e687SMark J Musante 	argv += 2;
58341195e687SMark J Musante 
58351195e687SMark J Musante 	if ((zhp = zpool_open(g_zfs, srcpool)) == NULL)
58361195e687SMark J Musante 		return (1);
58371195e687SMark J Musante 
58381195e687SMark J Musante 	config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
58391195e687SMark J Musante 	if (config == NULL) {
58401195e687SMark J Musante 		ret = 1;
58411195e687SMark J Musante 	} else {
58421195e687SMark J Musante 		if (flags.dryrun) {
58431195e687SMark J Musante 			(void) printf(gettext("would create '%s' with the "
58441195e687SMark J Musante 			    "following layout:\n\n"), newpool);
5845663207adSDon Brady 			print_vdev_tree(NULL, newpool, config, 0, "",
5846663207adSDon Brady 			    flags.name_flags);
58471195e687SMark J Musante 		}
58481195e687SMark J Musante 		nvlist_free(config);
58491195e687SMark J Musante 	}
58501195e687SMark J Musante 
58511195e687SMark J Musante 	zpool_close(zhp);
58521195e687SMark J Musante 
58531195e687SMark J Musante 	if (ret != 0 || flags.dryrun || !flags.import)
58541195e687SMark J Musante 		return (ret);
58551195e687SMark J Musante 
58561195e687SMark J Musante 	/*
58571195e687SMark J Musante 	 * The split was successful. Now we need to open the new
58581195e687SMark J Musante 	 * pool and import it.
58591195e687SMark J Musante 	 */
58601195e687SMark J Musante 	if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
58611195e687SMark J Musante 		return (1);
5862eb633035STom Caputi 
5863eb633035STom Caputi 	if (loadkeys) {
5864eb633035STom Caputi 		ret = zfs_crypto_attempt_load_keys(g_zfs, newpool);
5865eb633035STom Caputi 		if (ret != 0)
5866eb633035STom Caputi 			ret = 1;
5867eb633035STom Caputi 	}
5868eb633035STom Caputi 
58691195e687SMark J Musante 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
58701195e687SMark J Musante 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
58711195e687SMark J Musante 		ret = 1;
5872fe7cd8aaSCyril Plisko 		(void) fprintf(stderr, gettext("Split was successful, but "
58731195e687SMark J Musante 		    "the datasets could not all be mounted\n"));
58741195e687SMark J Musante 		(void) fprintf(stderr, gettext("Try doing '%s' with a "
58751195e687SMark J Musante 		    "different altroot\n"), "zpool import");
58761195e687SMark J Musante 	}
58771195e687SMark J Musante 	zpool_close(zhp);
58781195e687SMark J Musante 
58791195e687SMark J Musante 	return (ret);
58801195e687SMark J Musante }
58811195e687SMark J Musante 
58821195e687SMark J Musante 
58831195e687SMark J Musante 
5884fa9e4066Sahrens /*
5885441d80aaSlling  * zpool online <pool> <device> ...
5886fa9e4066Sahrens  */
5887fa9e4066Sahrens int
5888fa9e4066Sahrens zpool_do_online(int argc, char **argv)
5889fa9e4066Sahrens {
5890fa9e4066Sahrens 	int c, i;
5891fa9e4066Sahrens 	char *poolname;
5892fa9e4066Sahrens 	zpool_handle_t *zhp;
5893fa9e4066Sahrens 	int ret = 0;
58943d7072f8Seschrock 	vdev_state_t newstate;
5895573ca77eSGeorge Wilson 	int flags = 0;
5896fa9e4066Sahrens 
5897fa9e4066Sahrens 	/* check options */
5898573ca77eSGeorge Wilson 	while ((c = getopt(argc, argv, "et")) != -1) {
5899fa9e4066Sahrens 		switch (c) {
5900573ca77eSGeorge Wilson 		case 'e':
5901573ca77eSGeorge Wilson 			flags |= ZFS_ONLINE_EXPAND;
5902573ca77eSGeorge Wilson 			break;
5903fa9e4066Sahrens 		case 't':
5904fa9e4066Sahrens 		case '?':
5905fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5906fa9e4066Sahrens 			    optopt);
590799653d4eSeschrock 			usage(B_FALSE);
5908fa9e4066Sahrens 		}
5909fa9e4066Sahrens 	}
5910fa9e4066Sahrens 
5911fa9e4066Sahrens 	argc -= optind;
5912fa9e4066Sahrens 	argv += optind;
5913fa9e4066Sahrens 
5914fa9e4066Sahrens 	/* get pool name and check number of arguments */
5915fa9e4066Sahrens 	if (argc < 1) {
5916fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
591799653d4eSeschrock 		usage(B_FALSE);
5918fa9e4066Sahrens 	}
5919fa9e4066Sahrens 	if (argc < 2) {
5920fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
592199653d4eSeschrock 		usage(B_FALSE);
5922fa9e4066Sahrens 	}
5923fa9e4066Sahrens 
5924fa9e4066Sahrens 	poolname = argv[0];
5925fa9e4066Sahrens 
592699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
5927fa9e4066Sahrens 		return (1);
5928fa9e4066Sahrens 
59293d7072f8Seschrock 	for (i = 1; i < argc; i++) {
5930573ca77eSGeorge Wilson 		if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
59313d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
59323d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
59333d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
59343d7072f8Seschrock 				    argv[i]);
59353d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
59363d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
59373d7072f8Seschrock 					    "clear' to restore a faulted "
59383d7072f8Seschrock 					    "device\n"));
59393d7072f8Seschrock 				else
59403d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
59413d7072f8Seschrock 					    "replace' to replace devices "
59423d7072f8Seschrock 					    "that are no longer present\n"));
59433d7072f8Seschrock 			}
59443d7072f8Seschrock 		} else {
5945fa9e4066Sahrens 			ret = 1;
59463d7072f8Seschrock 		}
59473d7072f8Seschrock 	}
5948fa9e4066Sahrens 
594999653d4eSeschrock 	zpool_close(zhp);
595099653d4eSeschrock 
5951fa9e4066Sahrens 	return (ret);
5952fa9e4066Sahrens }
5953fa9e4066Sahrens 
5954fa9e4066Sahrens /*
5955441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
5956fa9e4066Sahrens  *
5957fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
5958fa9e4066Sahrens  *		so would appear to compromise pool availability.
5959fa9e4066Sahrens  *		(not supported yet)
5960fa9e4066Sahrens  *
5961fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
5962fa9e4066Sahrens  *		state will not be persistent across reboots.
5963fa9e4066Sahrens  */
5964fa9e4066Sahrens /* ARGSUSED */
5965fa9e4066Sahrens int
5966fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
5967fa9e4066Sahrens {
5968fa9e4066Sahrens 	int c, i;
5969fa9e4066Sahrens 	char *poolname;
5970fa9e4066Sahrens 	zpool_handle_t *zhp;
597199653d4eSeschrock 	int ret = 0;
597299653d4eSeschrock 	boolean_t istmp = B_FALSE;
5973fa9e4066Sahrens 
5974fa9e4066Sahrens 	/* check options */
5975fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
5976fa9e4066Sahrens 		switch (c) {
5977fa9e4066Sahrens 		case 't':
597899653d4eSeschrock 			istmp = B_TRUE;
5979441d80aaSlling 			break;
5980441d80aaSlling 		case 'f':
5981fa9e4066Sahrens 		case '?':
5982fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5983fa9e4066Sahrens 			    optopt);
598499653d4eSeschrock 			usage(B_FALSE);
5985fa9e4066Sahrens 		}
5986fa9e4066Sahrens 	}
5987fa9e4066Sahrens 
5988fa9e4066Sahrens 	argc -= optind;
5989fa9e4066Sahrens 	argv += optind;
5990fa9e4066Sahrens 
5991fa9e4066Sahrens 	/* get pool name and check number of arguments */
5992fa9e4066Sahrens 	if (argc < 1) {
5993fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
599499653d4eSeschrock 		usage(B_FALSE);
5995fa9e4066Sahrens 	}
5996fa9e4066Sahrens 	if (argc < 2) {
5997fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
599899653d4eSeschrock 		usage(B_FALSE);
5999fa9e4066Sahrens 	}
6000fa9e4066Sahrens 
6001fa9e4066Sahrens 	poolname = argv[0];
6002fa9e4066Sahrens 
600399653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
6004fa9e4066Sahrens 		return (1);
6005fa9e4066Sahrens 
60063d7072f8Seschrock 	for (i = 1; i < argc; i++) {
60073d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
6008fa9e4066Sahrens 			ret = 1;
60093d7072f8Seschrock 	}
6010fa9e4066Sahrens 
601199653d4eSeschrock 	zpool_close(zhp);
601299653d4eSeschrock 
6013fa9e4066Sahrens 	return (ret);
6014fa9e4066Sahrens }
6015fa9e4066Sahrens 
6016ea8dc4b6Seschrock /*
6017ea8dc4b6Seschrock  * zpool clear <pool> [device]
6018ea8dc4b6Seschrock  *
6019ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
6020ea8dc4b6Seschrock  */
6021ea8dc4b6Seschrock int
6022ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
6023ea8dc4b6Seschrock {
6024468c413aSTim Haley 	int c;
6025ea8dc4b6Seschrock 	int ret = 0;
6026468c413aSTim Haley 	boolean_t dryrun = B_FALSE;
6027468c413aSTim Haley 	boolean_t do_rewind = B_FALSE;
6028468c413aSTim Haley 	boolean_t xtreme_rewind = B_FALSE;
6029468c413aSTim Haley 	uint32_t rewind_policy = ZPOOL_NO_REWIND;
6030468c413aSTim Haley 	nvlist_t *policy = NULL;
6031ea8dc4b6Seschrock 	zpool_handle_t *zhp;
6032ea8dc4b6Seschrock 	char *pool, *device;
6033ea8dc4b6Seschrock 
6034468c413aSTim Haley 	/* check options */
6035468c413aSTim Haley 	while ((c = getopt(argc, argv, "FnX")) != -1) {
6036468c413aSTim Haley 		switch (c) {
6037468c413aSTim Haley 		case 'F':
6038468c413aSTim Haley 			do_rewind = B_TRUE;
6039468c413aSTim Haley 			break;
6040468c413aSTim Haley 		case 'n':
6041468c413aSTim Haley 			dryrun = B_TRUE;
6042468c413aSTim Haley 			break;
6043468c413aSTim Haley 		case 'X':
6044468c413aSTim Haley 			xtreme_rewind = B_TRUE;
6045468c413aSTim Haley 			break;
6046468c413aSTim Haley 		case '?':
6047468c413aSTim Haley 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6048468c413aSTim Haley 			    optopt);
6049468c413aSTim Haley 			usage(B_FALSE);
6050468c413aSTim Haley 		}
6051468c413aSTim Haley 	}
6052468c413aSTim Haley 
6053468c413aSTim Haley 	argc -= optind;
6054468c413aSTim Haley 	argv += optind;
6055468c413aSTim Haley 
6056468c413aSTim Haley 	if (argc < 1) {
6057ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
605899653d4eSeschrock 		usage(B_FALSE);
6059ea8dc4b6Seschrock 	}
6060ea8dc4b6Seschrock 
6061468c413aSTim Haley 	if (argc > 2) {
6062ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
606399653d4eSeschrock 		usage(B_FALSE);
6064ea8dc4b6Seschrock 	}
6065ea8dc4b6Seschrock 
6066468c413aSTim Haley 	if ((dryrun || xtreme_rewind) && !do_rewind) {
6067468c413aSTim Haley 		(void) fprintf(stderr,
6068468c413aSTim Haley 		    gettext("-n or -X only meaningful with -F\n"));
6069468c413aSTim Haley 		usage(B_FALSE);
6070468c413aSTim Haley 	}
6071468c413aSTim Haley 	if (dryrun)
6072468c413aSTim Haley 		rewind_policy = ZPOOL_TRY_REWIND;
6073468c413aSTim Haley 	else if (do_rewind)
6074468c413aSTim Haley 		rewind_policy = ZPOOL_DO_REWIND;
6075468c413aSTim Haley 	if (xtreme_rewind)
6076468c413aSTim Haley 		rewind_policy |= ZPOOL_EXTREME_REWIND;
6077468c413aSTim Haley 
6078468c413aSTim Haley 	/* In future, further rewind policy choices can be passed along here */
6079468c413aSTim Haley 	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
60805dafeea3SPavel Zakharov 	    nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY,
60815dafeea3SPavel Zakharov 	    rewind_policy) != 0) {
6082468c413aSTim Haley 		return (1);
60835dafeea3SPavel Zakharov 	}
6084468c413aSTim Haley 
6085468c413aSTim Haley 	pool = argv[0];
6086468c413aSTim Haley 	device = argc == 2 ? argv[1] : NULL;
6087ea8dc4b6Seschrock 
6088468c413aSTim Haley 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
6089468c413aSTim Haley 		nvlist_free(policy);
6090ea8dc4b6Seschrock 		return (1);
6091468c413aSTim Haley 	}
6092ea8dc4b6Seschrock 
6093468c413aSTim Haley 	if (zpool_clear(zhp, device, policy) != 0)
6094ea8dc4b6Seschrock 		ret = 1;
6095ea8dc4b6Seschrock 
6096ea8dc4b6Seschrock 	zpool_close(zhp);
6097ea8dc4b6Seschrock 
6098468c413aSTim Haley 	nvlist_free(policy);
6099468c413aSTim Haley 
6100ea8dc4b6Seschrock 	return (ret);
6101ea8dc4b6Seschrock }
6102ea8dc4b6Seschrock 
6103e9103aaeSGarrett D'Amore /*
6104e9103aaeSGarrett D'Amore  * zpool reguid <pool>
6105e9103aaeSGarrett D'Amore  */
6106e9103aaeSGarrett D'Amore int
6107e9103aaeSGarrett D'Amore zpool_do_reguid(int argc, char **argv)
6108e9103aaeSGarrett D'Amore {
6109e9103aaeSGarrett D'Amore 	int c;
6110e9103aaeSGarrett D'Amore 	char *poolname;
6111e9103aaeSGarrett D'Amore 	zpool_handle_t *zhp;
6112e9103aaeSGarrett D'Amore 	int ret = 0;
6113e9103aaeSGarrett D'Amore 
6114e9103aaeSGarrett D'Amore 	/* check options */
6115e9103aaeSGarrett D'Amore 	while ((c = getopt(argc, argv, "")) != -1) {
6116e9103aaeSGarrett D'Amore 		switch (c) {
6117e9103aaeSGarrett D'Amore 		case '?':
6118e9103aaeSGarrett D'Amore 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6119e9103aaeSGarrett D'Amore 			    optopt);
6120e9103aaeSGarrett D'Amore 			usage(B_FALSE);
6121e9103aaeSGarrett D'Amore 		}
6122e9103aaeSGarrett D'Amore 	}
6123e9103aaeSGarrett D'Amore 
6124e9103aaeSGarrett D'Amore 	argc -= optind;
6125e9103aaeSGarrett D'Amore 	argv += optind;
6126e9103aaeSGarrett D'Amore 
6127e9103aaeSGarrett D'Amore 	/* get pool name and check number of arguments */
6128e9103aaeSGarrett D'Amore 	if (argc < 1) {
6129e9103aaeSGarrett D'Amore 		(void) fprintf(stderr, gettext("missing pool name\n"));
6130e9103aaeSGarrett D'Amore 		usage(B_FALSE);
6131e9103aaeSGarrett D'Amore 	}
6132e9103aaeSGarrett D'Amore 
6133e9103aaeSGarrett D'Amore 	if (argc > 1) {
6134e9103aaeSGarrett D'Amore 		(void) fprintf(stderr, gettext("too many arguments\n"));
6135e9103aaeSGarrett D'Amore 		usage(B_FALSE);
6136e9103aaeSGarrett D'Amore 	}
6137e9103aaeSGarrett D'Amore 
6138e9103aaeSGarrett D'Amore 	poolname = argv[0];
6139e9103aaeSGarrett D'Amore 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
6140e9103aaeSGarrett D'Amore 		return (1);
6141e9103aaeSGarrett D'Amore 
6142e9103aaeSGarrett D'Amore 	ret = zpool_reguid(zhp);
6143e9103aaeSGarrett D'Amore 
6144e9103aaeSGarrett D'Amore 	zpool_close(zhp);
6145e9103aaeSGarrett D'Amore 	return (ret);
6146e9103aaeSGarrett D'Amore }
6147e9103aaeSGarrett D'Amore 
6148e9103aaeSGarrett D'Amore 
61494263d13fSGeorge Wilson /*
61504263d13fSGeorge Wilson  * zpool reopen <pool>
61514263d13fSGeorge Wilson  *
61524263d13fSGeorge Wilson  * Reopen the pool so that the kernel can update the sizes of all vdevs.
61534263d13fSGeorge Wilson  */
61544263d13fSGeorge Wilson int
61554263d13fSGeorge Wilson zpool_do_reopen(int argc, char **argv)
61564263d13fSGeorge Wilson {
615731d7e8faSGeorge Wilson 	int c;
61584263d13fSGeorge Wilson 	int ret = 0;
61594263d13fSGeorge Wilson 	zpool_handle_t *zhp;
61604263d13fSGeorge Wilson 	char *pool;
61614263d13fSGeorge Wilson 
616231d7e8faSGeorge Wilson 	/* check options */
616331d7e8faSGeorge Wilson 	while ((c = getopt(argc, argv, "")) != -1) {
616431d7e8faSGeorge Wilson 		switch (c) {
616531d7e8faSGeorge Wilson 		case '?':
616631d7e8faSGeorge Wilson 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
616731d7e8faSGeorge Wilson 			    optopt);
616831d7e8faSGeorge Wilson 			usage(B_FALSE);
616931d7e8faSGeorge Wilson 		}
617031d7e8faSGeorge Wilson 	}
617131d7e8faSGeorge Wilson 
61724263d13fSGeorge Wilson 	argc--;
61734263d13fSGeorge Wilson 	argv++;
61744263d13fSGeorge Wilson 
617531d7e8faSGeorge Wilson 	if (argc < 1) {
617631d7e8faSGeorge Wilson 		(void) fprintf(stderr, gettext("missing pool name\n"));
617731d7e8faSGeorge Wilson 		usage(B_FALSE);
617831d7e8faSGeorge Wilson 	}
617931d7e8faSGeorge Wilson 
618031d7e8faSGeorge Wilson 	if (argc > 1) {
618131d7e8faSGeorge Wilson 		(void) fprintf(stderr, gettext("too many arguments\n"));
618231d7e8faSGeorge Wilson 		usage(B_FALSE);
618331d7e8faSGeorge Wilson 	}
61844263d13fSGeorge Wilson 
61854263d13fSGeorge Wilson 	pool = argv[0];
61864263d13fSGeorge Wilson 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
61874263d13fSGeorge Wilson 		return (1);
61884263d13fSGeorge Wilson 
61894263d13fSGeorge Wilson 	ret = zpool_reopen(zhp);
61904263d13fSGeorge Wilson 	zpool_close(zhp);
61914263d13fSGeorge Wilson 	return (ret);
61924263d13fSGeorge Wilson }
61934263d13fSGeorge Wilson 
6194fa9e4066Sahrens typedef struct scrub_cbdata {
6195fa9e4066Sahrens 	int	cb_type;
619606eeb2adSek 	int	cb_argc;
619706eeb2adSek 	char	**cb_argv;
61981702cce7SAlek Pinchuk 	pool_scrub_cmd_t cb_scrub_cmd;
6199fa9e4066Sahrens } scrub_cbdata_t;
6200fa9e4066Sahrens 
620186714001SSerapheim Dimitropoulos static boolean_t
620286714001SSerapheim Dimitropoulos zpool_has_checkpoint(zpool_handle_t *zhp)
620386714001SSerapheim Dimitropoulos {
620486714001SSerapheim Dimitropoulos 	nvlist_t *config, *nvroot;
620586714001SSerapheim Dimitropoulos 
620686714001SSerapheim Dimitropoulos 	config = zpool_get_config(zhp, NULL);
620786714001SSerapheim Dimitropoulos 
620886714001SSerapheim Dimitropoulos 	if (config != NULL) {
620986714001SSerapheim Dimitropoulos 		pool_checkpoint_stat_t *pcs = NULL;
621086714001SSerapheim Dimitropoulos 		uint_t c;
621186714001SSerapheim Dimitropoulos 
621286714001SSerapheim Dimitropoulos 		nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
621386714001SSerapheim Dimitropoulos 		(void) nvlist_lookup_uint64_array(nvroot,
621486714001SSerapheim Dimitropoulos 		    ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c);
621586714001SSerapheim Dimitropoulos 
621686714001SSerapheim Dimitropoulos 		if (pcs == NULL || pcs->pcs_state == CS_NONE)
621786714001SSerapheim Dimitropoulos 			return (B_FALSE);
621886714001SSerapheim Dimitropoulos 
621986714001SSerapheim Dimitropoulos 		assert(pcs->pcs_state == CS_CHECKPOINT_EXISTS ||
622086714001SSerapheim Dimitropoulos 		    pcs->pcs_state == CS_CHECKPOINT_DISCARDING);
622186714001SSerapheim Dimitropoulos 		return (B_TRUE);
622286714001SSerapheim Dimitropoulos 	}
622386714001SSerapheim Dimitropoulos 
622486714001SSerapheim Dimitropoulos 	return (B_FALSE);
622586714001SSerapheim Dimitropoulos }
622686714001SSerapheim Dimitropoulos 
6227fa9e4066Sahrens int
6228fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
6229fa9e4066Sahrens {
6230fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
623106eeb2adSek 	int err;
6232fa9e4066Sahrens 
6233ea8dc4b6Seschrock 	/*
6234ea8dc4b6Seschrock 	 * Ignore faulted pools.
6235ea8dc4b6Seschrock 	 */
6236ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
6237e4c795beSTom Caputi 		(void) fprintf(stderr, gettext("cannot scan '%s': pool is "
6238ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
6239ea8dc4b6Seschrock 		return (1);
6240ea8dc4b6Seschrock 	}
6241ea8dc4b6Seschrock 
62421702cce7SAlek Pinchuk 	err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd);
624306eeb2adSek 
624486714001SSerapheim Dimitropoulos 	if (err == 0 && zpool_has_checkpoint(zhp) &&
624586714001SSerapheim Dimitropoulos 	    cb->cb_type == POOL_SCAN_SCRUB) {
624686714001SSerapheim Dimitropoulos 		(void) printf(gettext("warning: will not scrub state that "
624786714001SSerapheim Dimitropoulos 		    "belongs to the checkpoint of pool '%s'\n"),
624886714001SSerapheim Dimitropoulos 		    zpool_get_name(zhp));
624986714001SSerapheim Dimitropoulos 	}
625086714001SSerapheim Dimitropoulos 
625106eeb2adSek 	return (err != 0);
6252fa9e4066Sahrens }
6253fa9e4066Sahrens 
6254fa9e4066Sahrens /*
62551702cce7SAlek Pinchuk  * zpool scrub [-s | -p] <pool> ...
6256fa9e4066Sahrens  *
6257fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
62581702cce7SAlek Pinchuk  *	-p	Pause. Pause in-progress scrub.
6259fa9e4066Sahrens  */
6260fa9e4066Sahrens int
6261fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
6262fa9e4066Sahrens {
6263fa9e4066Sahrens 	int c;
6264fa9e4066Sahrens 	scrub_cbdata_t cb;
6265fa9e4066Sahrens 
62663f9d6ad7SLin Ling 	cb.cb_type = POOL_SCAN_SCRUB;
62671702cce7SAlek Pinchuk 	cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
6268fa9e4066Sahrens 
6269fa9e4066Sahrens 	/* check options */
62701702cce7SAlek Pinchuk 	while ((c = getopt(argc, argv, "sp")) != -1) {
6271fa9e4066Sahrens 		switch (c) {
6272fa9e4066Sahrens 		case 's':
62733f9d6ad7SLin Ling 			cb.cb_type = POOL_SCAN_NONE;
6274fa9e4066Sahrens 			break;
62751702cce7SAlek Pinchuk 		case 'p':
62761702cce7SAlek Pinchuk 			cb.cb_scrub_cmd = POOL_SCRUB_PAUSE;
62771702cce7SAlek Pinchuk 			break;
6278fa9e4066Sahrens 		case '?':
6279fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6280fa9e4066Sahrens 			    optopt);
628199653d4eSeschrock 			usage(B_FALSE);
6282fa9e4066Sahrens 		}
6283fa9e4066Sahrens 	}
6284fa9e4066Sahrens 
62851702cce7SAlek Pinchuk 	if (cb.cb_type == POOL_SCAN_NONE &&
62861702cce7SAlek Pinchuk 	    cb.cb_scrub_cmd == POOL_SCRUB_PAUSE) {
62871702cce7SAlek Pinchuk 		(void) fprintf(stderr, gettext("invalid option combination: "
62881702cce7SAlek Pinchuk 		    "-s and -p are mutually exclusive\n"));
62891702cce7SAlek Pinchuk 		usage(B_FALSE);
62901702cce7SAlek Pinchuk 	}
62911702cce7SAlek Pinchuk 
629206eeb2adSek 	cb.cb_argc = argc;
629306eeb2adSek 	cb.cb_argv = argv;
6294fa9e4066Sahrens 	argc -= optind;
6295fa9e4066Sahrens 	argv += optind;
6296fa9e4066Sahrens 
6297e4c795beSTom Caputi 	if (argc < 1) {
6298e4c795beSTom Caputi 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
6299e4c795beSTom Caputi 		usage(B_FALSE);
6300e4c795beSTom Caputi 	}
6301e4c795beSTom Caputi 
6302e4c795beSTom Caputi 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
6303e4c795beSTom Caputi }
6304e4c795beSTom Caputi 
6305e4c795beSTom Caputi /*
6306e4c795beSTom Caputi  * zpool resilver <pool> ...
6307e4c795beSTom Caputi  *
6308e4c795beSTom Caputi  *	Restarts any in-progress resilver
6309e4c795beSTom Caputi  */
6310e4c795beSTom Caputi int
6311e4c795beSTom Caputi zpool_do_resilver(int argc, char **argv)
6312e4c795beSTom Caputi {
6313e4c795beSTom Caputi 	int c;
6314e4c795beSTom Caputi 	scrub_cbdata_t cb;
6315e4c795beSTom Caputi 
6316e4c795beSTom Caputi 	cb.cb_type = POOL_SCAN_RESILVER;
6317e4c795beSTom Caputi 	cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
6318e4c795beSTom Caputi 	cb.cb_argc = argc;
6319e4c795beSTom Caputi 	cb.cb_argv = argv;
6320e4c795beSTom Caputi 
6321e4c795beSTom Caputi 	/* check options */
6322e4c795beSTom Caputi 	while ((c = getopt(argc, argv, "")) != -1) {
6323e4c795beSTom Caputi 		switch (c) {
6324e4c795beSTom Caputi 		case '?':
6325e4c795beSTom Caputi 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6326e4c795beSTom Caputi 			    optopt);
6327e4c795beSTom Caputi 			usage(B_FALSE);
6328e4c795beSTom Caputi 		}
6329e4c795beSTom Caputi 	}
6330e4c795beSTom Caputi 
6331e4c795beSTom Caputi 	argc -= optind;
6332e4c795beSTom Caputi 	argv += optind;
6333e4c795beSTom Caputi 
6334fa9e4066Sahrens 	if (argc < 1) {
6335fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
633699653d4eSeschrock 		usage(B_FALSE);
6337fa9e4066Sahrens 	}
6338fa9e4066Sahrens 
6339b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
6340fa9e4066Sahrens }
6341fa9e4066Sahrens 
6342084fd14fSBrian Behlendorf /*
6343084fd14fSBrian Behlendorf  * zpool trim [-d] [-r <rate>] [-c | -s] <pool> [<device> ...]
6344084fd14fSBrian Behlendorf  *
6345084fd14fSBrian Behlendorf  *	-c		Cancel. Ends any in-progress trim.
6346084fd14fSBrian Behlendorf  *	-d		Secure trim.  Requires kernel and device support.
6347084fd14fSBrian Behlendorf  *	-r <rate>	Sets the TRIM rate in bytes (per second). Supports
6348084fd14fSBrian Behlendorf  *			adding a multiplier suffix such as 'k' or 'm'.
6349084fd14fSBrian Behlendorf  *	-s		Suspend. TRIM can then be restarted with no flags.
6350084fd14fSBrian Behlendorf  */
6351084fd14fSBrian Behlendorf int
6352084fd14fSBrian Behlendorf zpool_do_trim(int argc, char **argv)
6353094e47e9SGeorge Wilson {
6354084fd14fSBrian Behlendorf 	struct option long_options[] = {
6355084fd14fSBrian Behlendorf 		{"cancel",	no_argument,		NULL,	'c'},
6356084fd14fSBrian Behlendorf 		{"secure",	no_argument,		NULL,	'd'},
6357084fd14fSBrian Behlendorf 		{"rate",	required_argument,	NULL,	'r'},
6358084fd14fSBrian Behlendorf 		{"suspend",	no_argument,		NULL,	's'},
6359084fd14fSBrian Behlendorf 		{0, 0, 0, 0}
6360084fd14fSBrian Behlendorf 	};
6361094e47e9SGeorge Wilson 
6362084fd14fSBrian Behlendorf 	pool_trim_func_t cmd_type = POOL_TRIM_START;
6363084fd14fSBrian Behlendorf 	uint64_t rate = 0;
6364084fd14fSBrian Behlendorf 	boolean_t secure = B_FALSE;
6365094e47e9SGeorge Wilson 
6366084fd14fSBrian Behlendorf 	int c;
6367084fd14fSBrian Behlendorf 	while ((c = getopt_long(argc, argv, "cdr:s", long_options, NULL))
6368084fd14fSBrian Behlendorf 	    != -1) {
6369084fd14fSBrian Behlendorf 		switch (c) {
6370084fd14fSBrian Behlendorf 		case 'c':
6371084fd14fSBrian Behlendorf 			if (cmd_type != POOL_TRIM_START &&
6372084fd14fSBrian Behlendorf 			    cmd_type != POOL_TRIM_CANCEL) {
6373084fd14fSBrian Behlendorf 				(void) fprintf(stderr, gettext("-c cannot be "
6374084fd14fSBrian Behlendorf 				    "combined with other options\n"));
6375084fd14fSBrian Behlendorf 				usage(B_FALSE);
6376084fd14fSBrian Behlendorf 			}
6377084fd14fSBrian Behlendorf 			cmd_type = POOL_TRIM_CANCEL;
6378084fd14fSBrian Behlendorf 			break;
6379084fd14fSBrian Behlendorf 		case 'd':
6380084fd14fSBrian Behlendorf 			if (cmd_type != POOL_TRIM_START) {
6381084fd14fSBrian Behlendorf 				(void) fprintf(stderr, gettext("-d cannot be "
6382084fd14fSBrian Behlendorf 				    "combined with the -c or -s options\n"));
6383084fd14fSBrian Behlendorf 				usage(B_FALSE);
6384084fd14fSBrian Behlendorf 			}
6385084fd14fSBrian Behlendorf 			secure = B_TRUE;
6386084fd14fSBrian Behlendorf 			break;
6387084fd14fSBrian Behlendorf 		case 'r':
6388084fd14fSBrian Behlendorf 			if (cmd_type != POOL_TRIM_START) {
6389084fd14fSBrian Behlendorf 				(void) fprintf(stderr, gettext("-r cannot be "
6390084fd14fSBrian Behlendorf 				    "combined with the -c or -s options\n"));
6391084fd14fSBrian Behlendorf 				usage(B_FALSE);
6392084fd14fSBrian Behlendorf 			}
6393084fd14fSBrian Behlendorf 			if (zfs_nicestrtonum(NULL, optarg, &rate) == -1) {
6394084fd14fSBrian Behlendorf 				(void) fprintf(stderr,
6395084fd14fSBrian Behlendorf 				    gettext("invalid value for rate\n"));
6396084fd14fSBrian Behlendorf 				usage(B_FALSE);
6397084fd14fSBrian Behlendorf 			}
6398084fd14fSBrian Behlendorf 			break;
6399084fd14fSBrian Behlendorf 		case 's':
6400084fd14fSBrian Behlendorf 			if (cmd_type != POOL_TRIM_START &&
6401084fd14fSBrian Behlendorf 			    cmd_type != POOL_TRIM_SUSPEND) {
6402084fd14fSBrian Behlendorf 				(void) fprintf(stderr, gettext("-s cannot be "
6403084fd14fSBrian Behlendorf 				    "combined with other options\n"));
6404084fd14fSBrian Behlendorf 				usage(B_FALSE);
6405084fd14fSBrian Behlendorf 			}
6406084fd14fSBrian Behlendorf 			cmd_type = POOL_TRIM_SUSPEND;
6407084fd14fSBrian Behlendorf 			break;
6408084fd14fSBrian Behlendorf 		case '?':
6409084fd14fSBrian Behlendorf 			if (optopt != 0) {
6410084fd14fSBrian Behlendorf 				(void) fprintf(stderr,
6411084fd14fSBrian Behlendorf 				    gettext("invalid option '%c'\n"), optopt);
6412084fd14fSBrian Behlendorf 			} else {
6413084fd14fSBrian Behlendorf 				(void) fprintf(stderr,
6414084fd14fSBrian Behlendorf 				    gettext("invalid option '%s'\n"),
6415084fd14fSBrian Behlendorf 				    argv[optind - 1]);
6416084fd14fSBrian Behlendorf 			}
6417084fd14fSBrian Behlendorf 			usage(B_FALSE);
6418084fd14fSBrian Behlendorf 		}
6419094e47e9SGeorge Wilson 	}
6420094e47e9SGeorge Wilson 
6421084fd14fSBrian Behlendorf 	argc -= optind;
6422084fd14fSBrian Behlendorf 	argv += optind;
6423084fd14fSBrian Behlendorf 
6424084fd14fSBrian Behlendorf 	if (argc < 1) {
6425084fd14fSBrian Behlendorf 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
6426084fd14fSBrian Behlendorf 		usage(B_FALSE);
6427084fd14fSBrian Behlendorf 		return (-1);
6428084fd14fSBrian Behlendorf 	}
6429084fd14fSBrian Behlendorf 
6430084fd14fSBrian Behlendorf 	char *poolname = argv[0];
6431084fd14fSBrian Behlendorf 	zpool_handle_t *zhp = zpool_open(g_zfs, poolname);
6432084fd14fSBrian Behlendorf 	if (zhp == NULL)
6433084fd14fSBrian Behlendorf 		return (-1);
6434084fd14fSBrian Behlendorf 
6435084fd14fSBrian Behlendorf 	trimflags_t trim_flags = {
6436084fd14fSBrian Behlendorf 		.secure = secure,
6437084fd14fSBrian Behlendorf 		.rate = rate,
6438084fd14fSBrian Behlendorf 	};
6439084fd14fSBrian Behlendorf 
6440084fd14fSBrian Behlendorf 	nvlist_t *vdevs = fnvlist_alloc();
6441084fd14fSBrian Behlendorf 	if (argc == 1) {
6442084fd14fSBrian Behlendorf 		/* no individual leaf vdevs specified, so add them all */
6443084fd14fSBrian Behlendorf 		nvlist_t *config = zpool_get_config(zhp, NULL);
6444084fd14fSBrian Behlendorf 		nvlist_t *nvroot = fnvlist_lookup_nvlist(config,
6445084fd14fSBrian Behlendorf 		    ZPOOL_CONFIG_VDEV_TREE);
6446084fd14fSBrian Behlendorf 		zpool_collect_leaves(zhp, nvroot, vdevs);
6447084fd14fSBrian Behlendorf 		trim_flags.fullpool = B_TRUE;
6448084fd14fSBrian Behlendorf 	} else {
6449084fd14fSBrian Behlendorf 		trim_flags.fullpool = B_FALSE;
6450084fd14fSBrian Behlendorf 		for (int i = 1; i < argc; i++) {
6451084fd14fSBrian Behlendorf 			fnvlist_add_boolean(vdevs, argv[i]);
6452084fd14fSBrian Behlendorf 		}
6453094e47e9SGeorge Wilson 	}
6454084fd14fSBrian Behlendorf 
6455084fd14fSBrian Behlendorf 	int error = zpool_trim(zhp, cmd_type, vdevs, &trim_flags);
6456084fd14fSBrian Behlendorf 
6457084fd14fSBrian Behlendorf 	fnvlist_free(vdevs);
6458084fd14fSBrian Behlendorf 	zpool_close(zhp);
6459084fd14fSBrian Behlendorf 
6460084fd14fSBrian Behlendorf 	return (error);
6461094e47e9SGeorge Wilson }
6462094e47e9SGeorge Wilson 
6463094e47e9SGeorge Wilson /*
6464084fd14fSBrian Behlendorf  * zpool initialize [-c | -s] <pool> [<vdev> ...]
6465094e47e9SGeorge Wilson  * Initialize all unused blocks in the specified vdevs, or all vdevs in the pool
6466094e47e9SGeorge Wilson  * if none specified.
6467094e47e9SGeorge Wilson  *
6468094e47e9SGeorge Wilson  *	-c	Cancel. Ends active initializing.
6469094e47e9SGeorge Wilson  *	-s	Suspend. Initializing can then be restarted with no flags.
6470094e47e9SGeorge Wilson  */
6471094e47e9SGeorge Wilson int
6472094e47e9SGeorge Wilson zpool_do_initialize(int argc, char **argv)
6473094e47e9SGeorge Wilson {
6474094e47e9SGeorge Wilson 	int c;
6475094e47e9SGeorge Wilson 	char *poolname;
6476094e47e9SGeorge Wilson 	zpool_handle_t *zhp;
6477094e47e9SGeorge Wilson 	nvlist_t *vdevs;
6478094e47e9SGeorge Wilson 	int err = 0;
6479094e47e9SGeorge Wilson 
6480094e47e9SGeorge Wilson 	struct option long_options[] = {
6481094e47e9SGeorge Wilson 		{"cancel",	no_argument,		NULL, 'c'},
6482094e47e9SGeorge Wilson 		{"suspend",	no_argument,		NULL, 's'},
6483094e47e9SGeorge Wilson 		{0, 0, 0, 0}
6484094e47e9SGeorge Wilson 	};
6485094e47e9SGeorge Wilson 
6486084fd14fSBrian Behlendorf 	pool_initialize_func_t cmd_type = POOL_INITIALIZE_START;
6487094e47e9SGeorge Wilson 	while ((c = getopt_long(argc, argv, "cs", long_options, NULL)) != -1) {
6488094e47e9SGeorge Wilson 		switch (c) {
6489094e47e9SGeorge Wilson 		case 'c':
6490084fd14fSBrian Behlendorf 			if (cmd_type != POOL_INITIALIZE_START &&
6491084fd14fSBrian Behlendorf 			    cmd_type != POOL_INITIALIZE_CANCEL) {
6492094e47e9SGeorge Wilson 				(void) fprintf(stderr, gettext("-c cannot be "
6493094e47e9SGeorge Wilson 				    "combined with other options\n"));
6494094e47e9SGeorge Wilson 				usage(B_FALSE);
6495094e47e9SGeorge Wilson 			}
6496094e47e9SGeorge Wilson 			cmd_type = POOL_INITIALIZE_CANCEL;
6497094e47e9SGeorge Wilson 			break;
6498094e47e9SGeorge Wilson 		case 's':
6499084fd14fSBrian Behlendorf 			if (cmd_type != POOL_INITIALIZE_START &&
6500084fd14fSBrian Behlendorf 			    cmd_type != POOL_INITIALIZE_SUSPEND) {
6501094e47e9SGeorge Wilson 				(void) fprintf(stderr, gettext("-s cannot be "
6502094e47e9SGeorge Wilson 				    "combined with other options\n"));
6503094e47e9SGeorge Wilson 				usage(B_FALSE);
6504094e47e9SGeorge Wilson 			}
6505094e47e9SGeorge Wilson 			cmd_type = POOL_INITIALIZE_SUSPEND;
6506094e47e9SGeorge Wilson 			break;
6507094e47e9SGeorge Wilson 		case '?':
6508094e47e9SGeorge Wilson 			if (optopt != 0) {
6509094e47e9SGeorge Wilson 				(void) fprintf(stderr,
6510094e47e9SGeorge Wilson 				    gettext("invalid option '%c'\n"), optopt);
6511094e47e9SGeorge Wilson 			} else {
6512094e47e9SGeorge Wilson 				(void) fprintf(stderr,
6513094e47e9SGeorge Wilson 				    gettext("invalid option '%s'\n"),
6514094e47e9SGeorge Wilson 				    argv[optind - 1]);
6515094e47e9SGeorge Wilson 			}
6516094e47e9SGeorge Wilson 			usage(B_FALSE);
6517094e47e9SGeorge Wilson 		}
6518094e47e9SGeorge Wilson 	}
6519094e47e9SGeorge Wilson 
6520094e47e9SGeorge Wilson 	argc -= optind;
6521094e47e9SGeorge Wilson 	argv += optind;
6522094e47e9SGeorge Wilson 
6523094e47e9SGeorge Wilson 	if (argc < 1) {
6524094e47e9SGeorge Wilson 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
6525094e47e9SGeorge Wilson 		usage(B_FALSE);
6526094e47e9SGeorge Wilson 		return (-1);
6527094e47e9SGeorge Wilson 	}
6528094e47e9SGeorge Wilson 
6529094e47e9SGeorge Wilson 	poolname = argv[0];
6530094e47e9SGeorge Wilson 	zhp = zpool_open(g_zfs, poolname);
6531094e47e9SGeorge Wilson 	if (zhp == NULL)
6532094e47e9SGeorge Wilson 		return (-1);
6533094e47e9SGeorge Wilson 
6534094e47e9SGeorge Wilson 	vdevs = fnvlist_alloc();
6535094e47e9SGeorge Wilson 	if (argc == 1) {
6536094e47e9SGeorge Wilson 		/* no individual leaf vdevs specified, so add them all */
6537094e47e9SGeorge Wilson 		nvlist_t *config = zpool_get_config(zhp, NULL);
6538094e47e9SGeorge Wilson 		nvlist_t *nvroot = fnvlist_lookup_nvlist(config,
6539094e47e9SGeorge Wilson 		    ZPOOL_CONFIG_VDEV_TREE);
6540094e47e9SGeorge Wilson 		zpool_collect_leaves(zhp, nvroot, vdevs);
6541094e47e9SGeorge Wilson 	} else {
6542084fd14fSBrian Behlendorf 		for (int i = 1; i < argc; i++) {
6543094e47e9SGeorge Wilson 			fnvlist_add_boolean(vdevs, argv[i]);
6544094e47e9SGeorge Wilson 		}
6545094e47e9SGeorge Wilson 	}
6546094e47e9SGeorge Wilson 
6547094e47e9SGeorge Wilson 	err = zpool_initialize(zhp, cmd_type, vdevs);
6548094e47e9SGeorge Wilson 
6549094e47e9SGeorge Wilson 	fnvlist_free(vdevs);
6550094e47e9SGeorge Wilson 	zpool_close(zhp);
6551094e47e9SGeorge Wilson 
6552094e47e9SGeorge Wilson 	return (err);
6553094e47e9SGeorge Wilson }
6554094e47e9SGeorge Wilson 
6555fa9e4066Sahrens /*
6556fa9e4066Sahrens  * Print out detailed scrub status.
6557fa9e4066Sahrens  */
65585cabbc6bSPrashanth Sreenivasa static void
65593f9d6ad7SLin Ling print_scan_status(pool_scan_stat_t *ps)
6560fa9e4066Sahrens {
65611702cce7SAlek Pinchuk 	time_t start, end, pause;
6562a3874b8bSToomas Soome 	uint64_t total_secs_left;
6563a3874b8bSToomas Soome 	uint64_t elapsed, secs_left, mins_left, hours_left, days_left;
6564a3874b8bSToomas Soome 	uint64_t pass_scanned, scanned, pass_issued, issued, total;
6565a3874b8bSToomas Soome 	uint_t scan_rate, issue_rate;
6566fa9e4066Sahrens 	double fraction_done;
6567a3874b8bSToomas Soome 	char processed_buf[7], scanned_buf[7], issued_buf[7], total_buf[7];
6568a3874b8bSToomas Soome 	char srate_buf[7], irate_buf[7];
6569fa9e4066Sahrens 
6570ce72e614SYuri Pankov 	(void) printf(gettext("  scan: "));
6571fa9e4066Sahrens 
65723f9d6ad7SLin Ling 	/* If there's never been a scan, there's not much to say. */
65733f9d6ad7SLin Ling 	if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
65743f9d6ad7SLin Ling 	    ps->pss_func >= POOL_SCAN_FUNCS) {
6575fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
6576fa9e4066Sahrens 		return;
6577fa9e4066Sahrens 	}
6578fa9e4066Sahrens 
65793f9d6ad7SLin Ling 	start = ps->pss_start_time;
65803f9d6ad7SLin Ling 	end = ps->pss_end_time;
65811702cce7SAlek Pinchuk 	pause = ps->pss_pass_scrub_pause;
6582a3874b8bSToomas Soome 
65833f9d6ad7SLin Ling 	zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
6584fa9e4066Sahrens 
65853f9d6ad7SLin Ling 	assert(ps->pss_func == POOL_SCAN_SCRUB ||
65863f9d6ad7SLin Ling 	    ps->pss_func == POOL_SCAN_RESILVER);
6587a3874b8bSToomas Soome 
65883f9d6ad7SLin Ling 	/*
65893f9d6ad7SLin Ling 	 * Scan is finished or canceled.
65903f9d6ad7SLin Ling 	 */
65913f9d6ad7SLin Ling 	if (ps->pss_state == DSS_FINISHED) {
6592a3874b8bSToomas Soome 		total_secs_left = end - start;
6593a3874b8bSToomas Soome 		days_left = total_secs_left / 60 / 60 / 24;
6594a3874b8bSToomas Soome 		hours_left = (total_secs_left / 60 / 60) % 24;
6595a3874b8bSToomas Soome 		mins_left = (total_secs_left / 60) % 60;
6596a3874b8bSToomas Soome 		secs_left = (total_secs_left % 60);
65973f9d6ad7SLin Ling 
65983f9d6ad7SLin Ling 		if (ps->pss_func == POOL_SCAN_SCRUB) {
6599a3874b8bSToomas Soome 			(void) printf(gettext("scrub repaired %s "
6600a3874b8bSToomas Soome 			    "in %llu days %02llu:%02llu:%02llu "
6601a3874b8bSToomas Soome 			    "with %llu errors on %s"), processed_buf,
6602a3874b8bSToomas Soome 			    (u_longlong_t)days_left, (u_longlong_t)hours_left,
6603a3874b8bSToomas Soome 			    (u_longlong_t)mins_left, (u_longlong_t)secs_left,
6604a3874b8bSToomas Soome 			    (u_longlong_t)ps->pss_errors, ctime(&end));
66053f9d6ad7SLin Ling 		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
6606a3874b8bSToomas Soome 			(void) printf(gettext("resilvered %s "
6607a3874b8bSToomas Soome 			    "in %llu days %02llu:%02llu:%02llu "
6608a3874b8bSToomas Soome 			    "with %llu errors on %s"), processed_buf,
6609a3874b8bSToomas Soome 			    (u_longlong_t)days_left, (u_longlong_t)hours_left,
6610a3874b8bSToomas Soome 			    (u_longlong_t)mins_left, (u_longlong_t)secs_left,
6611a3874b8bSToomas Soome 			    (u_longlong_t)ps->pss_errors, ctime(&end));
66123f9d6ad7SLin Ling 		}
66133f9d6ad7SLin Ling 		return;
66143f9d6ad7SLin Ling 	} else if (ps->pss_state == DSS_CANCELED) {
66153f9d6ad7SLin Ling 		if (ps->pss_func == POOL_SCAN_SCRUB) {
66163f9d6ad7SLin Ling 			(void) printf(gettext("scrub canceled on %s"),
66173f9d6ad7SLin Ling 			    ctime(&end));
66183f9d6ad7SLin Ling 		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
66193f9d6ad7SLin Ling 			(void) printf(gettext("resilver canceled on %s"),
66203f9d6ad7SLin Ling 			    ctime(&end));
66213f9d6ad7SLin Ling 		}
6622fa9e4066Sahrens 		return;
6623fa9e4066Sahrens 	}
6624fa9e4066Sahrens 
66253f9d6ad7SLin Ling 	assert(ps->pss_state == DSS_SCANNING);
66263f9d6ad7SLin Ling 
6627a3874b8bSToomas Soome 	/* Scan is in progress. Resilvers can't be paused. */
66283f9d6ad7SLin Ling 	if (ps->pss_func == POOL_SCAN_SCRUB) {
66291702cce7SAlek Pinchuk 		if (pause == 0) {
66301702cce7SAlek Pinchuk 			(void) printf(gettext("scrub in progress since %s"),
66311702cce7SAlek Pinchuk 			    ctime(&start));
66321702cce7SAlek Pinchuk 		} else {
6633a3874b8bSToomas Soome 			(void) printf(gettext("scrub paused since %s"),
6634a3874b8bSToomas Soome 			    ctime(&pause));
6635a3874b8bSToomas Soome 			(void) printf(gettext("\tscrub started on %s"),
66361702cce7SAlek Pinchuk 			    ctime(&start));
66371702cce7SAlek Pinchuk 		}
66383f9d6ad7SLin Ling 	} else if (ps->pss_func == POOL_SCAN_RESILVER) {
66393f9d6ad7SLin Ling 		(void) printf(gettext("resilver in progress since %s"),
66403f9d6ad7SLin Ling 		    ctime(&start));
66413f9d6ad7SLin Ling 	}
6642fa9e4066Sahrens 
6643a3874b8bSToomas Soome 	scanned = ps->pss_examined;
6644a3874b8bSToomas Soome 	pass_scanned = ps->pss_pass_exam;
6645a3874b8bSToomas Soome 	issued = ps->pss_issued;
6646a3874b8bSToomas Soome 	pass_issued = ps->pss_pass_issued;
66473f9d6ad7SLin Ling 	total = ps->pss_to_examine;
66483f9d6ad7SLin Ling 
6649a3874b8bSToomas Soome 	/* we are only done with a block once we have issued the IO for it  */
6650a3874b8bSToomas Soome 	fraction_done = (double)issued / total;
6651a3874b8bSToomas Soome 
6652a3874b8bSToomas Soome 	/* elapsed time for this pass, rounding up to 1 if it's 0 */
66533f9d6ad7SLin Ling 	elapsed = time(NULL) - ps->pss_pass_start;
66541702cce7SAlek Pinchuk 	elapsed -= ps->pss_pass_scrub_spent_paused;
6655a3874b8bSToomas Soome 	elapsed = (elapsed != 0) ? elapsed : 1;
6656a3874b8bSToomas Soome 
6657a3874b8bSToomas Soome 	scan_rate = pass_scanned / elapsed;
6658a3874b8bSToomas Soome 	issue_rate = pass_issued / elapsed;
66593db6627cSTom Caputi 	total_secs_left = (issue_rate != 0 && total >= issued) ?
6660a3874b8bSToomas Soome 	    ((total - issued) / issue_rate) : UINT64_MAX;
6661a3874b8bSToomas Soome 
6662a3874b8bSToomas Soome 	days_left = total_secs_left / 60 / 60 / 24;
6663a3874b8bSToomas Soome 	hours_left = (total_secs_left / 60 / 60) % 24;
6664a3874b8bSToomas Soome 	mins_left = (total_secs_left / 60) % 60;
6665a3874b8bSToomas Soome 	secs_left = (total_secs_left % 60);
6666a3874b8bSToomas Soome 
6667a3874b8bSToomas Soome 	/* format all of the numbers we will be reporting */
6668a3874b8bSToomas Soome 	zfs_nicenum(scanned, scanned_buf, sizeof (scanned_buf));
6669a3874b8bSToomas Soome 	zfs_nicenum(issued, issued_buf, sizeof (issued_buf));
66703f9d6ad7SLin Ling 	zfs_nicenum(total, total_buf, sizeof (total_buf));
6671a3874b8bSToomas Soome 	zfs_nicenum(scan_rate, srate_buf, sizeof (srate_buf));
6672a3874b8bSToomas Soome 	zfs_nicenum(issue_rate, irate_buf, sizeof (irate_buf));
66733f9d6ad7SLin Ling 
6674a3874b8bSToomas Soome 	/* do not print estimated time if we have a paused scrub */
66751702cce7SAlek Pinchuk 	if (pause == 0) {
6676a3874b8bSToomas Soome 		(void) printf(gettext("\t%s scanned at %s/s, "
6677a3874b8bSToomas Soome 		    "%s issued at %s/s, %s total\n"),
6678a3874b8bSToomas Soome 		    scanned_buf, srate_buf, issued_buf, irate_buf, total_buf);
667973d314ceSLin Ling 	} else {
6680a3874b8bSToomas Soome 		(void) printf(gettext("\t%s scanned, %s issued, %s total\n"),
6681a3874b8bSToomas Soome 		    scanned_buf, issued_buf, total_buf);
668273d314ceSLin Ling 	}
66833f9d6ad7SLin Ling 
66843f9d6ad7SLin Ling 	if (ps->pss_func == POOL_SCAN_RESILVER) {
6685a3874b8bSToomas Soome 		(void) printf(gettext("\t%s resilvered, %.2f%% done"),
66863f9d6ad7SLin Ling 		    processed_buf, 100 * fraction_done);
66873f9d6ad7SLin Ling 	} else if (ps->pss_func == POOL_SCAN_SCRUB) {
6688a3874b8bSToomas Soome 		(void) printf(gettext("\t%s repaired, %.2f%% done"),
66893f9d6ad7SLin Ling 		    processed_buf, 100 * fraction_done);
66903f9d6ad7SLin Ling 	}
6691a3874b8bSToomas Soome 
6692a3874b8bSToomas Soome 	if (pause == 0) {
66933db6627cSTom Caputi 		if (total_secs_left != UINT64_MAX &&
66943db6627cSTom Caputi 		    issue_rate >= 10 * 1024 * 1024) {
6695a3874b8bSToomas Soome 			(void) printf(gettext(", %llu days "
6696a3874b8bSToomas Soome 			    "%02llu:%02llu:%02llu to go\n"),
6697a3874b8bSToomas Soome 			    (u_longlong_t)days_left, (u_longlong_t)hours_left,
6698a3874b8bSToomas Soome 			    (u_longlong_t)mins_left, (u_longlong_t)secs_left);
6699a3874b8bSToomas Soome 		} else {
6700a3874b8bSToomas Soome 			(void) printf(gettext(", no estimated "
6701a3874b8bSToomas Soome 			    "completion time\n"));
6702a3874b8bSToomas Soome 		}
6703a3874b8bSToomas Soome 	} else {
6704a3874b8bSToomas Soome 		(void) printf(gettext("\n"));
6705a3874b8bSToomas Soome 	}
6706fa9e4066Sahrens }
6707fa9e4066Sahrens 
670886714001SSerapheim Dimitropoulos /*
670986714001SSerapheim Dimitropoulos  * As we don't scrub checkpointed blocks, we want to warn the
671086714001SSerapheim Dimitropoulos  * user that we skipped scanning some blocks if a checkpoint exists
671186714001SSerapheim Dimitropoulos  * or existed at any time during the scan.
671286714001SSerapheim Dimitropoulos  */
671386714001SSerapheim Dimitropoulos static void
671486714001SSerapheim Dimitropoulos print_checkpoint_scan_warning(pool_scan_stat_t *ps, pool_checkpoint_stat_t *pcs)
671586714001SSerapheim Dimitropoulos {
671686714001SSerapheim Dimitropoulos 	if (ps == NULL || pcs == NULL)
671786714001SSerapheim Dimitropoulos 		return;
671886714001SSerapheim Dimitropoulos 
671986714001SSerapheim Dimitropoulos 	if (pcs->pcs_state == CS_NONE ||
672086714001SSerapheim Dimitropoulos 	    pcs->pcs_state == CS_CHECKPOINT_DISCARDING)
672186714001SSerapheim Dimitropoulos 		return;
672286714001SSerapheim Dimitropoulos 
672386714001SSerapheim Dimitropoulos 	assert(pcs->pcs_state == CS_CHECKPOINT_EXISTS);
672486714001SSerapheim Dimitropoulos 
672586714001SSerapheim Dimitropoulos 	if (ps->pss_state == DSS_NONE)
672686714001SSerapheim Dimitropoulos 		return;
672786714001SSerapheim Dimitropoulos 
672886714001SSerapheim Dimitropoulos 	if ((ps->pss_state == DSS_FINISHED || ps->pss_state == DSS_CANCELED) &&
672986714001SSerapheim Dimitropoulos 	    ps->pss_end_time < pcs->pcs_start_time)
673086714001SSerapheim Dimitropoulos 		return;
673186714001SSerapheim Dimitropoulos 
673286714001SSerapheim Dimitropoulos 	if (ps->pss_state == DSS_FINISHED || ps->pss_state == DSS_CANCELED) {
673386714001SSerapheim Dimitropoulos 		(void) printf(gettext("    scan warning: skipped blocks "
673486714001SSerapheim Dimitropoulos 		    "that are only referenced by the checkpoint.\n"));
673586714001SSerapheim Dimitropoulos 	} else {
673686714001SSerapheim Dimitropoulos 		assert(ps->pss_state == DSS_SCANNING);
673786714001SSerapheim Dimitropoulos 		(void) printf(gettext("    scan warning: skipping blocks "
673886714001SSerapheim Dimitropoulos 		    "that are only referenced by the checkpoint.\n"));
673986714001SSerapheim Dimitropoulos 	}
674086714001SSerapheim Dimitropoulos }
674186714001SSerapheim Dimitropoulos 
67425cabbc6bSPrashanth Sreenivasa /*
67435cabbc6bSPrashanth Sreenivasa  * Print out detailed removal status.
67445cabbc6bSPrashanth Sreenivasa  */
67455cabbc6bSPrashanth Sreenivasa static void
67465cabbc6bSPrashanth Sreenivasa print_removal_status(zpool_handle_t *zhp, pool_removal_stat_t *prs)
67475cabbc6bSPrashanth Sreenivasa {
67485cabbc6bSPrashanth Sreenivasa 	char copied_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
67495cabbc6bSPrashanth Sreenivasa 	time_t start, end;
67505cabbc6bSPrashanth Sreenivasa 	nvlist_t *config, *nvroot;
67515cabbc6bSPrashanth Sreenivasa 	nvlist_t **child;
67525cabbc6bSPrashanth Sreenivasa 	uint_t children;
67535cabbc6bSPrashanth Sreenivasa 	char *vdev_name;
67545cabbc6bSPrashanth Sreenivasa 
67555cabbc6bSPrashanth Sreenivasa 	if (prs == NULL || prs->prs_state == DSS_NONE)
67565cabbc6bSPrashanth Sreenivasa 		return;
67575cabbc6bSPrashanth Sreenivasa 
67585cabbc6bSPrashanth Sreenivasa 	/*
67595cabbc6bSPrashanth Sreenivasa 	 * Determine name of vdev.
67605cabbc6bSPrashanth Sreenivasa 	 */
67615cabbc6bSPrashanth Sreenivasa 	config = zpool_get_config(zhp, NULL);
67625cabbc6bSPrashanth Sreenivasa 	nvroot = fnvlist_lookup_nvlist(config,
67635cabbc6bSPrashanth Sreenivasa 	    ZPOOL_CONFIG_VDEV_TREE);
67645cabbc6bSPrashanth Sreenivasa 	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
67655cabbc6bSPrashanth Sreenivasa 	    &child, &children) == 0);
67665cabbc6bSPrashanth Sreenivasa 	assert(prs->prs_removing_vdev < children);
67675cabbc6bSPrashanth Sreenivasa 	vdev_name = zpool_vdev_name(g_zfs, zhp,
67685cabbc6bSPrashanth Sreenivasa 	    child[prs->prs_removing_vdev], B_TRUE);
67695cabbc6bSPrashanth Sreenivasa 
67705cabbc6bSPrashanth Sreenivasa 	(void) printf(gettext("remove: "));
67715cabbc6bSPrashanth Sreenivasa 
67725cabbc6bSPrashanth Sreenivasa 	start = prs->prs_start_time;
67735cabbc6bSPrashanth Sreenivasa 	end = prs->prs_end_time;
67745cabbc6bSPrashanth Sreenivasa 	zfs_nicenum(prs->prs_copied, copied_buf, sizeof (copied_buf));
67755cabbc6bSPrashanth Sreenivasa 
67765cabbc6bSPrashanth Sreenivasa 	/*
67775cabbc6bSPrashanth Sreenivasa 	 * Removal is finished or canceled.
67785cabbc6bSPrashanth Sreenivasa 	 */
67795cabbc6bSPrashanth Sreenivasa 	if (prs->prs_state == DSS_FINISHED) {
67805cabbc6bSPrashanth Sreenivasa 		uint64_t minutes_taken = (end - start) / 60;
67815cabbc6bSPrashanth Sreenivasa 
67825cabbc6bSPrashanth Sreenivasa 		(void) printf(gettext("Removal of vdev %llu copied %s "
67835cabbc6bSPrashanth Sreenivasa 		    "in %lluh%um, completed on %s"),
67845cabbc6bSPrashanth Sreenivasa 		    (longlong_t)prs->prs_removing_vdev,
67855cabbc6bSPrashanth Sreenivasa 		    copied_buf,
67865cabbc6bSPrashanth Sreenivasa 		    (u_longlong_t)(minutes_taken / 60),
67875cabbc6bSPrashanth Sreenivasa 		    (uint_t)(minutes_taken % 60),
67885cabbc6bSPrashanth Sreenivasa 		    ctime((time_t *)&end));
67895cabbc6bSPrashanth Sreenivasa 	} else if (prs->prs_state == DSS_CANCELED) {
67905cabbc6bSPrashanth Sreenivasa 		(void) printf(gettext("Removal of %s canceled on %s"),
67915cabbc6bSPrashanth Sreenivasa 		    vdev_name, ctime(&end));
67925cabbc6bSPrashanth Sreenivasa 	} else {
67935cabbc6bSPrashanth Sreenivasa 		uint64_t copied, total, elapsed, mins_left, hours_left;
67945cabbc6bSPrashanth Sreenivasa 		double fraction_done;
67955cabbc6bSPrashanth Sreenivasa 		uint_t rate;
67965cabbc6bSPrashanth Sreenivasa 
67975cabbc6bSPrashanth Sreenivasa 		assert(prs->prs_state == DSS_SCANNING);
67985cabbc6bSPrashanth Sreenivasa 
67995cabbc6bSPrashanth Sreenivasa 		/*
68005cabbc6bSPrashanth Sreenivasa 		 * Removal is in progress.
68015cabbc6bSPrashanth Sreenivasa 		 */
68025cabbc6bSPrashanth Sreenivasa 		(void) printf(gettext(
68035cabbc6bSPrashanth Sreenivasa 		    "Evacuation of %s in progress since %s"),
68045cabbc6bSPrashanth Sreenivasa 		    vdev_name, ctime(&start));
68055cabbc6bSPrashanth Sreenivasa 
68065cabbc6bSPrashanth Sreenivasa 		copied = prs->prs_copied > 0 ? prs->prs_copied : 1;
68075cabbc6bSPrashanth Sreenivasa 		total = prs->prs_to_copy;
68085cabbc6bSPrashanth Sreenivasa 		fraction_done = (double)copied / total;
68095cabbc6bSPrashanth Sreenivasa 
68105cabbc6bSPrashanth Sreenivasa 		/* elapsed time for this pass */
68115cabbc6bSPrashanth Sreenivasa 		elapsed = time(NULL) - prs->prs_start_time;
68125cabbc6bSPrashanth Sreenivasa 		elapsed = elapsed > 0 ? elapsed : 1;
68135cabbc6bSPrashanth Sreenivasa 		rate = copied / elapsed;
68145cabbc6bSPrashanth Sreenivasa 		rate = rate > 0 ? rate : 1;
68155cabbc6bSPrashanth Sreenivasa 		mins_left = ((total - copied) / rate) / 60;
68165cabbc6bSPrashanth Sreenivasa 		hours_left = mins_left / 60;
68175cabbc6bSPrashanth Sreenivasa 
68185cabbc6bSPrashanth Sreenivasa 		zfs_nicenum(copied, examined_buf, sizeof (examined_buf));
68195cabbc6bSPrashanth Sreenivasa 		zfs_nicenum(total, total_buf, sizeof (total_buf));
68205cabbc6bSPrashanth Sreenivasa 		zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
68215cabbc6bSPrashanth Sreenivasa 
68225cabbc6bSPrashanth Sreenivasa 		/*
68235cabbc6bSPrashanth Sreenivasa 		 * do not print estimated time if hours_left is more than
68245cabbc6bSPrashanth Sreenivasa 		 * 30 days
68255cabbc6bSPrashanth Sreenivasa 		 */
68265cabbc6bSPrashanth Sreenivasa 		(void) printf(gettext("    %s copied out of %s at %s/s, "
68275cabbc6bSPrashanth Sreenivasa 		    "%.2f%% done"),
68285cabbc6bSPrashanth Sreenivasa 		    examined_buf, total_buf, rate_buf, 100 * fraction_done);
68295cabbc6bSPrashanth Sreenivasa 		if (hours_left < (30 * 24)) {
68305cabbc6bSPrashanth Sreenivasa 			(void) printf(gettext(", %lluh%um to go\n"),
68315cabbc6bSPrashanth Sreenivasa 			    (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
68325cabbc6bSPrashanth Sreenivasa 		} else {
68335cabbc6bSPrashanth Sreenivasa 			(void) printf(gettext(
68345cabbc6bSPrashanth Sreenivasa 			    ", (copy is slow, no estimated time)\n"));
68355cabbc6bSPrashanth Sreenivasa 		}
68365cabbc6bSPrashanth Sreenivasa 	}
68375cabbc6bSPrashanth Sreenivasa 
68385cabbc6bSPrashanth Sreenivasa 	if (prs->prs_mapping_memory > 0) {
68395cabbc6bSPrashanth Sreenivasa 		char mem_buf[7];
68405cabbc6bSPrashanth Sreenivasa 		zfs_nicenum(prs->prs_mapping_memory, mem_buf, sizeof (mem_buf));
68415cabbc6bSPrashanth Sreenivasa 		(void) printf(gettext("    %s memory used for "
68425cabbc6bSPrashanth Sreenivasa 		    "removed device mappings\n"),
68435cabbc6bSPrashanth Sreenivasa 		    mem_buf);
68445cabbc6bSPrashanth Sreenivasa 	}
68455cabbc6bSPrashanth Sreenivasa }
68465cabbc6bSPrashanth Sreenivasa 
684786714001SSerapheim Dimitropoulos static void
684886714001SSerapheim Dimitropoulos print_checkpoint_status(pool_checkpoint_stat_t *pcs)
684986714001SSerapheim Dimitropoulos {
685086714001SSerapheim Dimitropoulos 	time_t start;
685186714001SSerapheim Dimitropoulos 	char space_buf[7];
685286714001SSerapheim Dimitropoulos 
685386714001SSerapheim Dimitropoulos 	if (pcs == NULL || pcs->pcs_state == CS_NONE)
685486714001SSerapheim Dimitropoulos 		return;
685586714001SSerapheim Dimitropoulos 
685686714001SSerapheim Dimitropoulos 	(void) printf(gettext("checkpoint: "));
685786714001SSerapheim Dimitropoulos 
685886714001SSerapheim Dimitropoulos 	start = pcs->pcs_start_time;
685986714001SSerapheim Dimitropoulos 	zfs_nicenum(pcs->pcs_space, space_buf, sizeof (space_buf));
686086714001SSerapheim Dimitropoulos 
686186714001SSerapheim Dimitropoulos 	if (pcs->pcs_state == CS_CHECKPOINT_EXISTS) {
686286714001SSerapheim Dimitropoulos 		char *date = ctime(&start);
686386714001SSerapheim Dimitropoulos 
686486714001SSerapheim Dimitropoulos 		/*
686586714001SSerapheim Dimitropoulos 		 * ctime() adds a newline at the end of the generated
686686714001SSerapheim Dimitropoulos 		 * string, thus the weird format specifier and the
686786714001SSerapheim Dimitropoulos 		 * strlen() call used to chop it off from the output.
686886714001SSerapheim Dimitropoulos 		 */
686986714001SSerapheim Dimitropoulos 		(void) printf(gettext("created %.*s, consumes %s\n"),
687086714001SSerapheim Dimitropoulos 		    strlen(date) - 1, date, space_buf);
687186714001SSerapheim Dimitropoulos 		return;
687286714001SSerapheim Dimitropoulos 	}
687386714001SSerapheim Dimitropoulos 
687486714001SSerapheim Dimitropoulos 	assert(pcs->pcs_state == CS_CHECKPOINT_DISCARDING);
687586714001SSerapheim Dimitropoulos 
687686714001SSerapheim Dimitropoulos 	(void) printf(gettext("discarding, %s remaining.\n"),
687786714001SSerapheim Dimitropoulos 	    space_buf);
687886714001SSerapheim Dimitropoulos }
687986714001SSerapheim Dimitropoulos 
6880ea8dc4b6Seschrock static void
6881ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
6882ea8dc4b6Seschrock {
688375519f38Sek 	nvlist_t *nverrlist = NULL;
688455434c77Sek 	nvpair_t *elem;
688555434c77Sek 	char *pathname;
688655434c77Sek 	size_t len = MAXPATHLEN * 2;
6887ea8dc4b6Seschrock 
688855434c77Sek 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
6889ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
6890ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
6891ea8dc4b6Seschrock 		return;
6892ea8dc4b6Seschrock 	}
6893ea8dc4b6Seschrock 
689455434c77Sek 	(void) printf("errors: Permanent errors have been "
689555434c77Sek 	    "detected in the following files:\n\n");
6896ea8dc4b6Seschrock 
689755434c77Sek 	pathname = safe_malloc(len);
689855434c77Sek 	elem = NULL;
689955434c77Sek 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
690055434c77Sek 		nvlist_t *nv;
690155434c77Sek 		uint64_t dsobj, obj;
690255434c77Sek 
690355434c77Sek 		verify(nvpair_value_nvlist(elem, &nv) == 0);
690455434c77Sek 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
690555434c77Sek 		    &dsobj) == 0);
690655434c77Sek 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
690755434c77Sek 		    &obj) == 0);
690855434c77Sek 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
690955434c77Sek 		(void) printf("%7s %s\n", "", pathname);
691055434c77Sek 	}
691155434c77Sek 	free(pathname);
691255434c77Sek 	nvlist_free(nverrlist);
6913ea8dc4b6Seschrock }
6914ea8dc4b6Seschrock 
691599653d4eSeschrock static void
6916663207adSDon Brady print_spares(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t **spares,
6917663207adSDon Brady     uint_t nspares)
691899653d4eSeschrock {
691999653d4eSeschrock 	uint_t i;
692099653d4eSeschrock 	char *name;
692199653d4eSeschrock 
692299653d4eSeschrock 	if (nspares == 0)
692399653d4eSeschrock 		return;
692499653d4eSeschrock 
692599653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
692699653d4eSeschrock 
692799653d4eSeschrock 	for (i = 0; i < nspares; i++) {
6928663207adSDon Brady 		name = zpool_vdev_name(g_zfs, zhp, spares[i],
6929663207adSDon Brady 		    cb->cb_name_flags);
6930663207adSDon Brady 		print_status_config(zhp, cb, name, spares[i], 2, B_TRUE);
693199653d4eSeschrock 		free(name);
693299653d4eSeschrock 	}
693399653d4eSeschrock }
693499653d4eSeschrock 
6935fa94a07fSbrendan static void
6936663207adSDon Brady print_l2cache(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t **l2cache,
6937663207adSDon Brady     uint_t nl2cache)
6938fa94a07fSbrendan {
6939fa94a07fSbrendan 	uint_t i;
6940fa94a07fSbrendan 	char *name;
6941fa94a07fSbrendan 
6942fa94a07fSbrendan 	if (nl2cache == 0)
6943fa94a07fSbrendan 		return;
6944fa94a07fSbrendan 
6945fa94a07fSbrendan 	(void) printf(gettext("\tcache\n"));
6946fa94a07fSbrendan 
6947fa94a07fSbrendan 	for (i = 0; i < nl2cache; i++) {
6948663207adSDon Brady 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i],
6949663207adSDon Brady 		    cb->cb_name_flags);
6950663207adSDon Brady 		print_status_config(zhp, cb, name, l2cache[i], 2, B_FALSE);
6951aa8cf21aSNeil Perrin 		free(name);
6952aa8cf21aSNeil Perrin 	}
6953aa8cf21aSNeil Perrin }
6954aa8cf21aSNeil Perrin 
69559eb19f4dSGeorge Wilson static void
69569eb19f4dSGeorge Wilson print_dedup_stats(nvlist_t *config)
69579eb19f4dSGeorge Wilson {
69589eb19f4dSGeorge Wilson 	ddt_histogram_t *ddh;
69599eb19f4dSGeorge Wilson 	ddt_stat_t *dds;
69609eb19f4dSGeorge Wilson 	ddt_object_t *ddo;
69619eb19f4dSGeorge Wilson 	uint_t c;
69629eb19f4dSGeorge Wilson 
69639eb19f4dSGeorge Wilson 	/*
69649eb19f4dSGeorge Wilson 	 * If the pool was faulted then we may not have been able to
69652384d9f8SGeorge Wilson 	 * obtain the config. Otherwise, if we have anything in the dedup
69669eb19f4dSGeorge Wilson 	 * table continue processing the stats.
69679eb19f4dSGeorge Wilson 	 */
69689eb19f4dSGeorge Wilson 	if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
6969ce72e614SYuri Pankov 	    (uint64_t **)&ddo, &c) != 0)
69709eb19f4dSGeorge Wilson 		return;
69719eb19f4dSGeorge Wilson 
69729eb19f4dSGeorge Wilson 	(void) printf("\n");
6973ce72e614SYuri Pankov 	(void) printf(gettext(" dedup: "));
6974ce72e614SYuri Pankov 	if (ddo->ddo_count == 0) {
6975ce72e614SYuri Pankov 		(void) printf(gettext("no DDT entries\n"));
6976ce72e614SYuri Pankov 		return;
6977ce72e614SYuri Pankov 	}
6978ce72e614SYuri Pankov 
69799eb19f4dSGeorge Wilson 	(void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
69809eb19f4dSGeorge Wilson 	    (u_longlong_t)ddo->ddo_count,
69819eb19f4dSGeorge Wilson 	    (u_longlong_t)ddo->ddo_dspace,
69829eb19f4dSGeorge Wilson 	    (u_longlong_t)ddo->ddo_mspace);
69839eb19f4dSGeorge Wilson 
69849eb19f4dSGeorge Wilson 	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
69859eb19f4dSGeorge Wilson 	    (uint64_t **)&dds, &c) == 0);
69869eb19f4dSGeorge Wilson 	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
69879eb19f4dSGeorge Wilson 	    (uint64_t **)&ddh, &c) == 0);
69889eb19f4dSGeorge Wilson 	zpool_dump_ddt(dds, ddh);
69899eb19f4dSGeorge Wilson }
69909eb19f4dSGeorge Wilson 
6991fa9e4066Sahrens /*
6992fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
6993fa9e4066Sahrens  *
6994fa9e4066Sahrens  *        pool: tank
6995fa9e4066Sahrens  *	status: DEGRADED
6996fa9e4066Sahrens  *	reason: One or more devices ...
6997654b400cSJoshua M. Clulow  *         see: http://illumos.org/msg/ZFS-xxxx-01
6998fa9e4066Sahrens  *	config:
6999fa9e4066Sahrens  *		mirror		DEGRADED
7000fa9e4066Sahrens  *                c1t0d0	OK
7001ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
7002fa9e4066Sahrens  *
7003fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
7004fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
7005fa9e4066Sahrens  */
7006fa9e4066Sahrens int
7007fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
7008fa9e4066Sahrens {
7009fa9e4066Sahrens 	status_cbdata_t *cbp = data;
7010fa9e4066Sahrens 	nvlist_t *config, *nvroot;
7011fa9e4066Sahrens 	char *msgid;
7012fa9e4066Sahrens 	int reason;
7013eb633035STom Caputi 	zpool_errata_t errata;
701446657f8dSmmusante 	const char *health;
701546657f8dSmmusante 	uint_t c;
701646657f8dSmmusante 	vdev_stat_t *vs;
7017fa9e4066Sahrens 
7018088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
7019eb633035STom Caputi 	reason = zpool_get_status(zhp, &msgid, &errata);
7020fa9e4066Sahrens 
7021fa9e4066Sahrens 	cbp->cb_count++;
7022fa9e4066Sahrens 
7023fa9e4066Sahrens 	/*
7024fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
7025fa9e4066Sahrens 	 * problems.
7026fa9e4066Sahrens 	 */
7027b3a6f804STim Connors 	if (cbp->cb_explain &&
7028b3a6f804STim Connors 	    (reason == ZPOOL_STATUS_OK ||
7029b3a6f804STim Connors 	    reason == ZPOOL_STATUS_VERSION_OLDER ||
7030b3a6f804STim Connors 	    reason == ZPOOL_STATUS_FEAT_DISABLED)) {
7031e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
7032e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
7033e9dbad6fSeschrock 			    zpool_get_name(zhp));
7034e9dbad6fSeschrock 			if (cbp->cb_first)
7035e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
7036e9dbad6fSeschrock 		}
7037fa9e4066Sahrens 		return (0);
7038e9dbad6fSeschrock 	}
7039fa9e4066Sahrens 
7040fa9e4066Sahrens 	if (cbp->cb_first)
704199653d4eSeschrock 		cbp->cb_first = B_FALSE;
7042fa9e4066Sahrens 	else
7043fa9e4066Sahrens 		(void) printf("\n");
7044fa9e4066Sahrens 
70455cabbc6bSPrashanth Sreenivasa 	nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
70463f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
704746657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
7048990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
7049fa9e4066Sahrens 
7050fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
7051fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
7052fa9e4066Sahrens 
7053fa9e4066Sahrens 	switch (reason) {
7054fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
7055fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
7056fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
7057fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
7058fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
7059fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
7060fa9e4066Sahrens 		break;
7061fa9e4066Sahrens 
7062fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
7063fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
7064fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
7065fa9e4066Sahrens 		    "pool to continue functioning.\n"));
7066fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
7067fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
7068fa9e4066Sahrens 		break;
7069fa9e4066Sahrens 
7070fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
7071fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
7072fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
7073fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
7074fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
7075fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
7076fa9e4066Sahrens 		    "'zpool replace'.\n"));
7077fa9e4066Sahrens 		break;
7078fa9e4066Sahrens 
7079fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
7080fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
7081b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
7082fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
7083fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
7084468c413aSTim Haley 		zpool_explain_recover(zpool_get_handle(zhp),
7085468c413aSTim Haley 		    zpool_get_name(zhp), reason, config);
7086fa9e4066Sahrens 		break;
7087fa9e4066Sahrens 
7088fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
7089fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
7090fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
7091fa9e4066Sahrens 		    "made to correct the error.  Applications are "
7092fa9e4066Sahrens 		    "unaffected.\n"));
7093fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
7094fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
7095ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
7096fa9e4066Sahrens 		    "replace'.\n"));
7097fa9e4066Sahrens 		break;
7098fa9e4066Sahrens 
7099fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
7100fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
7101d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
7102fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
7103fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
7104fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
7105fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
7106fa9e4066Sahrens 		    "replace'.\n"));
7107fa9e4066Sahrens 		break;
7108fa9e4066Sahrens 
7109c25309d4SGeorge Wilson 	case ZPOOL_STATUS_REMOVED_DEV:
7110c25309d4SGeorge Wilson 		(void) printf(gettext("status: One or more devices has "
7111c25309d4SGeorge Wilson 		    "been removed by the administrator.\n\tSufficient "
7112c25309d4SGeorge Wilson 		    "replicas exist for the pool to continue functioning in "
7113c25309d4SGeorge Wilson 		    "a\n\tdegraded state.\n"));
7114c25309d4SGeorge Wilson 		(void) printf(gettext("action: Online the device using "
7115c25309d4SGeorge Wilson 		    "'zpool online' or replace the device with\n\t'zpool "
7116c25309d4SGeorge Wilson 		    "replace'.\n"));
7117c25309d4SGeorge Wilson 		break;
7118c25309d4SGeorge Wilson 
7119fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
7120fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
7121fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
7122fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
7123fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
7124fa9e4066Sahrens 		    "complete.\n"));
7125fa9e4066Sahrens 		break;
7126fa9e4066Sahrens 
7127ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
7128ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
7129ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
7130ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
7131ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
7132ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
7133ea8dc4b6Seschrock 		    "backup.\n"));
7134ea8dc4b6Seschrock 		break;
7135ea8dc4b6Seschrock 
7136ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
7137ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
7138ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
7139468c413aSTim Haley 		zpool_explain_recover(zpool_get_handle(zhp),
7140468c413aSTim Haley 		    zpool_get_name(zhp), reason, config);
7141ea8dc4b6Seschrock 		break;
7142ea8dc4b6Seschrock 
7143eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
714457221772SChristopher Siden 		(void) printf(gettext("status: The pool is formatted using a "
714557221772SChristopher Siden 		    "legacy on-disk format.  The pool can\n\tstill be used, "
714657221772SChristopher Siden 		    "but some features are unavailable.\n"));
7147eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
7148eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
714957221772SChristopher Siden 		    "be accessible on software that does not support feature\n"
715057221772SChristopher Siden 		    "\tflags.\n"));
7151eaca9bbdSeschrock 		break;
7152eaca9bbdSeschrock 
7153eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
7154eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
7155eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
7156eaca9bbdSeschrock 		    "be accessed on this system.\n"));
7157eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
7158eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
7159eaca9bbdSeschrock 		    "backup.\n"));
7160eaca9bbdSeschrock 		break;
7161eaca9bbdSeschrock 
716257221772SChristopher Siden 	case ZPOOL_STATUS_FEAT_DISABLED:
716357221772SChristopher Siden 		(void) printf(gettext("status: Some supported features are not "
716457221772SChristopher Siden 		    "enabled on the pool. The pool can\n\tstill be used, but "
716557221772SChristopher Siden 		    "some features are unavailable.\n"));
716657221772SChristopher Siden 		(void) printf(gettext("action: Enable all features using "
716757221772SChristopher Siden 		    "'zpool upgrade'. Once this is done,\n\tthe pool may no "
716857221772SChristopher Siden 		    "longer be accessible by software that does not support\n\t"
716957221772SChristopher Siden 		    "the features. See zpool-features(5) for details.\n"));
717057221772SChristopher Siden 		break;
717157221772SChristopher Siden 
7172ad135b5dSChristopher Siden 	case ZPOOL_STATUS_UNSUP_FEAT_READ:
7173ad135b5dSChristopher Siden 		(void) printf(gettext("status: The pool cannot be accessed on "
7174ad135b5dSChristopher Siden 		    "this system because it uses the\n\tfollowing feature(s) "
7175ad135b5dSChristopher Siden 		    "not supported on this system:\n"));
7176ad135b5dSChristopher Siden 		zpool_print_unsup_feat(config);
7177ad135b5dSChristopher Siden 		(void) printf("\n");
7178ad135b5dSChristopher Siden 		(void) printf(gettext("action: Access the pool from a system "
7179ad135b5dSChristopher Siden 		    "that supports the required feature(s),\n\tor restore the "
7180ad135b5dSChristopher Siden 		    "pool from backup.\n"));
7181ad135b5dSChristopher Siden 		break;
7182ad135b5dSChristopher Siden 
7183ad135b5dSChristopher Siden 	case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
7184ad135b5dSChristopher Siden 		(void) printf(gettext("status: The pool can only be accessed "
7185ad135b5dSChristopher Siden 		    "in read-only mode on this system. It\n\tcannot be "
7186ad135b5dSChristopher Siden 		    "accessed in read-write mode because it uses the "
7187ad135b5dSChristopher Siden 		    "following\n\tfeature(s) not supported on this system:\n"));
7188ad135b5dSChristopher Siden 		zpool_print_unsup_feat(config);
7189ad135b5dSChristopher Siden 		(void) printf("\n");
7190ad135b5dSChristopher Siden 		(void) printf(gettext("action: The pool cannot be accessed in "
7191ad135b5dSChristopher Siden 		    "read-write mode. Import the pool with\n"
7192ad135b5dSChristopher Siden 		    "\t\"-o readonly=on\", access the pool from a system that "
7193ad135b5dSChristopher Siden 		    "supports the\n\trequired feature(s), or restore the "
7194ad135b5dSChristopher Siden 		    "pool from backup.\n"));
7195ad135b5dSChristopher Siden 		break;
7196ad135b5dSChristopher Siden 
71973d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
71983d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
71993d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
72003d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
72013d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
72023d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
72033d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
72043d7072f8Seschrock 		break;
72053d7072f8Seschrock 
72063d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
72073d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
72083d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
72093d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
72103d7072f8Seschrock 		    "functioning.\n"));
72113d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
72123d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
72133d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
72143d7072f8Seschrock 		    "to be recovered.\n"));
72153d7072f8Seschrock 		break;
72163d7072f8Seschrock 
7217e0f1c0afSOlaf Faaland 	case ZPOOL_STATUS_IO_FAILURE_MMP:
7218e0f1c0afSOlaf Faaland 		(void) printf(gettext("status: The pool is suspended because "
7219e0f1c0afSOlaf Faaland 		    "multihost writes failed or were delayed;\n\tanother "
7220e0f1c0afSOlaf Faaland 		    "system could import the pool undetected.\n"));
7221e0f1c0afSOlaf Faaland 		(void) printf(gettext("action: Make sure the pool's devices "
7222e0f1c0afSOlaf Faaland 		    "are connected, then reboot your system and\n\timport the "
7223e0f1c0afSOlaf Faaland 		    "pool.\n"));
7224e0f1c0afSOlaf Faaland 		break;
7225e0f1c0afSOlaf Faaland 
722632b87932Sek 	case ZPOOL_STATUS_IO_FAILURE_WAIT:
722732b87932Sek 	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
722832b87932Sek 		(void) printf(gettext("status: One or more devices are "
72298a79c1b5Sek 		    "faulted in response to IO failures.\n"));
723032b87932Sek 		(void) printf(gettext("action: Make sure the affected devices "
723132b87932Sek 		    "are connected, then run 'zpool clear'.\n"));
723232b87932Sek 		break;
723332b87932Sek 
7234b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
7235b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record "
7236b87f3af3Sperrin 		    "could not be read.\n"
7237b87f3af3Sperrin 		    "\tWaiting for adminstrator intervention to fix the "
7238b87f3af3Sperrin 		    "faulted pool.\n"));
7239b87f3af3Sperrin 		(void) printf(gettext("action: Either restore the affected "
7240b87f3af3Sperrin 		    "device(s) and run 'zpool online',\n"
7241b87f3af3Sperrin 		    "\tor ignore the intent log records by running "
7242b87f3af3Sperrin 		    "'zpool clear'.\n"));
7243b87f3af3Sperrin 		break;
7244b87f3af3Sperrin 
7245eb633035STom Caputi 	case ZPOOL_STATUS_ERRATA:
7246eb633035STom Caputi 		(void) printf(gettext("status: Errata #%d detected.\n"),
7247eb633035STom Caputi 		    errata);
7248eb633035STom Caputi 
7249eb633035STom Caputi 		switch (errata) {
7250eb633035STom Caputi 		case ZPOOL_ERRATA_NONE:
7251eb633035STom Caputi 			break;
7252eb633035STom Caputi 
7253eb633035STom Caputi 		case ZPOOL_ERRATA_ZOL_2094_SCRUB:
7254eb633035STom Caputi 			(void) printf(gettext("action: To correct the issue "
7255eb633035STom Caputi 			    "run 'zpool scrub'.\n"));
7256eb633035STom Caputi 			break;
7257eb633035STom Caputi 
7258eb633035STom Caputi 		case ZPOOL_ERRATA_ZOL_6845_ENCRYPTION:
7259eb633035STom Caputi 			(void) printf(gettext("\tExisting encrypted datasets "
7260eb633035STom Caputi 			    "contain an on-disk incompatibility\n\twhich "
7261eb633035STom Caputi 			    "needs to be corrected.\n"));
7262eb633035STom Caputi 			(void) printf(gettext("action: To correct the issue "
7263eb633035STom Caputi 			    "backup existing encrypted datasets to new\n\t"
7264eb633035STom Caputi 			    "encrypted datasets and destroy the old ones. "
7265eb633035STom Caputi 			    "'zfs mount -o ro' can\n\tbe used to temporarily "
7266eb633035STom Caputi 			    "mount existing encrypted datasets readonly.\n"));
7267eb633035STom Caputi 			break;
7268eb633035STom Caputi 
7269eb633035STom Caputi 		case ZPOOL_ERRATA_ZOL_8308_ENCRYPTION:
7270eb633035STom Caputi 			(void) printf(gettext("\tExisting encrypted datasets "
7271eb633035STom Caputi 			    "contain an on-disk incompatibility\n\twhich "
7272eb633035STom Caputi 			    "needs to be corrected.\n"));
7273eb633035STom Caputi 			(void) printf(gettext("action: To correct the issue "
7274eb633035STom Caputi 			    "enable the bookmark_v2 feature and "
7275eb633035STom Caputi 			    "backup\n\tany existing encrypted datasets to "
7276eb633035STom Caputi 			    "new encrypted datasets and\n\tdestroy the old "
7277eb633035STom Caputi 			    "ones. If this pool does not contain any\n\t"
7278eb633035STom Caputi 			    "encrypted datasets, simply enable the "
7279eb633035STom Caputi 			    "bookmark_v2 feature\n"));
7280eb633035STom Caputi 			break;
7281eb633035STom Caputi 
7282eb633035STom Caputi 		default:
7283eb633035STom Caputi 			/*
7284eb633035STom Caputi 			 * All errata which allow the pool to be imported
7285eb633035STom Caputi 			 * must contain an action message.
7286eb633035STom Caputi 			 */
7287eb633035STom Caputi 			assert(0);
7288eb633035STom Caputi 		}
7289eb633035STom Caputi 		break;
7290eb633035STom Caputi 
7291fa9e4066Sahrens 	default:
7292fa9e4066Sahrens 		/*
7293fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
7294fa9e4066Sahrens 		 */
7295fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
7296fa9e4066Sahrens 	}
7297fa9e4066Sahrens 
7298fa9e4066Sahrens 	if (msgid != NULL)
7299654b400cSJoshua M. Clulow 		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
7300fa9e4066Sahrens 		    msgid);
7301fa9e4066Sahrens 
7302fa9e4066Sahrens 	if (config != NULL) {
7303ea8dc4b6Seschrock 		uint64_t nerr;
7304fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
7305fa94a07fSbrendan 		uint_t nspares, nl2cache;
730686714001SSerapheim Dimitropoulos 		pool_checkpoint_stat_t *pcs = NULL;
73073f9d6ad7SLin Ling 		pool_scan_stat_t *ps = NULL;
73085cabbc6bSPrashanth Sreenivasa 		pool_removal_stat_t *prs = NULL;
7309fa9e4066Sahrens 
731086714001SSerapheim Dimitropoulos 		(void) nvlist_lookup_uint64_array(nvroot,
731186714001SSerapheim Dimitropoulos 		    ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c);
73123f9d6ad7SLin Ling 		(void) nvlist_lookup_uint64_array(nvroot,
73133f9d6ad7SLin Ling 		    ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
73145cabbc6bSPrashanth Sreenivasa 		(void) nvlist_lookup_uint64_array(nvroot,
73155cabbc6bSPrashanth Sreenivasa 		    ZPOOL_CONFIG_REMOVAL_STATS, (uint64_t **)&prs, &c);
731686714001SSerapheim Dimitropoulos 
731786714001SSerapheim Dimitropoulos 		print_scan_status(ps);
731886714001SSerapheim Dimitropoulos 		print_checkpoint_scan_warning(ps, pcs);
73195cabbc6bSPrashanth Sreenivasa 		print_removal_status(zhp, prs);
732086714001SSerapheim Dimitropoulos 		print_checkpoint_status(pcs);
73215cabbc6bSPrashanth Sreenivasa 
7322663207adSDon Brady 		cbp->cb_namewidth = max_width(zhp, nvroot, 0, 0,
7323663207adSDon Brady 		    cbp->cb_name_flags);
7324663207adSDon Brady 		if (cbp->cb_namewidth < 10)
7325663207adSDon Brady 			cbp->cb_namewidth = 10;
7326fa9e4066Sahrens 
7327fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
7328663207adSDon Brady 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"),
7329663207adSDon Brady 		    cbp->cb_namewidth, "NAME", "STATE", "READ", "WRITE",
7330663207adSDon Brady 		    "CKSUM");
7331663207adSDon Brady 
7332dd50e0ccSTony Hutter 		if (cbp->cb_print_slow_ios)
7333dd50e0ccSTony Hutter 			(void) printf(" %5s", gettext("SLOW"));
7334dd50e0ccSTony Hutter 
7335663207adSDon Brady 		print_status_config(zhp, cbp, zpool_get_name(zhp), nvroot, 0,
7336663207adSDon Brady 		    B_FALSE);
7337663207adSDon Brady 
7338663207adSDon Brady 		print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_BIAS_DEDUP);
7339663207adSDon Brady 		print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_BIAS_SPECIAL);
7340663207adSDon Brady 		print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_CLASS_LOGS);
734199653d4eSeschrock 
7342fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
7343fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
7344663207adSDon Brady 			print_l2cache(zhp, cbp, l2cache, nl2cache);
7345fa94a07fSbrendan 
734699653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
734799653d4eSeschrock 		    &spares, &nspares) == 0)
7348663207adSDon Brady 			print_spares(zhp, cbp, spares, nspares);
7349ea8dc4b6Seschrock 
7350ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
7351ea8dc4b6Seschrock 		    &nerr) == 0) {
735255434c77Sek 			nvlist_t *nverrlist = NULL;
735355434c77Sek 
7354ea8dc4b6Seschrock 			/*
7355ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
7356ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
7357ea8dc4b6Seschrock 			 * uniquifying the results.
7358ea8dc4b6Seschrock 			 */
735975519f38Sek 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
736055434c77Sek 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
736155434c77Sek 				nvpair_t *elem;
736255434c77Sek 
736355434c77Sek 				elem = NULL;
736455434c77Sek 				nerr = 0;
736555434c77Sek 				while ((elem = nvlist_next_nvpair(nverrlist,
736655434c77Sek 				    elem)) != NULL) {
736755434c77Sek 					nerr++;
736855434c77Sek 				}
736955434c77Sek 			}
737055434c77Sek 			nvlist_free(nverrlist);
7371ea8dc4b6Seschrock 
7372ea8dc4b6Seschrock 			(void) printf("\n");
737399653d4eSeschrock 
7374ea8dc4b6Seschrock 			if (nerr == 0)
7375ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
7376ea8dc4b6Seschrock 				    "errors\n"));
7377ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
7378e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
73795ad82045Snd 				    "errors, use '-v' for a list\n"),
73805ad82045Snd 				    (u_longlong_t)nerr);
7381ea8dc4b6Seschrock 			else
7382ea8dc4b6Seschrock 				print_error_log(zhp);
7383ea8dc4b6Seschrock 		}
73849eb19f4dSGeorge Wilson 
73859eb19f4dSGeorge Wilson 		if (cbp->cb_dedup_stats)
73869eb19f4dSGeorge Wilson 			print_dedup_stats(config);
7387fa9e4066Sahrens 	} else {
7388fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
7389fa9e4066Sahrens 		    "determined.\n"));
7390fa9e4066Sahrens 	}
7391fa9e4066Sahrens 
7392fa9e4066Sahrens 	return (0);
7393fa9e4066Sahrens }
7394fa9e4066Sahrens 
7395fa9e4066Sahrens /*
7396dd50e0ccSTony Hutter  * zpool status [-igLpPstvx] [-T d|u] [pool] ... [interval [count]]
7397fa9e4066Sahrens  *
7398084fd14fSBrian Behlendorf  *	-i	Display vdev initialization status.
7399663207adSDon Brady  *	-g	Display guid for individual vdev name.
7400663207adSDon Brady  *	-L	Follow links when resolving vdev path name.
7401dd50e0ccSTony Hutter  *	-p	Display values in parsable (exact) format.
7402663207adSDon Brady  *	-P	Display full path for vdev name.
7403dd50e0ccSTony Hutter  *	-s	Display slow IOs column.
7404fa9e4066Sahrens  *	-v	Display complete error logs
7405fa9e4066Sahrens  *	-x	Display only pools with potential problems
74069eb19f4dSGeorge Wilson  *	-D	Display dedup status (undocumented)
7407084fd14fSBrian Behlendorf  *	-t	Display vdev TRIM status.
74083f9d6ad7SLin Ling  *	-T	Display a timestamp in date(1) or Unix format
7409fa9e4066Sahrens  *
7410fa9e4066Sahrens  * Describes the health status of all pools or some subset.
7411fa9e4066Sahrens  */
7412fa9e4066Sahrens int
7413fa9e4066Sahrens zpool_do_status(int argc, char **argv)
7414fa9e4066Sahrens {
7415fa9e4066Sahrens 	int c;
7416fa9e4066Sahrens 	int ret;
7417dd50e0ccSTony Hutter 	float interval = 0;
7418dd50e0ccSTony Hutter 	unsigned long count = 0;
7419fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
7420fa9e4066Sahrens 
7421fa9e4066Sahrens 	/* check options */
7422dd50e0ccSTony Hutter 	while ((c = getopt(argc, argv, "igLpPsvxDtT:")) != -1) {
7423fa9e4066Sahrens 		switch (c) {
7424084fd14fSBrian Behlendorf 		case 'i':
7425084fd14fSBrian Behlendorf 			cb.cb_print_vdev_init = B_TRUE;
7426084fd14fSBrian Behlendorf 			break;
7427663207adSDon Brady 		case 'g':
7428663207adSDon Brady 			cb.cb_name_flags |= VDEV_NAME_GUID;
7429663207adSDon Brady 			break;
7430663207adSDon Brady 		case 'L':
7431663207adSDon Brady 			cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
7432663207adSDon Brady 			break;
7433dd50e0ccSTony Hutter 		case 'p':
7434dd50e0ccSTony Hutter 			cb.cb_literal = B_TRUE;
7435dd50e0ccSTony Hutter 			break;
7436663207adSDon Brady 		case 'P':
7437663207adSDon Brady 			cb.cb_name_flags |= VDEV_NAME_PATH;
7438663207adSDon Brady 			break;
7439dd50e0ccSTony Hutter 		case 's':
7440dd50e0ccSTony Hutter 			cb.cb_print_slow_ios = B_TRUE;
7441dd50e0ccSTony Hutter 			break;
7442fa9e4066Sahrens 		case 'v':
744399653d4eSeschrock 			cb.cb_verbose = B_TRUE;
7444fa9e4066Sahrens 			break;
7445fa9e4066Sahrens 		case 'x':
744699653d4eSeschrock 			cb.cb_explain = B_TRUE;
7447fa9e4066Sahrens 			break;
74489eb19f4dSGeorge Wilson 		case 'D':
74499eb19f4dSGeorge Wilson 			cb.cb_dedup_stats = B_TRUE;
74509eb19f4dSGeorge Wilson 			break;
7451084fd14fSBrian Behlendorf 		case 't':
7452084fd14fSBrian Behlendorf 			cb.cb_print_vdev_trim = B_TRUE;
7453084fd14fSBrian Behlendorf 			break;
74543f9d6ad7SLin Ling 		case 'T':
74553f9d6ad7SLin Ling 			get_timestamp_arg(*optarg);
74563f9d6ad7SLin Ling 			break;
7457fa9e4066Sahrens 		case '?':
7458fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
7459fa9e4066Sahrens 			    optopt);
746099653d4eSeschrock 			usage(B_FALSE);
7461fa9e4066Sahrens 		}
7462fa9e4066Sahrens 	}
7463fa9e4066Sahrens 
7464fa9e4066Sahrens 	argc -= optind;
7465fa9e4066Sahrens 	argv += optind;
7466fa9e4066Sahrens 
74673f9d6ad7SLin Ling 	get_interval_count(&argc, argv, &interval, &count);
7468fa9e4066Sahrens 
7469e9dbad6fSeschrock 	if (argc == 0)
7470e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
7471e9dbad6fSeschrock 
74723f9d6ad7SLin Ling 	cb.cb_first = B_TRUE;
7473663207adSDon Brady 	cb.cb_print_status = B_TRUE;
7474fa9e4066Sahrens 
74753f9d6ad7SLin Ling 	for (;;) {
74763f9d6ad7SLin Ling 		if (timestamp_fmt != NODATE)
74773f9d6ad7SLin Ling 			print_timestamp(timestamp_fmt);
7478fa9e4066Sahrens 
74793f9d6ad7SLin Ling 		ret = for_each_pool(argc, argv, B_TRUE, NULL,
74803f9d6ad7SLin Ling 		    status_callback, &cb);
74813f9d6ad7SLin Ling 
74823f9d6ad7SLin Ling 		if (argc == 0 && cb.cb_count == 0)
74833f9d6ad7SLin Ling 			(void) printf(gettext("no pools available\n"));
74843f9d6ad7SLin Ling 		else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
74853f9d6ad7SLin Ling 			(void) printf(gettext("all pools are healthy\n"));
74863f9d6ad7SLin Ling 
74873f9d6ad7SLin Ling 		if (ret != 0)
74883f9d6ad7SLin Ling 			return (ret);
74893f9d6ad7SLin Ling 
74903f9d6ad7SLin Ling 		if (interval == 0)
74913f9d6ad7SLin Ling 			break;
74923f9d6ad7SLin Ling 
74933f9d6ad7SLin Ling 		if (count != 0 && --count == 0)
74943f9d6ad7SLin Ling 			break;
74953f9d6ad7SLin Ling 
7496dd50e0ccSTony Hutter 		(void) fsleep(interval);
74973f9d6ad7SLin Ling 	}
74983f9d6ad7SLin Ling 
74993f9d6ad7SLin Ling 	return (0);
7500fa9e4066Sahrens }
7501fa9e4066Sahrens 
7502eaca9bbdSeschrock typedef struct upgrade_cbdata {
7503eaca9bbdSeschrock 	int	cb_first;
750406eeb2adSek 	int	cb_argc;
7505990b4856Slling 	uint64_t cb_version;
750606eeb2adSek 	char	**cb_argv;
7507eaca9bbdSeschrock } upgrade_cbdata_t;
7508eaca9bbdSeschrock 
750957221772SChristopher Siden static int
751057221772SChristopher Siden upgrade_version(zpool_handle_t *zhp, uint64_t version)
751157221772SChristopher Siden {
751257221772SChristopher Siden 	int ret;
751357221772SChristopher Siden 	nvlist_t *config;
751457221772SChristopher Siden 	uint64_t oldversion;
751557221772SChristopher Siden 
751657221772SChristopher Siden 	config = zpool_get_config(zhp, NULL);
751757221772SChristopher Siden 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
751857221772SChristopher Siden 	    &oldversion) == 0);
751957221772SChristopher Siden 
752057221772SChristopher Siden 	assert(SPA_VERSION_IS_SUPPORTED(oldversion));
752157221772SChristopher Siden 	assert(oldversion < version);
752257221772SChristopher Siden 
752357221772SChristopher Siden 	ret = zpool_upgrade(zhp, version);
752457221772SChristopher Siden 	if (ret != 0)
752557221772SChristopher Siden 		return (ret);
752657221772SChristopher Siden 
752757221772SChristopher Siden 	if (version >= SPA_VERSION_FEATURES) {
752857221772SChristopher Siden 		(void) printf(gettext("Successfully upgraded "
752957221772SChristopher Siden 		    "'%s' from version %llu to feature flags.\n"),
753057221772SChristopher Siden 		    zpool_get_name(zhp), oldversion);
753157221772SChristopher Siden 	} else {
753257221772SChristopher Siden 		(void) printf(gettext("Successfully upgraded "
753357221772SChristopher Siden 		    "'%s' from version %llu to version %llu.\n"),
753457221772SChristopher Siden 		    zpool_get_name(zhp), oldversion, version);
753557221772SChristopher Siden 	}
753657221772SChristopher Siden 
753757221772SChristopher Siden 	return (0);
753857221772SChristopher Siden }
753957221772SChristopher Siden 
754057221772SChristopher Siden static int
754157221772SChristopher Siden upgrade_enable_all(zpool_handle_t *zhp, int *countp)
754257221772SChristopher Siden {
754357221772SChristopher Siden 	int i, ret, count;
754457221772SChristopher Siden 	boolean_t firstff = B_TRUE;
754557221772SChristopher Siden 	nvlist_t *enabled = zpool_get_features(zhp);
754657221772SChristopher Siden 
754757221772SChristopher Siden 	count = 0;
754857221772SChristopher Siden 	for (i = 0; i < SPA_FEATURES; i++) {
754957221772SChristopher Siden 		const char *fname = spa_feature_table[i].fi_uname;
755057221772SChristopher Siden 		const char *fguid = spa_feature_table[i].fi_guid;
755157221772SChristopher Siden 		if (!nvlist_exists(enabled, fguid)) {
755257221772SChristopher Siden 			char *propname;
755357221772SChristopher Siden 			verify(-1 != asprintf(&propname, "feature@%s", fname));
755457221772SChristopher Siden 			ret = zpool_set_prop(zhp, propname,
755557221772SChristopher Siden 			    ZFS_FEATURE_ENABLED);
755657221772SChristopher Siden 			if (ret != 0) {
755757221772SChristopher Siden 				free(propname);
755857221772SChristopher Siden 				return (ret);
755957221772SChristopher Siden 			}
756057221772SChristopher Siden 			count++;
756157221772SChristopher Siden 
756257221772SChristopher Siden 			if (firstff) {
756357221772SChristopher Siden 				(void) printf(gettext("Enabled the "
756457221772SChristopher Siden 				    "following features on '%s':\n"),
756557221772SChristopher Siden 				    zpool_get_name(zhp));
756657221772SChristopher Siden 				firstff = B_FALSE;
756757221772SChristopher Siden 			}
756857221772SChristopher Siden 			(void) printf(gettext("  %s\n"), fname);
756957221772SChristopher Siden 			free(propname);
757057221772SChristopher Siden 		}
757157221772SChristopher Siden 	}
757257221772SChristopher Siden 
757357221772SChristopher Siden 	if (countp != NULL)
757457221772SChristopher Siden 		*countp = count;
757557221772SChristopher Siden 	return (0);
757657221772SChristopher Siden }
757757221772SChristopher Siden 
7578eaca9bbdSeschrock static int
7579eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
7580eaca9bbdSeschrock {
7581eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
7582eaca9bbdSeschrock 	nvlist_t *config;
7583eaca9bbdSeschrock 	uint64_t version;
758457221772SChristopher Siden 	boolean_t printnl = B_FALSE;
758557221772SChristopher Siden 	int ret;
7586eaca9bbdSeschrock 
7587eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
7588eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
7589eaca9bbdSeschrock 	    &version) == 0);
7590eaca9bbdSeschrock 
759157221772SChristopher Siden 	assert(SPA_VERSION_IS_SUPPORTED(version));
7592eaca9bbdSeschrock 
759357221772SChristopher Siden 	if (version < cbp->cb_version) {
759457221772SChristopher Siden 		cbp->cb_first = B_FALSE;
759557221772SChristopher Siden 		ret = upgrade_version(zhp, cbp->cb_version);
759657221772SChristopher Siden 		if (ret != 0)
759757221772SChristopher Siden 			return (ret);
759857221772SChristopher Siden 		printnl = B_TRUE;
759957221772SChristopher Siden 
760057221772SChristopher Siden 		/*
760157221772SChristopher Siden 		 * If they did "zpool upgrade -a", then we could
760257221772SChristopher Siden 		 * be doing ioctls to different pools.  We need
760357221772SChristopher Siden 		 * to log this history once to each pool, and bypass
760457221772SChristopher Siden 		 * the normal history logging that happens in main().
760557221772SChristopher Siden 		 */
760657221772SChristopher Siden 		(void) zpool_log_history(g_zfs, history_str);
760757221772SChristopher Siden 		log_history = B_FALSE;
760857221772SChristopher Siden 	}
760957221772SChristopher Siden 
761057221772SChristopher Siden 	if (cbp->cb_version >= SPA_VERSION_FEATURES) {
761157221772SChristopher Siden 		int count;
761257221772SChristopher Siden 		ret = upgrade_enable_all(zhp, &count);
761357221772SChristopher Siden 		if (ret != 0)
761457221772SChristopher Siden 			return (ret);
761557221772SChristopher Siden 
761657221772SChristopher Siden 		if (count > 0) {
761799653d4eSeschrock 			cbp->cb_first = B_FALSE;
761857221772SChristopher Siden 			printnl = B_TRUE;
7619eaca9bbdSeschrock 		}
762057221772SChristopher Siden 	}
7621eaca9bbdSeschrock 
762257221772SChristopher Siden 	if (printnl) {
762357221772SChristopher Siden 		(void) printf(gettext("\n"));
762457221772SChristopher Siden 	}
762557221772SChristopher Siden 
762657221772SChristopher Siden 	return (0);
762757221772SChristopher Siden }
762857221772SChristopher Siden 
762957221772SChristopher Siden static int
763057221772SChristopher Siden upgrade_list_older_cb(zpool_handle_t *zhp, void *arg)
763157221772SChristopher Siden {
763257221772SChristopher Siden 	upgrade_cbdata_t *cbp = arg;
763357221772SChristopher Siden 	nvlist_t *config;
763457221772SChristopher Siden 	uint64_t version;
763557221772SChristopher Siden 
763657221772SChristopher Siden 	config = zpool_get_config(zhp, NULL);
763757221772SChristopher Siden 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
763857221772SChristopher Siden 	    &version) == 0);
763957221772SChristopher Siden 
764057221772SChristopher Siden 	assert(SPA_VERSION_IS_SUPPORTED(version));
764157221772SChristopher Siden 
764257221772SChristopher Siden 	if (version < SPA_VERSION_FEATURES) {
7643eaca9bbdSeschrock 		if (cbp->cb_first) {
7644eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
764557221772SChristopher Siden 			    "formatted with legacy version numbers and can\n"
764657221772SChristopher Siden 			    "be upgraded to use feature flags.  After "
764757221772SChristopher Siden 			    "being upgraded, these pools\nwill no "
764857221772SChristopher Siden 			    "longer be accessible by software that does not "
764957221772SChristopher Siden 			    "support feature\nflags.\n\n"));
7650eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
7651eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
765299653d4eSeschrock 			cbp->cb_first = B_FALSE;
7653eaca9bbdSeschrock 		}
7654eaca9bbdSeschrock 
76555ad82045Snd 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
7656eaca9bbdSeschrock 		    zpool_get_name(zhp));
7657eaca9bbdSeschrock 	}
7658eaca9bbdSeschrock 
765957221772SChristopher Siden 	return (0);
766057221772SChristopher Siden }
766157221772SChristopher Siden 
766257221772SChristopher Siden static int
766357221772SChristopher Siden upgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg)
766457221772SChristopher Siden {
766557221772SChristopher Siden 	upgrade_cbdata_t *cbp = arg;
766657221772SChristopher Siden 	nvlist_t *config;
766757221772SChristopher Siden 	uint64_t version;
766857221772SChristopher Siden 
766957221772SChristopher Siden 	config = zpool_get_config(zhp, NULL);
767057221772SChristopher Siden 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
767157221772SChristopher Siden 	    &version) == 0);
767257221772SChristopher Siden 
767357221772SChristopher Siden 	if (version >= SPA_VERSION_FEATURES) {
767457221772SChristopher Siden 		int i;
767557221772SChristopher Siden 		boolean_t poolfirst = B_TRUE;
767657221772SChristopher Siden 		nvlist_t *enabled = zpool_get_features(zhp);
767757221772SChristopher Siden 
767857221772SChristopher Siden 		for (i = 0; i < SPA_FEATURES; i++) {
767957221772SChristopher Siden 			const char *fguid = spa_feature_table[i].fi_guid;
768057221772SChristopher Siden 			const char *fname = spa_feature_table[i].fi_uname;
768157221772SChristopher Siden 			if (!nvlist_exists(enabled, fguid)) {
768257221772SChristopher Siden 				if (cbp->cb_first) {
768357221772SChristopher Siden 					(void) printf(gettext("\nSome "
768457221772SChristopher Siden 					    "supported features are not "
768557221772SChristopher Siden 					    "enabled on the following pools. "
768657221772SChristopher Siden 					    "Once a\nfeature is enabled the "
768757221772SChristopher Siden 					    "pool may become incompatible with "
768857221772SChristopher Siden 					    "software\nthat does not support "
768957221772SChristopher Siden 					    "the feature. See "
769057221772SChristopher Siden 					    "zpool-features(5) for "
769157221772SChristopher Siden 					    "details.\n\n"));
769257221772SChristopher Siden 					(void) printf(gettext("POOL  "
769357221772SChristopher Siden 					    "FEATURE\n"));
769457221772SChristopher Siden 					(void) printf(gettext("------"
769557221772SChristopher Siden 					    "---------\n"));
769657221772SChristopher Siden 					cbp->cb_first = B_FALSE;
769757221772SChristopher Siden 				}
769857221772SChristopher Siden 
769957221772SChristopher Siden 				if (poolfirst) {
770057221772SChristopher Siden 					(void) printf(gettext("%s\n"),
770157221772SChristopher Siden 					    zpool_get_name(zhp));
770257221772SChristopher Siden 					poolfirst = B_FALSE;
770357221772SChristopher Siden 				}
770457221772SChristopher Siden 
770557221772SChristopher Siden 				(void) printf(gettext("      %s\n"), fname);
770657221772SChristopher Siden 			}
770757221772SChristopher Siden 		}
770857221772SChristopher Siden 	}
770957221772SChristopher Siden 
771057221772SChristopher Siden 	return (0);
7711eaca9bbdSeschrock }
7712eaca9bbdSeschrock 
7713eaca9bbdSeschrock /* ARGSUSED */
7714eaca9bbdSeschrock static int
771506eeb2adSek upgrade_one(zpool_handle_t *zhp, void *data)
7716eaca9bbdSeschrock {
771757221772SChristopher Siden 	boolean_t printnl = B_FALSE;
7718990b4856Slling 	upgrade_cbdata_t *cbp = data;
7719990b4856Slling 	uint64_t cur_version;
7720eaca9bbdSeschrock 	int ret;
7721eaca9bbdSeschrock 
77228654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
77238654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
77248654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
77258654d025Sperrin 		    " to upgrade.\n"));
77268654d025Sperrin 		return (1);
77278654d025Sperrin 	}
7728990b4856Slling 
7729990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
7730e6c728e1Sbrendan 	if (cur_version > cbp->cb_version) {
7731eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
773257221772SChristopher Siden 		    "using more current version '%llu'.\n\n"),
7733e6c728e1Sbrendan 		    zpool_get_name(zhp), cur_version);
7734e6c728e1Sbrendan 		return (0);
7735e6c728e1Sbrendan 	}
773657221772SChristopher Siden 
773757221772SChristopher Siden 	if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) {
7738e6c728e1Sbrendan 		(void) printf(gettext("Pool '%s' is already formatted "
773957221772SChristopher Siden 		    "using version %llu.\n\n"), zpool_get_name(zhp),
774057221772SChristopher Siden 		    cbp->cb_version);
7741eaca9bbdSeschrock 		return (0);
7742eaca9bbdSeschrock 	}
7743eaca9bbdSeschrock 
774457221772SChristopher Siden 	if (cur_version != cbp->cb_version) {
774557221772SChristopher Siden 		printnl = B_TRUE;
774657221772SChristopher Siden 		ret = upgrade_version(zhp, cbp->cb_version);
774757221772SChristopher Siden 		if (ret != 0)
774857221772SChristopher Siden 			return (ret);
774957221772SChristopher Siden 	}
775006eeb2adSek 
775157221772SChristopher Siden 	if (cbp->cb_version >= SPA_VERSION_FEATURES) {
775257221772SChristopher Siden 		int count = 0;
775357221772SChristopher Siden 		ret = upgrade_enable_all(zhp, &count);
775457221772SChristopher Siden 		if (ret != 0)
775557221772SChristopher Siden 			return (ret);
775657221772SChristopher Siden 
775757221772SChristopher Siden 		if (count != 0) {
775857221772SChristopher Siden 			printnl = B_TRUE;
775957221772SChristopher Siden 		} else if (cur_version == SPA_VERSION) {
776057221772SChristopher Siden 			(void) printf(gettext("Pool '%s' already has all "
776157221772SChristopher Siden 			    "supported features enabled.\n"),
776257221772SChristopher Siden 			    zpool_get_name(zhp));
776357221772SChristopher Siden 		}
776457221772SChristopher Siden 	}
776557221772SChristopher Siden 
776657221772SChristopher Siden 	if (printnl) {
776757221772SChristopher Siden 		(void) printf(gettext("\n"));
776806eeb2adSek 	}
7769eaca9bbdSeschrock 
777057221772SChristopher Siden 	return (0);
7771eaca9bbdSeschrock }
7772eaca9bbdSeschrock 
7773eaca9bbdSeschrock /*
7774eaca9bbdSeschrock  * zpool upgrade
7775eaca9bbdSeschrock  * zpool upgrade -v
7776990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
7777eaca9bbdSeschrock  *
7778eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
7779eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
7780eaca9bbdSeschrock  * upgrade all pools.
7781eaca9bbdSeschrock  */
7782eaca9bbdSeschrock int
7783eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
7784eaca9bbdSeschrock {
7785eaca9bbdSeschrock 	int c;
7786eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
7787eaca9bbdSeschrock 	int ret = 0;
7788eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
778957221772SChristopher Siden 	boolean_t upgradeall = B_FALSE;
7790990b4856Slling 	char *end;
7791990b4856Slling 
7792eaca9bbdSeschrock 
7793eaca9bbdSeschrock 	/* check options */
7794478ed9adSEric Taylor 	while ((c = getopt(argc, argv, ":avV:")) != -1) {
7795eaca9bbdSeschrock 		switch (c) {
7796eaca9bbdSeschrock 		case 'a':
779757221772SChristopher Siden 			upgradeall = B_TRUE;
7798eaca9bbdSeschrock 			break;
7799eaca9bbdSeschrock 		case 'v':
7800eaca9bbdSeschrock 			showversions = B_TRUE;
7801eaca9bbdSeschrock 			break;
7802990b4856Slling 		case 'V':
7803990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
7804ad135b5dSChristopher Siden 			if (*end != '\0' ||
7805ad135b5dSChristopher Siden 			    !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) {
7806990b4856Slling 				(void) fprintf(stderr,
7807990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
7808990b4856Slling 				usage(B_FALSE);
7809990b4856Slling 			}
7810990b4856Slling 			break;
7811478ed9adSEric Taylor 		case ':':
7812478ed9adSEric Taylor 			(void) fprintf(stderr, gettext("missing argument for "
7813478ed9adSEric Taylor 			    "'%c' option\n"), optopt);
7814478ed9adSEric Taylor 			usage(B_FALSE);
7815478ed9adSEric Taylor 			break;
7816eaca9bbdSeschrock 		case '?':
7817eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
7818eaca9bbdSeschrock 			    optopt);
781999653d4eSeschrock 			usage(B_FALSE);
7820eaca9bbdSeschrock 		}
7821eaca9bbdSeschrock 	}
7822eaca9bbdSeschrock 
782306eeb2adSek 	cb.cb_argc = argc;
782406eeb2adSek 	cb.cb_argv = argv;
7825eaca9bbdSeschrock 	argc -= optind;
7826eaca9bbdSeschrock 	argv += optind;
7827eaca9bbdSeschrock 
7828351420b3Slling 	if (cb.cb_version == 0) {
7829351420b3Slling 		cb.cb_version = SPA_VERSION;
783057221772SChristopher Siden 	} else if (!upgradeall && argc == 0) {
7831351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
7832351420b3Slling 		    "incompatible with other arguments\n"));
7833351420b3Slling 		usage(B_FALSE);
7834351420b3Slling 	}
7835351420b3Slling 
7836eaca9bbdSeschrock 	if (showversions) {
783757221772SChristopher Siden 		if (upgradeall || argc != 0) {
7838eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
7839eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
784099653d4eSeschrock 			usage(B_FALSE);
7841eaca9bbdSeschrock 		}
784257221772SChristopher Siden 	} else if (upgradeall) {
7843eaca9bbdSeschrock 		if (argc != 0) {
7844351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
7845351420b3Slling 			    "be used along with a pool name\n"));
784699653d4eSeschrock 			usage(B_FALSE);
7847eaca9bbdSeschrock 		}
7848eaca9bbdSeschrock 	}
7849eaca9bbdSeschrock 
7850ad135b5dSChristopher Siden 	(void) printf(gettext("This system supports ZFS pool feature "
7851ad135b5dSChristopher Siden 	    "flags.\n\n"));
7852eaca9bbdSeschrock 	if (showversions) {
785357221772SChristopher Siden 		int i;
785457221772SChristopher Siden 
785557221772SChristopher Siden 		(void) printf(gettext("The following features are "
785657221772SChristopher Siden 		    "supported:\n\n"));
785757221772SChristopher Siden 		(void) printf(gettext("FEAT DESCRIPTION\n"));
785857221772SChristopher Siden 		(void) printf("----------------------------------------------"
785957221772SChristopher Siden 		    "---------------\n");
786057221772SChristopher Siden 		for (i = 0; i < SPA_FEATURES; i++) {
786157221772SChristopher Siden 			zfeature_info_t *fi = &spa_feature_table[i];
7862ca0cc391SMatthew Ahrens 			const char *ro =
7863ca0cc391SMatthew Ahrens 			    (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
786457221772SChristopher Siden 			    " (read-only compatible)" : "";
786557221772SChristopher Siden 
786657221772SChristopher Siden 			(void) printf("%-37s%s\n", fi->fi_uname, ro);
786757221772SChristopher Siden 			(void) printf("     %s\n", fi->fi_desc);
786857221772SChristopher Siden 		}
786957221772SChristopher Siden 		(void) printf("\n");
787057221772SChristopher Siden 
787157221772SChristopher Siden 		(void) printf(gettext("The following legacy versions are also "
7872d7d4af51Smmusante 		    "supported:\n\n"));
7873eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
7874eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
7875eaca9bbdSeschrock 		    "---------------\n");
787699653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
787744cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
787844cd46caSbillm 		    "(replicated metadata)\n"));
787999653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
788099653d4eSeschrock 		    "RAID-Z\n"));
7881d7306b64Sek 		(void) printf(gettext(" 4   zpool history\n"));
7882c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
7883c9431fa1Sahl 		    "algorithm\n"));
7884990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
78858654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
7886ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
78878eed72d4Sck 		(void) printf(gettext(" 9   refquota and refreservation "
7888a9799022Sck 		    "properties\n"));
7889fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
7890088f3894Sahrens 		(void) printf(gettext(" 11  Improved scrub performance\n"));
7891bb0ade09Sahrens 		(void) printf(gettext(" 12  Snapshot properties\n"));
789274e7dc98SMatthew Ahrens 		(void) printf(gettext(" 13  snapused property\n"));
789314843421SMatthew Ahrens 		(void) printf(gettext(" 14  passthrough-x aclinherit\n"));
789414843421SMatthew Ahrens 		(void) printf(gettext(" 15  user/group space accounting\n"));
7895478ed9adSEric Taylor 		(void) printf(gettext(" 16  stmf property support\n"));
78967aeab329SAdam Leventhal 		(void) printf(gettext(" 17  Triple-parity RAID-Z\n"));
7897b24ab676SJeff Bonwick 		(void) printf(gettext(" 18  Snapshot user holds\n"));
789888ecc943SGeorge Wilson 		(void) printf(gettext(" 19  Log device removal\n"));
7899b24ab676SJeff Bonwick 		(void) printf(gettext(" 20  Compression using zle "
7900b24ab676SJeff Bonwick 		    "(zero-length encoding)\n"));
7901b24ab676SJeff Bonwick 		(void) printf(gettext(" 21  Deduplication\n"));
790292241e0bSTom Erickson 		(void) printf(gettext(" 22  Received properties\n"));
79036e1f5caaSNeil Perrin 		(void) printf(gettext(" 23  Slim ZIL\n"));
79040a586ceaSMark Shellenbaum 		(void) printf(gettext(" 24  System attributes\n"));
79053f9d6ad7SLin Ling 		(void) printf(gettext(" 25  Improved scrub stats\n"));
7906cde58dbcSMatthew Ahrens 		(void) printf(gettext(" 26  Improved snapshot deletion "
7907cde58dbcSMatthew Ahrens 		    "performance\n"));
79086e0cbcaaSMatthew Ahrens 		(void) printf(gettext(" 27  Improved snapshot creation "
79096e0cbcaaSMatthew Ahrens 		    "performance\n"));
7910cb04b873SMark J Musante 		(void) printf(gettext(" 28  Multiple vdev replacements\n"));
7911b24ab676SJeff Bonwick 		(void) printf(gettext("\nFor more information on a particular "
79129a8685acSstephanie scheffler 		    "version, including supported releases,\n"));
79139a8685acSstephanie scheffler 		(void) printf(gettext("see the ZFS Administration Guide.\n\n"));
791457221772SChristopher Siden 	} else if (argc == 0 && upgradeall) {
791557221772SChristopher Siden 		cb.cb_first = B_TRUE;
791699653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
791757221772SChristopher Siden 		if (ret == 0 && cb.cb_first) {
791857221772SChristopher Siden 			if (cb.cb_version == SPA_VERSION) {
791957221772SChristopher Siden 				(void) printf(gettext("All pools are already "
792057221772SChristopher Siden 				    "formatted using feature flags.\n\n"));
792157221772SChristopher Siden 				(void) printf(gettext("Every feature flags "
792257221772SChristopher Siden 				    "pool already has all supported features "
792357221772SChristopher Siden 				    "enabled.\n"));
792457221772SChristopher Siden 			} else {
792557221772SChristopher Siden 				(void) printf(gettext("All pools are already "
792657221772SChristopher Siden 				    "formatted with version %llu or higher.\n"),
792757221772SChristopher Siden 				    cb.cb_version);
7928eaca9bbdSeschrock 			}
7929eaca9bbdSeschrock 		}
793057221772SChristopher Siden 	} else if (argc == 0) {
793157221772SChristopher Siden 		cb.cb_first = B_TRUE;
793257221772SChristopher Siden 		ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb);
793357221772SChristopher Siden 		assert(ret == 0);
7934eaca9bbdSeschrock 
793557221772SChristopher Siden 		if (cb.cb_first) {
793657221772SChristopher Siden 			(void) printf(gettext("All pools are formatted "
793757221772SChristopher Siden 			    "using feature flags.\n\n"));
793857221772SChristopher Siden 		} else {
793957221772SChristopher Siden 			(void) printf(gettext("\nUse 'zpool upgrade -v' "
794057221772SChristopher Siden 			    "for a list of available legacy versions.\n"));
794157221772SChristopher Siden 		}
794257221772SChristopher Siden 
794357221772SChristopher Siden 		cb.cb_first = B_TRUE;
794457221772SChristopher Siden 		ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb);
794557221772SChristopher Siden 		assert(ret == 0);
794657221772SChristopher Siden 
794757221772SChristopher Siden 		if (cb.cb_first) {
794857221772SChristopher Siden 			(void) printf(gettext("Every feature flags pool has "
794957221772SChristopher Siden 			    "all supported features enabled.\n"));
795057221772SChristopher Siden 		} else {
795157221772SChristopher Siden 			(void) printf(gettext("\n"));
7952eaca9bbdSeschrock 		}
7953eaca9bbdSeschrock 	} else {
7954b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
7955b1b8ab34Slling 		    upgrade_one, &cb);
795606eeb2adSek 	}
795706eeb2adSek 
795806eeb2adSek 	return (ret);
795906eeb2adSek }
796006eeb2adSek 
7961ecd6cf80Smarks typedef struct hist_cbdata {
7962ecd6cf80Smarks 	boolean_t first;
79634445fffbSMatthew Ahrens 	boolean_t longfmt;
79644445fffbSMatthew Ahrens 	boolean_t internal;
7965ecd6cf80Smarks } hist_cbdata_t;
7966ecd6cf80Smarks 
7967a52121eaSChunwei Chen static void
7968a52121eaSChunwei Chen print_history_records(nvlist_t *nvhis, hist_cbdata_t *cb)
796906eeb2adSek {
797006eeb2adSek 	nvlist_t **records;
797106eeb2adSek 	uint_t numrecords;
7972a52121eaSChunwei Chen 	int i;
797306eeb2adSek 
797406eeb2adSek 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
797506eeb2adSek 	    &records, &numrecords) == 0);
797606eeb2adSek 	for (i = 0; i < numrecords; i++) {
79774445fffbSMatthew Ahrens 		nvlist_t *rec = records[i];
79784445fffbSMatthew Ahrens 		char tbuf[30] = "";
7979ecd6cf80Smarks 
79804445fffbSMatthew Ahrens 		if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
79814445fffbSMatthew Ahrens 			time_t tsec;
79824445fffbSMatthew Ahrens 			struct tm t;
79834445fffbSMatthew Ahrens 
79844445fffbSMatthew Ahrens 			tsec = fnvlist_lookup_uint64(records[i],
79854445fffbSMatthew Ahrens 			    ZPOOL_HIST_TIME);
79864445fffbSMatthew Ahrens 			(void) localtime_r(&tsec, &t);
79874445fffbSMatthew Ahrens 			(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
79884445fffbSMatthew Ahrens 		}
7989ecd6cf80Smarks 
79904445fffbSMatthew Ahrens 		if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
79914445fffbSMatthew Ahrens 			(void) printf("%s %s", tbuf,
79924445fffbSMatthew Ahrens 			    fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
79934445fffbSMatthew Ahrens 		} else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
79944445fffbSMatthew Ahrens 			int ievent =
79954445fffbSMatthew Ahrens 			    fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
79964445fffbSMatthew Ahrens 			if (!cb->internal)
79974445fffbSMatthew Ahrens 				continue;
79984445fffbSMatthew Ahrens 			if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
79994445fffbSMatthew Ahrens 				(void) printf("%s unrecognized record:\n",
80004445fffbSMatthew Ahrens 				    tbuf);
80014445fffbSMatthew Ahrens 				dump_nvlist(rec, 4);
80024445fffbSMatthew Ahrens 				continue;
80034445fffbSMatthew Ahrens 			}
80044445fffbSMatthew Ahrens 			(void) printf("%s [internal %s txg:%lld] %s", tbuf,
80054445fffbSMatthew Ahrens 			    zfs_history_event_names[ievent],
80064445fffbSMatthew Ahrens 			    fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
80074445fffbSMatthew Ahrens 			    fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
80084445fffbSMatthew Ahrens 		} else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
80094445fffbSMatthew Ahrens 			if (!cb->internal)
8010ecd6cf80Smarks 				continue;
80114445fffbSMatthew Ahrens 			(void) printf("%s [txg:%lld] %s", tbuf,
80124445fffbSMatthew Ahrens 			    fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
80134445fffbSMatthew Ahrens 			    fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
80144445fffbSMatthew Ahrens 			if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
80154445fffbSMatthew Ahrens 				(void) printf(" %s (%llu)",
80164445fffbSMatthew Ahrens 				    fnvlist_lookup_string(rec,
80174445fffbSMatthew Ahrens 				    ZPOOL_HIST_DSNAME),
80184445fffbSMatthew Ahrens 				    fnvlist_lookup_uint64(rec,
80194445fffbSMatthew Ahrens 				    ZPOOL_HIST_DSID));
80204445fffbSMatthew Ahrens 			}
80214445fffbSMatthew Ahrens 			(void) printf(" %s", fnvlist_lookup_string(rec,
80224445fffbSMatthew Ahrens 			    ZPOOL_HIST_INT_STR));
80234445fffbSMatthew Ahrens 		} else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
80244445fffbSMatthew Ahrens 			if (!cb->internal)
80254445fffbSMatthew Ahrens 				continue;
80264445fffbSMatthew Ahrens 			(void) printf("%s ioctl %s\n", tbuf,
80274445fffbSMatthew Ahrens 			    fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
80284445fffbSMatthew Ahrens 			if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
80294445fffbSMatthew Ahrens 				(void) printf("    input:\n");
80304445fffbSMatthew Ahrens 				dump_nvlist(fnvlist_lookup_nvlist(rec,
80314445fffbSMatthew Ahrens 				    ZPOOL_HIST_INPUT_NVL), 8);
80324445fffbSMatthew Ahrens 			}
80334445fffbSMatthew Ahrens 			if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
80344445fffbSMatthew Ahrens 				(void) printf("    output:\n");
80354445fffbSMatthew Ahrens 				dump_nvlist(fnvlist_lookup_nvlist(rec,
80364445fffbSMatthew Ahrens 				    ZPOOL_HIST_OUTPUT_NVL), 8);
80374445fffbSMatthew Ahrens 			}
8038dfc11533SChris Williamson 			if (nvlist_exists(rec, ZPOOL_HIST_ERRNO)) {
8039dfc11533SChris Williamson 				(void) printf("    errno: %lld\n",
8040dfc11533SChris Williamson 				    fnvlist_lookup_int64(rec,
8041dfc11533SChris Williamson 				    ZPOOL_HIST_ERRNO));
8042dfc11533SChris Williamson 			}
80434445fffbSMatthew Ahrens 		} else {
80444445fffbSMatthew Ahrens 			if (!cb->internal)
8045ecd6cf80Smarks 				continue;
80464445fffbSMatthew Ahrens 			(void) printf("%s unrecognized record:\n", tbuf);
80474445fffbSMatthew Ahrens 			dump_nvlist(rec, 4);
804806eeb2adSek 		}
8049ecd6cf80Smarks 
8050ecd6cf80Smarks 		if (!cb->longfmt) {
8051ecd6cf80Smarks 			(void) printf("\n");
8052ecd6cf80Smarks 			continue;
8053ecd6cf80Smarks 		}
8054ecd6cf80Smarks 		(void) printf(" [");
80554445fffbSMatthew Ahrens 		if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
80564445fffbSMatthew Ahrens 			uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
80574445fffbSMatthew Ahrens 			struct passwd *pwd = getpwuid(who);
80584445fffbSMatthew Ahrens 			(void) printf("user %d ", (int)who);
80594445fffbSMatthew Ahrens 			if (pwd != NULL)
80604445fffbSMatthew Ahrens 				(void) printf("(%s) ", pwd->pw_name);
8061ecd6cf80Smarks 		}
80624445fffbSMatthew Ahrens 		if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
80634445fffbSMatthew Ahrens 			(void) printf("on %s",
80644445fffbSMatthew Ahrens 			    fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
8065ecd6cf80Smarks 		}
80664445fffbSMatthew Ahrens 		if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
80674445fffbSMatthew Ahrens 			(void) printf(":%s",
80684445fffbSMatthew Ahrens 			    fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
8069ecd6cf80Smarks 		}
8070ecd6cf80Smarks 		(void) printf("]");
8071ecd6cf80Smarks 		(void) printf("\n");
807206eeb2adSek 	}
8073a52121eaSChunwei Chen }
8074a52121eaSChunwei Chen 
8075a52121eaSChunwei Chen /*
8076a52121eaSChunwei Chen  * Print out the command history for a specific pool.
8077a52121eaSChunwei Chen  */
8078a52121eaSChunwei Chen static int
8079a52121eaSChunwei Chen get_history_one(zpool_handle_t *zhp, void *data)
8080a52121eaSChunwei Chen {
8081a52121eaSChunwei Chen 	nvlist_t *nvhis;
8082a52121eaSChunwei Chen 	int ret;
8083a52121eaSChunwei Chen 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
8084a52121eaSChunwei Chen 	uint64_t off = 0;
8085a52121eaSChunwei Chen 	boolean_t eof = B_FALSE;
8086a52121eaSChunwei Chen 
8087a52121eaSChunwei Chen 	cb->first = B_FALSE;
8088a52121eaSChunwei Chen 
8089a52121eaSChunwei Chen 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
8090a52121eaSChunwei Chen 
8091a52121eaSChunwei Chen 	while (!eof) {
8092a52121eaSChunwei Chen 		if ((ret = zpool_get_history(zhp, &nvhis, &off, &eof)) != 0)
8093a52121eaSChunwei Chen 			return (ret);
8094a52121eaSChunwei Chen 
8095a52121eaSChunwei Chen 		print_history_records(nvhis, cb);
8096a52121eaSChunwei Chen 		nvlist_free(nvhis);
8097a52121eaSChunwei Chen 	}
809806eeb2adSek 	(void) printf("\n");
809906eeb2adSek 
810006eeb2adSek 	return (ret);
810106eeb2adSek }
810206eeb2adSek 
810306eeb2adSek /*
810406eeb2adSek  * zpool history <pool>
810506eeb2adSek  *
810606eeb2adSek  * Displays the history of commands that modified pools.
810706eeb2adSek  */
810806eeb2adSek int
810906eeb2adSek zpool_do_history(int argc, char **argv)
811006eeb2adSek {
8111ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
811206eeb2adSek 	int ret;
8113ecd6cf80Smarks 	int c;
811406eeb2adSek 
8115ecd6cf80Smarks 	cbdata.first = B_TRUE;
8116ecd6cf80Smarks 	/* check options */
8117ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
8118ecd6cf80Smarks 		switch (c) {
8119ecd6cf80Smarks 		case 'l':
81204445fffbSMatthew Ahrens 			cbdata.longfmt = B_TRUE;
8121ecd6cf80Smarks 			break;
8122ecd6cf80Smarks 		case 'i':
81234445fffbSMatthew Ahrens 			cbdata.internal = B_TRUE;
8124ecd6cf80Smarks 			break;
8125ecd6cf80Smarks 		case '?':
8126ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
8127ecd6cf80Smarks 			    optopt);
8128ecd6cf80Smarks 			usage(B_FALSE);
8129ecd6cf80Smarks 		}
8130ecd6cf80Smarks 	}
813106eeb2adSek 	argc -= optind;
813206eeb2adSek 	argv += optind;
813306eeb2adSek 
8134b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
8135ecd6cf80Smarks 	    &cbdata);
813606eeb2adSek 
8137ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
813806eeb2adSek 		(void) printf(gettext("no pools available\n"));
813906eeb2adSek 		return (0);
8140eaca9bbdSeschrock 	}
8141eaca9bbdSeschrock 
8142eaca9bbdSeschrock 	return (ret);
8143eaca9bbdSeschrock }
8144eaca9bbdSeschrock 
8145b1b8ab34Slling static int
8146b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
8147b1b8ab34Slling {
8148990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
8149b1b8ab34Slling 	char value[MAXNAMELEN];
8150990b4856Slling 	zprop_source_t srctype;
8151990b4856Slling 	zprop_list_t *pl;
8152b1b8ab34Slling 
8153b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
8154b1b8ab34Slling 
8155b1b8ab34Slling 		/*
8156990b4856Slling 		 * Skip the special fake placeholder. This will also skip
8157990b4856Slling 		 * over the name property when 'all' is specified.
8158b1b8ab34Slling 		 */
8159990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
8160b1b8ab34Slling 		    pl == cbp->cb_proplist)
8161b1b8ab34Slling 			continue;
8162b1b8ab34Slling 
8163ad135b5dSChristopher Siden 		if (pl->pl_prop == ZPROP_INVAL &&
8164ad135b5dSChristopher Siden 		    (zpool_prop_feature(pl->pl_user_prop) ||
8165ad135b5dSChristopher Siden 		    zpool_prop_unsupported(pl->pl_user_prop))) {
8166ad135b5dSChristopher Siden 			srctype = ZPROP_SRC_LOCAL;
8167b1b8ab34Slling 
8168ad135b5dSChristopher Siden 			if (zpool_prop_get_feature(zhp, pl->pl_user_prop,
8169ad135b5dSChristopher Siden 			    value, sizeof (value)) == 0) {
8170ad135b5dSChristopher Siden 				zprop_print_one_property(zpool_get_name(zhp),
8171ad135b5dSChristopher Siden 				    cbp, pl->pl_user_prop, value, srctype,
8172ad135b5dSChristopher Siden 				    NULL, NULL);
8173ad135b5dSChristopher Siden 			}
8174ad135b5dSChristopher Siden 		} else {
8175ad135b5dSChristopher Siden 			if (zpool_get_prop(zhp, pl->pl_prop, value,
8176c58b3526SAdam Stevko 			    sizeof (value), &srctype, cbp->cb_literal) != 0)
8177ad135b5dSChristopher Siden 				continue;
8178ad135b5dSChristopher Siden 
8179ad135b5dSChristopher Siden 			zprop_print_one_property(zpool_get_name(zhp), cbp,
8180ad135b5dSChristopher Siden 			    zpool_prop_to_name(pl->pl_prop), value, srctype,
8181ad135b5dSChristopher Siden 			    NULL, NULL);
8182ad135b5dSChristopher Siden 		}
8183b1b8ab34Slling 	}
8184b1b8ab34Slling 	return (0);
8185b1b8ab34Slling }
8186b1b8ab34Slling 
8187c58b3526SAdam Stevko /*
8188c58b3526SAdam Stevko  * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ...
8189c58b3526SAdam Stevko  *
8190c58b3526SAdam Stevko  *	-H	Scripted mode.  Don't display headers, and separate properties
8191c58b3526SAdam Stevko  *		by a single tab.
8192c58b3526SAdam Stevko  *	-o	List of columns to display.  Defaults to
8193c58b3526SAdam Stevko  *		"name,property,value,source".
819404e56356SAndriy Gapon  *	-p	Diplay values in parsable (exact) format.
8195c58b3526SAdam Stevko  *
8196c58b3526SAdam Stevko  * Get properties of pools in the system. Output space statistics
8197c58b3526SAdam Stevko  * for each one as well as other attributes.
8198c58b3526SAdam Stevko  */
8199b1b8ab34Slling int
8200b1b8ab34Slling zpool_do_get(int argc, char **argv)
8201b1b8ab34Slling {
8202990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
8203990b4856Slling 	zprop_list_t fake_name = { 0 };
8204b1b8ab34Slling 	int ret;
8205c58b3526SAdam Stevko 	int c, i;
8206c58b3526SAdam Stevko 	char *value;
8207b1b8ab34Slling 
8208b1b8ab34Slling 	cb.cb_first = B_TRUE;
8209c58b3526SAdam Stevko 
8210c58b3526SAdam Stevko 	/*
8211c58b3526SAdam Stevko 	 * Set up default columns and sources.
8212c58b3526SAdam Stevko 	 */
8213990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
8214b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
8215b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
8216b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
8217b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
8218990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
8219b1b8ab34Slling 
8220c58b3526SAdam Stevko 	/* check options */
8221c58b3526SAdam Stevko 	while ((c = getopt(argc, argv, ":Hpo:")) != -1) {
8222c58b3526SAdam Stevko 		switch (c) {
8223c58b3526SAdam Stevko 		case 'p':
8224c58b3526SAdam Stevko 			cb.cb_literal = B_TRUE;
8225c58b3526SAdam Stevko 			break;
8226c58b3526SAdam Stevko 		case 'H':
8227c58b3526SAdam Stevko 			cb.cb_scripted = B_TRUE;
8228c58b3526SAdam Stevko 			break;
8229c58b3526SAdam Stevko 		case 'o':
8230c58b3526SAdam Stevko 			bzero(&cb.cb_columns, sizeof (cb.cb_columns));
8231c58b3526SAdam Stevko 			i = 0;
8232c58b3526SAdam Stevko 			while (*optarg != '\0') {
8233c58b3526SAdam Stevko 				static char *col_subopts[] =
8234c58b3526SAdam Stevko 				{ "name", "property", "value", "source",
8235c58b3526SAdam Stevko 				"all", NULL };
8236c58b3526SAdam Stevko 
8237c58b3526SAdam Stevko 				if (i == ZFS_GET_NCOLS) {
8238c58b3526SAdam Stevko 					(void) fprintf(stderr, gettext("too "
8239c58b3526SAdam Stevko 					"many fields given to -o "
8240c58b3526SAdam Stevko 					"option\n"));
8241c58b3526SAdam Stevko 					usage(B_FALSE);
8242c58b3526SAdam Stevko 				}
8243c58b3526SAdam Stevko 
8244c58b3526SAdam Stevko 				switch (getsubopt(&optarg, col_subopts,
8245c58b3526SAdam Stevko 				    &value)) {
8246c58b3526SAdam Stevko 				case 0:
8247c58b3526SAdam Stevko 					cb.cb_columns[i++] = GET_COL_NAME;
8248c58b3526SAdam Stevko 					break;
8249c58b3526SAdam Stevko 				case 1:
8250c58b3526SAdam Stevko 					cb.cb_columns[i++] = GET_COL_PROPERTY;
8251c58b3526SAdam Stevko 					break;
8252c58b3526SAdam Stevko 				case 2:
8253c58b3526SAdam Stevko 					cb.cb_columns[i++] = GET_COL_VALUE;
8254c58b3526SAdam Stevko 					break;
8255c58b3526SAdam Stevko 				case 3:
8256c58b3526SAdam Stevko 					cb.cb_columns[i++] = GET_COL_SOURCE;
8257c58b3526SAdam Stevko 					break;
8258c58b3526SAdam Stevko 				case 4:
8259c58b3526SAdam Stevko 					if (i > 0) {
8260c58b3526SAdam Stevko 						(void) fprintf(stderr,
8261c58b3526SAdam Stevko 						    gettext("\"all\" conflicts "
8262c58b3526SAdam Stevko 						    "with specific fields "
8263c58b3526SAdam Stevko 						    "given to -o option\n"));
8264c58b3526SAdam Stevko 						usage(B_FALSE);
8265c58b3526SAdam Stevko 					}
8266c58b3526SAdam Stevko 					cb.cb_columns[0] = GET_COL_NAME;
8267c58b3526SAdam Stevko 					cb.cb_columns[1] = GET_COL_PROPERTY;
8268c58b3526SAdam Stevko 					cb.cb_columns[2] = GET_COL_VALUE;
8269c58b3526SAdam Stevko 					cb.cb_columns[3] = GET_COL_SOURCE;
8270c58b3526SAdam Stevko 					i = ZFS_GET_NCOLS;
8271c58b3526SAdam Stevko 					break;
8272c58b3526SAdam Stevko 				default:
8273c58b3526SAdam Stevko 					(void) fprintf(stderr,
8274c58b3526SAdam Stevko 					    gettext("invalid column name "
8275c58b3526SAdam Stevko 					    "'%s'\n"), value);
8276c58b3526SAdam Stevko 					usage(B_FALSE);
8277c58b3526SAdam Stevko 				}
8278c58b3526SAdam Stevko 			}
8279c58b3526SAdam Stevko 			break;
8280c58b3526SAdam Stevko 		case '?':
8281c58b3526SAdam Stevko 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
8282c58b3526SAdam Stevko 			    optopt);
8283c58b3526SAdam Stevko 			usage(B_FALSE);
8284c58b3526SAdam Stevko 		}
8285c58b3526SAdam Stevko 	}
8286c58b3526SAdam Stevko 
8287c58b3526SAdam Stevko 	argc -= optind;
8288c58b3526SAdam Stevko 	argv += optind;
8289c58b3526SAdam Stevko 
8290c58b3526SAdam Stevko 	if (argc < 1) {
8291c58b3526SAdam Stevko 		(void) fprintf(stderr, gettext("missing property "
8292c58b3526SAdam Stevko 		    "argument\n"));
8293c58b3526SAdam Stevko 		usage(B_FALSE);
8294c58b3526SAdam Stevko 	}
8295c58b3526SAdam Stevko 
8296c58b3526SAdam Stevko 	if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist,
8297990b4856Slling 	    ZFS_TYPE_POOL) != 0)
8298b1b8ab34Slling 		usage(B_FALSE);
8299b1b8ab34Slling 
8300c58b3526SAdam Stevko 	argc--;
8301c58b3526SAdam Stevko 	argv++;
8302c58b3526SAdam Stevko 
8303b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
8304990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
8305b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
8306b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
8307b1b8ab34Slling 		cb.cb_proplist = &fake_name;
8308b1b8ab34Slling 	}
8309b1b8ab34Slling 
8310c58b3526SAdam Stevko 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
8311b1b8ab34Slling 	    get_callback, &cb);
8312b1b8ab34Slling 
8313b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
8314990b4856Slling 		zprop_free_list(fake_name.pl_next);
8315b1b8ab34Slling 	else
8316990b4856Slling 		zprop_free_list(cb.cb_proplist);
8317b1b8ab34Slling 
8318b1b8ab34Slling 	return (ret);
8319b1b8ab34Slling }
8320b1b8ab34Slling 
8321b1b8ab34Slling typedef struct set_cbdata {
8322b1b8ab34Slling 	char *cb_propname;
8323b1b8ab34Slling 	char *cb_value;
8324b1b8ab34Slling 	boolean_t cb_any_successful;
8325b1b8ab34Slling } set_cbdata_t;
8326b1b8ab34Slling 
8327b1b8ab34Slling int
8328b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
8329b1b8ab34Slling {
8330b1b8ab34Slling 	int error;
8331b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
8332b1b8ab34Slling 
8333b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
8334b1b8ab34Slling 
8335b1b8ab34Slling 	if (!error)
8336b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
8337b1b8ab34Slling 
8338b1b8ab34Slling 	return (error);
8339b1b8ab34Slling }
8340b1b8ab34Slling 
8341b1b8ab34Slling int
8342b1b8ab34Slling zpool_do_set(int argc, char **argv)
8343b1b8ab34Slling {
8344b1b8ab34Slling 	set_cbdata_t cb = { 0 };
8345b1b8ab34Slling 	int error;
8346b1b8ab34Slling 
8347b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
8348b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
8349b1b8ab34Slling 		    argv[1][1]);
8350b1b8ab34Slling 		usage(B_FALSE);
8351b1b8ab34Slling 	}
8352b1b8ab34Slling 
8353b1b8ab34Slling 	if (argc < 2) {
8354b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
8355b1b8ab34Slling 		    "argument\n"));
8356b1b8ab34Slling 		usage(B_FALSE);
8357b1b8ab34Slling 	}
8358b1b8ab34Slling 
8359b1b8ab34Slling 	if (argc < 3) {
8360b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
8361b1b8ab34Slling 		usage(B_FALSE);
8362b1b8ab34Slling 	}
8363b1b8ab34Slling 
8364b1b8ab34Slling 	if (argc > 3) {
8365b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
8366b1b8ab34Slling 		usage(B_FALSE);
8367b1b8ab34Slling 	}
8368b1b8ab34Slling 
8369b1b8ab34Slling 	cb.cb_propname = argv[1];
8370b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
8371b1b8ab34Slling 	if (cb.cb_value == NULL) {
8372b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
8373b1b8ab34Slling 		    "property=value argument\n"));
8374b1b8ab34Slling 		usage(B_FALSE);
8375b1b8ab34Slling 	}
8376b1b8ab34Slling 
8377b1b8ab34Slling 	*(cb.cb_value) = '\0';
8378b1b8ab34Slling 	cb.cb_value++;
8379b1b8ab34Slling 
8380b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
8381b1b8ab34Slling 	    set_callback, &cb);
8382b1b8ab34Slling 
8383b1b8ab34Slling 	return (error);
8384b1b8ab34Slling }
8385b1b8ab34Slling 
8386b1b8ab34Slling static int
8387b1b8ab34Slling find_command_idx(char *command, int *idx)
8388b1b8ab34Slling {
8389b1b8ab34Slling 	int i;
8390b1b8ab34Slling 
8391b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
8392b1b8ab34Slling 		if (command_table[i].name == NULL)
8393b1b8ab34Slling 			continue;
8394b1b8ab34Slling 
8395b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
8396b1b8ab34Slling 			*idx = i;
8397b1b8ab34Slling 			return (0);
8398b1b8ab34Slling 		}
8399b1b8ab34Slling 	}
8400b1b8ab34Slling 	return (1);
8401b1b8ab34Slling }
8402b1b8ab34Slling 
8403fa9e4066Sahrens int
8404fa9e4066Sahrens main(int argc, char **argv)
8405fa9e4066Sahrens {
8406b327cd3fSIgor Kozhukhov 	int ret = 0;
8407fa9e4066Sahrens 	int i;
8408fa9e4066Sahrens 	char *cmdname;
8409fa9e4066Sahrens 
8410fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
8411fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
8412fa9e4066Sahrens 
841399653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
841499653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
8415203a47d8Snd 		    "initialize ZFS library\n"));
841699653d4eSeschrock 		return (1);
841799653d4eSeschrock 	}
841899653d4eSeschrock 
841999653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
842099653d4eSeschrock 
8421fa9e4066Sahrens 	opterr = 0;
8422fa9e4066Sahrens 
8423fa9e4066Sahrens 	/*
8424fa9e4066Sahrens 	 * Make sure the user has specified some command.
8425fa9e4066Sahrens 	 */
8426fa9e4066Sahrens 	if (argc < 2) {
8427fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
842899653d4eSeschrock 		usage(B_FALSE);
8429fa9e4066Sahrens 	}
8430fa9e4066Sahrens 
8431fa9e4066Sahrens 	cmdname = argv[1];
8432fa9e4066Sahrens 
8433fa9e4066Sahrens 	/*
8434fa9e4066Sahrens 	 * Special case '-?'
8435fa9e4066Sahrens 	 */
8436fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
843799653d4eSeschrock 		usage(B_TRUE);
8438fa9e4066Sahrens 
84394445fffbSMatthew Ahrens 	zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
84402a6b87f0Sek 
8441fa9e4066Sahrens 	/*
8442fa9e4066Sahrens 	 * Run the appropriate command.
8443fa9e4066Sahrens 	 */
8444b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
8445b1b8ab34Slling 		current_command = &command_table[i];
8446b1b8ab34Slling 		ret = command_table[i].func(argc - 1, argv + 1);
844791ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
844891ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
844991ebeef5Sahrens 		current_command = &command_table[i];
845091ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
845191ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
845291ebeef5Sahrens 		/*
845391ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
845491ebeef5Sahrens 		 * it as such.
845591ebeef5Sahrens 		 */
8456ea8dc4b6Seschrock 		char buf[16384];
8457ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
8458fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
8459fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
846091ebeef5Sahrens 	} else {
8461fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
8462fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
846399653d4eSeschrock 		usage(B_FALSE);
8464fa9e4066Sahrens 	}
8465fa9e4066Sahrens 
84664445fffbSMatthew Ahrens 	if (ret == 0 && log_history)
84674445fffbSMatthew Ahrens 		(void) zpool_log_history(g_zfs, history_str);
84684445fffbSMatthew Ahrens 
846999653d4eSeschrock 	libzfs_fini(g_zfs);
847099653d4eSeschrock 
8471fa9e4066Sahrens 	/*
8472fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
8473fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
8474fa9e4066Sahrens 	 */
8475fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
8476fa9e4066Sahrens 		(void) printf("dumping core by request\n");
8477fa9e4066Sahrens 		abort();
8478fa9e4066Sahrens 	}
8479fa9e4066Sahrens 
8480fa9e4066Sahrens 	return (ret);
8481fa9e4066Sahrens }
8482