xref: /illumos-gate/usr/src/cmd/zpool/zpool_main.c (revision ad135b5d644628e791c3188a6ecbd9c257961ef8)
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.
24ce72e614SYuri Pankov  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
254263d13fSGeorge Wilson  * Copyright (c) 2012 by Delphix. All rights reserved.
26e1d5e507SFrederik Wessels  * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
27fa9e4066Sahrens  */
28fa9e4066Sahrens 
29fa9e4066Sahrens #include <assert.h>
30fa9e4066Sahrens #include <ctype.h>
31fa9e4066Sahrens #include <dirent.h>
32fa9e4066Sahrens #include <errno.h>
33fa9e4066Sahrens #include <fcntl.h>
34fa9e4066Sahrens #include <libgen.h>
35fa9e4066Sahrens #include <libintl.h>
36fa9e4066Sahrens #include <libuutil.h>
37fa9e4066Sahrens #include <locale.h>
38fa9e4066Sahrens #include <stdio.h>
39fa9e4066Sahrens #include <stdlib.h>
40fa9e4066Sahrens #include <string.h>
41fa9e4066Sahrens #include <strings.h>
42fa9e4066Sahrens #include <unistd.h>
43fa9e4066Sahrens #include <priv.h>
44ecd6cf80Smarks #include <pwd.h>
45ecd6cf80Smarks #include <zone.h>
464263d13fSGeorge Wilson #include <zfs_prop.h>
47b1b8ab34Slling #include <sys/fs/zfs.h>
48fa9e4066Sahrens #include <sys/stat.h>
49fa9e4066Sahrens 
50fa9e4066Sahrens #include <libzfs.h>
51fa9e4066Sahrens 
52fa9e4066Sahrens #include "zpool_util.h"
53b7b97454Sperrin #include "zfs_comutil.h"
54*ad135b5dSChristopher Siden #include "zfeature_common.h"
55fa9e4066Sahrens 
5626fd7700SKrishnendu Sadhukhan - Sun Microsystems #include "statcommon.h"
5726fd7700SKrishnendu Sadhukhan - Sun Microsystems 
58fa9e4066Sahrens static int zpool_do_create(int, char **);
59fa9e4066Sahrens static int zpool_do_destroy(int, char **);
60fa9e4066Sahrens 
61fa9e4066Sahrens static int zpool_do_add(int, char **);
6299653d4eSeschrock static int zpool_do_remove(int, char **);
63fa9e4066Sahrens 
64fa9e4066Sahrens static int zpool_do_list(int, char **);
65fa9e4066Sahrens static int zpool_do_iostat(int, char **);
66fa9e4066Sahrens static int zpool_do_status(int, char **);
67fa9e4066Sahrens 
68fa9e4066Sahrens static int zpool_do_online(int, char **);
69fa9e4066Sahrens static int zpool_do_offline(int, char **);
70ea8dc4b6Seschrock static int zpool_do_clear(int, char **);
714263d13fSGeorge Wilson static int zpool_do_reopen(int, char **);
72fa9e4066Sahrens 
73e9103aaeSGarrett D'Amore static int zpool_do_reguid(int, char **);
74e9103aaeSGarrett D'Amore 
75fa9e4066Sahrens static int zpool_do_attach(int, char **);
76fa9e4066Sahrens static int zpool_do_detach(int, char **);
77fa9e4066Sahrens static int zpool_do_replace(int, char **);
781195e687SMark J Musante static int zpool_do_split(int, char **);
79fa9e4066Sahrens 
80fa9e4066Sahrens static int zpool_do_scrub(int, char **);
81fa9e4066Sahrens 
82fa9e4066Sahrens static int zpool_do_import(int, char **);
83fa9e4066Sahrens static int zpool_do_export(int, char **);
84fa9e4066Sahrens 
85eaca9bbdSeschrock static int zpool_do_upgrade(int, char **);
86eaca9bbdSeschrock 
8706eeb2adSek static int zpool_do_history(int, char **);
8806eeb2adSek 
89b1b8ab34Slling static int zpool_do_get(int, char **);
90b1b8ab34Slling static int zpool_do_set(int, char **);
91b1b8ab34Slling 
92fa9e4066Sahrens /*
93fa9e4066Sahrens  * These libumem hooks provide a reasonable set of defaults for the allocator's
94fa9e4066Sahrens  * debugging facilities.
95fa9e4066Sahrens  */
9629ab75c9Srm 
9729ab75c9Srm #ifdef DEBUG
98fa9e4066Sahrens const char *
9999653d4eSeschrock _umem_debug_init(void)
100fa9e4066Sahrens {
101fa9e4066Sahrens 	return ("default,verbose"); /* $UMEM_DEBUG setting */
102fa9e4066Sahrens }
103fa9e4066Sahrens 
104fa9e4066Sahrens const char *
105fa9e4066Sahrens _umem_logging_init(void)
106fa9e4066Sahrens {
107fa9e4066Sahrens 	return ("fail,contents"); /* $UMEM_LOGGING setting */
108fa9e4066Sahrens }
10929ab75c9Srm #endif
110fa9e4066Sahrens 
11165cd9f28Seschrock typedef enum {
11265cd9f28Seschrock 	HELP_ADD,
11365cd9f28Seschrock 	HELP_ATTACH,
114ea8dc4b6Seschrock 	HELP_CLEAR,
11565cd9f28Seschrock 	HELP_CREATE,
11665cd9f28Seschrock 	HELP_DESTROY,
11765cd9f28Seschrock 	HELP_DETACH,
11865cd9f28Seschrock 	HELP_EXPORT,
11906eeb2adSek 	HELP_HISTORY,
12065cd9f28Seschrock 	HELP_IMPORT,
12165cd9f28Seschrock 	HELP_IOSTAT,
12265cd9f28Seschrock 	HELP_LIST,
12365cd9f28Seschrock 	HELP_OFFLINE,
12465cd9f28Seschrock 	HELP_ONLINE,
12565cd9f28Seschrock 	HELP_REPLACE,
12699653d4eSeschrock 	HELP_REMOVE,
12765cd9f28Seschrock 	HELP_SCRUB,
128eaca9bbdSeschrock 	HELP_STATUS,
129b1b8ab34Slling 	HELP_UPGRADE,
130b1b8ab34Slling 	HELP_GET,
1311195e687SMark J Musante 	HELP_SET,
132e9103aaeSGarrett D'Amore 	HELP_SPLIT,
1334263d13fSGeorge Wilson 	HELP_REGUID,
1344263d13fSGeorge Wilson 	HELP_REOPEN
13565cd9f28Seschrock } zpool_help_t;
13665cd9f28Seschrock 
13765cd9f28Seschrock 
138fa9e4066Sahrens typedef struct zpool_command {
139fa9e4066Sahrens 	const char	*name;
140fa9e4066Sahrens 	int		(*func)(int, char **);
14165cd9f28Seschrock 	zpool_help_t	usage;
142fa9e4066Sahrens } zpool_command_t;
143fa9e4066Sahrens 
144fa9e4066Sahrens /*
145fa9e4066Sahrens  * Master command table.  Each ZFS command has a name, associated function, and
146ea8dc4b6Seschrock  * usage message.  The usage messages need to be internationalized, so we have
147ea8dc4b6Seschrock  * to have a function to return the usage message based on a command index.
14865cd9f28Seschrock  *
14965cd9f28Seschrock  * These commands are organized according to how they are displayed in the usage
15065cd9f28Seschrock  * message.  An empty command (one with a NULL name) indicates an empty line in
15165cd9f28Seschrock  * the generic usage message.
152fa9e4066Sahrens  */
153fa9e4066Sahrens static zpool_command_t command_table[] = {
15465cd9f28Seschrock 	{ "create",	zpool_do_create,	HELP_CREATE		},
15565cd9f28Seschrock 	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
156fa9e4066Sahrens 	{ NULL },
15765cd9f28Seschrock 	{ "add",	zpool_do_add,		HELP_ADD		},
15899653d4eSeschrock 	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
159fa9e4066Sahrens 	{ NULL },
16065cd9f28Seschrock 	{ "list",	zpool_do_list,		HELP_LIST		},
16165cd9f28Seschrock 	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
16265cd9f28Seschrock 	{ "status",	zpool_do_status,	HELP_STATUS		},
163fa9e4066Sahrens 	{ NULL },
16465cd9f28Seschrock 	{ "online",	zpool_do_online,	HELP_ONLINE		},
16565cd9f28Seschrock 	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
166ea8dc4b6Seschrock 	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
1674263d13fSGeorge Wilson 	{ "reopen",	zpool_do_reopen,	HELP_REOPEN		},
168fa9e4066Sahrens 	{ NULL },
16965cd9f28Seschrock 	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
17065cd9f28Seschrock 	{ "detach",	zpool_do_detach,	HELP_DETACH		},
17165cd9f28Seschrock 	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
1721195e687SMark J Musante 	{ "split",	zpool_do_split,		HELP_SPLIT		},
173fa9e4066Sahrens 	{ NULL },
17465cd9f28Seschrock 	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
175fa9e4066Sahrens 	{ NULL },
17665cd9f28Seschrock 	{ "import",	zpool_do_import,	HELP_IMPORT		},
17765cd9f28Seschrock 	{ "export",	zpool_do_export,	HELP_EXPORT		},
17806eeb2adSek 	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
179e9103aaeSGarrett D'Amore 	{ "reguid",	zpool_do_reguid,	HELP_REGUID		},
18006eeb2adSek 	{ NULL },
181b1b8ab34Slling 	{ "history",	zpool_do_history,	HELP_HISTORY		},
182b1b8ab34Slling 	{ "get",	zpool_do_get,		HELP_GET		},
183b1b8ab34Slling 	{ "set",	zpool_do_set,		HELP_SET		},
184fa9e4066Sahrens };
185fa9e4066Sahrens 
186fa9e4066Sahrens #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
187fa9e4066Sahrens 
188fa9e4066Sahrens zpool_command_t *current_command;
1892a6b87f0Sek static char history_str[HIS_MAX_RECORD_LEN];
190fa9e4066Sahrens 
19126fd7700SKrishnendu Sadhukhan - Sun Microsystems static uint_t timestamp_fmt = NODATE;
19226fd7700SKrishnendu Sadhukhan - Sun Microsystems 
19365cd9f28Seschrock static const char *
19465cd9f28Seschrock get_usage(zpool_help_t idx) {
19565cd9f28Seschrock 	switch (idx) {
19665cd9f28Seschrock 	case HELP_ADD:
19765cd9f28Seschrock 		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
19865cd9f28Seschrock 	case HELP_ATTACH:
19965cd9f28Seschrock 		return (gettext("\tattach [-f] <pool> <device> "
200e45ce728Sahrens 		    "<new-device>\n"));
201ea8dc4b6Seschrock 	case HELP_CLEAR:
202468c413aSTim Haley 		return (gettext("\tclear [-nF] <pool> [device]\n"));
20365cd9f28Seschrock 	case HELP_CREATE:
204*ad135b5dSChristopher Siden 		return (gettext("\tcreate [-fnd] [-o property=value] ... \n"
2050a48a24eStimh 		    "\t    [-O file-system-property=value] ... \n"
206990b4856Slling 		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
20765cd9f28Seschrock 	case HELP_DESTROY:
20865cd9f28Seschrock 		return (gettext("\tdestroy [-f] <pool>\n"));
20965cd9f28Seschrock 	case HELP_DETACH:
21065cd9f28Seschrock 		return (gettext("\tdetach <pool> <device>\n"));
21165cd9f28Seschrock 	case HELP_EXPORT:
21265cd9f28Seschrock 		return (gettext("\texport [-f] <pool> ...\n"));
21306eeb2adSek 	case HELP_HISTORY:
214ecd6cf80Smarks 		return (gettext("\thistory [-il] [<pool>] ...\n"));
21565cd9f28Seschrock 	case HELP_IMPORT:
2164c58d714Sdarrenm 		return (gettext("\timport [-d dir] [-D]\n"
217f9af39baSGeorge Wilson 		    "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n"
2182f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
219f9af39baSGeorge Wilson 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
220f9af39baSGeorge Wilson 		    "[-R root] [-F [-n]] -a\n"
2212f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
222f9af39baSGeorge Wilson 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
223f9af39baSGeorge Wilson 		    "[-R root] [-F [-n]]\n"
224f9af39baSGeorge Wilson 		    "\t    <pool | id> [newpool]\n"));
22565cd9f28Seschrock 	case HELP_IOSTAT:
22626fd7700SKrishnendu Sadhukhan - Sun Microsystems 		return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
22765cd9f28Seschrock 		    "[count]]\n"));
22865cd9f28Seschrock 	case HELP_LIST:
229990b4856Slling 		return (gettext("\tlist [-H] [-o property[,...]] "
2303f9d6ad7SLin Ling 		    "[-T d|u] [pool] ... [interval [count]]\n"));
23165cd9f28Seschrock 	case HELP_OFFLINE:
232441d80aaSlling 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
23365cd9f28Seschrock 	case HELP_ONLINE:
234441d80aaSlling 		return (gettext("\tonline <pool> <device> ...\n"));
23565cd9f28Seschrock 	case HELP_REPLACE:
23665cd9f28Seschrock 		return (gettext("\treplace [-f] <pool> <device> "
237e45ce728Sahrens 		    "[new-device]\n"));
23899653d4eSeschrock 	case HELP_REMOVE:
239fa94a07fSbrendan 		return (gettext("\tremove <pool> <device> ...\n"));
2404263d13fSGeorge Wilson 	case HELP_REOPEN:
2414263d13fSGeorge Wilson 		return (""); /* Undocumented command */
24265cd9f28Seschrock 	case HELP_SCRUB:
24365cd9f28Seschrock 		return (gettext("\tscrub [-s] <pool> ...\n"));
24465cd9f28Seschrock 	case HELP_STATUS:
2453f9d6ad7SLin Ling 		return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
2463f9d6ad7SLin Ling 		    "[count]]\n"));
247eaca9bbdSeschrock 	case HELP_UPGRADE:
248eaca9bbdSeschrock 		return (gettext("\tupgrade\n"
249eaca9bbdSeschrock 		    "\tupgrade -v\n"
250990b4856Slling 		    "\tupgrade [-V version] <-a | pool ...>\n"));
251b1b8ab34Slling 	case HELP_GET:
252e45ce728Sahrens 		return (gettext("\tget <\"all\" | property[,...]> "
253b1b8ab34Slling 		    "<pool> ...\n"));
254b1b8ab34Slling 	case HELP_SET:
255b1b8ab34Slling 		return (gettext("\tset <property=value> <pool> \n"));
2561195e687SMark J Musante 	case HELP_SPLIT:
2571195e687SMark J Musante 		return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
2581195e687SMark J Musante 		    "\t    [-o property=value] <pool> <newpool> "
2591195e687SMark J Musante 		    "[<device> ...]\n"));
260e9103aaeSGarrett D'Amore 	case HELP_REGUID:
261e9103aaeSGarrett D'Amore 		return (gettext("\treguid <pool>\n"));
26265cd9f28Seschrock 	}
26365cd9f28Seschrock 
26465cd9f28Seschrock 	abort();
26565cd9f28Seschrock 	/* NOTREACHED */
26665cd9f28Seschrock }
26765cd9f28Seschrock 
268fa9e4066Sahrens 
269b1b8ab34Slling /*
270b1b8ab34Slling  * Callback routine that will print out a pool property value.
271b1b8ab34Slling  */
272990b4856Slling static int
273990b4856Slling print_prop_cb(int prop, void *cb)
274b1b8ab34Slling {
275b1b8ab34Slling 	FILE *fp = cb;
276b1b8ab34Slling 
277b24ab676SJeff Bonwick 	(void) fprintf(fp, "\t%-15s  ", zpool_prop_to_name(prop));
278b1b8ab34Slling 
279990b4856Slling 	if (zpool_prop_readonly(prop))
280990b4856Slling 		(void) fprintf(fp, "  NO   ");
281990b4856Slling 	else
282b24ab676SJeff Bonwick 		(void) fprintf(fp, " YES   ");
283990b4856Slling 
284b1b8ab34Slling 	if (zpool_prop_values(prop) == NULL)
285b1b8ab34Slling 		(void) fprintf(fp, "-\n");
286b1b8ab34Slling 	else
287b1b8ab34Slling 		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
288b1b8ab34Slling 
289990b4856Slling 	return (ZPROP_CONT);
290b1b8ab34Slling }
291b1b8ab34Slling 
292fa9e4066Sahrens /*
293fa9e4066Sahrens  * Display usage message.  If we're inside a command, display only the usage for
294fa9e4066Sahrens  * that command.  Otherwise, iterate over the entire command table and display
295fa9e4066Sahrens  * a complete usage message.
296fa9e4066Sahrens  */
297fa9e4066Sahrens void
29899653d4eSeschrock usage(boolean_t requested)
299fa9e4066Sahrens {
300fa9e4066Sahrens 	FILE *fp = requested ? stdout : stderr;
301fa9e4066Sahrens 
302fa9e4066Sahrens 	if (current_command == NULL) {
303fa9e4066Sahrens 		int i;
304fa9e4066Sahrens 
305fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
306fa9e4066Sahrens 		(void) fprintf(fp,
307fa9e4066Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
308fa9e4066Sahrens 
309fa9e4066Sahrens 		for (i = 0; i < NCOMMAND; i++) {
310fa9e4066Sahrens 			if (command_table[i].name == NULL)
311fa9e4066Sahrens 				(void) fprintf(fp, "\n");
312fa9e4066Sahrens 			else
313fa9e4066Sahrens 				(void) fprintf(fp, "%s",
31465cd9f28Seschrock 				    get_usage(command_table[i].usage));
315fa9e4066Sahrens 		}
316fa9e4066Sahrens 	} else {
317fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
31865cd9f28Seschrock 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
319fa9e4066Sahrens 	}
320fa9e4066Sahrens 
321b1b8ab34Slling 	if (current_command != NULL &&
322b1b8ab34Slling 	    ((strcmp(current_command->name, "set") == 0) ||
323990b4856Slling 	    (strcmp(current_command->name, "get") == 0) ||
324990b4856Slling 	    (strcmp(current_command->name, "list") == 0))) {
325b1b8ab34Slling 
326b1b8ab34Slling 		(void) fprintf(fp,
327b1b8ab34Slling 		    gettext("\nthe following properties are supported:\n"));
328b1b8ab34Slling 
329b24ab676SJeff Bonwick 		(void) fprintf(fp, "\n\t%-15s  %s   %s\n\n",
330990b4856Slling 		    "PROPERTY", "EDIT", "VALUES");
331b1b8ab34Slling 
332b1b8ab34Slling 		/* Iterate over all properties */
333990b4856Slling 		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
334990b4856Slling 		    ZFS_TYPE_POOL);
335*ad135b5dSChristopher Siden 
336*ad135b5dSChristopher Siden 		(void) fprintf(fp, "\t%-15s   ", "feature@...");
337*ad135b5dSChristopher Siden 		(void) fprintf(fp, "YES   disabled | enabled | active\n");
338*ad135b5dSChristopher Siden 
339*ad135b5dSChristopher Siden 		(void) fprintf(fp, gettext("\nThe feature@ properties must be "
340*ad135b5dSChristopher Siden 		    "appended with a feature name.\nSee zpool-features(5).\n"));
341b1b8ab34Slling 	}
342b1b8ab34Slling 
343e9dbad6fSeschrock 	/*
344e9dbad6fSeschrock 	 * See comments at end of main().
345e9dbad6fSeschrock 	 */
346e9dbad6fSeschrock 	if (getenv("ZFS_ABORT") != NULL) {
347e9dbad6fSeschrock 		(void) printf("dumping core by request\n");
348e9dbad6fSeschrock 		abort();
349e9dbad6fSeschrock 	}
350e9dbad6fSeschrock 
351fa9e4066Sahrens 	exit(requested ? 0 : 2);
352fa9e4066Sahrens }
353fa9e4066Sahrens 
354fa9e4066Sahrens void
3558654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
3568654d025Sperrin     boolean_t print_logs)
357fa9e4066Sahrens {
358fa9e4066Sahrens 	nvlist_t **child;
359fa9e4066Sahrens 	uint_t c, children;
360afefbcddSeschrock 	char *vname;
361fa9e4066Sahrens 
362fa9e4066Sahrens 	if (name != NULL)
363fa9e4066Sahrens 		(void) printf("\t%*s%s\n", indent, "", name);
364fa9e4066Sahrens 
365fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
366fa9e4066Sahrens 	    &child, &children) != 0)
367fa9e4066Sahrens 		return;
368fa9e4066Sahrens 
369afefbcddSeschrock 	for (c = 0; c < children; c++) {
3708654d025Sperrin 		uint64_t is_log = B_FALSE;
3718654d025Sperrin 
3728654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3738654d025Sperrin 		    &is_log);
3748654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
3758654d025Sperrin 			continue;
3768654d025Sperrin 
37788ecc943SGeorge Wilson 		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
3788654d025Sperrin 		print_vdev_tree(zhp, vname, child[c], indent + 2,
3798654d025Sperrin 		    B_FALSE);
380afefbcddSeschrock 		free(vname);
381afefbcddSeschrock 	}
382fa9e4066Sahrens }
383fa9e4066Sahrens 
384990b4856Slling /*
385990b4856Slling  * Add a property pair (name, string-value) into a property nvlist.
386990b4856Slling  */
387990b4856Slling static int
3880a48a24eStimh add_prop_list(const char *propname, char *propval, nvlist_t **props,
3890a48a24eStimh     boolean_t poolprop)
390990b4856Slling {
3910a48a24eStimh 	zpool_prop_t prop = ZPROP_INVAL;
3920a48a24eStimh 	zfs_prop_t fprop;
393990b4856Slling 	nvlist_t *proplist;
3940a48a24eStimh 	const char *normnm;
3950a48a24eStimh 	char *strval;
396990b4856Slling 
397990b4856Slling 	if (*props == NULL &&
398990b4856Slling 	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
399990b4856Slling 		(void) fprintf(stderr,
400990b4856Slling 		    gettext("internal error: out of memory\n"));
401990b4856Slling 		return (1);
402990b4856Slling 	}
403990b4856Slling 
404990b4856Slling 	proplist = *props;
405990b4856Slling 
4060a48a24eStimh 	if (poolprop) {
407*ad135b5dSChristopher Siden 		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
408*ad135b5dSChristopher Siden 		    !zpool_prop_feature(propname)) {
4090a48a24eStimh 			(void) fprintf(stderr, gettext("property '%s' is "
4100a48a24eStimh 			    "not a valid pool property\n"), propname);
4110a48a24eStimh 			return (2);
4120a48a24eStimh 		}
413*ad135b5dSChristopher Siden 		if (zpool_prop_feature(propname))
414*ad135b5dSChristopher Siden 			normnm = propname;
415*ad135b5dSChristopher Siden 		else
416*ad135b5dSChristopher Siden 			normnm = zpool_prop_to_name(prop);
4170a48a24eStimh 	} else {
41814843421SMatthew Ahrens 		if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
41914843421SMatthew Ahrens 			normnm = zfs_prop_to_name(fprop);
42014843421SMatthew Ahrens 		} else {
42114843421SMatthew Ahrens 			normnm = propname;
4220a48a24eStimh 		}
423990b4856Slling 	}
424990b4856Slling 
4250a48a24eStimh 	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
4260a48a24eStimh 	    prop != ZPOOL_PROP_CACHEFILE) {
427990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' "
428990b4856Slling 		    "specified multiple times\n"), propname);
429990b4856Slling 		return (2);
430990b4856Slling 	}
431990b4856Slling 
4320a48a24eStimh 	if (nvlist_add_string(proplist, normnm, propval) != 0) {
433990b4856Slling 		(void) fprintf(stderr, gettext("internal "
434990b4856Slling 		    "error: out of memory\n"));
435990b4856Slling 		return (1);
436990b4856Slling 	}
437990b4856Slling 
438990b4856Slling 	return (0);
439990b4856Slling }
440990b4856Slling 
441fa9e4066Sahrens /*
442fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
443fa9e4066Sahrens  *
444fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
445fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
446fa9e4066Sahrens  *		they were to be added.
447fa9e4066Sahrens  *
448fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
449fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
450fa9e4066Sahrens  * libzfs.
451fa9e4066Sahrens  */
452fa9e4066Sahrens int
453fa9e4066Sahrens zpool_do_add(int argc, char **argv)
454fa9e4066Sahrens {
45599653d4eSeschrock 	boolean_t force = B_FALSE;
45699653d4eSeschrock 	boolean_t dryrun = B_FALSE;
457fa9e4066Sahrens 	int c;
458fa9e4066Sahrens 	nvlist_t *nvroot;
459fa9e4066Sahrens 	char *poolname;
460fa9e4066Sahrens 	int ret;
461fa9e4066Sahrens 	zpool_handle_t *zhp;
462fa9e4066Sahrens 	nvlist_t *config;
463fa9e4066Sahrens 
464fa9e4066Sahrens 	/* check options */
465fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
466fa9e4066Sahrens 		switch (c) {
467fa9e4066Sahrens 		case 'f':
46899653d4eSeschrock 			force = B_TRUE;
469fa9e4066Sahrens 			break;
470fa9e4066Sahrens 		case 'n':
47199653d4eSeschrock 			dryrun = B_TRUE;
472fa9e4066Sahrens 			break;
473fa9e4066Sahrens 		case '?':
474fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
475fa9e4066Sahrens 			    optopt);
47699653d4eSeschrock 			usage(B_FALSE);
477fa9e4066Sahrens 		}
478fa9e4066Sahrens 	}
479fa9e4066Sahrens 
480fa9e4066Sahrens 	argc -= optind;
481fa9e4066Sahrens 	argv += optind;
482fa9e4066Sahrens 
483fa9e4066Sahrens 	/* get pool name and check number of arguments */
484fa9e4066Sahrens 	if (argc < 1) {
485fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
48699653d4eSeschrock 		usage(B_FALSE);
487fa9e4066Sahrens 	}
488fa9e4066Sahrens 	if (argc < 2) {
489fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
49099653d4eSeschrock 		usage(B_FALSE);
491fa9e4066Sahrens 	}
492fa9e4066Sahrens 
493fa9e4066Sahrens 	poolname = argv[0];
494fa9e4066Sahrens 
495fa9e4066Sahrens 	argc--;
496fa9e4066Sahrens 	argv++;
497fa9e4066Sahrens 
49899653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
499fa9e4066Sahrens 		return (1);
500fa9e4066Sahrens 
501088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
502fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
503fa9e4066Sahrens 		    poolname);
504fa9e4066Sahrens 		zpool_close(zhp);
505fa9e4066Sahrens 		return (1);
506fa9e4066Sahrens 	}
507fa9e4066Sahrens 
508fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
509705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
510705040edSEric Taylor 	    argc, argv);
511fa9e4066Sahrens 	if (nvroot == NULL) {
512fa9e4066Sahrens 		zpool_close(zhp);
513fa9e4066Sahrens 		return (1);
514fa9e4066Sahrens 	}
515fa9e4066Sahrens 
516fa9e4066Sahrens 	if (dryrun) {
517fa9e4066Sahrens 		nvlist_t *poolnvroot;
518fa9e4066Sahrens 
519fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
520fa9e4066Sahrens 		    &poolnvroot) == 0);
521fa9e4066Sahrens 
522fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
523fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
524fa9e4066Sahrens 
5258654d025Sperrin 		/* print original main pool and new tree */
5268654d025Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
5278654d025Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
5288654d025Sperrin 
5298654d025Sperrin 		/* Do the same for the logs */
5308654d025Sperrin 		if (num_logs(poolnvroot) > 0) {
5318654d025Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
5328654d025Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
5338654d025Sperrin 		} else if (num_logs(nvroot) > 0) {
5348654d025Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
5358654d025Sperrin 		}
536fa9e4066Sahrens 
537fa9e4066Sahrens 		ret = 0;
538fa9e4066Sahrens 	} else {
539fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
540fa9e4066Sahrens 	}
541fa9e4066Sahrens 
54299653d4eSeschrock 	nvlist_free(nvroot);
54399653d4eSeschrock 	zpool_close(zhp);
54499653d4eSeschrock 
54599653d4eSeschrock 	return (ret);
54699653d4eSeschrock }
54799653d4eSeschrock 
54899653d4eSeschrock /*
5493f9d6ad7SLin Ling  * zpool remove  <pool> <vdev> ...
55099653d4eSeschrock  *
5513f9d6ad7SLin Ling  * Removes the given vdev from the pool.  Currently, this supports removing
5523f9d6ad7SLin Ling  * spares, cache, and log devices from the pool.
55399653d4eSeschrock  */
55499653d4eSeschrock int
55599653d4eSeschrock zpool_do_remove(int argc, char **argv)
55699653d4eSeschrock {
55799653d4eSeschrock 	char *poolname;
558fa94a07fSbrendan 	int i, ret = 0;
55999653d4eSeschrock 	zpool_handle_t *zhp;
56099653d4eSeschrock 
56199653d4eSeschrock 	argc--;
56299653d4eSeschrock 	argv++;
56399653d4eSeschrock 
56499653d4eSeschrock 	/* get pool name and check number of arguments */
56599653d4eSeschrock 	if (argc < 1) {
56699653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
56799653d4eSeschrock 		usage(B_FALSE);
56899653d4eSeschrock 	}
56999653d4eSeschrock 	if (argc < 2) {
57099653d4eSeschrock 		(void) fprintf(stderr, gettext("missing device\n"));
57199653d4eSeschrock 		usage(B_FALSE);
57299653d4eSeschrock 	}
57399653d4eSeschrock 
57499653d4eSeschrock 	poolname = argv[0];
57599653d4eSeschrock 
57699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
57799653d4eSeschrock 		return (1);
57899653d4eSeschrock 
579fa94a07fSbrendan 	for (i = 1; i < argc; i++) {
580fa94a07fSbrendan 		if (zpool_vdev_remove(zhp, argv[i]) != 0)
581fa94a07fSbrendan 			ret = 1;
582fa94a07fSbrendan 	}
58399653d4eSeschrock 
584fa9e4066Sahrens 	return (ret);
585fa9e4066Sahrens }
586fa9e4066Sahrens 
587fa9e4066Sahrens /*
588*ad135b5dSChristopher Siden  * zpool create [-fnd] [-o property=value] ...
5890a48a24eStimh  *		[-O file-system-property=value] ...
5900a48a24eStimh  *		[-R root] [-m mountpoint] <pool> <dev> ...
591fa9e4066Sahrens  *
592fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
593fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
594fa9e4066Sahrens  *		were to be created.
595fa9e4066Sahrens  *      -R	Create a pool under an alternate root
596fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
597*ad135b5dSChristopher Siden  *		'/<pool>'
598990b4856Slling  *	-o	Set property=value.
599*ad135b5dSChristopher Siden  *	-d	Don't automatically enable all supported pool features
600*ad135b5dSChristopher Siden  *		(individual features can be enabled with -o).
6010a48a24eStimh  *	-O	Set fsproperty=value in the pool's root file system
602fa9e4066Sahrens  *
603b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
604fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
605fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
606fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
607fa9e4066Sahrens  */
608fa9e4066Sahrens int
609fa9e4066Sahrens zpool_do_create(int argc, char **argv)
610fa9e4066Sahrens {
61199653d4eSeschrock 	boolean_t force = B_FALSE;
61299653d4eSeschrock 	boolean_t dryrun = B_FALSE;
613*ad135b5dSChristopher Siden 	boolean_t enable_all_pool_feat = B_TRUE;
614fa9e4066Sahrens 	int c;
615990b4856Slling 	nvlist_t *nvroot = NULL;
616fa9e4066Sahrens 	char *poolname;
617990b4856Slling 	int ret = 1;
618fa9e4066Sahrens 	char *altroot = NULL;
619fa9e4066Sahrens 	char *mountpoint = NULL;
6200a48a24eStimh 	nvlist_t *fsprops = NULL;
621990b4856Slling 	nvlist_t *props = NULL;
6222f8aaab3Seschrock 	char *propval;
623fa9e4066Sahrens 
624fa9e4066Sahrens 	/* check options */
625*ad135b5dSChristopher Siden 	while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) {
626fa9e4066Sahrens 		switch (c) {
627fa9e4066Sahrens 		case 'f':
62899653d4eSeschrock 			force = B_TRUE;
629fa9e4066Sahrens 			break;
630fa9e4066Sahrens 		case 'n':
63199653d4eSeschrock 			dryrun = B_TRUE;
632fa9e4066Sahrens 			break;
633*ad135b5dSChristopher Siden 		case 'd':
634*ad135b5dSChristopher Siden 			enable_all_pool_feat = B_FALSE;
635*ad135b5dSChristopher Siden 			break;
636fa9e4066Sahrens 		case 'R':
637fa9e4066Sahrens 			altroot = optarg;
638990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
6390a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
640990b4856Slling 				goto errout;
6412f8aaab3Seschrock 			if (nvlist_lookup_string(props,
6422f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
6432f8aaab3Seschrock 			    &propval) == 0)
6442f8aaab3Seschrock 				break;
645990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
6460a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
647990b4856Slling 				goto errout;
648fa9e4066Sahrens 			break;
649fa9e4066Sahrens 		case 'm':
650fa9e4066Sahrens 			mountpoint = optarg;
651fa9e4066Sahrens 			break;
652990b4856Slling 		case 'o':
653990b4856Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
654990b4856Slling 				(void) fprintf(stderr, gettext("missing "
655990b4856Slling 				    "'=' for -o option\n"));
656990b4856Slling 				goto errout;
657990b4856Slling 			}
658990b4856Slling 			*propval = '\0';
659990b4856Slling 			propval++;
660990b4856Slling 
6610a48a24eStimh 			if (add_prop_list(optarg, propval, &props, B_TRUE))
6620a48a24eStimh 				goto errout;
663*ad135b5dSChristopher Siden 
664*ad135b5dSChristopher Siden 			/*
665*ad135b5dSChristopher Siden 			 * If the user is creating a pool that doesn't support
666*ad135b5dSChristopher Siden 			 * feature flags, don't enable any features.
667*ad135b5dSChristopher Siden 			 */
668*ad135b5dSChristopher Siden 			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) {
669*ad135b5dSChristopher Siden 				char *end;
670*ad135b5dSChristopher Siden 				u_longlong_t ver;
671*ad135b5dSChristopher Siden 
672*ad135b5dSChristopher Siden 				ver = strtoull(propval, &end, 10);
673*ad135b5dSChristopher Siden 				if (*end == '\0' &&
674*ad135b5dSChristopher Siden 				    ver < SPA_VERSION_FEATURES) {
675*ad135b5dSChristopher Siden 					enable_all_pool_feat = B_FALSE;
676*ad135b5dSChristopher Siden 				}
677*ad135b5dSChristopher Siden 			}
6780a48a24eStimh 			break;
6790a48a24eStimh 		case 'O':
6800a48a24eStimh 			if ((propval = strchr(optarg, '=')) == NULL) {
6810a48a24eStimh 				(void) fprintf(stderr, gettext("missing "
6820a48a24eStimh 				    "'=' for -O option\n"));
6830a48a24eStimh 				goto errout;
6840a48a24eStimh 			}
6850a48a24eStimh 			*propval = '\0';
6860a48a24eStimh 			propval++;
6870a48a24eStimh 
6880a48a24eStimh 			if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
689990b4856Slling 				goto errout;
690990b4856Slling 			break;
691fa9e4066Sahrens 		case ':':
692fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
693fa9e4066Sahrens 			    "'%c' option\n"), optopt);
694990b4856Slling 			goto badusage;
695fa9e4066Sahrens 		case '?':
696fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
697fa9e4066Sahrens 			    optopt);
698990b4856Slling 			goto badusage;
699fa9e4066Sahrens 		}
700fa9e4066Sahrens 	}
701fa9e4066Sahrens 
702fa9e4066Sahrens 	argc -= optind;
703fa9e4066Sahrens 	argv += optind;
704fa9e4066Sahrens 
705fa9e4066Sahrens 	/* get pool name and check number of arguments */
706fa9e4066Sahrens 	if (argc < 1) {
707fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
708990b4856Slling 		goto badusage;
709fa9e4066Sahrens 	}
710fa9e4066Sahrens 	if (argc < 2) {
711fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
712990b4856Slling 		goto badusage;
713fa9e4066Sahrens 	}
714fa9e4066Sahrens 
715fa9e4066Sahrens 	poolname = argv[0];
716fa9e4066Sahrens 
717fa9e4066Sahrens 	/*
718fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
719fa9e4066Sahrens 	 * user to use 'zfs create' instead.
720fa9e4066Sahrens 	 */
721fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
722fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
723fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
724fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
725fa9e4066Sahrens 		    "create a dataset\n"));
726990b4856Slling 		goto errout;
727fa9e4066Sahrens 	}
728fa9e4066Sahrens 
729fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
730705040edSEric Taylor 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
731705040edSEric Taylor 	    argc - 1, argv + 1);
732fa9e4066Sahrens 	if (nvroot == NULL)
7330a48a24eStimh 		goto errout;
734fa9e4066Sahrens 
73599653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
736b7b97454Sperrin 	if (!zfs_allocatable_devs(nvroot)) {
73799653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
73899653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
73999653d4eSeschrock 		    "specified\n"));
740990b4856Slling 		goto errout;
74199653d4eSeschrock 	}
74299653d4eSeschrock 
743fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
744fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
745e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
746990b4856Slling 		goto errout;
747fa9e4066Sahrens 	}
748fa9e4066Sahrens 
749fa9e4066Sahrens 	/*
750fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
751fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
752fa9e4066Sahrens 	 */
753fa9e4066Sahrens 	if (mountpoint == NULL ||
754fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
755fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
756fa9e4066Sahrens 		char buf[MAXPATHLEN];
75711022c7cStimh 		DIR *dirp;
758fa9e4066Sahrens 
759fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
760fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
761fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
762fa9e4066Sahrens 			    "'none'\n"), mountpoint);
763990b4856Slling 			goto errout;
764fa9e4066Sahrens 		}
765fa9e4066Sahrens 
766fa9e4066Sahrens 		if (mountpoint == NULL) {
767fa9e4066Sahrens 			if (altroot != NULL)
768fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
769fa9e4066Sahrens 				    altroot, poolname);
770fa9e4066Sahrens 			else
771fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
772fa9e4066Sahrens 				    poolname);
773fa9e4066Sahrens 		} else {
774fa9e4066Sahrens 			if (altroot != NULL)
775fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
776fa9e4066Sahrens 				    altroot, mountpoint);
777fa9e4066Sahrens 			else
778fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
779fa9e4066Sahrens 				    mountpoint);
780fa9e4066Sahrens 		}
781fa9e4066Sahrens 
78211022c7cStimh 		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
78311022c7cStimh 			(void) fprintf(stderr, gettext("mountpoint '%s' : "
78411022c7cStimh 			    "%s\n"), buf, strerror(errno));
785fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
786fa9e4066Sahrens 			    "option to provide a different default\n"));
787990b4856Slling 			goto errout;
78811022c7cStimh 		} else if (dirp) {
78911022c7cStimh 			int count = 0;
79011022c7cStimh 
79111022c7cStimh 			while (count < 3 && readdir(dirp) != NULL)
79211022c7cStimh 				count++;
79311022c7cStimh 			(void) closedir(dirp);
79411022c7cStimh 
79511022c7cStimh 			if (count > 2) {
79611022c7cStimh 				(void) fprintf(stderr, gettext("mountpoint "
79711022c7cStimh 				    "'%s' exists and is not empty\n"), buf);
79811022c7cStimh 				(void) fprintf(stderr, gettext("use '-m' "
79911022c7cStimh 				    "option to provide a "
80011022c7cStimh 				    "different default\n"));
80111022c7cStimh 				goto errout;
80211022c7cStimh 			}
803fa9e4066Sahrens 		}
804fa9e4066Sahrens 	}
805fa9e4066Sahrens 
806fa9e4066Sahrens 	if (dryrun) {
807fa9e4066Sahrens 		/*
808fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
809fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
810fa9e4066Sahrens 		 * appropriate hierarchy.
811fa9e4066Sahrens 		 */
812fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
813fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
814fa9e4066Sahrens 
8158654d025Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
8168654d025Sperrin 		if (num_logs(nvroot) > 0)
8178654d025Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
818fa9e4066Sahrens 
819fa9e4066Sahrens 		ret = 0;
820fa9e4066Sahrens 	} else {
821fa9e4066Sahrens 		/*
822fa9e4066Sahrens 		 * Hand off to libzfs.
823fa9e4066Sahrens 		 */
824*ad135b5dSChristopher Siden 		if (enable_all_pool_feat) {
825*ad135b5dSChristopher Siden 			int i;
826*ad135b5dSChristopher Siden 			for (i = 0; i < SPA_FEATURES; i++) {
827*ad135b5dSChristopher Siden 				char propname[MAXPATHLEN];
828*ad135b5dSChristopher Siden 				zfeature_info_t *feat = &spa_feature_table[i];
829*ad135b5dSChristopher Siden 
830*ad135b5dSChristopher Siden 				(void) snprintf(propname, sizeof (propname),
831*ad135b5dSChristopher Siden 				    "feature@%s", feat->fi_uname);
832*ad135b5dSChristopher Siden 
833*ad135b5dSChristopher Siden 				/*
834*ad135b5dSChristopher Siden 				 * Skip feature if user specified it manually
835*ad135b5dSChristopher Siden 				 * on the command line.
836*ad135b5dSChristopher Siden 				 */
837*ad135b5dSChristopher Siden 				if (nvlist_exists(props, propname))
838*ad135b5dSChristopher Siden 					continue;
839*ad135b5dSChristopher Siden 
840*ad135b5dSChristopher Siden 				if (add_prop_list(propname, ZFS_FEATURE_ENABLED,
841*ad135b5dSChristopher Siden 				    &props, B_TRUE) != 0)
842*ad135b5dSChristopher Siden 					goto errout;
843*ad135b5dSChristopher Siden 			}
844*ad135b5dSChristopher Siden 		}
8450a48a24eStimh 		if (zpool_create(g_zfs, poolname,
8460a48a24eStimh 		    nvroot, props, fsprops) == 0) {
84799653d4eSeschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
848fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
849fa9e4066Sahrens 			if (pool != NULL) {
850fa9e4066Sahrens 				if (mountpoint != NULL)
851fa9e4066Sahrens 					verify(zfs_prop_set(pool,
852e9dbad6fSeschrock 					    zfs_prop_to_name(
853e9dbad6fSeschrock 					    ZFS_PROP_MOUNTPOINT),
854fa9e4066Sahrens 					    mountpoint) == 0);
855fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
856da6c28aaSamw 					ret = zfs_shareall(pool);
857fa9e4066Sahrens 				zfs_close(pool);
858fa9e4066Sahrens 			}
85999653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
86099653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
86199653d4eSeschrock 			    "been omitted\n"));
862fa9e4066Sahrens 		}
863fa9e4066Sahrens 	}
864fa9e4066Sahrens 
865990b4856Slling errout:
8662f8aaab3Seschrock 	nvlist_free(nvroot);
8670a48a24eStimh 	nvlist_free(fsprops);
8682f8aaab3Seschrock 	nvlist_free(props);
869fa9e4066Sahrens 	return (ret);
870990b4856Slling badusage:
8710a48a24eStimh 	nvlist_free(fsprops);
872990b4856Slling 	nvlist_free(props);
873990b4856Slling 	usage(B_FALSE);
874990b4856Slling 	return (2);
875fa9e4066Sahrens }
876fa9e4066Sahrens 
877fa9e4066Sahrens /*
878fa9e4066Sahrens  * zpool destroy <pool>
879fa9e4066Sahrens  *
880fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
881fa9e4066Sahrens  *
882fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
883fa9e4066Sahrens  */
884fa9e4066Sahrens int
885fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
886fa9e4066Sahrens {
88799653d4eSeschrock 	boolean_t force = B_FALSE;
888fa9e4066Sahrens 	int c;
889fa9e4066Sahrens 	char *pool;
890fa9e4066Sahrens 	zpool_handle_t *zhp;
891fa9e4066Sahrens 	int ret;
892fa9e4066Sahrens 
893fa9e4066Sahrens 	/* check options */
894fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
895fa9e4066Sahrens 		switch (c) {
896fa9e4066Sahrens 		case 'f':
89799653d4eSeschrock 			force = B_TRUE;
898fa9e4066Sahrens 			break;
899fa9e4066Sahrens 		case '?':
900fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
901fa9e4066Sahrens 			    optopt);
90299653d4eSeschrock 			usage(B_FALSE);
903fa9e4066Sahrens 		}
904fa9e4066Sahrens 	}
905fa9e4066Sahrens 
906fa9e4066Sahrens 	argc -= optind;
907fa9e4066Sahrens 	argv += optind;
908fa9e4066Sahrens 
909fa9e4066Sahrens 	/* check arguments */
910fa9e4066Sahrens 	if (argc < 1) {
911fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
91299653d4eSeschrock 		usage(B_FALSE);
913fa9e4066Sahrens 	}
914fa9e4066Sahrens 	if (argc > 1) {
915fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
91699653d4eSeschrock 		usage(B_FALSE);
917fa9e4066Sahrens 	}
918fa9e4066Sahrens 
919fa9e4066Sahrens 	pool = argv[0];
920fa9e4066Sahrens 
92199653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
922fa9e4066Sahrens 		/*
923fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
924fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
925fa9e4066Sahrens 		 */
926fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
927fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
928fa9e4066Sahrens 			    "destroy a dataset\n"));
929fa9e4066Sahrens 		return (1);
930fa9e4066Sahrens 	}
931fa9e4066Sahrens 
932f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
933fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
934fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
935fa9e4066Sahrens 		return (1);
936fa9e4066Sahrens 	}
937fa9e4066Sahrens 
938fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
939fa9e4066Sahrens 
940fa9e4066Sahrens 	zpool_close(zhp);
941fa9e4066Sahrens 
942fa9e4066Sahrens 	return (ret);
943fa9e4066Sahrens }
944fa9e4066Sahrens 
945fa9e4066Sahrens /*
946fa9e4066Sahrens  * zpool export [-f] <pool> ...
947fa9e4066Sahrens  *
948fa9e4066Sahrens  *	-f	Forcefully unmount datasets
949fa9e4066Sahrens  *
950b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
951fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
952fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
953fa9e4066Sahrens  */
954fa9e4066Sahrens int
955fa9e4066Sahrens zpool_do_export(int argc, char **argv)
956fa9e4066Sahrens {
95799653d4eSeschrock 	boolean_t force = B_FALSE;
958394ab0cbSGeorge Wilson 	boolean_t hardforce = B_FALSE;
959fa9e4066Sahrens 	int c;
960fa9e4066Sahrens 	zpool_handle_t *zhp;
961fa9e4066Sahrens 	int ret;
962fa9e4066Sahrens 	int i;
963fa9e4066Sahrens 
964fa9e4066Sahrens 	/* check options */
965394ab0cbSGeorge Wilson 	while ((c = getopt(argc, argv, "fF")) != -1) {
966fa9e4066Sahrens 		switch (c) {
967fa9e4066Sahrens 		case 'f':
96899653d4eSeschrock 			force = B_TRUE;
969fa9e4066Sahrens 			break;
970394ab0cbSGeorge Wilson 		case 'F':
971394ab0cbSGeorge Wilson 			hardforce = B_TRUE;
972394ab0cbSGeorge Wilson 			break;
973fa9e4066Sahrens 		case '?':
974fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
975fa9e4066Sahrens 			    optopt);
97699653d4eSeschrock 			usage(B_FALSE);
977fa9e4066Sahrens 		}
978fa9e4066Sahrens 	}
979fa9e4066Sahrens 
980fa9e4066Sahrens 	argc -= optind;
981fa9e4066Sahrens 	argv += optind;
982fa9e4066Sahrens 
983fa9e4066Sahrens 	/* check arguments */
984fa9e4066Sahrens 	if (argc < 1) {
985fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
98699653d4eSeschrock 		usage(B_FALSE);
987fa9e4066Sahrens 	}
988fa9e4066Sahrens 
989fa9e4066Sahrens 	ret = 0;
990fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
99199653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
992fa9e4066Sahrens 			ret = 1;
993fa9e4066Sahrens 			continue;
994fa9e4066Sahrens 		}
995fa9e4066Sahrens 
996f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
997fa9e4066Sahrens 			ret = 1;
998fa9e4066Sahrens 			zpool_close(zhp);
999fa9e4066Sahrens 			continue;
1000fa9e4066Sahrens 		}
1001fa9e4066Sahrens 
1002394ab0cbSGeorge Wilson 		if (hardforce) {
1003394ab0cbSGeorge Wilson 			if (zpool_export_force(zhp) != 0)
1004394ab0cbSGeorge Wilson 				ret = 1;
1005394ab0cbSGeorge Wilson 		} else if (zpool_export(zhp, force) != 0) {
1006fa9e4066Sahrens 			ret = 1;
1007394ab0cbSGeorge Wilson 		}
1008fa9e4066Sahrens 
1009fa9e4066Sahrens 		zpool_close(zhp);
1010fa9e4066Sahrens 	}
1011fa9e4066Sahrens 
1012fa9e4066Sahrens 	return (ret);
1013fa9e4066Sahrens }
1014fa9e4066Sahrens 
1015fa9e4066Sahrens /*
1016fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
1017fa9e4066Sahrens  * name column.
1018fa9e4066Sahrens  */
1019fa9e4066Sahrens static int
1020c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
1021fa9e4066Sahrens {
102288ecc943SGeorge Wilson 	char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
1023fa9e4066Sahrens 	nvlist_t **child;
1024fa9e4066Sahrens 	uint_t c, children;
1025fa9e4066Sahrens 	int ret;
1026fa9e4066Sahrens 
1027fa9e4066Sahrens 	if (strlen(name) + depth > max)
1028fa9e4066Sahrens 		max = strlen(name) + depth;
1029fa9e4066Sahrens 
1030afefbcddSeschrock 	free(name);
1031afefbcddSeschrock 
103299653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
103399653d4eSeschrock 	    &child, &children) == 0) {
103499653d4eSeschrock 		for (c = 0; c < children; c++)
103599653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
103699653d4eSeschrock 			    max)) > max)
103799653d4eSeschrock 				max = ret;
103899653d4eSeschrock 	}
103999653d4eSeschrock 
1040fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1041fa94a07fSbrendan 	    &child, &children) == 0) {
1042fa94a07fSbrendan 		for (c = 0; c < children; c++)
1043fa94a07fSbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
1044fa94a07fSbrendan 			    max)) > max)
1045fa94a07fSbrendan 				max = ret;
1046fa94a07fSbrendan 	}
1047fa94a07fSbrendan 
1048fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
104999653d4eSeschrock 	    &child, &children) == 0) {
105099653d4eSeschrock 		for (c = 0; c < children; c++)
105199653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
105299653d4eSeschrock 			    max)) > max)
105399653d4eSeschrock 				max = ret;
105499653d4eSeschrock 	}
1055fa9e4066Sahrens 
1056fa9e4066Sahrens 
1057fa9e4066Sahrens 	return (max);
1058fa9e4066Sahrens }
1059fa9e4066Sahrens 
1060e6ca193dSGeorge Wilson typedef struct spare_cbdata {
1061e6ca193dSGeorge Wilson 	uint64_t	cb_guid;
1062e6ca193dSGeorge Wilson 	zpool_handle_t	*cb_zhp;
1063e6ca193dSGeorge Wilson } spare_cbdata_t;
1064e6ca193dSGeorge Wilson 
1065e6ca193dSGeorge Wilson static boolean_t
1066e6ca193dSGeorge Wilson find_vdev(nvlist_t *nv, uint64_t search)
1067e6ca193dSGeorge Wilson {
1068e6ca193dSGeorge Wilson 	uint64_t guid;
1069e6ca193dSGeorge Wilson 	nvlist_t **child;
1070e6ca193dSGeorge Wilson 	uint_t c, children;
1071e6ca193dSGeorge Wilson 
1072e6ca193dSGeorge Wilson 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
1073e6ca193dSGeorge Wilson 	    search == guid)
1074e6ca193dSGeorge Wilson 		return (B_TRUE);
1075e6ca193dSGeorge Wilson 
1076e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1077e6ca193dSGeorge Wilson 	    &child, &children) == 0) {
1078e6ca193dSGeorge Wilson 		for (c = 0; c < children; c++)
1079e6ca193dSGeorge Wilson 			if (find_vdev(child[c], search))
1080e6ca193dSGeorge Wilson 				return (B_TRUE);
1081e6ca193dSGeorge Wilson 	}
1082e6ca193dSGeorge Wilson 
1083e6ca193dSGeorge Wilson 	return (B_FALSE);
1084e6ca193dSGeorge Wilson }
1085e6ca193dSGeorge Wilson 
1086e6ca193dSGeorge Wilson static int
1087e6ca193dSGeorge Wilson find_spare(zpool_handle_t *zhp, void *data)
1088e6ca193dSGeorge Wilson {
1089e6ca193dSGeorge Wilson 	spare_cbdata_t *cbp = data;
1090e6ca193dSGeorge Wilson 	nvlist_t *config, *nvroot;
1091e6ca193dSGeorge Wilson 
1092e6ca193dSGeorge Wilson 	config = zpool_get_config(zhp, NULL);
1093e6ca193dSGeorge Wilson 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1094e6ca193dSGeorge Wilson 	    &nvroot) == 0);
1095e6ca193dSGeorge Wilson 
1096e6ca193dSGeorge Wilson 	if (find_vdev(nvroot, cbp->cb_guid)) {
1097e6ca193dSGeorge Wilson 		cbp->cb_zhp = zhp;
1098e6ca193dSGeorge Wilson 		return (1);
1099e6ca193dSGeorge Wilson 	}
1100e6ca193dSGeorge Wilson 
1101e6ca193dSGeorge Wilson 	zpool_close(zhp);
1102e6ca193dSGeorge Wilson 	return (0);
1103e6ca193dSGeorge Wilson }
1104e6ca193dSGeorge Wilson 
1105e6ca193dSGeorge Wilson /*
1106e6ca193dSGeorge Wilson  * Print out configuration state as requested by status_callback.
1107e6ca193dSGeorge Wilson  */
1108e6ca193dSGeorge Wilson void
1109e6ca193dSGeorge Wilson print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
1110e6ca193dSGeorge Wilson     int namewidth, int depth, boolean_t isspare)
1111e6ca193dSGeorge Wilson {
1112e6ca193dSGeorge Wilson 	nvlist_t **child;
1113e6ca193dSGeorge Wilson 	uint_t c, children;
11143f9d6ad7SLin Ling 	pool_scan_stat_t *ps = NULL;
1115e6ca193dSGeorge Wilson 	vdev_stat_t *vs;
11163f9d6ad7SLin Ling 	char rbuf[6], wbuf[6], cbuf[6];
1117e6ca193dSGeorge Wilson 	char *vname;
1118e6ca193dSGeorge Wilson 	uint64_t notpresent;
1119e6ca193dSGeorge Wilson 	spare_cbdata_t cb;
1120e6ca193dSGeorge Wilson 	char *state;
1121e6ca193dSGeorge Wilson 
1122e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1123e6ca193dSGeorge Wilson 	    &child, &children) != 0)
1124e6ca193dSGeorge Wilson 		children = 0;
1125e6ca193dSGeorge Wilson 
11263f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
11273f9d6ad7SLin Ling 	    (uint64_t **)&vs, &c) == 0);
11283f9d6ad7SLin Ling 
1129e6ca193dSGeorge Wilson 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1130e6ca193dSGeorge Wilson 	if (isspare) {
1131e6ca193dSGeorge Wilson 		/*
1132e6ca193dSGeorge Wilson 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
1133e6ca193dSGeorge Wilson 		 * online drives.
1134e6ca193dSGeorge Wilson 		 */
1135e6ca193dSGeorge Wilson 		if (vs->vs_aux == VDEV_AUX_SPARED)
1136e6ca193dSGeorge Wilson 			state = "INUSE";
1137e6ca193dSGeorge Wilson 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
1138e6ca193dSGeorge Wilson 			state = "AVAIL";
1139e6ca193dSGeorge Wilson 	}
1140e6ca193dSGeorge Wilson 
1141e6ca193dSGeorge Wilson 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
1142e6ca193dSGeorge Wilson 	    name, state);
1143e6ca193dSGeorge Wilson 
1144e6ca193dSGeorge Wilson 	if (!isspare) {
1145e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
1146e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
1147e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
1148e6ca193dSGeorge Wilson 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
1149e6ca193dSGeorge Wilson 	}
1150e6ca193dSGeorge Wilson 
1151e6ca193dSGeorge Wilson 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1152e6ca193dSGeorge Wilson 	    &notpresent) == 0) {
1153e6ca193dSGeorge Wilson 		char *path;
1154e6ca193dSGeorge Wilson 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
1155e6ca193dSGeorge Wilson 		(void) printf("  was %s", path);
1156e6ca193dSGeorge Wilson 	} else if (vs->vs_aux != 0) {
1157e6ca193dSGeorge Wilson 		(void) printf("  ");
1158e6ca193dSGeorge Wilson 
1159e6ca193dSGeorge Wilson 		switch (vs->vs_aux) {
1160e6ca193dSGeorge Wilson 		case VDEV_AUX_OPEN_FAILED:
1161e6ca193dSGeorge Wilson 			(void) printf(gettext("cannot open"));
1162e6ca193dSGeorge Wilson 			break;
1163e6ca193dSGeorge Wilson 
1164e6ca193dSGeorge Wilson 		case VDEV_AUX_BAD_GUID_SUM:
1165e6ca193dSGeorge Wilson 			(void) printf(gettext("missing device"));
1166e6ca193dSGeorge Wilson 			break;
1167e6ca193dSGeorge Wilson 
1168e6ca193dSGeorge Wilson 		case VDEV_AUX_NO_REPLICAS:
1169e6ca193dSGeorge Wilson 			(void) printf(gettext("insufficient replicas"));
1170e6ca193dSGeorge Wilson 			break;
1171e6ca193dSGeorge Wilson 
1172e6ca193dSGeorge Wilson 		case VDEV_AUX_VERSION_NEWER:
1173e6ca193dSGeorge Wilson 			(void) printf(gettext("newer version"));
1174e6ca193dSGeorge Wilson 			break;
1175e6ca193dSGeorge Wilson 
1176*ad135b5dSChristopher Siden 		case VDEV_AUX_UNSUP_FEAT:
1177*ad135b5dSChristopher Siden 			(void) printf(gettext("unsupported feature(s)"));
1178*ad135b5dSChristopher Siden 			break;
1179*ad135b5dSChristopher Siden 
1180e6ca193dSGeorge Wilson 		case VDEV_AUX_SPARED:
1181e6ca193dSGeorge Wilson 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1182e6ca193dSGeorge Wilson 			    &cb.cb_guid) == 0);
1183e6ca193dSGeorge Wilson 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
1184e6ca193dSGeorge Wilson 				if (strcmp(zpool_get_name(cb.cb_zhp),
1185e6ca193dSGeorge Wilson 				    zpool_get_name(zhp)) == 0)
1186e6ca193dSGeorge Wilson 					(void) printf(gettext("currently in "
1187e6ca193dSGeorge Wilson 					    "use"));
1188e6ca193dSGeorge Wilson 				else
1189e6ca193dSGeorge Wilson 					(void) printf(gettext("in use by "
1190e6ca193dSGeorge Wilson 					    "pool '%s'"),
1191e6ca193dSGeorge Wilson 					    zpool_get_name(cb.cb_zhp));
1192e6ca193dSGeorge Wilson 				zpool_close(cb.cb_zhp);
1193e6ca193dSGeorge Wilson 			} else {
1194e6ca193dSGeorge Wilson 				(void) printf(gettext("currently in use"));
1195e6ca193dSGeorge Wilson 			}
1196e6ca193dSGeorge Wilson 			break;
1197e6ca193dSGeorge Wilson 
1198e6ca193dSGeorge Wilson 		case VDEV_AUX_ERR_EXCEEDED:
1199e6ca193dSGeorge Wilson 			(void) printf(gettext("too many errors"));
1200e6ca193dSGeorge Wilson 			break;
1201e6ca193dSGeorge Wilson 
1202e6ca193dSGeorge Wilson 		case VDEV_AUX_IO_FAILURE:
1203e6ca193dSGeorge Wilson 			(void) printf(gettext("experienced I/O failures"));
1204e6ca193dSGeorge Wilson 			break;
1205e6ca193dSGeorge Wilson 
1206e6ca193dSGeorge Wilson 		case VDEV_AUX_BAD_LOG:
1207e6ca193dSGeorge Wilson 			(void) printf(gettext("bad intent log"));
1208e6ca193dSGeorge Wilson 			break;
1209e6ca193dSGeorge Wilson 
1210069f55e2SEric Schrock 		case VDEV_AUX_EXTERNAL:
1211069f55e2SEric Schrock 			(void) printf(gettext("external device fault"));
1212069f55e2SEric Schrock 			break;
1213069f55e2SEric Schrock 
12141195e687SMark J Musante 		case VDEV_AUX_SPLIT_POOL:
12151195e687SMark J Musante 			(void) printf(gettext("split into new pool"));
12161195e687SMark J Musante 			break;
12171195e687SMark J Musante 
1218e6ca193dSGeorge Wilson 		default:
1219e6ca193dSGeorge Wilson 			(void) printf(gettext("corrupted data"));
1220e6ca193dSGeorge Wilson 			break;
1221e6ca193dSGeorge Wilson 		}
12223f9d6ad7SLin Ling 	}
12233f9d6ad7SLin Ling 
12243f9d6ad7SLin Ling 	(void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS,
12253f9d6ad7SLin Ling 	    (uint64_t **)&ps, &c);
12263f9d6ad7SLin Ling 
12273f9d6ad7SLin Ling 	if (ps && ps->pss_state == DSS_SCANNING &&
12283f9d6ad7SLin Ling 	    vs->vs_scan_processed != 0 && children == 0) {
12293f9d6ad7SLin Ling 		(void) printf(gettext("  (%s)"),
12303f9d6ad7SLin Ling 		    (ps->pss_func == POOL_SCAN_RESILVER) ?
12313f9d6ad7SLin Ling 		    "resilvering" : "repairing");
1232e6ca193dSGeorge Wilson 	}
1233e6ca193dSGeorge Wilson 
1234e6ca193dSGeorge Wilson 	(void) printf("\n");
1235e6ca193dSGeorge Wilson 
1236e6ca193dSGeorge Wilson 	for (c = 0; c < children; c++) {
123788ecc943SGeorge Wilson 		uint64_t islog = B_FALSE, ishole = B_FALSE;
1238e6ca193dSGeorge Wilson 
123988ecc943SGeorge Wilson 		/* Don't print logs or holes here */
1240e6ca193dSGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
124188ecc943SGeorge Wilson 		    &islog);
124288ecc943SGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
124388ecc943SGeorge Wilson 		    &ishole);
124488ecc943SGeorge Wilson 		if (islog || ishole)
1245e6ca193dSGeorge Wilson 			continue;
124688ecc943SGeorge Wilson 		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1247e6ca193dSGeorge Wilson 		print_status_config(zhp, vname, child[c],
1248e6ca193dSGeorge Wilson 		    namewidth, depth + 2, isspare);
1249e6ca193dSGeorge Wilson 		free(vname);
1250e6ca193dSGeorge Wilson 	}
1251e6ca193dSGeorge Wilson }
1252e6ca193dSGeorge Wilson 
1253fa9e4066Sahrens 
1254fa9e4066Sahrens /*
1255fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
1256fa9e4066Sahrens  * pool, printing out the name and status for each one.
1257fa9e4066Sahrens  */
1258fa9e4066Sahrens void
1259e6ca193dSGeorge Wilson print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
1260fa9e4066Sahrens {
1261fa9e4066Sahrens 	nvlist_t **child;
1262fa9e4066Sahrens 	uint_t c, children;
1263fa9e4066Sahrens 	vdev_stat_t *vs;
1264afefbcddSeschrock 	char *type, *vname;
1265fa9e4066Sahrens 
1266fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
126788ecc943SGeorge Wilson 	if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
126888ecc943SGeorge Wilson 	    strcmp(type, VDEV_TYPE_HOLE) == 0)
1269fa9e4066Sahrens 		return;
1270fa9e4066Sahrens 
12713f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1272fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
1273fa9e4066Sahrens 
1274fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
1275990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1276fa9e4066Sahrens 
1277fa9e4066Sahrens 	if (vs->vs_aux != 0) {
12783d7072f8Seschrock 		(void) printf("  ");
1279fa9e4066Sahrens 
1280fa9e4066Sahrens 		switch (vs->vs_aux) {
1281fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
1282fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
1283fa9e4066Sahrens 			break;
1284fa9e4066Sahrens 
1285fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
1286fa9e4066Sahrens 			(void) printf(gettext("missing device"));
1287fa9e4066Sahrens 			break;
1288fa9e4066Sahrens 
1289fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
1290fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
1291fa9e4066Sahrens 			break;
1292fa9e4066Sahrens 
1293eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
1294eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
1295eaca9bbdSeschrock 			break;
1296eaca9bbdSeschrock 
1297*ad135b5dSChristopher Siden 		case VDEV_AUX_UNSUP_FEAT:
1298*ad135b5dSChristopher Siden 			(void) printf(gettext("unsupported feature(s)"));
1299*ad135b5dSChristopher Siden 			break;
1300*ad135b5dSChristopher Siden 
13013d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
13023d7072f8Seschrock 			(void) printf(gettext("too many errors"));
13033d7072f8Seschrock 			break;
13043d7072f8Seschrock 
1305fa9e4066Sahrens 		default:
1306fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
1307fa9e4066Sahrens 			break;
1308fa9e4066Sahrens 		}
1309fa9e4066Sahrens 	}
1310fa9e4066Sahrens 	(void) printf("\n");
1311fa9e4066Sahrens 
1312fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1313fa9e4066Sahrens 	    &child, &children) != 0)
1314fa9e4066Sahrens 		return;
1315fa9e4066Sahrens 
1316afefbcddSeschrock 	for (c = 0; c < children; c++) {
13178654d025Sperrin 		uint64_t is_log = B_FALSE;
13188654d025Sperrin 
13198654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
13208654d025Sperrin 		    &is_log);
1321e6ca193dSGeorge Wilson 		if (is_log)
13228654d025Sperrin 			continue;
13238654d025Sperrin 
132488ecc943SGeorge Wilson 		vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
1325e6ca193dSGeorge Wilson 		print_import_config(vname, child[c], namewidth, depth + 2);
1326afefbcddSeschrock 		free(vname);
1327afefbcddSeschrock 	}
132899653d4eSeschrock 
1329fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1330fa94a07fSbrendan 	    &child, &children) == 0) {
1331fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
1332fa94a07fSbrendan 		for (c = 0; c < children; c++) {
133388ecc943SGeorge Wilson 			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1334fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1335fa94a07fSbrendan 			free(vname);
1336fa94a07fSbrendan 		}
1337fa94a07fSbrendan 	}
133899653d4eSeschrock 
1339fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1340fa94a07fSbrendan 	    &child, &children) == 0) {
1341fa94a07fSbrendan 		(void) printf(gettext("\tspares\n"));
1342fa94a07fSbrendan 		for (c = 0; c < children; c++) {
134388ecc943SGeorge Wilson 			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1344fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1345fa94a07fSbrendan 			free(vname);
1346fa94a07fSbrendan 		}
134799653d4eSeschrock 	}
1348fa9e4066Sahrens }
1349fa9e4066Sahrens 
1350e6ca193dSGeorge Wilson /*
1351e6ca193dSGeorge Wilson  * Print log vdevs.
1352e6ca193dSGeorge Wilson  * Logs are recorded as top level vdevs in the main pool child array
1353e6ca193dSGeorge Wilson  * but with "is_log" set to 1. We use either print_status_config() or
1354e6ca193dSGeorge Wilson  * print_import_config() to print the top level logs then any log
1355e6ca193dSGeorge Wilson  * children (eg mirrored slogs) are printed recursively - which
1356e6ca193dSGeorge Wilson  * works because only the top level vdev is marked "is_log"
1357e6ca193dSGeorge Wilson  */
1358e6ca193dSGeorge Wilson static void
1359e6ca193dSGeorge Wilson print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
1360e6ca193dSGeorge Wilson {
1361e6ca193dSGeorge Wilson 	uint_t c, children;
1362e6ca193dSGeorge Wilson 	nvlist_t **child;
1363e6ca193dSGeorge Wilson 
1364e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1365e6ca193dSGeorge Wilson 	    &children) != 0)
1366e6ca193dSGeorge Wilson 		return;
1367e6ca193dSGeorge Wilson 
1368e6ca193dSGeorge Wilson 	(void) printf(gettext("\tlogs\n"));
1369e6ca193dSGeorge Wilson 
1370e6ca193dSGeorge Wilson 	for (c = 0; c < children; c++) {
1371e6ca193dSGeorge Wilson 		uint64_t is_log = B_FALSE;
1372e6ca193dSGeorge Wilson 		char *name;
1373e6ca193dSGeorge Wilson 
1374e6ca193dSGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1375e6ca193dSGeorge Wilson 		    &is_log);
1376e6ca193dSGeorge Wilson 		if (!is_log)
1377e6ca193dSGeorge Wilson 			continue;
137888ecc943SGeorge Wilson 		name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1379e6ca193dSGeorge Wilson 		if (verbose)
1380e6ca193dSGeorge Wilson 			print_status_config(zhp, name, child[c], namewidth,
1381e6ca193dSGeorge Wilson 			    2, B_FALSE);
1382e6ca193dSGeorge Wilson 		else
1383e6ca193dSGeorge Wilson 			print_import_config(name, child[c], namewidth, 2);
1384e6ca193dSGeorge Wilson 		free(name);
1385e6ca193dSGeorge Wilson 	}
1386e6ca193dSGeorge Wilson }
1387468c413aSTim Haley 
1388fa9e4066Sahrens /*
1389fa9e4066Sahrens  * Display the status for the given pool.
1390fa9e4066Sahrens  */
1391fa9e4066Sahrens static void
1392fa9e4066Sahrens show_import(nvlist_t *config)
1393fa9e4066Sahrens {
1394fa9e4066Sahrens 	uint64_t pool_state;
1395fa9e4066Sahrens 	vdev_stat_t *vs;
1396fa9e4066Sahrens 	char *name;
1397fa9e4066Sahrens 	uint64_t guid;
1398fa9e4066Sahrens 	char *msgid;
1399fa9e4066Sahrens 	nvlist_t *nvroot;
1400fa9e4066Sahrens 	int reason;
140146657f8dSmmusante 	const char *health;
1402fa9e4066Sahrens 	uint_t vsc;
1403fa9e4066Sahrens 	int namewidth;
14048704186eSDan McDonald 	char *comment;
1405fa9e4066Sahrens 
1406fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1407fa9e4066Sahrens 	    &name) == 0);
1408fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1409fa9e4066Sahrens 	    &guid) == 0);
1410fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1411fa9e4066Sahrens 	    &pool_state) == 0);
1412fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1413fa9e4066Sahrens 	    &nvroot) == 0);
1414fa9e4066Sahrens 
14153f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
1416fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1417990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1418fa9e4066Sahrens 
1419fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1420fa9e4066Sahrens 
14218704186eSDan McDonald 	(void) printf(gettext("   pool: %s\n"), name);
14228704186eSDan McDonald 	(void) printf(gettext("     id: %llu\n"), (u_longlong_t)guid);
14238704186eSDan McDonald 	(void) printf(gettext("  state: %s"), health);
14244c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
1425b1b8ab34Slling 		(void) printf(gettext(" (DESTROYED)"));
14264c58d714Sdarrenm 	(void) printf("\n");
1427fa9e4066Sahrens 
1428fa9e4066Sahrens 	switch (reason) {
1429fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1430fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1431fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
14328704186eSDan McDonald 		(void) printf(gettext(" status: One or more devices are "
14338704186eSDan McDonald 		    "missing from the system.\n"));
1434fa9e4066Sahrens 		break;
1435fa9e4066Sahrens 
1436fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1437fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
14388704186eSDan McDonald 		(void) printf(gettext(" status: One or more devices contains "
1439fa9e4066Sahrens 		    "corrupted data.\n"));
1440fa9e4066Sahrens 		break;
1441fa9e4066Sahrens 
1442fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
14438704186eSDan McDonald 		(void) printf(
14448704186eSDan McDonald 		    gettext(" status: The pool data is corrupted.\n"));
1445fa9e4066Sahrens 		break;
1446fa9e4066Sahrens 
1447441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
14488704186eSDan McDonald 		(void) printf(gettext(" status: One or more devices "
1449441d80aaSlling 		    "are offlined.\n"));
1450441d80aaSlling 		break;
1451441d80aaSlling 
1452ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
14538704186eSDan McDonald 		(void) printf(gettext(" status: The pool metadata is "
1454ea8dc4b6Seschrock 		    "corrupted.\n"));
1455ea8dc4b6Seschrock 		break;
1456ea8dc4b6Seschrock 
1457eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
14588704186eSDan McDonald 		(void) printf(gettext(" status: The pool is formatted using an "
1459eaca9bbdSeschrock 		    "older on-disk version.\n"));
1460eaca9bbdSeschrock 		break;
1461eaca9bbdSeschrock 
1462eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
14638704186eSDan McDonald 		(void) printf(gettext(" status: The pool is formatted using an "
1464eaca9bbdSeschrock 		    "incompatible version.\n"));
1465eaca9bbdSeschrock 		break;
1466b87f3af3Sperrin 
1467*ad135b5dSChristopher Siden 	case ZPOOL_STATUS_UNSUP_FEAT_READ:
1468*ad135b5dSChristopher Siden 		(void) printf(gettext("status: The pool uses the following "
1469*ad135b5dSChristopher Siden 		    "feature(s) not supported on this sytem:\n"));
1470*ad135b5dSChristopher Siden 		zpool_print_unsup_feat(config);
1471*ad135b5dSChristopher Siden 		break;
1472*ad135b5dSChristopher Siden 
1473*ad135b5dSChristopher Siden 	case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
1474*ad135b5dSChristopher Siden 		(void) printf(gettext("status: The pool can only be accessed "
1475*ad135b5dSChristopher Siden 		    "in read-only mode on this system. It\n\tcannot be "
1476*ad135b5dSChristopher Siden 		    "accessed in read-write mode because it uses the "
1477*ad135b5dSChristopher Siden 		    "following\n\tfeature(s) not supported on this system:\n"));
1478*ad135b5dSChristopher Siden 		zpool_print_unsup_feat(config);
1479*ad135b5dSChristopher Siden 		break;
1480*ad135b5dSChristopher Siden 
148195173954Sek 	case ZPOOL_STATUS_HOSTID_MISMATCH:
14828704186eSDan McDonald 		(void) printf(gettext(" status: The pool was last accessed by "
148395173954Sek 		    "another system.\n"));
148495173954Sek 		break;
1485b87f3af3Sperrin 
14863d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
14873d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
14888704186eSDan McDonald 		(void) printf(gettext(" status: One or more devices are "
14893d7072f8Seschrock 		    "faulted.\n"));
14903d7072f8Seschrock 		break;
14913d7072f8Seschrock 
1492b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
14938704186eSDan McDonald 		(void) printf(gettext(" status: An intent log record cannot be "
1494b87f3af3Sperrin 		    "read.\n"));
1495b87f3af3Sperrin 		break;
1496b87f3af3Sperrin 
14973f9d6ad7SLin Ling 	case ZPOOL_STATUS_RESILVERING:
14988704186eSDan McDonald 		(void) printf(gettext(" status: One or more devices were being "
14993f9d6ad7SLin Ling 		    "resilvered.\n"));
15003f9d6ad7SLin Ling 		break;
15013f9d6ad7SLin Ling 
1502fa9e4066Sahrens 	default:
1503fa9e4066Sahrens 		/*
1504fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1505fa9e4066Sahrens 		 */
1506fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1507fa9e4066Sahrens 	}
1508fa9e4066Sahrens 
1509fa9e4066Sahrens 	/*
1510fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1511fa9e4066Sahrens 	 */
151246657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1513eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
15148704186eSDan McDonald 			(void) printf(gettext(" action: The pool can be "
1515eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1516eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1517eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
151895173954Sek 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
15198704186eSDan McDonald 			(void) printf(gettext(" action: The pool can be "
152095173954Sek 			    "imported using its name or numeric "
152195173954Sek 			    "identifier and\n\tthe '-f' flag.\n"));
1522fa9e4066Sahrens 		else
15238704186eSDan McDonald 			(void) printf(gettext(" action: The pool can be "
1524eaca9bbdSeschrock 			    "imported using its name or numeric "
1525eaca9bbdSeschrock 			    "identifier.\n"));
152646657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
15278704186eSDan McDonald 		(void) printf(gettext(" action: The pool can be imported "
1528fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1529eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1530fa9e4066Sahrens 	} else {
1531eaca9bbdSeschrock 		switch (reason) {
1532eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
15338704186eSDan McDonald 			(void) printf(gettext(" action: The pool cannot be "
1534eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1535eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1536eaca9bbdSeschrock 			    "backup.\n"));
1537eaca9bbdSeschrock 			break;
1538*ad135b5dSChristopher Siden 		case ZPOOL_STATUS_UNSUP_FEAT_READ:
1539*ad135b5dSChristopher Siden 			(void) printf(gettext("action: The pool cannot be "
1540*ad135b5dSChristopher Siden 			    "imported. Access the pool on a system that "
1541*ad135b5dSChristopher Siden 			    "supports\n\tthe required feature(s), or recreate "
1542*ad135b5dSChristopher Siden 			    "the pool from backup.\n"));
1543*ad135b5dSChristopher Siden 			break;
1544*ad135b5dSChristopher Siden 		case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
1545*ad135b5dSChristopher Siden 			(void) printf(gettext("action: The pool cannot be "
1546*ad135b5dSChristopher Siden 			    "imported in read-write mode. Import the pool "
1547*ad135b5dSChristopher Siden 			    "with\n"
1548*ad135b5dSChristopher Siden 			    "\t\"-o readonly=on\", access the pool on a system "
1549*ad135b5dSChristopher Siden 			    "that supports the\n\trequired feature(s), or "
1550*ad135b5dSChristopher Siden 			    "recreate the pool from backup.\n"));
1551*ad135b5dSChristopher Siden 			break;
1552eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1553eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1554eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
15558704186eSDan McDonald 			(void) printf(gettext(" action: The pool cannot be "
1556fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1557fa9e4066Sahrens 			    "again.\n"));
1558eaca9bbdSeschrock 			break;
1559eaca9bbdSeschrock 		default:
15608704186eSDan McDonald 			(void) printf(gettext(" action: The pool cannot be "
1561fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1562eaca9bbdSeschrock 		}
1563eaca9bbdSeschrock 	}
1564eaca9bbdSeschrock 
15658704186eSDan McDonald 	/* Print the comment attached to the pool. */
15668704186eSDan McDonald 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
15678704186eSDan McDonald 		(void) printf(gettext("comment: %s\n"), comment);
15688704186eSDan McDonald 
156946657f8dSmmusante 	/*
157046657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
157146657f8dSmmusante 	 * is "corrupt data":
157246657f8dSmmusante 	 */
157346657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
157446657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
157546657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1576eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1577eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1578eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1579eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1580eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
158118ce54dfSek 			    "another system, but can be imported using\n\t"
1582eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1583fa9e4066Sahrens 	}
1584fa9e4066Sahrens 
1585fa9e4066Sahrens 	if (msgid != NULL)
1586654b400cSJoshua M. Clulow 		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
1587fa9e4066Sahrens 		    msgid);
1588fa9e4066Sahrens 
15898704186eSDan McDonald 	(void) printf(gettext(" config:\n\n"));
1590fa9e4066Sahrens 
1591c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1592fa9e4066Sahrens 	if (namewidth < 10)
1593fa9e4066Sahrens 		namewidth = 10;
15948654d025Sperrin 
1595e6ca193dSGeorge Wilson 	print_import_config(name, nvroot, namewidth, 0);
1596e6ca193dSGeorge Wilson 	if (num_logs(nvroot) > 0)
1597e6ca193dSGeorge Wilson 		print_logs(NULL, nvroot, namewidth, B_FALSE);
1598fa9e4066Sahrens 
1599fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
160046657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1601fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
160246657f8dSmmusante 		    "configuration cannot be determined.\n"));
1603fa9e4066Sahrens 	}
1604fa9e4066Sahrens }
1605fa9e4066Sahrens 
1606fa9e4066Sahrens /*
1607fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1608990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1609990b4856Slling  * within the pool.
1610fa9e4066Sahrens  */
1611fa9e4066Sahrens static int
1612fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
16134b964adaSGeorge Wilson     nvlist_t *props, int flags)
1614fa9e4066Sahrens {
1615fa9e4066Sahrens 	zpool_handle_t *zhp;
1616fa9e4066Sahrens 	char *name;
1617fa9e4066Sahrens 	uint64_t state;
1618eaca9bbdSeschrock 	uint64_t version;
1619fa9e4066Sahrens 
1620fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1621fa9e4066Sahrens 	    &name) == 0);
1622fa9e4066Sahrens 
1623fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1624fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1625eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1626eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1627*ad135b5dSChristopher Siden 	if (!SPA_VERSION_IS_SUPPORTED(version)) {
1628eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1629*ad135b5dSChristopher Siden 		    "is formatted using an unsupported ZFS version\n"), name);
1630eaca9bbdSeschrock 		return (1);
16314b964adaSGeorge Wilson 	} else if (state != POOL_STATE_EXPORTED &&
16324b964adaSGeorge Wilson 	    !(flags & ZFS_IMPORT_ANY_HOST)) {
163395173954Sek 		uint64_t hostid;
163495173954Sek 
163595173954Sek 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
163695173954Sek 		    &hostid) == 0) {
163795173954Sek 			if ((unsigned long)hostid != gethostid()) {
163895173954Sek 				char *hostname;
163995173954Sek 				uint64_t timestamp;
164095173954Sek 				time_t t;
164195173954Sek 
164295173954Sek 				verify(nvlist_lookup_string(config,
164395173954Sek 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
164495173954Sek 				verify(nvlist_lookup_uint64(config,
164595173954Sek 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
164695173954Sek 				t = timestamp;
164795173954Sek 				(void) fprintf(stderr, gettext("cannot import "
164895173954Sek 				    "'%s': pool may be in use from other "
164995173954Sek 				    "system, it was last accessed by %s "
165095173954Sek 				    "(hostid: 0x%lx) on %s"), name, hostname,
165195173954Sek 				    (unsigned long)hostid,
165295173954Sek 				    asctime(localtime(&t)));
165395173954Sek 				(void) fprintf(stderr, gettext("use '-f' to "
165495173954Sek 				    "import anyway\n"));
165595173954Sek 				return (1);
165695173954Sek 			}
165795173954Sek 		} else {
165895173954Sek 			(void) fprintf(stderr, gettext("cannot import '%s': "
165995173954Sek 			    "pool may be in use from other system\n"), name);
166095173954Sek 			(void) fprintf(stderr, gettext("use '-f' to import "
166195173954Sek 			    "anyway\n"));
166295173954Sek 			return (1);
166395173954Sek 		}
1664fa9e4066Sahrens 	}
1665fa9e4066Sahrens 
16664b964adaSGeorge Wilson 	if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
1667fa9e4066Sahrens 		return (1);
1668fa9e4066Sahrens 
1669fa9e4066Sahrens 	if (newname != NULL)
1670fa9e4066Sahrens 		name = (char *)newname;
1671fa9e4066Sahrens 
16724f0f5e5bSVictor Latushkin 	if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
16734f0f5e5bSVictor Latushkin 		return (1);
1674fa9e4066Sahrens 
1675379c004dSEric Schrock 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
1676f9af39baSGeorge Wilson 	    !(flags & ZFS_IMPORT_ONLY) &&
1677379c004dSEric Schrock 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1678fa9e4066Sahrens 		zpool_close(zhp);
1679fa9e4066Sahrens 		return (1);
1680fa9e4066Sahrens 	}
1681fa9e4066Sahrens 
1682fa9e4066Sahrens 	zpool_close(zhp);
1683468c413aSTim Haley 	return (0);
1684fa9e4066Sahrens }
1685fa9e4066Sahrens 
1686fa9e4066Sahrens /*
16874c58d714Sdarrenm  * zpool import [-d dir] [-D]
16882f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
16892f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
16902f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
1691468c413aSTim Haley  *              [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool]
16922f8aaab3Seschrock  *
16932f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
16942f8aaab3Seschrock  *		devices.
1695fa9e4066Sahrens  *
1696fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1697fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1698fa9e4066Sahrens  *
16994c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
17004c58d714Sdarrenm  *              specified destroyed pools.
17014c58d714Sdarrenm  *
1702fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1703fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1704fa9e4066Sahrens  *		is rebooted.
1705fa9e4066Sahrens  *
1706468c413aSTim Haley  *       -V	Import even in the presence of faulted vdevs.  This is an
1707c5904d13Seschrock  *       	intentionally undocumented option for testing purposes, and
1708c5904d13Seschrock  *       	treats the pool configuration as complete, leaving any bad
17094f0f5e5bSVictor Latushkin  *		vdevs in the FAULTED state. In other words, it does verbatim
17104f0f5e5bSVictor Latushkin  *		import.
1711c5904d13Seschrock  *
1712468c413aSTim Haley  *       -f	Force import, even if it appears that the pool is active.
1713468c413aSTim Haley  *
1714468c413aSTim Haley  *       -F     Attempt rewind if necessary.
1715468c413aSTim Haley  *
1716468c413aSTim Haley  *       -n     See if rewind would work, but don't actually rewind.
1717468c413aSTim Haley  *
1718f9af39baSGeorge Wilson  *       -N     Import the pool but don't mount datasets.
1719f9af39baSGeorge Wilson  *
1720f9af39baSGeorge Wilson  *       -T     Specify a starting txg to use for import. This option is
1721f9af39baSGeorge Wilson  *       	intentionally undocumented option for testing purposes.
1722f9af39baSGeorge Wilson  *
1723fa9e4066Sahrens  *       -a	Import all pools found.
1724fa9e4066Sahrens  *
1725990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1726ecd6cf80Smarks  *
1727fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1728fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1729fa9e4066Sahrens  */
1730fa9e4066Sahrens int
1731fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1732fa9e4066Sahrens {
1733fa9e4066Sahrens 	char **searchdirs = NULL;
1734fa9e4066Sahrens 	int nsearch = 0;
1735fa9e4066Sahrens 	int c;
1736d41c4376SMark J Musante 	int err = 0;
17372f8aaab3Seschrock 	nvlist_t *pools = NULL;
173899653d4eSeschrock 	boolean_t do_all = B_FALSE;
173999653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1740fa9e4066Sahrens 	char *mntopts = NULL;
1741fa9e4066Sahrens 	nvpair_t *elem;
1742fa9e4066Sahrens 	nvlist_t *config;
174324e697d4Sck 	uint64_t searchguid = 0;
174424e697d4Sck 	char *searchname = NULL;
1745990b4856Slling 	char *propval;
1746fa9e4066Sahrens 	nvlist_t *found_config;
1747468c413aSTim Haley 	nvlist_t *policy = NULL;
1748ecd6cf80Smarks 	nvlist_t *props = NULL;
174999653d4eSeschrock 	boolean_t first;
17504b964adaSGeorge Wilson 	int flags = ZFS_IMPORT_NORMAL;
1751468c413aSTim Haley 	uint32_t rewind_policy = ZPOOL_NO_REWIND;
1752468c413aSTim Haley 	boolean_t dryrun = B_FALSE;
1753468c413aSTim Haley 	boolean_t do_rewind = B_FALSE;
1754468c413aSTim Haley 	boolean_t xtreme_rewind = B_FALSE;
1755f9af39baSGeorge Wilson 	uint64_t pool_state, txg = -1ULL;
17562f8aaab3Seschrock 	char *cachefile = NULL;
1757d41c4376SMark J Musante 	importargs_t idata = { 0 };
1758f9af39baSGeorge Wilson 	char *endptr;
1759fa9e4066Sahrens 
1760fa9e4066Sahrens 	/* check options */
1761f9af39baSGeorge Wilson 	while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) {
1762fa9e4066Sahrens 		switch (c) {
1763fa9e4066Sahrens 		case 'a':
176499653d4eSeschrock 			do_all = B_TRUE;
1765fa9e4066Sahrens 			break;
17662f8aaab3Seschrock 		case 'c':
17672f8aaab3Seschrock 			cachefile = optarg;
17682f8aaab3Seschrock 			break;
1769fa9e4066Sahrens 		case 'd':
1770fa9e4066Sahrens 			if (searchdirs == NULL) {
1771fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1772fa9e4066Sahrens 			} else {
1773fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1774fa9e4066Sahrens 				    sizeof (char *));
1775fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1776fa9e4066Sahrens 				    sizeof (char *));
1777fa9e4066Sahrens 				free(searchdirs);
1778fa9e4066Sahrens 				searchdirs = tmp;
1779fa9e4066Sahrens 			}
1780fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1781fa9e4066Sahrens 			break;
17824c58d714Sdarrenm 		case 'D':
178399653d4eSeschrock 			do_destroyed = B_TRUE;
17844c58d714Sdarrenm 			break;
1785fa9e4066Sahrens 		case 'f':
17864b964adaSGeorge Wilson 			flags |= ZFS_IMPORT_ANY_HOST;
1787fa9e4066Sahrens 			break;
1788c5904d13Seschrock 		case 'F':
1789468c413aSTim Haley 			do_rewind = B_TRUE;
1790468c413aSTim Haley 			break;
17914b964adaSGeorge Wilson 		case 'm':
17924b964adaSGeorge Wilson 			flags |= ZFS_IMPORT_MISSING_LOG;
17934b964adaSGeorge Wilson 			break;
1794468c413aSTim Haley 		case 'n':
1795468c413aSTim Haley 			dryrun = B_TRUE;
1796c5904d13Seschrock 			break;
1797f9af39baSGeorge Wilson 		case 'N':
1798f9af39baSGeorge Wilson 			flags |= ZFS_IMPORT_ONLY;
1799f9af39baSGeorge Wilson 			break;
1800fa9e4066Sahrens 		case 'o':
1801990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1802990b4856Slling 				*propval = '\0';
1803990b4856Slling 				propval++;
18040a48a24eStimh 				if (add_prop_list(optarg, propval,
18050a48a24eStimh 				    &props, B_TRUE))
1806990b4856Slling 					goto error;
1807990b4856Slling 			} else {
1808990b4856Slling 				mntopts = optarg;
1809990b4856Slling 			}
1810fa9e4066Sahrens 			break;
1811fa9e4066Sahrens 		case 'R':
1812990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
18130a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1814990b4856Slling 				goto error;
18152f8aaab3Seschrock 			if (nvlist_lookup_string(props,
18162f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
18172f8aaab3Seschrock 			    &propval) == 0)
18182f8aaab3Seschrock 				break;
1819990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
18200a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1821990b4856Slling 				goto error;
1822fa9e4066Sahrens 			break;
1823f9af39baSGeorge Wilson 		case 'T':
1824f9af39baSGeorge Wilson 			errno = 0;
1825f9af39baSGeorge Wilson 			txg = strtoull(optarg, &endptr, 10);
1826f9af39baSGeorge Wilson 			if (errno != 0 || *endptr != '\0') {
1827f9af39baSGeorge Wilson 				(void) fprintf(stderr,
1828f9af39baSGeorge Wilson 				    gettext("invalid txg value\n"));
1829f9af39baSGeorge Wilson 				usage(B_FALSE);
1830f9af39baSGeorge Wilson 			}
1831f9af39baSGeorge Wilson 			rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
1832f9af39baSGeorge Wilson 			break;
1833468c413aSTim Haley 		case 'V':
18344b964adaSGeorge Wilson 			flags |= ZFS_IMPORT_VERBATIM;
1835468c413aSTim Haley 			break;
1836468c413aSTim Haley 		case 'X':
1837468c413aSTim Haley 			xtreme_rewind = B_TRUE;
1838468c413aSTim Haley 			break;
1839fa9e4066Sahrens 		case ':':
1840fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1841fa9e4066Sahrens 			    "'%c' option\n"), optopt);
184299653d4eSeschrock 			usage(B_FALSE);
1843fa9e4066Sahrens 			break;
1844fa9e4066Sahrens 		case '?':
1845fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1846fa9e4066Sahrens 			    optopt);
184799653d4eSeschrock 			usage(B_FALSE);
1848fa9e4066Sahrens 		}
1849fa9e4066Sahrens 	}
1850fa9e4066Sahrens 
1851fa9e4066Sahrens 	argc -= optind;
1852fa9e4066Sahrens 	argv += optind;
1853fa9e4066Sahrens 
18542f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
18552f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
18562f8aaab3Seschrock 		usage(B_FALSE);
18572f8aaab3Seschrock 	}
18582f8aaab3Seschrock 
1859468c413aSTim Haley 	if ((dryrun || xtreme_rewind) && !do_rewind) {
1860468c413aSTim Haley 		(void) fprintf(stderr,
1861468c413aSTim Haley 		    gettext("-n or -X only meaningful with -F\n"));
1862468c413aSTim Haley 		usage(B_FALSE);
1863468c413aSTim Haley 	}
1864468c413aSTim Haley 	if (dryrun)
1865468c413aSTim Haley 		rewind_policy = ZPOOL_TRY_REWIND;
1866468c413aSTim Haley 	else if (do_rewind)
1867468c413aSTim Haley 		rewind_policy = ZPOOL_DO_REWIND;
1868468c413aSTim Haley 	if (xtreme_rewind)
1869468c413aSTim Haley 		rewind_policy |= ZPOOL_EXTREME_REWIND;
1870468c413aSTim Haley 
1871468c413aSTim Haley 	/* In the future, we can capture further policy and include it here */
1872468c413aSTim Haley 	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
1873f9af39baSGeorge Wilson 	    nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 ||
1874468c413aSTim Haley 	    nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
1875468c413aSTim Haley 		goto error;
1876468c413aSTim Haley 
1877fa9e4066Sahrens 	if (searchdirs == NULL) {
1878fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1879fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1880fa9e4066Sahrens 		nsearch = 1;
1881fa9e4066Sahrens 	}
1882fa9e4066Sahrens 
1883fa9e4066Sahrens 	/* check argument count */
1884fa9e4066Sahrens 	if (do_all) {
1885fa9e4066Sahrens 		if (argc != 0) {
1886fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
188799653d4eSeschrock 			usage(B_FALSE);
1888fa9e4066Sahrens 		}
1889fa9e4066Sahrens 	} else {
1890fa9e4066Sahrens 		if (argc > 2) {
1891fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
189299653d4eSeschrock 			usage(B_FALSE);
1893fa9e4066Sahrens 		}
1894fa9e4066Sahrens 
1895fa9e4066Sahrens 		/*
1896fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1897fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1898fa9e4066Sahrens 		 * silently fail.
1899fa9e4066Sahrens 		 */
1900fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1901fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1902fa9e4066Sahrens 			    "discover pools: permission denied\n"));
190399653d4eSeschrock 			free(searchdirs);
1904468c413aSTim Haley 			nvlist_free(policy);
1905fa9e4066Sahrens 			return (1);
1906fa9e4066Sahrens 		}
1907fa9e4066Sahrens 	}
1908fa9e4066Sahrens 
1909fa9e4066Sahrens 	/*
1910fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1911fa9e4066Sahrens 	 *
1912fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1913fa9e4066Sahrens 	 *		each one.
1914fa9e4066Sahrens 	 *
1915fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1916fa9e4066Sahrens 	 *
1917fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1918fa9e4066Sahrens 	 *		name and import that one.
19194c58d714Sdarrenm 	 *
19204c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1921fa9e4066Sahrens 	 */
1922fa9e4066Sahrens 	if (argc != 0) {
1923fa9e4066Sahrens 		char *endptr;
1924fa9e4066Sahrens 
1925fa9e4066Sahrens 		errno = 0;
1926fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1927fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1928fa9e4066Sahrens 			searchname = argv[0];
1929fa9e4066Sahrens 		found_config = NULL;
1930fa9e4066Sahrens 
193124e697d4Sck 		/*
1932d41c4376SMark J Musante 		 * User specified a name or guid.  Ensure it's unique.
193324e697d4Sck 		 */
1934d41c4376SMark J Musante 		idata.unique = B_TRUE;
193524e697d4Sck 	}
193624e697d4Sck 
1937d41c4376SMark J Musante 
1938d41c4376SMark J Musante 	idata.path = searchdirs;
1939d41c4376SMark J Musante 	idata.paths = nsearch;
1940d41c4376SMark J Musante 	idata.poolname = searchname;
1941d41c4376SMark J Musante 	idata.guid = searchguid;
1942d41c4376SMark J Musante 	idata.cachefile = cachefile;
1943d41c4376SMark J Musante 
1944d41c4376SMark J Musante 	pools = zpool_search_import(g_zfs, &idata);
1945d41c4376SMark J Musante 
1946d41c4376SMark J Musante 	if (pools != NULL && idata.exists &&
1947d41c4376SMark J Musante 	    (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
1948d41c4376SMark J Musante 		(void) fprintf(stderr, gettext("cannot import '%s': "
1949d41c4376SMark J Musante 		    "a pool with that name already exists\n"),
1950d41c4376SMark J Musante 		    argv[0]);
1951d41c4376SMark J Musante 		(void) fprintf(stderr, gettext("use the form '%s "
1952d41c4376SMark J Musante 		    "<pool | id> <newpool>' to give it a new name\n"),
1953d41c4376SMark J Musante 		    "zpool import");
1954d41c4376SMark J Musante 		err = 1;
1955d41c4376SMark J Musante 	} else if (pools == NULL && idata.exists) {
1956d41c4376SMark J Musante 		(void) fprintf(stderr, gettext("cannot import '%s': "
1957d41c4376SMark J Musante 		    "a pool with that name is already created/imported,\n"),
1958d41c4376SMark J Musante 		    argv[0]);
1959d41c4376SMark J Musante 		(void) fprintf(stderr, gettext("and no additional pools "
1960d41c4376SMark J Musante 		    "with that name were found\n"));
1961d41c4376SMark J Musante 		err = 1;
1962d41c4376SMark J Musante 	} else if (pools == NULL) {
196324e697d4Sck 		if (argc != 0) {
196424e697d4Sck 			(void) fprintf(stderr, gettext("cannot import '%s': "
196524e697d4Sck 			    "no such pool available\n"), argv[0]);
196624e697d4Sck 		}
1967d41c4376SMark J Musante 		err = 1;
1968d41c4376SMark J Musante 	}
1969d41c4376SMark J Musante 
1970d41c4376SMark J Musante 	if (err == 1) {
197124e697d4Sck 		free(searchdirs);
1972468c413aSTim Haley 		nvlist_free(policy);
197324e697d4Sck 		return (1);
197424e697d4Sck 	}
197524e697d4Sck 
197624e697d4Sck 	/*
197724e697d4Sck 	 * At this point we have a list of import candidate configs. Even if
197824e697d4Sck 	 * we were searching by pool name or guid, we still need to
197924e697d4Sck 	 * post-process the list to deal with pool state and possible
198024e697d4Sck 	 * duplicate names.
198124e697d4Sck 	 */
1982fa9e4066Sahrens 	err = 0;
1983fa9e4066Sahrens 	elem = NULL;
198499653d4eSeschrock 	first = B_TRUE;
1985fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1986fa9e4066Sahrens 
1987fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1988fa9e4066Sahrens 
19894c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
19904c58d714Sdarrenm 		    &pool_state) == 0);
19914c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
19924c58d714Sdarrenm 			continue;
19934c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
19944c58d714Sdarrenm 			continue;
19954c58d714Sdarrenm 
1996468c413aSTim Haley 		verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY,
1997468c413aSTim Haley 		    policy) == 0);
1998468c413aSTim Haley 
1999fa9e4066Sahrens 		if (argc == 0) {
2000fa9e4066Sahrens 			if (first)
200199653d4eSeschrock 				first = B_FALSE;
20023bb79becSeschrock 			else if (!do_all)
2003fa9e4066Sahrens 				(void) printf("\n");
2004fa9e4066Sahrens 
2005468c413aSTim Haley 			if (do_all) {
2006fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
20074b964adaSGeorge Wilson 				    props, flags);
2008468c413aSTim Haley 			} else {
2009fa9e4066Sahrens 				show_import(config);
2010468c413aSTim Haley 			}
2011fa9e4066Sahrens 		} else if (searchname != NULL) {
2012fa9e4066Sahrens 			char *name;
2013fa9e4066Sahrens 
2014fa9e4066Sahrens 			/*
2015fa9e4066Sahrens 			 * We are searching for a pool based on name.
2016fa9e4066Sahrens 			 */
2017fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
2018fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
2019fa9e4066Sahrens 
2020fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
2021fa9e4066Sahrens 				if (found_config != NULL) {
2022fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
2023fa9e4066Sahrens 					    "cannot import '%s': more than "
2024fa9e4066Sahrens 					    "one matching pool\n"), searchname);
2025fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
2026fa9e4066Sahrens 					    "import by numeric ID instead\n"));
202799653d4eSeschrock 					err = B_TRUE;
2028fa9e4066Sahrens 				}
2029fa9e4066Sahrens 				found_config = config;
2030fa9e4066Sahrens 			}
2031fa9e4066Sahrens 		} else {
2032fa9e4066Sahrens 			uint64_t guid;
2033fa9e4066Sahrens 
2034fa9e4066Sahrens 			/*
2035fa9e4066Sahrens 			 * Search for a pool by guid.
2036fa9e4066Sahrens 			 */
2037fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
2038fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
2039fa9e4066Sahrens 
2040fa9e4066Sahrens 			if (guid == searchguid)
2041fa9e4066Sahrens 				found_config = config;
2042fa9e4066Sahrens 		}
2043fa9e4066Sahrens 	}
2044fa9e4066Sahrens 
2045fa9e4066Sahrens 	/*
2046fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
2047fa9e4066Sahrens 	 * pool, and then do the import.
2048fa9e4066Sahrens 	 */
2049fa9e4066Sahrens 	if (argc != 0 && err == 0) {
2050fa9e4066Sahrens 		if (found_config == NULL) {
2051fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
2052fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
205399653d4eSeschrock 			err = B_TRUE;
2054fa9e4066Sahrens 		} else {
2055fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
20564b964adaSGeorge Wilson 			    argv[1], mntopts, props, flags);
2057fa9e4066Sahrens 		}
2058fa9e4066Sahrens 	}
2059fa9e4066Sahrens 
2060fa9e4066Sahrens 	/*
2061fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
2062fa9e4066Sahrens 	 * found.
2063fa9e4066Sahrens 	 */
2064fa9e4066Sahrens 	if (argc == 0 && first)
2065fa9e4066Sahrens 		(void) fprintf(stderr,
2066fa9e4066Sahrens 		    gettext("no pools available to import\n"));
2067fa9e4066Sahrens 
2068ecd6cf80Smarks error:
20692f8aaab3Seschrock 	nvlist_free(props);
2070fa9e4066Sahrens 	nvlist_free(pools);
2071468c413aSTim Haley 	nvlist_free(policy);
207299653d4eSeschrock 	free(searchdirs);
2073fa9e4066Sahrens 
2074fa9e4066Sahrens 	return (err ? 1 : 0);
2075fa9e4066Sahrens }
2076fa9e4066Sahrens 
2077fa9e4066Sahrens typedef struct iostat_cbdata {
20784263d13fSGeorge Wilson 	boolean_t cb_verbose;
2079fa9e4066Sahrens 	int cb_namewidth;
20804263d13fSGeorge Wilson 	int cb_iteration;
20814263d13fSGeorge Wilson 	zpool_list_t *cb_list;
2082fa9e4066Sahrens } iostat_cbdata_t;
2083fa9e4066Sahrens 
2084fa9e4066Sahrens static void
2085fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
2086fa9e4066Sahrens {
2087fa9e4066Sahrens 	int i = 0;
2088fa9e4066Sahrens 
2089fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
2090fa9e4066Sahrens 		(void) printf("-");
2091fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
2092fa9e4066Sahrens }
2093fa9e4066Sahrens 
2094fa9e4066Sahrens static void
2095fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
2096fa9e4066Sahrens {
2097fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
2098fa9e4066Sahrens 	    cb->cb_namewidth, "");
2099485bbbf5SGeorge Wilson 	(void) printf("%-*s  alloc   free   read  write   read  write\n",
2100fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
2101fa9e4066Sahrens 	print_iostat_separator(cb);
2102fa9e4066Sahrens }
2103fa9e4066Sahrens 
2104fa9e4066Sahrens /*
2105fa9e4066Sahrens  * Display a single statistic.
2106fa9e4066Sahrens  */
2107990b4856Slling static void
2108fa9e4066Sahrens print_one_stat(uint64_t value)
2109fa9e4066Sahrens {
2110fa9e4066Sahrens 	char buf[64];
2111fa9e4066Sahrens 
2112fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
2113fa9e4066Sahrens 	(void) printf("  %5s", buf);
2114fa9e4066Sahrens }
2115fa9e4066Sahrens 
2116fa9e4066Sahrens /*
2117fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
2118fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
2119fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
2120fa9e4066Sahrens  */
2121fa9e4066Sahrens void
2122c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
2123c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
2124fa9e4066Sahrens {
2125fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
2126fa9e4066Sahrens 	uint_t c, children;
2127fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
2128fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
2129fa9e4066Sahrens 	uint64_t tdelta;
2130fa9e4066Sahrens 	double scale;
2131afefbcddSeschrock 	char *vname;
2132fa9e4066Sahrens 
2133fa9e4066Sahrens 	if (oldnv != NULL) {
21343f9d6ad7SLin Ling 		verify(nvlist_lookup_uint64_array(oldnv,
21353f9d6ad7SLin Ling 		    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
2136fa9e4066Sahrens 	} else {
2137fa9e4066Sahrens 		oldvs = &zerovs;
2138fa9e4066Sahrens 	}
2139fa9e4066Sahrens 
21403f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
2141fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
2142fa9e4066Sahrens 
2143fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
2144fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
2145fa9e4066Sahrens 	else
2146fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
2147fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
2148fa9e4066Sahrens 
2149fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
2150fa9e4066Sahrens 
2151fa9e4066Sahrens 	if (tdelta == 0)
2152fa9e4066Sahrens 		scale = 1.0;
2153fa9e4066Sahrens 	else
2154fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
2155fa9e4066Sahrens 
2156fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
2157fa9e4066Sahrens 	if (newvs->vs_space == 0) {
2158fa9e4066Sahrens 		(void) printf("      -      -");
2159fa9e4066Sahrens 	} else {
2160fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
2161fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
2162fa9e4066Sahrens 	}
2163fa9e4066Sahrens 
2164fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
2165fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
2166fa9e4066Sahrens 
2167fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
2168fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
2169fa9e4066Sahrens 
2170fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
2171fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
2172fa9e4066Sahrens 
2173fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
2174fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
2175fa9e4066Sahrens 
2176fa9e4066Sahrens 	(void) printf("\n");
2177fa9e4066Sahrens 
2178fa9e4066Sahrens 	if (!cb->cb_verbose)
2179fa9e4066Sahrens 		return;
2180fa9e4066Sahrens 
2181fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
2182fa9e4066Sahrens 	    &newchild, &children) != 0)
2183fa9e4066Sahrens 		return;
2184fa9e4066Sahrens 
2185fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
2186fa9e4066Sahrens 	    &oldchild, &c) != 0)
2187fa9e4066Sahrens 		return;
2188fa9e4066Sahrens 
2189afefbcddSeschrock 	for (c = 0; c < children; c++) {
21909d439f90SMike Harsch 		uint64_t ishole = B_FALSE, islog = B_FALSE;
21913f9d6ad7SLin Ling 
21929d439f90SMike Harsch 		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
21939d439f90SMike Harsch 		    &ishole);
21949d439f90SMike Harsch 
21959d439f90SMike Harsch 		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
21969d439f90SMike Harsch 		    &islog);
21979d439f90SMike Harsch 
21989d439f90SMike Harsch 		if (ishole || islog)
21993f9d6ad7SLin Ling 			continue;
22003f9d6ad7SLin Ling 
220188ecc943SGeorge Wilson 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
2202c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2203afefbcddSeschrock 		    newchild[c], cb, depth + 2);
2204afefbcddSeschrock 		free(vname);
2205afefbcddSeschrock 	}
2206fa94a07fSbrendan 
22079d439f90SMike Harsch 	/*
22089d439f90SMike Harsch 	 * Log device section
22099d439f90SMike Harsch 	 */
22109d439f90SMike Harsch 
22119d439f90SMike Harsch 	if (num_logs(newnv) > 0) {
22129d439f90SMike Harsch 		(void) printf("%-*s      -      -      -      -      -      "
22139d439f90SMike Harsch 		    "-\n", cb->cb_namewidth, "logs");
22149d439f90SMike Harsch 
22159d439f90SMike Harsch 		for (c = 0; c < children; c++) {
22169d439f90SMike Harsch 			uint64_t islog = B_FALSE;
22179d439f90SMike Harsch 			(void) nvlist_lookup_uint64(newchild[c],
22189d439f90SMike Harsch 			    ZPOOL_CONFIG_IS_LOG, &islog);
22199d439f90SMike Harsch 
22209d439f90SMike Harsch 			if (islog) {
22219d439f90SMike Harsch 				vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
22229d439f90SMike Harsch 				    B_FALSE);
22239d439f90SMike Harsch 				print_vdev_stats(zhp, vname, oldnv ?
22249d439f90SMike Harsch 				    oldchild[c] : NULL, newchild[c],
22259d439f90SMike Harsch 				    cb, depth + 2);
22269d439f90SMike Harsch 				free(vname);
22279d439f90SMike Harsch 			}
22289d439f90SMike Harsch 		}
22299d439f90SMike Harsch 
22309d439f90SMike Harsch 	}
22319d439f90SMike Harsch 
2232fa94a07fSbrendan 	/*
2233fa94a07fSbrendan 	 * Include level 2 ARC devices in iostat output
2234fa94a07fSbrendan 	 */
2235fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
2236fa94a07fSbrendan 	    &newchild, &children) != 0)
2237fa94a07fSbrendan 		return;
2238fa94a07fSbrendan 
2239fa94a07fSbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
2240fa94a07fSbrendan 	    &oldchild, &c) != 0)
2241fa94a07fSbrendan 		return;
2242fa94a07fSbrendan 
2243fa94a07fSbrendan 	if (children > 0) {
2244fa94a07fSbrendan 		(void) printf("%-*s      -      -      -      -      -      "
2245fa94a07fSbrendan 		    "-\n", cb->cb_namewidth, "cache");
2246fa94a07fSbrendan 		for (c = 0; c < children; c++) {
224788ecc943SGeorge Wilson 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
224888ecc943SGeorge Wilson 			    B_FALSE);
2249fa94a07fSbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2250fa94a07fSbrendan 			    newchild[c], cb, depth + 2);
2251fa94a07fSbrendan 			free(vname);
2252fa94a07fSbrendan 		}
2253fa94a07fSbrendan 	}
2254fa9e4066Sahrens }
2255fa9e4066Sahrens 
2256088e9d47Seschrock static int
2257088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
2258088e9d47Seschrock {
2259088e9d47Seschrock 	iostat_cbdata_t *cb = data;
226094de1d4cSeschrock 	boolean_t missing;
2261088e9d47Seschrock 
2262088e9d47Seschrock 	/*
2263088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
2264088e9d47Seschrock 	 */
226594de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
226694de1d4cSeschrock 		return (-1);
226794de1d4cSeschrock 
226894de1d4cSeschrock 	if (missing)
2269088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
2270088e9d47Seschrock 
2271088e9d47Seschrock 	return (0);
2272088e9d47Seschrock }
2273088e9d47Seschrock 
2274fa9e4066Sahrens /*
2275fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
2276fa9e4066Sahrens  */
2277fa9e4066Sahrens int
2278fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
2279fa9e4066Sahrens {
2280fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
2281fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
2282fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
2283fa9e4066Sahrens 
2284088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
2285fa9e4066Sahrens 
2286088e9d47Seschrock 	if (cb->cb_iteration == 1)
2287fa9e4066Sahrens 		oldconfig = NULL;
2288fa9e4066Sahrens 
2289fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
2290fa9e4066Sahrens 	    &newnvroot) == 0);
2291fa9e4066Sahrens 
2292088e9d47Seschrock 	if (oldconfig == NULL)
2293fa9e4066Sahrens 		oldnvroot = NULL;
2294088e9d47Seschrock 	else
2295088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
2296088e9d47Seschrock 		    &oldnvroot) == 0);
2297fa9e4066Sahrens 
2298fa9e4066Sahrens 	/*
2299fa9e4066Sahrens 	 * Print out the statistics for the pool.
2300fa9e4066Sahrens 	 */
2301c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
2302fa9e4066Sahrens 
2303fa9e4066Sahrens 	if (cb->cb_verbose)
2304fa9e4066Sahrens 		print_iostat_separator(cb);
2305fa9e4066Sahrens 
2306fa9e4066Sahrens 	return (0);
2307fa9e4066Sahrens }
2308fa9e4066Sahrens 
2309fa9e4066Sahrens int
2310fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
2311fa9e4066Sahrens {
2312fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
2313fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2314fa9e4066Sahrens 
2315088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
2316fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2317fa9e4066Sahrens 		    &nvroot) == 0);
2318fa9e4066Sahrens 		if (!cb->cb_verbose)
2319fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
2320fa9e4066Sahrens 		else
2321e1d5e507SFrederik Wessels 			cb->cb_namewidth = max_width(zhp, nvroot, 0,
2322e1d5e507SFrederik Wessels 			    cb->cb_namewidth);
2323fa9e4066Sahrens 	}
2324fa9e4066Sahrens 
2325fa9e4066Sahrens 	/*
2326fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
2327fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
2328fa9e4066Sahrens 	 */
2329fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
2330fa9e4066Sahrens 		cb->cb_namewidth = 10;
2331fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
2332fa9e4066Sahrens 		cb->cb_namewidth = 38;
2333fa9e4066Sahrens 
2334fa9e4066Sahrens 	return (0);
2335fa9e4066Sahrens }
2336fa9e4066Sahrens 
2337fa9e4066Sahrens /*
23383f9d6ad7SLin Ling  * Parse the input string, get the 'interval' and 'count' value if there is one.
2339fa9e4066Sahrens  */
23403f9d6ad7SLin Ling static void
23413f9d6ad7SLin Ling get_interval_count(int *argcp, char **argv, unsigned long *iv,
23423f9d6ad7SLin Ling     unsigned long *cnt)
2343fa9e4066Sahrens {
2344fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
23453f9d6ad7SLin Ling 	int argc = *argcp, errno;
2346fa9e4066Sahrens 
2347fa9e4066Sahrens 	/*
2348fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
2349fa9e4066Sahrens 	 */
2350fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2351fa9e4066Sahrens 		char *end;
2352fa9e4066Sahrens 
2353fa9e4066Sahrens 		errno = 0;
2354fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
2355fa9e4066Sahrens 
2356fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
2357fa9e4066Sahrens 			if (interval == 0) {
2358fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
2359fa9e4066Sahrens 				    "cannot be zero\n"));
236099653d4eSeschrock 				usage(B_FALSE);
2361fa9e4066Sahrens 			}
2362fa9e4066Sahrens 			/*
2363fa9e4066Sahrens 			 * Ignore the last parameter
2364fa9e4066Sahrens 			 */
2365fa9e4066Sahrens 			argc--;
2366fa9e4066Sahrens 		} else {
2367fa9e4066Sahrens 			/*
2368fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
2369fa9e4066Sahrens 			 * user will get a more informative error message later
2370fa9e4066Sahrens 			 * on.
2371fa9e4066Sahrens 			 */
2372fa9e4066Sahrens 			interval = 0;
2373fa9e4066Sahrens 		}
2374fa9e4066Sahrens 	}
2375fa9e4066Sahrens 
2376fa9e4066Sahrens 	/*
2377fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
23783f9d6ad7SLin Ling 	 * and an interval.
2379fa9e4066Sahrens 	 */
2380fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2381fa9e4066Sahrens 		char *end;
2382fa9e4066Sahrens 
2383fa9e4066Sahrens 		errno = 0;
2384fa9e4066Sahrens 		count = interval;
2385fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
2386fa9e4066Sahrens 
2387fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
2388fa9e4066Sahrens 			if (interval == 0) {
2389fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
2390fa9e4066Sahrens 				    "cannot be zero\n"));
239199653d4eSeschrock 				usage(B_FALSE);
2392fa9e4066Sahrens 			}
2393fa9e4066Sahrens 
2394fa9e4066Sahrens 			/*
2395fa9e4066Sahrens 			 * Ignore the last parameter
2396fa9e4066Sahrens 			 */
2397fa9e4066Sahrens 			argc--;
2398fa9e4066Sahrens 		} else {
2399fa9e4066Sahrens 			interval = 0;
2400fa9e4066Sahrens 		}
2401fa9e4066Sahrens 	}
2402fa9e4066Sahrens 
24033f9d6ad7SLin Ling 	*iv = interval;
24043f9d6ad7SLin Ling 	*cnt = count;
24053f9d6ad7SLin Ling 	*argcp = argc;
24063f9d6ad7SLin Ling }
24073f9d6ad7SLin Ling 
24083f9d6ad7SLin Ling static void
24093f9d6ad7SLin Ling get_timestamp_arg(char c)
24103f9d6ad7SLin Ling {
24113f9d6ad7SLin Ling 	if (c == 'u')
24123f9d6ad7SLin Ling 		timestamp_fmt = UDATE;
24133f9d6ad7SLin Ling 	else if (c == 'd')
24143f9d6ad7SLin Ling 		timestamp_fmt = DDATE;
24153f9d6ad7SLin Ling 	else
24163f9d6ad7SLin Ling 		usage(B_FALSE);
24173f9d6ad7SLin Ling }
24183f9d6ad7SLin Ling 
24193f9d6ad7SLin Ling /*
24203f9d6ad7SLin Ling  * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]]
24213f9d6ad7SLin Ling  *
24223f9d6ad7SLin Ling  *	-v	Display statistics for individual vdevs
24233f9d6ad7SLin Ling  *	-T	Display a timestamp in date(1) or Unix format
24243f9d6ad7SLin Ling  *
24253f9d6ad7SLin Ling  * This command can be tricky because we want to be able to deal with pool
24263f9d6ad7SLin Ling  * creation/destruction as well as vdev configuration changes.  The bulk of this
24273f9d6ad7SLin Ling  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
24283f9d6ad7SLin Ling  * on pool_list_update() to detect the addition of new pools.  Configuration
24293f9d6ad7SLin Ling  * changes are all handled within libzfs.
24303f9d6ad7SLin Ling  */
24313f9d6ad7SLin Ling int
24323f9d6ad7SLin Ling zpool_do_iostat(int argc, char **argv)
24333f9d6ad7SLin Ling {
24343f9d6ad7SLin Ling 	int c;
24353f9d6ad7SLin Ling 	int ret;
24363f9d6ad7SLin Ling 	int npools;
24373f9d6ad7SLin Ling 	unsigned long interval = 0, count = 0;
24383f9d6ad7SLin Ling 	zpool_list_t *list;
24393f9d6ad7SLin Ling 	boolean_t verbose = B_FALSE;
24403f9d6ad7SLin Ling 	iostat_cbdata_t cb;
24413f9d6ad7SLin Ling 
24423f9d6ad7SLin Ling 	/* check options */
24433f9d6ad7SLin Ling 	while ((c = getopt(argc, argv, "T:v")) != -1) {
24443f9d6ad7SLin Ling 		switch (c) {
24453f9d6ad7SLin Ling 		case 'T':
24463f9d6ad7SLin Ling 			get_timestamp_arg(*optarg);
24473f9d6ad7SLin Ling 			break;
24483f9d6ad7SLin Ling 		case 'v':
24493f9d6ad7SLin Ling 			verbose = B_TRUE;
24503f9d6ad7SLin Ling 			break;
24513f9d6ad7SLin Ling 		case '?':
24523f9d6ad7SLin Ling 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
24533f9d6ad7SLin Ling 			    optopt);
24543f9d6ad7SLin Ling 			usage(B_FALSE);
24553f9d6ad7SLin Ling 		}
24563f9d6ad7SLin Ling 	}
24573f9d6ad7SLin Ling 
24583f9d6ad7SLin Ling 	argc -= optind;
24593f9d6ad7SLin Ling 	argv += optind;
24603f9d6ad7SLin Ling 
24613f9d6ad7SLin Ling 	get_interval_count(&argc, argv, &interval, &count);
24623f9d6ad7SLin Ling 
2463fa9e4066Sahrens 	/*
2464fa9e4066Sahrens 	 * Construct the list of all interesting pools.
2465fa9e4066Sahrens 	 */
2466fa9e4066Sahrens 	ret = 0;
2467b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
2468fa9e4066Sahrens 		return (1);
2469fa9e4066Sahrens 
247099653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
247199653d4eSeschrock 		pool_list_free(list);
2472fa9e4066Sahrens 		return (1);
247399653d4eSeschrock 	}
2474fa9e4066Sahrens 
2475fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
247699653d4eSeschrock 		pool_list_free(list);
2477fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
2478fa9e4066Sahrens 		return (1);
2479fa9e4066Sahrens 	}
2480fa9e4066Sahrens 
2481fa9e4066Sahrens 	/*
2482fa9e4066Sahrens 	 * Enter the main iostat loop.
2483fa9e4066Sahrens 	 */
2484fa9e4066Sahrens 	cb.cb_list = list;
2485fa9e4066Sahrens 	cb.cb_verbose = verbose;
2486fa9e4066Sahrens 	cb.cb_iteration = 0;
2487fa9e4066Sahrens 	cb.cb_namewidth = 0;
2488fa9e4066Sahrens 
2489fa9e4066Sahrens 	for (;;) {
2490fa9e4066Sahrens 		pool_list_update(list);
2491fa9e4066Sahrens 
2492fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
2493fa9e4066Sahrens 			break;
2494fa9e4066Sahrens 
2495088e9d47Seschrock 		/*
2496088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
2497088e9d47Seschrock 		 * before calculating the maximum name width, so that any
2498088e9d47Seschrock 		 * configuration changes are properly accounted for.
2499088e9d47Seschrock 		 */
250099653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
2501088e9d47Seschrock 
2502fa9e4066Sahrens 		/*
2503fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
2504fa9e4066Sahrens 		 * for the pool / device name column across all pools.
2505fa9e4066Sahrens 		 */
2506fa9e4066Sahrens 		cb.cb_namewidth = 0;
250799653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2508fa9e4066Sahrens 
250926fd7700SKrishnendu Sadhukhan - Sun Microsystems 		if (timestamp_fmt != NODATE)
251026fd7700SKrishnendu Sadhukhan - Sun Microsystems 			print_timestamp(timestamp_fmt);
251126fd7700SKrishnendu Sadhukhan - Sun Microsystems 
2512fa9e4066Sahrens 		/*
2513fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
2514fa9e4066Sahrens 		 */
2515fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
2516fa9e4066Sahrens 			print_iostat_header(&cb);
2517fa9e4066Sahrens 
251899653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2519fa9e4066Sahrens 
2520fa9e4066Sahrens 		/*
2521fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
2522fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
2523fa9e4066Sahrens 		 */
2524fa9e4066Sahrens 		if (npools > 1 && !verbose)
2525fa9e4066Sahrens 			print_iostat_separator(&cb);
2526fa9e4066Sahrens 
2527fa9e4066Sahrens 		if (verbose)
2528fa9e4066Sahrens 			(void) printf("\n");
2529fa9e4066Sahrens 
253039c23413Seschrock 		/*
253139c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
253239c23413Seschrock 		 * indefinitely.
253339c23413Seschrock 		 */
253439c23413Seschrock 		(void) fflush(stdout);
253539c23413Seschrock 
2536fa9e4066Sahrens 		if (interval == 0)
2537fa9e4066Sahrens 			break;
2538fa9e4066Sahrens 
2539fa9e4066Sahrens 		if (count != 0 && --count == 0)
2540fa9e4066Sahrens 			break;
2541fa9e4066Sahrens 
2542fa9e4066Sahrens 		(void) sleep(interval);
2543fa9e4066Sahrens 	}
2544fa9e4066Sahrens 
2545fa9e4066Sahrens 	pool_list_free(list);
2546fa9e4066Sahrens 
2547fa9e4066Sahrens 	return (ret);
2548fa9e4066Sahrens }
2549fa9e4066Sahrens 
2550fa9e4066Sahrens typedef struct list_cbdata {
25514263d13fSGeorge Wilson 	boolean_t	cb_verbose;
25524263d13fSGeorge Wilson 	int		cb_namewidth;
255399653d4eSeschrock 	boolean_t	cb_scripted;
2554990b4856Slling 	zprop_list_t	*cb_proplist;
2555fa9e4066Sahrens } list_cbdata_t;
2556fa9e4066Sahrens 
2557fa9e4066Sahrens /*
2558fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
2559fa9e4066Sahrens  */
2560990b4856Slling static void
25614263d13fSGeorge Wilson print_header(list_cbdata_t *cb)
2562fa9e4066Sahrens {
25634263d13fSGeorge Wilson 	zprop_list_t *pl = cb->cb_proplist;
2564*ad135b5dSChristopher Siden 	char headerbuf[ZPOOL_MAXPROPLEN];
2565990b4856Slling 	const char *header;
2566990b4856Slling 	boolean_t first = B_TRUE;
2567990b4856Slling 	boolean_t right_justify;
25684263d13fSGeorge Wilson 	size_t width = 0;
2569990b4856Slling 
2570990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
25714263d13fSGeorge Wilson 		width = pl->pl_width;
25724263d13fSGeorge Wilson 		if (first && cb->cb_verbose) {
25734263d13fSGeorge Wilson 			/*
25744263d13fSGeorge Wilson 			 * Reset the width to accommodate the verbose listing
25754263d13fSGeorge Wilson 			 * of devices.
25764263d13fSGeorge Wilson 			 */
25774263d13fSGeorge Wilson 			width = cb->cb_namewidth;
25784263d13fSGeorge Wilson 		}
25794263d13fSGeorge Wilson 
2580990b4856Slling 		if (!first)
2581fa9e4066Sahrens 			(void) printf("  ");
2582fa9e4066Sahrens 		else
2583990b4856Slling 			first = B_FALSE;
2584990b4856Slling 
2585*ad135b5dSChristopher Siden 		right_justify = B_FALSE;
2586*ad135b5dSChristopher Siden 		if (pl->pl_prop != ZPROP_INVAL) {
2587*ad135b5dSChristopher Siden 			header = zpool_prop_column_name(pl->pl_prop);
2588*ad135b5dSChristopher Siden 			right_justify = zpool_prop_align_right(pl->pl_prop);
2589*ad135b5dSChristopher Siden 		} else {
2590*ad135b5dSChristopher Siden 			int i;
2591*ad135b5dSChristopher Siden 
2592*ad135b5dSChristopher Siden 			for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
2593*ad135b5dSChristopher Siden 				headerbuf[i] = toupper(pl->pl_user_prop[i]);
2594*ad135b5dSChristopher Siden 			headerbuf[i] = '\0';
2595*ad135b5dSChristopher Siden 			header = headerbuf;
2596*ad135b5dSChristopher Siden 		}
2597fa9e4066Sahrens 
2598990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
2599990b4856Slling 			(void) printf("%s", header);
2600990b4856Slling 		else if (right_justify)
26014263d13fSGeorge Wilson 			(void) printf("%*s", width, header);
2602990b4856Slling 		else
26034263d13fSGeorge Wilson 			(void) printf("%-*s", width, header);
26044263d13fSGeorge Wilson 
2605fa9e4066Sahrens 	}
2606fa9e4066Sahrens 
2607fa9e4066Sahrens 	(void) printf("\n");
2608fa9e4066Sahrens }
2609fa9e4066Sahrens 
2610990b4856Slling /*
2611990b4856Slling  * Given a pool and a list of properties, print out all the properties according
2612990b4856Slling  * to the described layout.
2613990b4856Slling  */
2614990b4856Slling static void
26154263d13fSGeorge Wilson print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
2616fa9e4066Sahrens {
26174263d13fSGeorge Wilson 	zprop_list_t *pl = cb->cb_proplist;
2618990b4856Slling 	boolean_t first = B_TRUE;
2619990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
2620990b4856Slling 	char *propstr;
2621990b4856Slling 	boolean_t right_justify;
26224263d13fSGeorge Wilson 	size_t width;
2623990b4856Slling 
2624990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
26254263d13fSGeorge Wilson 
26264263d13fSGeorge Wilson 		width = pl->pl_width;
26274263d13fSGeorge Wilson 		if (first && cb->cb_verbose) {
26284263d13fSGeorge Wilson 			/*
26294263d13fSGeorge Wilson 			 * Reset the width to accommodate the verbose listing
26304263d13fSGeorge Wilson 			 * of devices.
26314263d13fSGeorge Wilson 			 */
26324263d13fSGeorge Wilson 			width = cb->cb_namewidth;
26334263d13fSGeorge Wilson 		}
26344263d13fSGeorge Wilson 
2635990b4856Slling 		if (!first) {
26364263d13fSGeorge Wilson 			if (cb->cb_scripted)
2637fa9e4066Sahrens 				(void) printf("\t");
2638fa9e4066Sahrens 			else
2639fa9e4066Sahrens 				(void) printf("  ");
2640990b4856Slling 		} else {
2641990b4856Slling 			first = B_FALSE;
2642fa9e4066Sahrens 		}
2643fa9e4066Sahrens 
2644990b4856Slling 		right_justify = B_FALSE;
2645990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
26464263d13fSGeorge Wilson 			if (pl->pl_prop == ZPOOL_PROP_EXPANDSZ &&
26474263d13fSGeorge Wilson 			    zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0)
26484263d13fSGeorge Wilson 				propstr = "-";
26494263d13fSGeorge Wilson 			else if (zpool_get_prop(zhp, pl->pl_prop, property,
2650990b4856Slling 			    sizeof (property), NULL) != 0)
2651990b4856Slling 				propstr = "-";
2652fa9e4066Sahrens 			else
2653990b4856Slling 				propstr = property;
2654fa9e4066Sahrens 
2655990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2656*ad135b5dSChristopher Siden 		} else if ((zpool_prop_feature(pl->pl_user_prop) ||
2657*ad135b5dSChristopher Siden 		    zpool_prop_unsupported(pl->pl_user_prop)) &&
2658*ad135b5dSChristopher Siden 		    zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
2659*ad135b5dSChristopher Siden 		    sizeof (property)) == 0) {
2660*ad135b5dSChristopher Siden 			propstr = property;
2661990b4856Slling 		} else {
2662990b4856Slling 			propstr = "-";
2663990b4856Slling 		}
2664fa9e4066Sahrens 
2665fa9e4066Sahrens 
2666990b4856Slling 		/*
2667990b4856Slling 		 * If this is being called in scripted mode, or if this is the
2668990b4856Slling 		 * last column and it is left-justified, don't include a width
2669990b4856Slling 		 * format specifier.
2670990b4856Slling 		 */
26714263d13fSGeorge Wilson 		if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
2672990b4856Slling 			(void) printf("%s", propstr);
2673990b4856Slling 		else if (right_justify)
2674990b4856Slling 			(void) printf("%*s", width, propstr);
2675990b4856Slling 		else
2676990b4856Slling 			(void) printf("%-*s", width, propstr);
2677990b4856Slling 	}
2678fa9e4066Sahrens 
2679990b4856Slling 	(void) printf("\n");
2680990b4856Slling }
2681fa9e4066Sahrens 
26824263d13fSGeorge Wilson static void
26834263d13fSGeorge Wilson print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted)
26844263d13fSGeorge Wilson {
26854263d13fSGeorge Wilson 	char propval[64];
26864263d13fSGeorge Wilson 	boolean_t fixed;
26874263d13fSGeorge Wilson 	size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
26884263d13fSGeorge Wilson 
26894263d13fSGeorge Wilson 	zfs_nicenum(value, propval, sizeof (propval));
26904263d13fSGeorge Wilson 
26914263d13fSGeorge Wilson 	if (prop == ZPOOL_PROP_EXPANDSZ && value == 0)
26924263d13fSGeorge Wilson 		(void) strlcpy(propval, "-", sizeof (propval));
26934263d13fSGeorge Wilson 
26944263d13fSGeorge Wilson 	if (scripted)
26954263d13fSGeorge Wilson 		(void) printf("\t%s", propval);
26964263d13fSGeorge Wilson 	else
26974263d13fSGeorge Wilson 		(void) printf("  %*s", width, propval);
26984263d13fSGeorge Wilson }
26994263d13fSGeorge Wilson 
27004263d13fSGeorge Wilson void
27014263d13fSGeorge Wilson print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
27024263d13fSGeorge Wilson     list_cbdata_t *cb, int depth)
27034263d13fSGeorge Wilson {
27044263d13fSGeorge Wilson 	nvlist_t **child;
27054263d13fSGeorge Wilson 	vdev_stat_t *vs;
27064263d13fSGeorge Wilson 	uint_t c, children;
27074263d13fSGeorge Wilson 	char *vname;
27084263d13fSGeorge Wilson 	boolean_t scripted = cb->cb_scripted;
27094263d13fSGeorge Wilson 
27104263d13fSGeorge Wilson 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
27114263d13fSGeorge Wilson 	    (uint64_t **)&vs, &c) == 0);
27124263d13fSGeorge Wilson 
27134263d13fSGeorge Wilson 	if (name != NULL) {
27144263d13fSGeorge Wilson 		if (scripted)
27154263d13fSGeorge Wilson 			(void) printf("\t%s", name);
27164263d13fSGeorge Wilson 		else if (strlen(name) + depth > cb->cb_namewidth)
27174263d13fSGeorge Wilson 			(void) printf("%*s%s", depth, "", name);
27184263d13fSGeorge Wilson 		else
27194263d13fSGeorge Wilson 			(void) printf("%*s%s%*s", depth, "", name,
27204263d13fSGeorge Wilson 			    (int)(cb->cb_namewidth - strlen(name) - depth), "");
27214263d13fSGeorge Wilson 
27224263d13fSGeorge Wilson 		/* only toplevel vdevs have capacity stats */
27234263d13fSGeorge Wilson 		if (vs->vs_space == 0) {
27244263d13fSGeorge Wilson 			if (scripted)
27254263d13fSGeorge Wilson 				(void) printf("\t-\t-\t-");
27264263d13fSGeorge Wilson 			else
27274263d13fSGeorge Wilson 				(void) printf("      -      -      -");
27284263d13fSGeorge Wilson 		} else {
27294263d13fSGeorge Wilson 			print_one_column(ZPOOL_PROP_SIZE, vs->vs_space,
27304263d13fSGeorge Wilson 			    scripted);
27314263d13fSGeorge Wilson 			print_one_column(ZPOOL_PROP_CAPACITY, vs->vs_alloc,
27324263d13fSGeorge Wilson 			    scripted);
27334263d13fSGeorge Wilson 			print_one_column(ZPOOL_PROP_FREE,
27344263d13fSGeorge Wilson 			    vs->vs_space - vs->vs_alloc, scripted);
27354263d13fSGeorge Wilson 		}
27364263d13fSGeorge Wilson 		print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize,
27374263d13fSGeorge Wilson 		    scripted);
27384263d13fSGeorge Wilson 		(void) printf("\n");
27394263d13fSGeorge Wilson 	}
27404263d13fSGeorge Wilson 
27414263d13fSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
27424263d13fSGeorge Wilson 	    &child, &children) != 0)
27434263d13fSGeorge Wilson 		return;
27444263d13fSGeorge Wilson 
27454263d13fSGeorge Wilson 	for (c = 0; c < children; c++) {
27464263d13fSGeorge Wilson 		uint64_t ishole = B_FALSE;
27474263d13fSGeorge Wilson 
27484263d13fSGeorge Wilson 		if (nvlist_lookup_uint64(child[c],
27494263d13fSGeorge Wilson 		    ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
27504263d13fSGeorge Wilson 			continue;
27514263d13fSGeorge Wilson 
27524263d13fSGeorge Wilson 		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
27534263d13fSGeorge Wilson 		print_list_stats(zhp, vname, child[c], cb, depth + 2);
27544263d13fSGeorge Wilson 		free(vname);
27554263d13fSGeorge Wilson 	}
27564263d13fSGeorge Wilson 
27574263d13fSGeorge Wilson 	/*
27584263d13fSGeorge Wilson 	 * Include level 2 ARC devices in iostat output
27594263d13fSGeorge Wilson 	 */
27604263d13fSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
27614263d13fSGeorge Wilson 	    &child, &children) != 0)
27624263d13fSGeorge Wilson 		return;
27634263d13fSGeorge Wilson 
27644263d13fSGeorge Wilson 	if (children > 0) {
27654263d13fSGeorge Wilson 		(void) printf("%-*s      -      -      -      -      -      "
27664263d13fSGeorge Wilson 		    "-\n", cb->cb_namewidth, "cache");
27674263d13fSGeorge Wilson 		for (c = 0; c < children; c++) {
27684263d13fSGeorge Wilson 			vname = zpool_vdev_name(g_zfs, zhp, child[c],
27694263d13fSGeorge Wilson 			    B_FALSE);
27704263d13fSGeorge Wilson 			print_list_stats(zhp, vname, child[c], cb, depth + 2);
27714263d13fSGeorge Wilson 			free(vname);
27724263d13fSGeorge Wilson 		}
27734263d13fSGeorge Wilson 	}
27744263d13fSGeorge Wilson }
27754263d13fSGeorge Wilson 
27764263d13fSGeorge Wilson 
2777990b4856Slling /*
2778990b4856Slling  * Generic callback function to list a pool.
2779990b4856Slling  */
2780990b4856Slling int
2781990b4856Slling list_callback(zpool_handle_t *zhp, void *data)
2782990b4856Slling {
2783990b4856Slling 	list_cbdata_t *cbp = data;
27844263d13fSGeorge Wilson 	nvlist_t *config;
27854263d13fSGeorge Wilson 	nvlist_t *nvroot;
2786fa9e4066Sahrens 
27874263d13fSGeorge Wilson 	config = zpool_get_config(zhp, NULL);
2788fa9e4066Sahrens 
27894263d13fSGeorge Wilson 	print_pool(zhp, cbp);
27904263d13fSGeorge Wilson 	if (!cbp->cb_verbose)
27914263d13fSGeorge Wilson 		return (0);
27924263d13fSGeorge Wilson 
27934263d13fSGeorge Wilson 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
27944263d13fSGeorge Wilson 	    &nvroot) == 0);
27954263d13fSGeorge Wilson 	print_list_stats(zhp, NULL, nvroot, cbp, 0);
2796fa9e4066Sahrens 
2797fa9e4066Sahrens 	return (0);
2798fa9e4066Sahrens }
2799fa9e4066Sahrens 
2800fa9e4066Sahrens /*
28013f9d6ad7SLin Ling  * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
2802fa9e4066Sahrens  *
2803990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2804990b4856Slling  *		by a single tab.
2805990b4856Slling  *	-o	List of properties to display.  Defaults to
2806485bbbf5SGeorge Wilson  *		"name,size,allocated,free,capacity,health,altroot"
28073f9d6ad7SLin Ling  *	-T	Display a timestamp in date(1) or Unix format
2808fa9e4066Sahrens  *
2809fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2810fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2811fa9e4066Sahrens  */
2812fa9e4066Sahrens int
2813fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2814fa9e4066Sahrens {
2815fa9e4066Sahrens 	int c;
2816fa9e4066Sahrens 	int ret;
2817fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2818990b4856Slling 	static char default_props[] =
28194263d13fSGeorge Wilson 	    "name,size,allocated,free,expandsize,capacity,dedupratio,"
28204263d13fSGeorge Wilson 	    "health,altroot";
2821990b4856Slling 	char *props = default_props;
28223f9d6ad7SLin Ling 	unsigned long interval = 0, count = 0;
28234263d13fSGeorge Wilson 	zpool_list_t *list;
28244263d13fSGeorge Wilson 	boolean_t first = B_TRUE;
2825fa9e4066Sahrens 
2826fa9e4066Sahrens 	/* check options */
28274263d13fSGeorge Wilson 	while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) {
2828fa9e4066Sahrens 		switch (c) {
2829fa9e4066Sahrens 		case 'H':
283099653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2831fa9e4066Sahrens 			break;
2832fa9e4066Sahrens 		case 'o':
2833990b4856Slling 			props = optarg;
2834fa9e4066Sahrens 			break;
28353f9d6ad7SLin Ling 		case 'T':
28363f9d6ad7SLin Ling 			get_timestamp_arg(*optarg);
28373f9d6ad7SLin Ling 			break;
28384263d13fSGeorge Wilson 		case 'v':
28394263d13fSGeorge Wilson 			cb.cb_verbose = B_TRUE;
28404263d13fSGeorge Wilson 			break;
2841fa9e4066Sahrens 		case ':':
2842fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2843fa9e4066Sahrens 			    "'%c' option\n"), optopt);
284499653d4eSeschrock 			usage(B_FALSE);
2845fa9e4066Sahrens 			break;
2846fa9e4066Sahrens 		case '?':
2847fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2848fa9e4066Sahrens 			    optopt);
284999653d4eSeschrock 			usage(B_FALSE);
2850fa9e4066Sahrens 		}
2851fa9e4066Sahrens 	}
2852fa9e4066Sahrens 
2853fa9e4066Sahrens 	argc -= optind;
2854fa9e4066Sahrens 	argv += optind;
2855fa9e4066Sahrens 
28563f9d6ad7SLin Ling 	get_interval_count(&argc, argv, &interval, &count);
28573f9d6ad7SLin Ling 
2858990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
2859990b4856Slling 		usage(B_FALSE);
2860fa9e4066Sahrens 
28614263d13fSGeorge Wilson 	if ((list = pool_list_get(argc, argv, &cb.cb_proplist, &ret)) == NULL)
28624263d13fSGeorge Wilson 		return (1);
28634263d13fSGeorge Wilson 
28644263d13fSGeorge Wilson 	if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
28654263d13fSGeorge Wilson 		(void) printf(gettext("no pools available\n"));
28664263d13fSGeorge Wilson 		zprop_free_list(cb.cb_proplist);
28674263d13fSGeorge Wilson 		return (0);
28684263d13fSGeorge Wilson 	}
2869fa9e4066Sahrens 
28703f9d6ad7SLin Ling 	for (;;) {
28714263d13fSGeorge Wilson 		pool_list_update(list);
28724263d13fSGeorge Wilson 
28734263d13fSGeorge Wilson 		if (pool_list_count(list) == 0)
28744263d13fSGeorge Wilson 			break;
28754263d13fSGeorge Wilson 
28764263d13fSGeorge Wilson 		cb.cb_namewidth = 0;
28774263d13fSGeorge Wilson 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2878990b4856Slling 
28793f9d6ad7SLin Ling 		if (timestamp_fmt != NODATE)
28803f9d6ad7SLin Ling 			print_timestamp(timestamp_fmt);
2881fa9e4066Sahrens 
28824263d13fSGeorge Wilson 		if (!cb.cb_scripted && (first || cb.cb_verbose)) {
28834263d13fSGeorge Wilson 			print_header(&cb);
28844263d13fSGeorge Wilson 			first = B_FALSE;
28853f9d6ad7SLin Ling 		}
28864263d13fSGeorge Wilson 		ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
28873f9d6ad7SLin Ling 
28883f9d6ad7SLin Ling 		if (interval == 0)
28893f9d6ad7SLin Ling 			break;
28903f9d6ad7SLin Ling 
28913f9d6ad7SLin Ling 		if (count != 0 && --count == 0)
28923f9d6ad7SLin Ling 			break;
28933f9d6ad7SLin Ling 
28943f9d6ad7SLin Ling 		(void) sleep(interval);
2895fa9e4066Sahrens 	}
2896fa9e4066Sahrens 
28973f9d6ad7SLin Ling 	zprop_free_list(cb.cb_proplist);
2898fa9e4066Sahrens 	return (ret);
2899fa9e4066Sahrens }
2900fa9e4066Sahrens 
2901fa9e4066Sahrens static nvlist_t *
2902fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2903fa9e4066Sahrens {
2904fa9e4066Sahrens 	nvlist_t **child;
2905fa9e4066Sahrens 	uint_t c, children;
2906fa9e4066Sahrens 	nvlist_t *match;
2907fa9e4066Sahrens 	char *path;
2908fa9e4066Sahrens 
2909fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2910fa9e4066Sahrens 	    &child, &children) != 0) {
2911fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2912fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2913fa9e4066Sahrens 			name += 9;
2914fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2915fa9e4066Sahrens 			path += 9;
2916fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2917fa9e4066Sahrens 			return (nv);
2918fa9e4066Sahrens 		return (NULL);
2919fa9e4066Sahrens 	}
2920fa9e4066Sahrens 
2921fa9e4066Sahrens 	for (c = 0; c < children; c++)
2922fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2923fa9e4066Sahrens 			return (match);
2924fa9e4066Sahrens 
2925fa9e4066Sahrens 	return (NULL);
2926fa9e4066Sahrens }
2927fa9e4066Sahrens 
2928fa9e4066Sahrens static int
2929fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2930fa9e4066Sahrens {
293199653d4eSeschrock 	boolean_t force = B_FALSE;
2932fa9e4066Sahrens 	int c;
2933fa9e4066Sahrens 	nvlist_t *nvroot;
2934fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2935fa9e4066Sahrens 	zpool_handle_t *zhp;
293699653d4eSeschrock 	int ret;
2937fa9e4066Sahrens 
2938fa9e4066Sahrens 	/* check options */
2939fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2940fa9e4066Sahrens 		switch (c) {
2941fa9e4066Sahrens 		case 'f':
294299653d4eSeschrock 			force = B_TRUE;
2943fa9e4066Sahrens 			break;
2944fa9e4066Sahrens 		case '?':
2945fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2946fa9e4066Sahrens 			    optopt);
294799653d4eSeschrock 			usage(B_FALSE);
2948fa9e4066Sahrens 		}
2949fa9e4066Sahrens 	}
2950fa9e4066Sahrens 
2951fa9e4066Sahrens 	argc -= optind;
2952fa9e4066Sahrens 	argv += optind;
2953fa9e4066Sahrens 
2954fa9e4066Sahrens 	/* get pool name and check number of arguments */
2955fa9e4066Sahrens 	if (argc < 1) {
2956fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
295799653d4eSeschrock 		usage(B_FALSE);
2958fa9e4066Sahrens 	}
2959fa9e4066Sahrens 
2960fa9e4066Sahrens 	poolname = argv[0];
2961fa9e4066Sahrens 
2962fa9e4066Sahrens 	if (argc < 2) {
2963fa9e4066Sahrens 		(void) fprintf(stderr,
2964fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
296599653d4eSeschrock 		usage(B_FALSE);
2966fa9e4066Sahrens 	}
2967fa9e4066Sahrens 
2968fa9e4066Sahrens 	old_disk = argv[1];
2969fa9e4066Sahrens 
2970fa9e4066Sahrens 	if (argc < 3) {
2971fa9e4066Sahrens 		if (!replacing) {
2972fa9e4066Sahrens 			(void) fprintf(stderr,
2973fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
297499653d4eSeschrock 			usage(B_FALSE);
2975fa9e4066Sahrens 		}
2976fa9e4066Sahrens 		new_disk = old_disk;
2977fa9e4066Sahrens 		argc -= 1;
2978fa9e4066Sahrens 		argv += 1;
2979fa9e4066Sahrens 	} else {
2980fa9e4066Sahrens 		new_disk = argv[2];
2981fa9e4066Sahrens 		argc -= 2;
2982fa9e4066Sahrens 		argv += 2;
2983fa9e4066Sahrens 	}
2984fa9e4066Sahrens 
2985fa9e4066Sahrens 	if (argc > 1) {
2986fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
298799653d4eSeschrock 		usage(B_FALSE);
2988fa9e4066Sahrens 	}
2989fa9e4066Sahrens 
299099653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2991fa9e4066Sahrens 		return (1);
2992fa9e4066Sahrens 
29938488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2994fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2995fa9e4066Sahrens 		    poolname);
2996fa9e4066Sahrens 		zpool_close(zhp);
2997fa9e4066Sahrens 		return (1);
2998fa9e4066Sahrens 	}
2999fa9e4066Sahrens 
3000705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
3001705040edSEric Taylor 	    argc, argv);
3002fa9e4066Sahrens 	if (nvroot == NULL) {
3003fa9e4066Sahrens 		zpool_close(zhp);
3004fa9e4066Sahrens 		return (1);
3005fa9e4066Sahrens 	}
3006fa9e4066Sahrens 
300799653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
300899653d4eSeschrock 
300999653d4eSeschrock 	nvlist_free(nvroot);
301099653d4eSeschrock 	zpool_close(zhp);
301199653d4eSeschrock 
301299653d4eSeschrock 	return (ret);
3013fa9e4066Sahrens }
3014fa9e4066Sahrens 
3015fa9e4066Sahrens /*
3016fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
3017fa9e4066Sahrens  *
3018fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
3019fa9e4066Sahrens  *
3020fa9e4066Sahrens  * Replace <device> with <new_device>.
3021fa9e4066Sahrens  */
3022fa9e4066Sahrens /* ARGSUSED */
3023fa9e4066Sahrens int
3024fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
3025fa9e4066Sahrens {
3026fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
3027fa9e4066Sahrens }
3028fa9e4066Sahrens 
3029fa9e4066Sahrens /*
3030fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
3031fa9e4066Sahrens  *
3032fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
3033fa9e4066Sahrens  *
3034fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
3035fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
3036fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
3037fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
3038fa9e4066Sahrens  */
3039fa9e4066Sahrens int
3040fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
3041fa9e4066Sahrens {
3042fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
3043fa9e4066Sahrens }
3044fa9e4066Sahrens 
3045fa9e4066Sahrens /*
3046fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
3047fa9e4066Sahrens  *
3048fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
3049fa9e4066Sahrens  *		(not supported yet)
3050fa9e4066Sahrens  *
3051fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
3052fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
3053fa9e4066Sahrens  * has the only valid copy of some data.
3054fa9e4066Sahrens  */
3055fa9e4066Sahrens /* ARGSUSED */
3056fa9e4066Sahrens int
3057fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
3058fa9e4066Sahrens {
3059fa9e4066Sahrens 	int c;
3060fa9e4066Sahrens 	char *poolname, *path;
3061fa9e4066Sahrens 	zpool_handle_t *zhp;
306299653d4eSeschrock 	int ret;
3063fa9e4066Sahrens 
3064fa9e4066Sahrens 	/* check options */
3065fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
3066fa9e4066Sahrens 		switch (c) {
3067fa9e4066Sahrens 		case 'f':
3068fa9e4066Sahrens 		case '?':
3069fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3070fa9e4066Sahrens 			    optopt);
307199653d4eSeschrock 			usage(B_FALSE);
3072fa9e4066Sahrens 		}
3073fa9e4066Sahrens 	}
3074fa9e4066Sahrens 
3075fa9e4066Sahrens 	argc -= optind;
3076fa9e4066Sahrens 	argv += optind;
3077fa9e4066Sahrens 
3078fa9e4066Sahrens 	/* get pool name and check number of arguments */
3079fa9e4066Sahrens 	if (argc < 1) {
3080fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
308199653d4eSeschrock 		usage(B_FALSE);
3082fa9e4066Sahrens 	}
3083fa9e4066Sahrens 
3084fa9e4066Sahrens 	if (argc < 2) {
3085fa9e4066Sahrens 		(void) fprintf(stderr,
3086fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
308799653d4eSeschrock 		usage(B_FALSE);
3088fa9e4066Sahrens 	}
3089fa9e4066Sahrens 
3090fa9e4066Sahrens 	poolname = argv[0];
3091fa9e4066Sahrens 	path = argv[1];
3092fa9e4066Sahrens 
309399653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3094fa9e4066Sahrens 		return (1);
3095fa9e4066Sahrens 
309699653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
309799653d4eSeschrock 
309899653d4eSeschrock 	zpool_close(zhp);
309999653d4eSeschrock 
310099653d4eSeschrock 	return (ret);
3101fa9e4066Sahrens }
3102fa9e4066Sahrens 
31031195e687SMark J Musante /*
31041195e687SMark J Musante  * zpool split [-n] [-o prop=val] ...
31051195e687SMark J Musante  *		[-o mntopt] ...
31061195e687SMark J Musante  *		[-R altroot] <pool> <newpool> [<device> ...]
31071195e687SMark J Musante  *
31081195e687SMark J Musante  *	-n	Do not split the pool, but display the resulting layout if
31091195e687SMark J Musante  *		it were to be split.
31101195e687SMark J Musante  *	-o	Set property=value, or set mount options.
31111195e687SMark J Musante  *	-R	Mount the split-off pool under an alternate root.
31121195e687SMark J Musante  *
31131195e687SMark J Musante  * Splits the named pool and gives it the new pool name.  Devices to be split
31141195e687SMark J Musante  * off may be listed, provided that no more than one device is specified
31151195e687SMark J Musante  * per top-level vdev mirror.  The newly split pool is left in an exported
31161195e687SMark J Musante  * state unless -R is specified.
31171195e687SMark J Musante  *
31181195e687SMark J Musante  * Restrictions: the top-level of the pool pool must only be made up of
31191195e687SMark J Musante  * mirrors; all devices in the pool must be healthy; no device may be
31201195e687SMark J Musante  * undergoing a resilvering operation.
31211195e687SMark J Musante  */
31221195e687SMark J Musante int
31231195e687SMark J Musante zpool_do_split(int argc, char **argv)
31241195e687SMark J Musante {
31251195e687SMark J Musante 	char *srcpool, *newpool, *propval;
31261195e687SMark J Musante 	char *mntopts = NULL;
31271195e687SMark J Musante 	splitflags_t flags;
31281195e687SMark J Musante 	int c, ret = 0;
31291195e687SMark J Musante 	zpool_handle_t *zhp;
31301195e687SMark J Musante 	nvlist_t *config, *props = NULL;
31311195e687SMark J Musante 
31321195e687SMark J Musante 	flags.dryrun = B_FALSE;
31331195e687SMark J Musante 	flags.import = B_FALSE;
31341195e687SMark J Musante 
31351195e687SMark J Musante 	/* check options */
31361195e687SMark J Musante 	while ((c = getopt(argc, argv, ":R:no:")) != -1) {
31371195e687SMark J Musante 		switch (c) {
31381195e687SMark J Musante 		case 'R':
31391195e687SMark J Musante 			flags.import = B_TRUE;
31401195e687SMark J Musante 			if (add_prop_list(
31411195e687SMark J Musante 			    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
31421195e687SMark J Musante 			    &props, B_TRUE) != 0) {
31431195e687SMark J Musante 				if (props)
31441195e687SMark J Musante 					nvlist_free(props);
31451195e687SMark J Musante 				usage(B_FALSE);
31461195e687SMark J Musante 			}
31471195e687SMark J Musante 			break;
31481195e687SMark J Musante 		case 'n':
31491195e687SMark J Musante 			flags.dryrun = B_TRUE;
31501195e687SMark J Musante 			break;
31511195e687SMark J Musante 		case 'o':
31521195e687SMark J Musante 			if ((propval = strchr(optarg, '=')) != NULL) {
31531195e687SMark J Musante 				*propval = '\0';
31541195e687SMark J Musante 				propval++;
31551195e687SMark J Musante 				if (add_prop_list(optarg, propval,
31561195e687SMark J Musante 				    &props, B_TRUE) != 0) {
31571195e687SMark J Musante 					if (props)
31581195e687SMark J Musante 						nvlist_free(props);
31591195e687SMark J Musante 					usage(B_FALSE);
31601195e687SMark J Musante 				}
31611195e687SMark J Musante 			} else {
31621195e687SMark J Musante 				mntopts = optarg;
31631195e687SMark J Musante 			}
31641195e687SMark J Musante 			break;
31651195e687SMark J Musante 		case ':':
31661195e687SMark J Musante 			(void) fprintf(stderr, gettext("missing argument for "
31671195e687SMark J Musante 			    "'%c' option\n"), optopt);
31681195e687SMark J Musante 			usage(B_FALSE);
31691195e687SMark J Musante 			break;
31701195e687SMark J Musante 		case '?':
31711195e687SMark J Musante 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
31721195e687SMark J Musante 			    optopt);
31731195e687SMark J Musante 			usage(B_FALSE);
31741195e687SMark J Musante 			break;
31751195e687SMark J Musante 		}
31761195e687SMark J Musante 	}
31771195e687SMark J Musante 
31781195e687SMark J Musante 	if (!flags.import && mntopts != NULL) {
31791195e687SMark J Musante 		(void) fprintf(stderr, gettext("setting mntopts is only "
31801195e687SMark J Musante 		    "valid when importing the pool\n"));
31811195e687SMark J Musante 		usage(B_FALSE);
31821195e687SMark J Musante 	}
31831195e687SMark J Musante 
31841195e687SMark J Musante 	argc -= optind;
31851195e687SMark J Musante 	argv += optind;
31861195e687SMark J Musante 
31871195e687SMark J Musante 	if (argc < 1) {
31881195e687SMark J Musante 		(void) fprintf(stderr, gettext("Missing pool name\n"));
31891195e687SMark J Musante 		usage(B_FALSE);
31901195e687SMark J Musante 	}
31911195e687SMark J Musante 	if (argc < 2) {
31921195e687SMark J Musante 		(void) fprintf(stderr, gettext("Missing new pool name\n"));
31931195e687SMark J Musante 		usage(B_FALSE);
31941195e687SMark J Musante 	}
31951195e687SMark J Musante 
31961195e687SMark J Musante 	srcpool = argv[0];
31971195e687SMark J Musante 	newpool = argv[1];
31981195e687SMark J Musante 
31991195e687SMark J Musante 	argc -= 2;
32001195e687SMark J Musante 	argv += 2;
32011195e687SMark J Musante 
32021195e687SMark J Musante 	if ((zhp = zpool_open(g_zfs, srcpool)) == NULL)
32031195e687SMark J Musante 		return (1);
32041195e687SMark J Musante 
32051195e687SMark J Musante 	config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
32061195e687SMark J Musante 	if (config == NULL) {
32071195e687SMark J Musante 		ret = 1;
32081195e687SMark J Musante 	} else {
32091195e687SMark J Musante 		if (flags.dryrun) {
32101195e687SMark J Musante 			(void) printf(gettext("would create '%s' with the "
32111195e687SMark J Musante 			    "following layout:\n\n"), newpool);
32121195e687SMark J Musante 			print_vdev_tree(NULL, newpool, config, 0, B_FALSE);
32131195e687SMark J Musante 		}
32141195e687SMark J Musante 		nvlist_free(config);
32151195e687SMark J Musante 	}
32161195e687SMark J Musante 
32171195e687SMark J Musante 	zpool_close(zhp);
32181195e687SMark J Musante 
32191195e687SMark J Musante 	if (ret != 0 || flags.dryrun || !flags.import)
32201195e687SMark J Musante 		return (ret);
32211195e687SMark J Musante 
32221195e687SMark J Musante 	/*
32231195e687SMark J Musante 	 * The split was successful. Now we need to open the new
32241195e687SMark J Musante 	 * pool and import it.
32251195e687SMark J Musante 	 */
32261195e687SMark J Musante 	if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
32271195e687SMark J Musante 		return (1);
32281195e687SMark J Musante 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
32291195e687SMark J Musante 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
32301195e687SMark J Musante 		ret = 1;
32311195e687SMark J Musante 		(void) fprintf(stderr, gettext("Split was succssful, but "
32321195e687SMark J Musante 		    "the datasets could not all be mounted\n"));
32331195e687SMark J Musante 		(void) fprintf(stderr, gettext("Try doing '%s' with a "
32341195e687SMark J Musante 		    "different altroot\n"), "zpool import");
32351195e687SMark J Musante 	}
32361195e687SMark J Musante 	zpool_close(zhp);
32371195e687SMark J Musante 
32381195e687SMark J Musante 	return (ret);
32391195e687SMark J Musante }
32401195e687SMark J Musante 
32411195e687SMark J Musante 
32421195e687SMark J Musante 
3243fa9e4066Sahrens /*
3244441d80aaSlling  * zpool online <pool> <device> ...
3245fa9e4066Sahrens  */
3246fa9e4066Sahrens int
3247fa9e4066Sahrens zpool_do_online(int argc, char **argv)
3248fa9e4066Sahrens {
3249fa9e4066Sahrens 	int c, i;
3250fa9e4066Sahrens 	char *poolname;
3251fa9e4066Sahrens 	zpool_handle_t *zhp;
3252fa9e4066Sahrens 	int ret = 0;
32533d7072f8Seschrock 	vdev_state_t newstate;
3254573ca77eSGeorge Wilson 	int flags = 0;
3255fa9e4066Sahrens 
3256fa9e4066Sahrens 	/* check options */
3257573ca77eSGeorge Wilson 	while ((c = getopt(argc, argv, "et")) != -1) {
3258fa9e4066Sahrens 		switch (c) {
3259573ca77eSGeorge Wilson 		case 'e':
3260573ca77eSGeorge Wilson 			flags |= ZFS_ONLINE_EXPAND;
3261573ca77eSGeorge Wilson 			break;
3262fa9e4066Sahrens 		case 't':
3263fa9e4066Sahrens 		case '?':
3264fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3265fa9e4066Sahrens 			    optopt);
326699653d4eSeschrock 			usage(B_FALSE);
3267fa9e4066Sahrens 		}
3268fa9e4066Sahrens 	}
3269fa9e4066Sahrens 
3270fa9e4066Sahrens 	argc -= optind;
3271fa9e4066Sahrens 	argv += optind;
3272fa9e4066Sahrens 
3273fa9e4066Sahrens 	/* get pool name and check number of arguments */
3274fa9e4066Sahrens 	if (argc < 1) {
3275fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
327699653d4eSeschrock 		usage(B_FALSE);
3277fa9e4066Sahrens 	}
3278fa9e4066Sahrens 	if (argc < 2) {
3279fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
328099653d4eSeschrock 		usage(B_FALSE);
3281fa9e4066Sahrens 	}
3282fa9e4066Sahrens 
3283fa9e4066Sahrens 	poolname = argv[0];
3284fa9e4066Sahrens 
328599653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3286fa9e4066Sahrens 		return (1);
3287fa9e4066Sahrens 
32883d7072f8Seschrock 	for (i = 1; i < argc; i++) {
3289573ca77eSGeorge Wilson 		if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
32903d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
32913d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
32923d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
32933d7072f8Seschrock 				    argv[i]);
32943d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
32953d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
32963d7072f8Seschrock 					    "clear' to restore a faulted "
32973d7072f8Seschrock 					    "device\n"));
32983d7072f8Seschrock 				else
32993d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
33003d7072f8Seschrock 					    "replace' to replace devices "
33013d7072f8Seschrock 					    "that are no longer present\n"));
33023d7072f8Seschrock 			}
33033d7072f8Seschrock 		} else {
3304fa9e4066Sahrens 			ret = 1;
33053d7072f8Seschrock 		}
33063d7072f8Seschrock 	}
3307fa9e4066Sahrens 
330899653d4eSeschrock 	zpool_close(zhp);
330999653d4eSeschrock 
3310fa9e4066Sahrens 	return (ret);
3311fa9e4066Sahrens }
3312fa9e4066Sahrens 
3313fa9e4066Sahrens /*
3314441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
3315fa9e4066Sahrens  *
3316fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
3317fa9e4066Sahrens  *		so would appear to compromise pool availability.
3318fa9e4066Sahrens  *		(not supported yet)
3319fa9e4066Sahrens  *
3320fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
3321fa9e4066Sahrens  *		state will not be persistent across reboots.
3322fa9e4066Sahrens  */
3323fa9e4066Sahrens /* ARGSUSED */
3324fa9e4066Sahrens int
3325fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
3326fa9e4066Sahrens {
3327fa9e4066Sahrens 	int c, i;
3328fa9e4066Sahrens 	char *poolname;
3329fa9e4066Sahrens 	zpool_handle_t *zhp;
333099653d4eSeschrock 	int ret = 0;
333199653d4eSeschrock 	boolean_t istmp = B_FALSE;
3332fa9e4066Sahrens 
3333fa9e4066Sahrens 	/* check options */
3334fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
3335fa9e4066Sahrens 		switch (c) {
3336fa9e4066Sahrens 		case 't':
333799653d4eSeschrock 			istmp = B_TRUE;
3338441d80aaSlling 			break;
3339441d80aaSlling 		case 'f':
3340fa9e4066Sahrens 		case '?':
3341fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3342fa9e4066Sahrens 			    optopt);
334399653d4eSeschrock 			usage(B_FALSE);
3344fa9e4066Sahrens 		}
3345fa9e4066Sahrens 	}
3346fa9e4066Sahrens 
3347fa9e4066Sahrens 	argc -= optind;
3348fa9e4066Sahrens 	argv += optind;
3349fa9e4066Sahrens 
3350fa9e4066Sahrens 	/* get pool name and check number of arguments */
3351fa9e4066Sahrens 	if (argc < 1) {
3352fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
335399653d4eSeschrock 		usage(B_FALSE);
3354fa9e4066Sahrens 	}
3355fa9e4066Sahrens 	if (argc < 2) {
3356fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
335799653d4eSeschrock 		usage(B_FALSE);
3358fa9e4066Sahrens 	}
3359fa9e4066Sahrens 
3360fa9e4066Sahrens 	poolname = argv[0];
3361fa9e4066Sahrens 
336299653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3363fa9e4066Sahrens 		return (1);
3364fa9e4066Sahrens 
33653d7072f8Seschrock 	for (i = 1; i < argc; i++) {
33663d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
3367fa9e4066Sahrens 			ret = 1;
33683d7072f8Seschrock 	}
3369fa9e4066Sahrens 
337099653d4eSeschrock 	zpool_close(zhp);
337199653d4eSeschrock 
3372fa9e4066Sahrens 	return (ret);
3373fa9e4066Sahrens }
3374fa9e4066Sahrens 
3375ea8dc4b6Seschrock /*
3376ea8dc4b6Seschrock  * zpool clear <pool> [device]
3377ea8dc4b6Seschrock  *
3378ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
3379ea8dc4b6Seschrock  */
3380ea8dc4b6Seschrock int
3381ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
3382ea8dc4b6Seschrock {
3383468c413aSTim Haley 	int c;
3384ea8dc4b6Seschrock 	int ret = 0;
3385468c413aSTim Haley 	boolean_t dryrun = B_FALSE;
3386468c413aSTim Haley 	boolean_t do_rewind = B_FALSE;
3387468c413aSTim Haley 	boolean_t xtreme_rewind = B_FALSE;
3388468c413aSTim Haley 	uint32_t rewind_policy = ZPOOL_NO_REWIND;
3389468c413aSTim Haley 	nvlist_t *policy = NULL;
3390ea8dc4b6Seschrock 	zpool_handle_t *zhp;
3391ea8dc4b6Seschrock 	char *pool, *device;
3392ea8dc4b6Seschrock 
3393468c413aSTim Haley 	/* check options */
3394468c413aSTim Haley 	while ((c = getopt(argc, argv, "FnX")) != -1) {
3395468c413aSTim Haley 		switch (c) {
3396468c413aSTim Haley 		case 'F':
3397468c413aSTim Haley 			do_rewind = B_TRUE;
3398468c413aSTim Haley 			break;
3399468c413aSTim Haley 		case 'n':
3400468c413aSTim Haley 			dryrun = B_TRUE;
3401468c413aSTim Haley 			break;
3402468c413aSTim Haley 		case 'X':
3403468c413aSTim Haley 			xtreme_rewind = B_TRUE;
3404468c413aSTim Haley 			break;
3405468c413aSTim Haley 		case '?':
3406468c413aSTim Haley 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3407468c413aSTim Haley 			    optopt);
3408468c413aSTim Haley 			usage(B_FALSE);
3409468c413aSTim Haley 		}
3410468c413aSTim Haley 	}
3411468c413aSTim Haley 
3412468c413aSTim Haley 	argc -= optind;
3413468c413aSTim Haley 	argv += optind;
3414468c413aSTim Haley 
3415468c413aSTim Haley 	if (argc < 1) {
3416ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
341799653d4eSeschrock 		usage(B_FALSE);
3418ea8dc4b6Seschrock 	}
3419ea8dc4b6Seschrock 
3420468c413aSTim Haley 	if (argc > 2) {
3421ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
342299653d4eSeschrock 		usage(B_FALSE);
3423ea8dc4b6Seschrock 	}
3424ea8dc4b6Seschrock 
3425468c413aSTim Haley 	if ((dryrun || xtreme_rewind) && !do_rewind) {
3426468c413aSTim Haley 		(void) fprintf(stderr,
3427468c413aSTim Haley 		    gettext("-n or -X only meaningful with -F\n"));
3428468c413aSTim Haley 		usage(B_FALSE);
3429468c413aSTim Haley 	}
3430468c413aSTim Haley 	if (dryrun)
3431468c413aSTim Haley 		rewind_policy = ZPOOL_TRY_REWIND;
3432468c413aSTim Haley 	else if (do_rewind)
3433468c413aSTim Haley 		rewind_policy = ZPOOL_DO_REWIND;
3434468c413aSTim Haley 	if (xtreme_rewind)
3435468c413aSTim Haley 		rewind_policy |= ZPOOL_EXTREME_REWIND;
3436468c413aSTim Haley 
3437468c413aSTim Haley 	/* In future, further rewind policy choices can be passed along here */
3438468c413aSTim Haley 	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
3439468c413aSTim Haley 	    nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
3440468c413aSTim Haley 		return (1);
3441468c413aSTim Haley 
3442468c413aSTim Haley 	pool = argv[0];
3443468c413aSTim Haley 	device = argc == 2 ? argv[1] : NULL;
3444ea8dc4b6Seschrock 
3445468c413aSTim Haley 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
3446468c413aSTim Haley 		nvlist_free(policy);
3447ea8dc4b6Seschrock 		return (1);
3448468c413aSTim Haley 	}
3449ea8dc4b6Seschrock 
3450468c413aSTim Haley 	if (zpool_clear(zhp, device, policy) != 0)
3451ea8dc4b6Seschrock 		ret = 1;
3452ea8dc4b6Seschrock 
3453ea8dc4b6Seschrock 	zpool_close(zhp);
3454ea8dc4b6Seschrock 
3455468c413aSTim Haley 	nvlist_free(policy);
3456468c413aSTim Haley 
3457ea8dc4b6Seschrock 	return (ret);
3458ea8dc4b6Seschrock }
3459ea8dc4b6Seschrock 
3460e9103aaeSGarrett D'Amore /*
3461e9103aaeSGarrett D'Amore  * zpool reguid <pool>
3462e9103aaeSGarrett D'Amore  */
3463e9103aaeSGarrett D'Amore int
3464e9103aaeSGarrett D'Amore zpool_do_reguid(int argc, char **argv)
3465e9103aaeSGarrett D'Amore {
3466e9103aaeSGarrett D'Amore 	int c;
3467e9103aaeSGarrett D'Amore 	char *poolname;
3468e9103aaeSGarrett D'Amore 	zpool_handle_t *zhp;
3469e9103aaeSGarrett D'Amore 	int ret = 0;
3470e9103aaeSGarrett D'Amore 
3471e9103aaeSGarrett D'Amore 	/* check options */
3472e9103aaeSGarrett D'Amore 	while ((c = getopt(argc, argv, "")) != -1) {
3473e9103aaeSGarrett D'Amore 		switch (c) {
3474e9103aaeSGarrett D'Amore 		case '?':
3475e9103aaeSGarrett D'Amore 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3476e9103aaeSGarrett D'Amore 			    optopt);
3477e9103aaeSGarrett D'Amore 			usage(B_FALSE);
3478e9103aaeSGarrett D'Amore 		}
3479e9103aaeSGarrett D'Amore 	}
3480e9103aaeSGarrett D'Amore 
3481e9103aaeSGarrett D'Amore 	argc -= optind;
3482e9103aaeSGarrett D'Amore 	argv += optind;
3483e9103aaeSGarrett D'Amore 
3484e9103aaeSGarrett D'Amore 	/* get pool name and check number of arguments */
3485e9103aaeSGarrett D'Amore 	if (argc < 1) {
3486e9103aaeSGarrett D'Amore 		(void) fprintf(stderr, gettext("missing pool name\n"));
3487e9103aaeSGarrett D'Amore 		usage(B_FALSE);
3488e9103aaeSGarrett D'Amore 	}
3489e9103aaeSGarrett D'Amore 
3490e9103aaeSGarrett D'Amore 	if (argc > 1) {
3491e9103aaeSGarrett D'Amore 		(void) fprintf(stderr, gettext("too many arguments\n"));
3492e9103aaeSGarrett D'Amore 		usage(B_FALSE);
3493e9103aaeSGarrett D'Amore 	}
3494e9103aaeSGarrett D'Amore 
3495e9103aaeSGarrett D'Amore 	poolname = argv[0];
3496e9103aaeSGarrett D'Amore 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3497e9103aaeSGarrett D'Amore 		return (1);
3498e9103aaeSGarrett D'Amore 
3499e9103aaeSGarrett D'Amore 	ret = zpool_reguid(zhp);
3500e9103aaeSGarrett D'Amore 
3501e9103aaeSGarrett D'Amore 	zpool_close(zhp);
3502e9103aaeSGarrett D'Amore 	return (ret);
3503e9103aaeSGarrett D'Amore }
3504e9103aaeSGarrett D'Amore 
3505e9103aaeSGarrett D'Amore 
35064263d13fSGeorge Wilson /*
35074263d13fSGeorge Wilson  * zpool reopen <pool>
35084263d13fSGeorge Wilson  *
35094263d13fSGeorge Wilson  * Reopen the pool so that the kernel can update the sizes of all vdevs.
35104263d13fSGeorge Wilson  *
35114263d13fSGeorge Wilson  * NOTE: This command is currently undocumented.  If the command is ever
35124263d13fSGeorge Wilson  * exposed then the appropriate usage() messages will need to be made.
35134263d13fSGeorge Wilson  */
35144263d13fSGeorge Wilson int
35154263d13fSGeorge Wilson zpool_do_reopen(int argc, char **argv)
35164263d13fSGeorge Wilson {
35174263d13fSGeorge Wilson 	int ret = 0;
35184263d13fSGeorge Wilson 	zpool_handle_t *zhp;
35194263d13fSGeorge Wilson 	char *pool;
35204263d13fSGeorge Wilson 
35214263d13fSGeorge Wilson 	argc--;
35224263d13fSGeorge Wilson 	argv++;
35234263d13fSGeorge Wilson 
35244263d13fSGeorge Wilson 	if (argc != 1)
35254263d13fSGeorge Wilson 		return (2);
35264263d13fSGeorge Wilson 
35274263d13fSGeorge Wilson 	pool = argv[0];
35284263d13fSGeorge Wilson 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
35294263d13fSGeorge Wilson 		return (1);
35304263d13fSGeorge Wilson 
35314263d13fSGeorge Wilson 	ret = zpool_reopen(zhp);
35324263d13fSGeorge Wilson 	zpool_close(zhp);
35334263d13fSGeorge Wilson 	return (ret);
35344263d13fSGeorge Wilson }
35354263d13fSGeorge Wilson 
3536fa9e4066Sahrens typedef struct scrub_cbdata {
3537fa9e4066Sahrens 	int	cb_type;
353806eeb2adSek 	int	cb_argc;
353906eeb2adSek 	char	**cb_argv;
3540fa9e4066Sahrens } scrub_cbdata_t;
3541fa9e4066Sahrens 
3542fa9e4066Sahrens int
3543fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
3544fa9e4066Sahrens {
3545fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
354606eeb2adSek 	int err;
3547fa9e4066Sahrens 
3548ea8dc4b6Seschrock 	/*
3549ea8dc4b6Seschrock 	 * Ignore faulted pools.
3550ea8dc4b6Seschrock 	 */
3551ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
3552ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
3553ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
3554ea8dc4b6Seschrock 		return (1);
3555ea8dc4b6Seschrock 	}
3556ea8dc4b6Seschrock 
35573f9d6ad7SLin Ling 	err = zpool_scan(zhp, cb->cb_type);
355806eeb2adSek 
355906eeb2adSek 	return (err != 0);
3560fa9e4066Sahrens }
3561fa9e4066Sahrens 
3562fa9e4066Sahrens /*
3563fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
3564fa9e4066Sahrens  *
3565fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
3566fa9e4066Sahrens  */
3567fa9e4066Sahrens int
3568fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
3569fa9e4066Sahrens {
3570fa9e4066Sahrens 	int c;
3571fa9e4066Sahrens 	scrub_cbdata_t cb;
3572fa9e4066Sahrens 
35733f9d6ad7SLin Ling 	cb.cb_type = POOL_SCAN_SCRUB;
3574fa9e4066Sahrens 
3575fa9e4066Sahrens 	/* check options */
3576fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
3577fa9e4066Sahrens 		switch (c) {
3578fa9e4066Sahrens 		case 's':
35793f9d6ad7SLin Ling 			cb.cb_type = POOL_SCAN_NONE;
3580fa9e4066Sahrens 			break;
3581fa9e4066Sahrens 		case '?':
3582fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3583fa9e4066Sahrens 			    optopt);
358499653d4eSeschrock 			usage(B_FALSE);
3585fa9e4066Sahrens 		}
3586fa9e4066Sahrens 	}
3587fa9e4066Sahrens 
358806eeb2adSek 	cb.cb_argc = argc;
358906eeb2adSek 	cb.cb_argv = argv;
3590fa9e4066Sahrens 	argc -= optind;
3591fa9e4066Sahrens 	argv += optind;
3592fa9e4066Sahrens 
3593fa9e4066Sahrens 	if (argc < 1) {
3594fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
359599653d4eSeschrock 		usage(B_FALSE);
3596fa9e4066Sahrens 	}
3597fa9e4066Sahrens 
3598b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
3599fa9e4066Sahrens }
3600fa9e4066Sahrens 
3601fa9e4066Sahrens typedef struct status_cbdata {
360299653d4eSeschrock 	int		cb_count;
3603e9dbad6fSeschrock 	boolean_t	cb_allpools;
360499653d4eSeschrock 	boolean_t	cb_verbose;
360599653d4eSeschrock 	boolean_t	cb_explain;
360699653d4eSeschrock 	boolean_t	cb_first;
36079eb19f4dSGeorge Wilson 	boolean_t	cb_dedup_stats;
3608fa9e4066Sahrens } status_cbdata_t;
3609fa9e4066Sahrens 
3610fa9e4066Sahrens /*
3611fa9e4066Sahrens  * Print out detailed scrub status.
3612fa9e4066Sahrens  */
3613fa9e4066Sahrens void
36143f9d6ad7SLin Ling print_scan_status(pool_scan_stat_t *ps)
3615fa9e4066Sahrens {
36163f9d6ad7SLin Ling 	time_t start, end;
361773d314ceSLin Ling 	uint64_t elapsed, mins_left, hours_left;
36183f9d6ad7SLin Ling 	uint64_t pass_exam, examined, total;
36193f9d6ad7SLin Ling 	uint_t rate;
3620fa9e4066Sahrens 	double fraction_done;
36213f9d6ad7SLin Ling 	char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
3622fa9e4066Sahrens 
3623ce72e614SYuri Pankov 	(void) printf(gettext("  scan: "));
3624fa9e4066Sahrens 
36253f9d6ad7SLin Ling 	/* If there's never been a scan, there's not much to say. */
36263f9d6ad7SLin Ling 	if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
36273f9d6ad7SLin Ling 	    ps->pss_func >= POOL_SCAN_FUNCS) {
3628fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
3629fa9e4066Sahrens 		return;
3630fa9e4066Sahrens 	}
3631fa9e4066Sahrens 
36323f9d6ad7SLin Ling 	start = ps->pss_start_time;
36333f9d6ad7SLin Ling 	end = ps->pss_end_time;
36343f9d6ad7SLin Ling 	zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
3635fa9e4066Sahrens 
36363f9d6ad7SLin Ling 	assert(ps->pss_func == POOL_SCAN_SCRUB ||
36373f9d6ad7SLin Ling 	    ps->pss_func == POOL_SCAN_RESILVER);
36383f9d6ad7SLin Ling 	/*
36393f9d6ad7SLin Ling 	 * Scan is finished or canceled.
36403f9d6ad7SLin Ling 	 */
36413f9d6ad7SLin Ling 	if (ps->pss_state == DSS_FINISHED) {
36423f9d6ad7SLin Ling 		uint64_t minutes_taken = (end - start) / 60;
36433f9d6ad7SLin Ling 		char *fmt;
36443f9d6ad7SLin Ling 
36453f9d6ad7SLin Ling 		if (ps->pss_func == POOL_SCAN_SCRUB) {
36463f9d6ad7SLin Ling 			fmt = gettext("scrub repaired %s in %lluh%um with "
36473f9d6ad7SLin Ling 			    "%llu errors on %s");
36483f9d6ad7SLin Ling 		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
36493f9d6ad7SLin Ling 			fmt = gettext("resilvered %s in %lluh%um with "
36503f9d6ad7SLin Ling 			    "%llu errors on %s");
36513f9d6ad7SLin Ling 		}
36523f9d6ad7SLin Ling 		/* LINTED */
36533f9d6ad7SLin Ling 		(void) printf(fmt, processed_buf,
365418ce54dfSek 		    (u_longlong_t)(minutes_taken / 60),
365518ce54dfSek 		    (uint_t)(minutes_taken % 60),
36563f9d6ad7SLin Ling 		    (u_longlong_t)ps->pss_errors,
36573f9d6ad7SLin Ling 		    ctime((time_t *)&end));
36583f9d6ad7SLin Ling 		return;
36593f9d6ad7SLin Ling 	} else if (ps->pss_state == DSS_CANCELED) {
36603f9d6ad7SLin Ling 		if (ps->pss_func == POOL_SCAN_SCRUB) {
36613f9d6ad7SLin Ling 			(void) printf(gettext("scrub canceled on %s"),
36623f9d6ad7SLin Ling 			    ctime(&end));
36633f9d6ad7SLin Ling 		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
36643f9d6ad7SLin Ling 			(void) printf(gettext("resilver canceled on %s"),
36653f9d6ad7SLin Ling 			    ctime(&end));
36663f9d6ad7SLin Ling 		}
3667fa9e4066Sahrens 		return;
3668fa9e4066Sahrens 	}
3669fa9e4066Sahrens 
36703f9d6ad7SLin Ling 	assert(ps->pss_state == DSS_SCANNING);
36713f9d6ad7SLin Ling 
36723f9d6ad7SLin Ling 	/*
36733f9d6ad7SLin Ling 	 * Scan is in progress.
36743f9d6ad7SLin Ling 	 */
36753f9d6ad7SLin Ling 	if (ps->pss_func == POOL_SCAN_SCRUB) {
36763f9d6ad7SLin Ling 		(void) printf(gettext("scrub in progress since %s"),
36773f9d6ad7SLin Ling 		    ctime(&start));
36783f9d6ad7SLin Ling 	} else if (ps->pss_func == POOL_SCAN_RESILVER) {
36793f9d6ad7SLin Ling 		(void) printf(gettext("resilver in progress since %s"),
36803f9d6ad7SLin Ling 		    ctime(&start));
36813f9d6ad7SLin Ling 	}
3682fa9e4066Sahrens 
36833f9d6ad7SLin Ling 	examined = ps->pss_examined ? ps->pss_examined : 1;
36843f9d6ad7SLin Ling 	total = ps->pss_to_examine;
3685fa9e4066Sahrens 	fraction_done = (double)examined / total;
36863f9d6ad7SLin Ling 
36873f9d6ad7SLin Ling 	/* elapsed time for this pass */
36883f9d6ad7SLin Ling 	elapsed = time(NULL) - ps->pss_pass_start;
36893f9d6ad7SLin Ling 	elapsed = elapsed ? elapsed : 1;
36903f9d6ad7SLin Ling 	pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1;
36913f9d6ad7SLin Ling 	rate = pass_exam / elapsed;
36923f9d6ad7SLin Ling 	rate = rate ? rate : 1;
36933f9d6ad7SLin Ling 	mins_left = ((total - examined) / rate) / 60;
369473d314ceSLin Ling 	hours_left = mins_left / 60;
36953f9d6ad7SLin Ling 
36963f9d6ad7SLin Ling 	zfs_nicenum(examined, examined_buf, sizeof (examined_buf));
36973f9d6ad7SLin Ling 	zfs_nicenum(total, total_buf, sizeof (total_buf));
36983f9d6ad7SLin Ling 	zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
36993f9d6ad7SLin Ling 
370073d314ceSLin Ling 	/*
370173d314ceSLin Ling 	 * do not print estimated time if hours_left is more than 30 days
370273d314ceSLin Ling 	 */
370373d314ceSLin Ling 	(void) printf(gettext("    %s scanned out of %s at %s/s"),
370473d314ceSLin Ling 	    examined_buf, total_buf, rate_buf);
370573d314ceSLin Ling 	if (hours_left < (30 * 24)) {
370673d314ceSLin Ling 		(void) printf(gettext(", %lluh%um to go\n"),
370773d314ceSLin Ling 		    (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
370873d314ceSLin Ling 	} else {
370973d314ceSLin Ling 		(void) printf(gettext(
371073d314ceSLin Ling 		    ", (scan is slow, no estimated time)\n"));
371173d314ceSLin Ling 	}
37123f9d6ad7SLin Ling 
37133f9d6ad7SLin Ling 	if (ps->pss_func == POOL_SCAN_RESILVER) {
37143f9d6ad7SLin Ling 		(void) printf(gettext("    %s resilvered, %.2f%% done\n"),
37153f9d6ad7SLin Ling 		    processed_buf, 100 * fraction_done);
37163f9d6ad7SLin Ling 	} else if (ps->pss_func == POOL_SCAN_SCRUB) {
37173f9d6ad7SLin Ling 		(void) printf(gettext("    %s repaired, %.2f%% done\n"),
37183f9d6ad7SLin Ling 		    processed_buf, 100 * fraction_done);
37193f9d6ad7SLin Ling 	}
3720fa9e4066Sahrens }
3721fa9e4066Sahrens 
3722ea8dc4b6Seschrock static void
3723ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
3724ea8dc4b6Seschrock {
372575519f38Sek 	nvlist_t *nverrlist = NULL;
372655434c77Sek 	nvpair_t *elem;
372755434c77Sek 	char *pathname;
372855434c77Sek 	size_t len = MAXPATHLEN * 2;
3729ea8dc4b6Seschrock 
373055434c77Sek 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
3731ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
3732ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
3733ea8dc4b6Seschrock 		return;
3734ea8dc4b6Seschrock 	}
3735ea8dc4b6Seschrock 
373655434c77Sek 	(void) printf("errors: Permanent errors have been "
373755434c77Sek 	    "detected in the following files:\n\n");
3738ea8dc4b6Seschrock 
373955434c77Sek 	pathname = safe_malloc(len);
374055434c77Sek 	elem = NULL;
374155434c77Sek 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
374255434c77Sek 		nvlist_t *nv;
374355434c77Sek 		uint64_t dsobj, obj;
374455434c77Sek 
374555434c77Sek 		verify(nvpair_value_nvlist(elem, &nv) == 0);
374655434c77Sek 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
374755434c77Sek 		    &dsobj) == 0);
374855434c77Sek 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
374955434c77Sek 		    &obj) == 0);
375055434c77Sek 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
375155434c77Sek 		(void) printf("%7s %s\n", "", pathname);
375255434c77Sek 	}
375355434c77Sek 	free(pathname);
375455434c77Sek 	nvlist_free(nverrlist);
3755ea8dc4b6Seschrock }
3756ea8dc4b6Seschrock 
375799653d4eSeschrock static void
375899653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
375999653d4eSeschrock     int namewidth)
376099653d4eSeschrock {
376199653d4eSeschrock 	uint_t i;
376299653d4eSeschrock 	char *name;
376399653d4eSeschrock 
376499653d4eSeschrock 	if (nspares == 0)
376599653d4eSeschrock 		return;
376699653d4eSeschrock 
376799653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
376899653d4eSeschrock 
376999653d4eSeschrock 	for (i = 0; i < nspares; i++) {
377088ecc943SGeorge Wilson 		name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE);
377199653d4eSeschrock 		print_status_config(zhp, name, spares[i],
3772aa8cf21aSNeil Perrin 		    namewidth, 2, B_TRUE);
377399653d4eSeschrock 		free(name);
377499653d4eSeschrock 	}
377599653d4eSeschrock }
377699653d4eSeschrock 
3777fa94a07fSbrendan static void
3778fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
3779fa94a07fSbrendan     int namewidth)
3780fa94a07fSbrendan {
3781fa94a07fSbrendan 	uint_t i;
3782fa94a07fSbrendan 	char *name;
3783fa94a07fSbrendan 
3784fa94a07fSbrendan 	if (nl2cache == 0)
3785fa94a07fSbrendan 		return;
3786fa94a07fSbrendan 
3787fa94a07fSbrendan 	(void) printf(gettext("\tcache\n"));
3788fa94a07fSbrendan 
3789fa94a07fSbrendan 	for (i = 0; i < nl2cache; i++) {
379088ecc943SGeorge Wilson 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE);
3791fa94a07fSbrendan 		print_status_config(zhp, name, l2cache[i],
3792aa8cf21aSNeil Perrin 		    namewidth, 2, B_FALSE);
3793aa8cf21aSNeil Perrin 		free(name);
3794aa8cf21aSNeil Perrin 	}
3795aa8cf21aSNeil Perrin }
3796aa8cf21aSNeil Perrin 
37979eb19f4dSGeorge Wilson static void
37989eb19f4dSGeorge Wilson print_dedup_stats(nvlist_t *config)
37999eb19f4dSGeorge Wilson {
38009eb19f4dSGeorge Wilson 	ddt_histogram_t *ddh;
38019eb19f4dSGeorge Wilson 	ddt_stat_t *dds;
38029eb19f4dSGeorge Wilson 	ddt_object_t *ddo;
38039eb19f4dSGeorge Wilson 	uint_t c;
38049eb19f4dSGeorge Wilson 
38059eb19f4dSGeorge Wilson 	/*
38069eb19f4dSGeorge Wilson 	 * If the pool was faulted then we may not have been able to
38072384d9f8SGeorge Wilson 	 * obtain the config. Otherwise, if we have anything in the dedup
38089eb19f4dSGeorge Wilson 	 * table continue processing the stats.
38099eb19f4dSGeorge Wilson 	 */
38109eb19f4dSGeorge Wilson 	if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
3811ce72e614SYuri Pankov 	    (uint64_t **)&ddo, &c) != 0)
38129eb19f4dSGeorge Wilson 		return;
38139eb19f4dSGeorge Wilson 
38149eb19f4dSGeorge Wilson 	(void) printf("\n");
3815ce72e614SYuri Pankov 	(void) printf(gettext(" dedup: "));
3816ce72e614SYuri Pankov 	if (ddo->ddo_count == 0) {
3817ce72e614SYuri Pankov 		(void) printf(gettext("no DDT entries\n"));
3818ce72e614SYuri Pankov 		return;
3819ce72e614SYuri Pankov 	}
3820ce72e614SYuri Pankov 
38219eb19f4dSGeorge Wilson 	(void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
38229eb19f4dSGeorge Wilson 	    (u_longlong_t)ddo->ddo_count,
38239eb19f4dSGeorge Wilson 	    (u_longlong_t)ddo->ddo_dspace,
38249eb19f4dSGeorge Wilson 	    (u_longlong_t)ddo->ddo_mspace);
38259eb19f4dSGeorge Wilson 
38269eb19f4dSGeorge Wilson 	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
38279eb19f4dSGeorge Wilson 	    (uint64_t **)&dds, &c) == 0);
38289eb19f4dSGeorge Wilson 	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
38299eb19f4dSGeorge Wilson 	    (uint64_t **)&ddh, &c) == 0);
38309eb19f4dSGeorge Wilson 	zpool_dump_ddt(dds, ddh);
38319eb19f4dSGeorge Wilson }
38329eb19f4dSGeorge Wilson 
3833fa9e4066Sahrens /*
3834fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
3835fa9e4066Sahrens  *
3836fa9e4066Sahrens  *        pool: tank
3837fa9e4066Sahrens  *	status: DEGRADED
3838fa9e4066Sahrens  *	reason: One or more devices ...
3839654b400cSJoshua M. Clulow  *         see: http://illumos.org/msg/ZFS-xxxx-01
3840fa9e4066Sahrens  *	config:
3841fa9e4066Sahrens  *		mirror		DEGRADED
3842fa9e4066Sahrens  *                c1t0d0	OK
3843ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
3844fa9e4066Sahrens  *
3845fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
3846fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
3847fa9e4066Sahrens  */
3848fa9e4066Sahrens int
3849fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
3850fa9e4066Sahrens {
3851fa9e4066Sahrens 	status_cbdata_t *cbp = data;
3852fa9e4066Sahrens 	nvlist_t *config, *nvroot;
3853fa9e4066Sahrens 	char *msgid;
3854fa9e4066Sahrens 	int reason;
385546657f8dSmmusante 	const char *health;
385646657f8dSmmusante 	uint_t c;
385746657f8dSmmusante 	vdev_stat_t *vs;
3858fa9e4066Sahrens 
3859088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
3860fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
3861fa9e4066Sahrens 
3862fa9e4066Sahrens 	cbp->cb_count++;
3863fa9e4066Sahrens 
3864fa9e4066Sahrens 	/*
3865fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
3866fa9e4066Sahrens 	 * problems.
3867fa9e4066Sahrens 	 */
3868e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
3869e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
3870e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
3871e9dbad6fSeschrock 			    zpool_get_name(zhp));
3872e9dbad6fSeschrock 			if (cbp->cb_first)
3873e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
3874e9dbad6fSeschrock 		}
3875fa9e4066Sahrens 		return (0);
3876e9dbad6fSeschrock 	}
3877fa9e4066Sahrens 
3878fa9e4066Sahrens 	if (cbp->cb_first)
387999653d4eSeschrock 		cbp->cb_first = B_FALSE;
3880fa9e4066Sahrens 	else
3881fa9e4066Sahrens 		(void) printf("\n");
3882fa9e4066Sahrens 
388346657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
388446657f8dSmmusante 	    &nvroot) == 0);
38853f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
388646657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
3887990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3888fa9e4066Sahrens 
3889fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
3890fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
3891fa9e4066Sahrens 
3892fa9e4066Sahrens 	switch (reason) {
3893fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
3894fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3895fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
3896fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
3897fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3898fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3899fa9e4066Sahrens 		break;
3900fa9e4066Sahrens 
3901fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
3902fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3903fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
3904fa9e4066Sahrens 		    "pool to continue functioning.\n"));
3905fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3906fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3907fa9e4066Sahrens 		break;
3908fa9e4066Sahrens 
3909fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
3910fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3911fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
3912fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
3913fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
3914fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
3915fa9e4066Sahrens 		    "'zpool replace'.\n"));
3916fa9e4066Sahrens 		break;
3917fa9e4066Sahrens 
3918fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3919fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3920b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
3921fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
3922fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
3923468c413aSTim Haley 		zpool_explain_recover(zpool_get_handle(zhp),
3924468c413aSTim Haley 		    zpool_get_name(zhp), reason, config);
3925fa9e4066Sahrens 		break;
3926fa9e4066Sahrens 
3927fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
3928fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3929fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
3930fa9e4066Sahrens 		    "made to correct the error.  Applications are "
3931fa9e4066Sahrens 		    "unaffected.\n"));
3932fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
3933fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
3934ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
3935fa9e4066Sahrens 		    "replace'.\n"));
3936fa9e4066Sahrens 		break;
3937fa9e4066Sahrens 
3938fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
3939fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3940d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
3941fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
3942fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
3943fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
3944fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
3945fa9e4066Sahrens 		    "replace'.\n"));
3946fa9e4066Sahrens 		break;
3947fa9e4066Sahrens 
3948c25309d4SGeorge Wilson 	case ZPOOL_STATUS_REMOVED_DEV:
3949c25309d4SGeorge Wilson 		(void) printf(gettext("status: One or more devices has "
3950c25309d4SGeorge Wilson 		    "been removed by the administrator.\n\tSufficient "
3951c25309d4SGeorge Wilson 		    "replicas exist for the pool to continue functioning in "
3952c25309d4SGeorge Wilson 		    "a\n\tdegraded state.\n"));
3953c25309d4SGeorge Wilson 		(void) printf(gettext("action: Online the device using "
3954c25309d4SGeorge Wilson 		    "'zpool online' or replace the device with\n\t'zpool "
3955c25309d4SGeorge Wilson 		    "replace'.\n"));
3956c25309d4SGeorge Wilson 		break;
3957c25309d4SGeorge Wilson 
3958fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
3959fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
3960fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3961fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
3962fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3963fa9e4066Sahrens 		    "complete.\n"));
3964fa9e4066Sahrens 		break;
3965fa9e4066Sahrens 
3966ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3967ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3968ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3969ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3970ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3971ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3972ea8dc4b6Seschrock 		    "backup.\n"));
3973ea8dc4b6Seschrock 		break;
3974ea8dc4b6Seschrock 
3975ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3976ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3977ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3978468c413aSTim Haley 		zpool_explain_recover(zpool_get_handle(zhp),
3979468c413aSTim Haley 		    zpool_get_name(zhp), reason, config);
3980ea8dc4b6Seschrock 		break;
3981ea8dc4b6Seschrock 
3982eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3983eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3984eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3985eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3986eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3987eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3988eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3989eaca9bbdSeschrock 		break;
3990eaca9bbdSeschrock 
3991eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3992eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3993eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3994eaca9bbdSeschrock 		    "be accessed on this system.\n"));
3995eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
3996eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
3997eaca9bbdSeschrock 		    "backup.\n"));
3998eaca9bbdSeschrock 		break;
3999eaca9bbdSeschrock 
4000*ad135b5dSChristopher Siden 	case ZPOOL_STATUS_UNSUP_FEAT_READ:
4001*ad135b5dSChristopher Siden 		(void) printf(gettext("status: The pool cannot be accessed on "
4002*ad135b5dSChristopher Siden 		    "this system because it uses the\n\tfollowing feature(s) "
4003*ad135b5dSChristopher Siden 		    "not supported on this system:\n"));
4004*ad135b5dSChristopher Siden 		zpool_print_unsup_feat(config);
4005*ad135b5dSChristopher Siden 		(void) printf("\n");
4006*ad135b5dSChristopher Siden 		(void) printf(gettext("action: Access the pool from a system "
4007*ad135b5dSChristopher Siden 		    "that supports the required feature(s),\n\tor restore the "
4008*ad135b5dSChristopher Siden 		    "pool from backup.\n"));
4009*ad135b5dSChristopher Siden 		break;
4010*ad135b5dSChristopher Siden 
4011*ad135b5dSChristopher Siden 	case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
4012*ad135b5dSChristopher Siden 		(void) printf(gettext("status: The pool can only be accessed "
4013*ad135b5dSChristopher Siden 		    "in read-only mode on this system. It\n\tcannot be "
4014*ad135b5dSChristopher Siden 		    "accessed in read-write mode because it uses the "
4015*ad135b5dSChristopher Siden 		    "following\n\tfeature(s) not supported on this system:\n"));
4016*ad135b5dSChristopher Siden 		zpool_print_unsup_feat(config);
4017*ad135b5dSChristopher Siden 		(void) printf("\n");
4018*ad135b5dSChristopher Siden 		(void) printf(gettext("action: The pool cannot be accessed in "
4019*ad135b5dSChristopher Siden 		    "read-write mode. Import the pool with\n"
4020*ad135b5dSChristopher Siden 		    "\t\"-o readonly=on\", access the pool from a system that "
4021*ad135b5dSChristopher Siden 		    "supports the\n\trequired feature(s), or restore the "
4022*ad135b5dSChristopher Siden 		    "pool from backup.\n"));
4023*ad135b5dSChristopher Siden 		break;
4024*ad135b5dSChristopher Siden 
40253d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
40263d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
40273d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
40283d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
40293d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
40303d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
40313d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
40323d7072f8Seschrock 		break;
40333d7072f8Seschrock 
40343d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
40353d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
40363d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
40373d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
40383d7072f8Seschrock 		    "functioning.\n"));
40393d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
40403d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
40413d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
40423d7072f8Seschrock 		    "to be recovered.\n"));
40433d7072f8Seschrock 		break;
40443d7072f8Seschrock 
404532b87932Sek 	case ZPOOL_STATUS_IO_FAILURE_WAIT:
404632b87932Sek 	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
404732b87932Sek 		(void) printf(gettext("status: One or more devices are "
40488a79c1b5Sek 		    "faulted in response to IO failures.\n"));
404932b87932Sek 		(void) printf(gettext("action: Make sure the affected devices "
405032b87932Sek 		    "are connected, then run 'zpool clear'.\n"));
405132b87932Sek 		break;
405232b87932Sek 
4053b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
4054b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record "
4055b87f3af3Sperrin 		    "could not be read.\n"
4056b87f3af3Sperrin 		    "\tWaiting for adminstrator intervention to fix the "
4057b87f3af3Sperrin 		    "faulted pool.\n"));
4058b87f3af3Sperrin 		(void) printf(gettext("action: Either restore the affected "
4059b87f3af3Sperrin 		    "device(s) and run 'zpool online',\n"
4060b87f3af3Sperrin 		    "\tor ignore the intent log records by running "
4061b87f3af3Sperrin 		    "'zpool clear'.\n"));
4062b87f3af3Sperrin 		break;
4063b87f3af3Sperrin 
4064fa9e4066Sahrens 	default:
4065fa9e4066Sahrens 		/*
4066fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
4067fa9e4066Sahrens 		 */
4068fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
4069fa9e4066Sahrens 	}
4070fa9e4066Sahrens 
4071fa9e4066Sahrens 	if (msgid != NULL)
4072654b400cSJoshua M. Clulow 		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
4073fa9e4066Sahrens 		    msgid);
4074fa9e4066Sahrens 
4075fa9e4066Sahrens 	if (config != NULL) {
4076fa9e4066Sahrens 		int namewidth;
4077ea8dc4b6Seschrock 		uint64_t nerr;
4078fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
4079fa94a07fSbrendan 		uint_t nspares, nl2cache;
40803f9d6ad7SLin Ling 		pool_scan_stat_t *ps = NULL;
4081fa9e4066Sahrens 
40823f9d6ad7SLin Ling 		(void) nvlist_lookup_uint64_array(nvroot,
40833f9d6ad7SLin Ling 		    ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
40843f9d6ad7SLin Ling 		print_scan_status(ps);
4085fa9e4066Sahrens 
4086c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
4087fa9e4066Sahrens 		if (namewidth < 10)
4088fa9e4066Sahrens 			namewidth = 10;
4089fa9e4066Sahrens 
4090fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
4091fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
4092fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
4093c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
4094aa8cf21aSNeil Perrin 		    namewidth, 0, B_FALSE);
409599653d4eSeschrock 
40964dea40f0SNeil Perrin 		if (num_logs(nvroot) > 0)
4097e6ca193dSGeorge Wilson 			print_logs(zhp, nvroot, namewidth, B_TRUE);
4098fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
4099fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
4100fa94a07fSbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
4101fa94a07fSbrendan 
410299653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
410399653d4eSeschrock 		    &spares, &nspares) == 0)
410499653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
4105ea8dc4b6Seschrock 
4106ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
4107ea8dc4b6Seschrock 		    &nerr) == 0) {
410855434c77Sek 			nvlist_t *nverrlist = NULL;
410955434c77Sek 
4110ea8dc4b6Seschrock 			/*
4111ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
4112ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
4113ea8dc4b6Seschrock 			 * uniquifying the results.
4114ea8dc4b6Seschrock 			 */
411575519f38Sek 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
411655434c77Sek 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
411755434c77Sek 				nvpair_t *elem;
411855434c77Sek 
411955434c77Sek 				elem = NULL;
412055434c77Sek 				nerr = 0;
412155434c77Sek 				while ((elem = nvlist_next_nvpair(nverrlist,
412255434c77Sek 				    elem)) != NULL) {
412355434c77Sek 					nerr++;
412455434c77Sek 				}
412555434c77Sek 			}
412655434c77Sek 			nvlist_free(nverrlist);
4127ea8dc4b6Seschrock 
4128ea8dc4b6Seschrock 			(void) printf("\n");
412999653d4eSeschrock 
4130ea8dc4b6Seschrock 			if (nerr == 0)
4131ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
4132ea8dc4b6Seschrock 				    "errors\n"));
4133ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
4134e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
41355ad82045Snd 				    "errors, use '-v' for a list\n"),
41365ad82045Snd 				    (u_longlong_t)nerr);
4137ea8dc4b6Seschrock 			else
4138ea8dc4b6Seschrock 				print_error_log(zhp);
4139ea8dc4b6Seschrock 		}
41409eb19f4dSGeorge Wilson 
41419eb19f4dSGeorge Wilson 		if (cbp->cb_dedup_stats)
41429eb19f4dSGeorge Wilson 			print_dedup_stats(config);
4143fa9e4066Sahrens 	} else {
4144fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
4145fa9e4066Sahrens 		    "determined.\n"));
4146fa9e4066Sahrens 	}
4147fa9e4066Sahrens 
4148fa9e4066Sahrens 	return (0);
4149fa9e4066Sahrens }
4150fa9e4066Sahrens 
4151fa9e4066Sahrens /*
41523f9d6ad7SLin Ling  * zpool status [-vx] [-T d|u] [pool] ... [interval [count]]
4153fa9e4066Sahrens  *
4154fa9e4066Sahrens  *	-v	Display complete error logs
4155fa9e4066Sahrens  *	-x	Display only pools with potential problems
41569eb19f4dSGeorge Wilson  *	-D	Display dedup status (undocumented)
41573f9d6ad7SLin Ling  *	-T	Display a timestamp in date(1) or Unix format
4158fa9e4066Sahrens  *
4159fa9e4066Sahrens  * Describes the health status of all pools or some subset.
4160fa9e4066Sahrens  */
4161fa9e4066Sahrens int
4162fa9e4066Sahrens zpool_do_status(int argc, char **argv)
4163fa9e4066Sahrens {
4164fa9e4066Sahrens 	int c;
4165fa9e4066Sahrens 	int ret;
41663f9d6ad7SLin Ling 	unsigned long interval = 0, count = 0;
4167fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
4168fa9e4066Sahrens 
4169fa9e4066Sahrens 	/* check options */
41703f9d6ad7SLin Ling 	while ((c = getopt(argc, argv, "vxDT:")) != -1) {
4171fa9e4066Sahrens 		switch (c) {
4172fa9e4066Sahrens 		case 'v':
417399653d4eSeschrock 			cb.cb_verbose = B_TRUE;
4174fa9e4066Sahrens 			break;
4175fa9e4066Sahrens 		case 'x':
417699653d4eSeschrock 			cb.cb_explain = B_TRUE;
4177fa9e4066Sahrens 			break;
41789eb19f4dSGeorge Wilson 		case 'D':
41799eb19f4dSGeorge Wilson 			cb.cb_dedup_stats = B_TRUE;
41809eb19f4dSGeorge Wilson 			break;
41813f9d6ad7SLin Ling 		case 'T':
41823f9d6ad7SLin Ling 			get_timestamp_arg(*optarg);
41833f9d6ad7SLin Ling 			break;
4184fa9e4066Sahrens 		case '?':
4185fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4186fa9e4066Sahrens 			    optopt);
418799653d4eSeschrock 			usage(B_FALSE);
4188fa9e4066Sahrens 		}
4189fa9e4066Sahrens 	}
4190fa9e4066Sahrens 
4191fa9e4066Sahrens 	argc -= optind;
4192fa9e4066Sahrens 	argv += optind;
4193fa9e4066Sahrens 
41943f9d6ad7SLin Ling 	get_interval_count(&argc, argv, &interval, &count);
4195fa9e4066Sahrens 
4196e9dbad6fSeschrock 	if (argc == 0)
4197e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
4198e9dbad6fSeschrock 
41993f9d6ad7SLin Ling 	cb.cb_first = B_TRUE;
4200fa9e4066Sahrens 
42013f9d6ad7SLin Ling 	for (;;) {
42023f9d6ad7SLin Ling 		if (timestamp_fmt != NODATE)
42033f9d6ad7SLin Ling 			print_timestamp(timestamp_fmt);
4204fa9e4066Sahrens 
42053f9d6ad7SLin Ling 		ret = for_each_pool(argc, argv, B_TRUE, NULL,
42063f9d6ad7SLin Ling 		    status_callback, &cb);
42073f9d6ad7SLin Ling 
42083f9d6ad7SLin Ling 		if (argc == 0 && cb.cb_count == 0)
42093f9d6ad7SLin Ling 			(void) printf(gettext("no pools available\n"));
42103f9d6ad7SLin Ling 		else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
42113f9d6ad7SLin Ling 			(void) printf(gettext("all pools are healthy\n"));
42123f9d6ad7SLin Ling 
42133f9d6ad7SLin Ling 		if (ret != 0)
42143f9d6ad7SLin Ling 			return (ret);
42153f9d6ad7SLin Ling 
42163f9d6ad7SLin Ling 		if (interval == 0)
42173f9d6ad7SLin Ling 			break;
42183f9d6ad7SLin Ling 
42193f9d6ad7SLin Ling 		if (count != 0 && --count == 0)
42203f9d6ad7SLin Ling 			break;
42213f9d6ad7SLin Ling 
42223f9d6ad7SLin Ling 		(void) sleep(interval);
42233f9d6ad7SLin Ling 	}
42243f9d6ad7SLin Ling 
42253f9d6ad7SLin Ling 	return (0);
4226fa9e4066Sahrens }
4227fa9e4066Sahrens 
4228eaca9bbdSeschrock typedef struct upgrade_cbdata {
4229eaca9bbdSeschrock 	int	cb_all;
4230eaca9bbdSeschrock 	int	cb_first;
4231eaca9bbdSeschrock 	int	cb_newer;
423206eeb2adSek 	int	cb_argc;
4233990b4856Slling 	uint64_t cb_version;
423406eeb2adSek 	char	**cb_argv;
4235eaca9bbdSeschrock } upgrade_cbdata_t;
4236eaca9bbdSeschrock 
4237eaca9bbdSeschrock static int
4238eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
4239eaca9bbdSeschrock {
4240eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
4241eaca9bbdSeschrock 	nvlist_t *config;
4242eaca9bbdSeschrock 	uint64_t version;
4243eaca9bbdSeschrock 	int ret = 0;
4244eaca9bbdSeschrock 
4245eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
4246eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
4247eaca9bbdSeschrock 	    &version) == 0);
4248eaca9bbdSeschrock 
4249*ad135b5dSChristopher Siden 	if (!cbp->cb_newer && SPA_VERSION_IS_SUPPORTED(version) &&
4250*ad135b5dSChristopher Siden 	    version != SPA_VERSION) {
4251eaca9bbdSeschrock 		if (!cbp->cb_all) {
4252eaca9bbdSeschrock 			if (cbp->cb_first) {
4253eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
4254eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
4255eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
4256eaca9bbdSeschrock 				    "longer be accessible by older software "
4257eaca9bbdSeschrock 				    "versions.\n\n"));
4258eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
4259eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
426099653d4eSeschrock 				cbp->cb_first = B_FALSE;
4261eaca9bbdSeschrock 			}
4262eaca9bbdSeschrock 
42635ad82045Snd 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
4264eaca9bbdSeschrock 			    zpool_get_name(zhp));
4265eaca9bbdSeschrock 		} else {
426699653d4eSeschrock 			cbp->cb_first = B_FALSE;
4267990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
426806eeb2adSek 			if (!ret) {
4269eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
4270990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
427106eeb2adSek 			}
4272eaca9bbdSeschrock 		}
4273*ad135b5dSChristopher Siden 	} else if (cbp->cb_newer && !SPA_VERSION_IS_SUPPORTED(version)) {
4274eaca9bbdSeschrock 		assert(!cbp->cb_all);
4275eaca9bbdSeschrock 
4276eaca9bbdSeschrock 		if (cbp->cb_first) {
4277eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
4278*ad135b5dSChristopher Siden 			    "formatted using an unsupported software version "
4279*ad135b5dSChristopher Siden 			    "and\ncannot be accessed on the current "
4280*ad135b5dSChristopher Siden 			    "system.\n\n"));
4281eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
4282eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
428399653d4eSeschrock 			cbp->cb_first = B_FALSE;
4284eaca9bbdSeschrock 		}
4285eaca9bbdSeschrock 
42865ad82045Snd 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
4287eaca9bbdSeschrock 		    zpool_get_name(zhp));
4288eaca9bbdSeschrock 	}
4289eaca9bbdSeschrock 
4290eaca9bbdSeschrock 	zpool_close(zhp);
4291eaca9bbdSeschrock 	return (ret);
4292eaca9bbdSeschrock }
4293eaca9bbdSeschrock 
4294eaca9bbdSeschrock /* ARGSUSED */
4295eaca9bbdSeschrock static int
429606eeb2adSek upgrade_one(zpool_handle_t *zhp, void *data)
4297eaca9bbdSeschrock {
4298990b4856Slling 	upgrade_cbdata_t *cbp = data;
4299990b4856Slling 	uint64_t cur_version;
4300eaca9bbdSeschrock 	int ret;
4301eaca9bbdSeschrock 
43028654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
43038654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
43048654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
43058654d025Sperrin 		    " to upgrade.\n"));
43068654d025Sperrin 		return (1);
43078654d025Sperrin 	}
4308990b4856Slling 
4309990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
4310e6c728e1Sbrendan 	if (cur_version > cbp->cb_version) {
4311eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
4312e6c728e1Sbrendan 		    "using more current version '%llu'.\n"),
4313e6c728e1Sbrendan 		    zpool_get_name(zhp), cur_version);
4314e6c728e1Sbrendan 		return (0);
4315e6c728e1Sbrendan 	}
4316e6c728e1Sbrendan 	if (cur_version == cbp->cb_version) {
4317e6c728e1Sbrendan 		(void) printf(gettext("Pool '%s' is already formatted "
4318e6c728e1Sbrendan 		    "using the current version.\n"), zpool_get_name(zhp));
4319eaca9bbdSeschrock 		return (0);
4320eaca9bbdSeschrock 	}
4321eaca9bbdSeschrock 
4322990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
432306eeb2adSek 
432406eeb2adSek 	if (!ret) {
432544cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
4326990b4856Slling 		    "from version %llu to version %llu\n\n"),
4327990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
4328990b4856Slling 		    (u_longlong_t)cbp->cb_version);
432906eeb2adSek 	}
4330eaca9bbdSeschrock 
4331eaca9bbdSeschrock 	return (ret != 0);
4332eaca9bbdSeschrock }
4333eaca9bbdSeschrock 
4334eaca9bbdSeschrock /*
4335eaca9bbdSeschrock  * zpool upgrade
4336eaca9bbdSeschrock  * zpool upgrade -v
4337990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
4338eaca9bbdSeschrock  *
4339eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
4340eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
4341eaca9bbdSeschrock  * upgrade all pools.
4342eaca9bbdSeschrock  */
4343eaca9bbdSeschrock int
4344eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
4345eaca9bbdSeschrock {
4346eaca9bbdSeschrock 	int c;
4347eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
4348eaca9bbdSeschrock 	int ret = 0;
4349eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
4350990b4856Slling 	char *end;
4351990b4856Slling 
4352eaca9bbdSeschrock 
4353eaca9bbdSeschrock 	/* check options */
4354478ed9adSEric Taylor 	while ((c = getopt(argc, argv, ":avV:")) != -1) {
4355eaca9bbdSeschrock 		switch (c) {
4356eaca9bbdSeschrock 		case 'a':
435799653d4eSeschrock 			cb.cb_all = B_TRUE;
4358eaca9bbdSeschrock 			break;
4359eaca9bbdSeschrock 		case 'v':
4360eaca9bbdSeschrock 			showversions = B_TRUE;
4361eaca9bbdSeschrock 			break;
4362990b4856Slling 		case 'V':
4363990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
4364*ad135b5dSChristopher Siden 			if (*end != '\0' ||
4365*ad135b5dSChristopher Siden 			    !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) {
4366990b4856Slling 				(void) fprintf(stderr,
4367990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
4368990b4856Slling 				usage(B_FALSE);
4369990b4856Slling 			}
4370990b4856Slling 			break;
4371478ed9adSEric Taylor 		case ':':
4372478ed9adSEric Taylor 			(void) fprintf(stderr, gettext("missing argument for "
4373478ed9adSEric Taylor 			    "'%c' option\n"), optopt);
4374478ed9adSEric Taylor 			usage(B_FALSE);
4375478ed9adSEric Taylor 			break;
4376eaca9bbdSeschrock 		case '?':
4377eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4378eaca9bbdSeschrock 			    optopt);
437999653d4eSeschrock 			usage(B_FALSE);
4380eaca9bbdSeschrock 		}
4381eaca9bbdSeschrock 	}
4382eaca9bbdSeschrock 
438306eeb2adSek 	cb.cb_argc = argc;
438406eeb2adSek 	cb.cb_argv = argv;
4385eaca9bbdSeschrock 	argc -= optind;
4386eaca9bbdSeschrock 	argv += optind;
4387eaca9bbdSeschrock 
4388351420b3Slling 	if (cb.cb_version == 0) {
4389351420b3Slling 		cb.cb_version = SPA_VERSION;
4390351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
4391351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
4392351420b3Slling 		    "incompatible with other arguments\n"));
4393351420b3Slling 		usage(B_FALSE);
4394351420b3Slling 	}
4395351420b3Slling 
4396eaca9bbdSeschrock 	if (showversions) {
4397eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
4398eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
4399eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
440099653d4eSeschrock 			usage(B_FALSE);
4401eaca9bbdSeschrock 		}
4402eaca9bbdSeschrock 	} else if (cb.cb_all) {
4403eaca9bbdSeschrock 		if (argc != 0) {
4404351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
4405351420b3Slling 			    "be used along with a pool name\n"));
440699653d4eSeschrock 			usage(B_FALSE);
4407eaca9bbdSeschrock 		}
4408eaca9bbdSeschrock 	}
4409eaca9bbdSeschrock 
4410*ad135b5dSChristopher Siden 	(void) printf(gettext("This system supports ZFS pool feature "
4411*ad135b5dSChristopher Siden 	    "flags.\n\n"));
441299653d4eSeschrock 	cb.cb_first = B_TRUE;
4413eaca9bbdSeschrock 	if (showversions) {
4414eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
4415d7d4af51Smmusante 		    "supported:\n\n"));
4416eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
4417eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
4418eaca9bbdSeschrock 		    "---------------\n");
441999653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
442044cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
442144cd46caSbillm 		    "(replicated metadata)\n"));
442299653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
442399653d4eSeschrock 		    "RAID-Z\n"));
4424d7306b64Sek 		(void) printf(gettext(" 4   zpool history\n"));
4425c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
4426c9431fa1Sahl 		    "algorithm\n"));
4427990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
44288654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
4429ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
44308eed72d4Sck 		(void) printf(gettext(" 9   refquota and refreservation "
4431a9799022Sck 		    "properties\n"));
4432fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
4433088f3894Sahrens 		(void) printf(gettext(" 11  Improved scrub performance\n"));
4434bb0ade09Sahrens 		(void) printf(gettext(" 12  Snapshot properties\n"));
443574e7dc98SMatthew Ahrens 		(void) printf(gettext(" 13  snapused property\n"));
443614843421SMatthew Ahrens 		(void) printf(gettext(" 14  passthrough-x aclinherit\n"));
443714843421SMatthew Ahrens 		(void) printf(gettext(" 15  user/group space accounting\n"));
4438478ed9adSEric Taylor 		(void) printf(gettext(" 16  stmf property support\n"));
44397aeab329SAdam Leventhal 		(void) printf(gettext(" 17  Triple-parity RAID-Z\n"));
4440b24ab676SJeff Bonwick 		(void) printf(gettext(" 18  Snapshot user holds\n"));
444188ecc943SGeorge Wilson 		(void) printf(gettext(" 19  Log device removal\n"));
4442b24ab676SJeff Bonwick 		(void) printf(gettext(" 20  Compression using zle "
4443b24ab676SJeff Bonwick 		    "(zero-length encoding)\n"));
4444b24ab676SJeff Bonwick 		(void) printf(gettext(" 21  Deduplication\n"));
444592241e0bSTom Erickson 		(void) printf(gettext(" 22  Received properties\n"));
44466e1f5caaSNeil Perrin 		(void) printf(gettext(" 23  Slim ZIL\n"));
44470a586ceaSMark Shellenbaum 		(void) printf(gettext(" 24  System attributes\n"));
44483f9d6ad7SLin Ling 		(void) printf(gettext(" 25  Improved scrub stats\n"));
4449cde58dbcSMatthew Ahrens 		(void) printf(gettext(" 26  Improved snapshot deletion "
4450cde58dbcSMatthew Ahrens 		    "performance\n"));
44516e0cbcaaSMatthew Ahrens 		(void) printf(gettext(" 27  Improved snapshot creation "
44526e0cbcaaSMatthew Ahrens 		    "performance\n"));
4453cb04b873SMark J Musante 		(void) printf(gettext(" 28  Multiple vdev replacements\n"));
4454b24ab676SJeff Bonwick 		(void) printf(gettext("\nFor more information on a particular "
44559a8685acSstephanie scheffler 		    "version, including supported releases,\n"));
44569a8685acSstephanie scheffler 		(void) printf(gettext("see the ZFS Administration Guide.\n\n"));
4457eaca9bbdSeschrock 	} else if (argc == 0) {
4458eaca9bbdSeschrock 		int notfound;
4459eaca9bbdSeschrock 
446099653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
4461eaca9bbdSeschrock 		notfound = cb.cb_first;
4462eaca9bbdSeschrock 
4463eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
4464eaca9bbdSeschrock 			if (!cb.cb_first)
4465eaca9bbdSeschrock 				(void) printf("\n");
4466eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
4467eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
446899653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
4469eaca9bbdSeschrock 			if (!cb.cb_first) {
4470eaca9bbdSeschrock 				notfound = B_FALSE;
4471eaca9bbdSeschrock 				(void) printf("\n");
4472eaca9bbdSeschrock 			}
4473eaca9bbdSeschrock 		}
4474eaca9bbdSeschrock 
4475eaca9bbdSeschrock 		if (ret == 0) {
4476eaca9bbdSeschrock 			if (notfound)
4477eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
4478eaca9bbdSeschrock 				    "using this version.\n"));
4479eaca9bbdSeschrock 			else if (!cb.cb_all)
4480eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
4481eaca9bbdSeschrock 				    "for a list of available versions and "
4482eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
4483eaca9bbdSeschrock 		}
4484eaca9bbdSeschrock 	} else {
4485b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
4486b1b8ab34Slling 		    upgrade_one, &cb);
448706eeb2adSek 	}
448806eeb2adSek 
448906eeb2adSek 	return (ret);
449006eeb2adSek }
449106eeb2adSek 
4492ecd6cf80Smarks typedef struct hist_cbdata {
4493ecd6cf80Smarks 	boolean_t first;
4494ecd6cf80Smarks 	int longfmt;
4495ecd6cf80Smarks 	int internal;
4496ecd6cf80Smarks } hist_cbdata_t;
4497ecd6cf80Smarks 
449806eeb2adSek /*
449906eeb2adSek  * Print out the command history for a specific pool.
450006eeb2adSek  */
450106eeb2adSek static int
450206eeb2adSek get_history_one(zpool_handle_t *zhp, void *data)
450306eeb2adSek {
450406eeb2adSek 	nvlist_t *nvhis;
450506eeb2adSek 	nvlist_t **records;
450606eeb2adSek 	uint_t numrecords;
450706eeb2adSek 	char *cmdstr;
4508ecd6cf80Smarks 	char *pathstr;
450906eeb2adSek 	uint64_t dst_time;
451006eeb2adSek 	time_t tsec;
451106eeb2adSek 	struct tm t;
451206eeb2adSek 	char tbuf[30];
451306eeb2adSek 	int ret, i;
4514ecd6cf80Smarks 	uint64_t who;
4515ecd6cf80Smarks 	struct passwd *pwd;
4516ecd6cf80Smarks 	char *hostname;
4517ecd6cf80Smarks 	char *zonename;
4518ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
4519ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
4520ecd6cf80Smarks 	uint64_t txg;
4521ecd6cf80Smarks 	uint64_t ievent;
452206eeb2adSek 
4523ecd6cf80Smarks 	cb->first = B_FALSE;
452406eeb2adSek 
452506eeb2adSek 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
452606eeb2adSek 
452706eeb2adSek 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
452806eeb2adSek 		return (ret);
452906eeb2adSek 
453006eeb2adSek 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
453106eeb2adSek 	    &records, &numrecords) == 0);
453206eeb2adSek 	for (i = 0; i < numrecords; i++) {
453306eeb2adSek 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
4534ecd6cf80Smarks 		    &dst_time) != 0)
4535ecd6cf80Smarks 			continue;
4536ecd6cf80Smarks 
4537ecd6cf80Smarks 		/* is it an internal event or a standard event? */
4538ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
4539ecd6cf80Smarks 		    &cmdstr) != 0) {
4540ecd6cf80Smarks 			if (cb->internal == 0)
4541ecd6cf80Smarks 				continue;
4542ecd6cf80Smarks 
4543ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
4544ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
4545ecd6cf80Smarks 				continue;
4546ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
4547ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
4548ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
4549ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
4550088f3894Sahrens 			if (ievent >= LOG_END)
4551ecd6cf80Smarks 				continue;
4552ecd6cf80Smarks 			(void) snprintf(internalstr,
4553ecd6cf80Smarks 			    sizeof (internalstr),
4554ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
45553f9d6ad7SLin Ling 			    zfs_history_event_names[ievent], txg,
4556ecd6cf80Smarks 			    pathstr);
4557ecd6cf80Smarks 			cmdstr = internalstr;
455806eeb2adSek 		}
4559ecd6cf80Smarks 		tsec = dst_time;
4560ecd6cf80Smarks 		(void) localtime_r(&tsec, &t);
4561ecd6cf80Smarks 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
4562ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
4563ecd6cf80Smarks 
4564ecd6cf80Smarks 		if (!cb->longfmt) {
4565ecd6cf80Smarks 			(void) printf("\n");
4566ecd6cf80Smarks 			continue;
4567ecd6cf80Smarks 		}
4568ecd6cf80Smarks 		(void) printf(" [");
4569ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
4570ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
4571ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
4572ecd6cf80Smarks 			if (pwd)
4573ecd6cf80Smarks 				(void) printf("user %s on",
4574ecd6cf80Smarks 				    pwd->pw_name);
4575ecd6cf80Smarks 			else
4576ecd6cf80Smarks 				(void) printf("user %d on",
4577ecd6cf80Smarks 				    (int)who);
4578ecd6cf80Smarks 		} else {
4579ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
4580ecd6cf80Smarks 			continue;
4581ecd6cf80Smarks 		}
4582ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
4583ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
4584ecd6cf80Smarks 			(void) printf(" %s", hostname);
4585ecd6cf80Smarks 		}
4586ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
4587ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
4588ecd6cf80Smarks 			(void) printf(":%s", zonename);
4589ecd6cf80Smarks 		}
4590ecd6cf80Smarks 
4591ecd6cf80Smarks 		(void) printf("]");
4592ecd6cf80Smarks 		(void) printf("\n");
459306eeb2adSek 	}
459406eeb2adSek 	(void) printf("\n");
459506eeb2adSek 	nvlist_free(nvhis);
459606eeb2adSek 
459706eeb2adSek 	return (ret);
459806eeb2adSek }
459906eeb2adSek 
460006eeb2adSek /*
460106eeb2adSek  * zpool history <pool>
460206eeb2adSek  *
460306eeb2adSek  * Displays the history of commands that modified pools.
460406eeb2adSek  */
4605ecd6cf80Smarks 
4606ecd6cf80Smarks 
460706eeb2adSek int
460806eeb2adSek zpool_do_history(int argc, char **argv)
460906eeb2adSek {
4610ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
461106eeb2adSek 	int ret;
4612ecd6cf80Smarks 	int c;
461306eeb2adSek 
4614ecd6cf80Smarks 	cbdata.first = B_TRUE;
4615ecd6cf80Smarks 	/* check options */
4616ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
4617ecd6cf80Smarks 		switch (c) {
4618ecd6cf80Smarks 		case 'l':
4619ecd6cf80Smarks 			cbdata.longfmt = 1;
4620ecd6cf80Smarks 			break;
4621ecd6cf80Smarks 		case 'i':
4622ecd6cf80Smarks 			cbdata.internal = 1;
4623ecd6cf80Smarks 			break;
4624ecd6cf80Smarks 		case '?':
4625ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4626ecd6cf80Smarks 			    optopt);
4627ecd6cf80Smarks 			usage(B_FALSE);
4628ecd6cf80Smarks 		}
4629ecd6cf80Smarks 	}
463006eeb2adSek 	argc -= optind;
463106eeb2adSek 	argv += optind;
463206eeb2adSek 
4633b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
4634ecd6cf80Smarks 	    &cbdata);
463506eeb2adSek 
4636ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
463706eeb2adSek 		(void) printf(gettext("no pools available\n"));
463806eeb2adSek 		return (0);
4639eaca9bbdSeschrock 	}
4640eaca9bbdSeschrock 
4641eaca9bbdSeschrock 	return (ret);
4642eaca9bbdSeschrock }
4643eaca9bbdSeschrock 
4644b1b8ab34Slling static int
4645b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
4646b1b8ab34Slling {
4647990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
4648b1b8ab34Slling 	char value[MAXNAMELEN];
4649990b4856Slling 	zprop_source_t srctype;
4650990b4856Slling 	zprop_list_t *pl;
4651b1b8ab34Slling 
4652b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
4653b1b8ab34Slling 
4654b1b8ab34Slling 		/*
4655990b4856Slling 		 * Skip the special fake placeholder. This will also skip
4656990b4856Slling 		 * over the name property when 'all' is specified.
4657b1b8ab34Slling 		 */
4658990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
4659b1b8ab34Slling 		    pl == cbp->cb_proplist)
4660b1b8ab34Slling 			continue;
4661b1b8ab34Slling 
4662*ad135b5dSChristopher Siden 		if (pl->pl_prop == ZPROP_INVAL &&
4663*ad135b5dSChristopher Siden 		    (zpool_prop_feature(pl->pl_user_prop) ||
4664*ad135b5dSChristopher Siden 		    zpool_prop_unsupported(pl->pl_user_prop))) {
4665*ad135b5dSChristopher Siden 			srctype = ZPROP_SRC_LOCAL;
4666b1b8ab34Slling 
4667*ad135b5dSChristopher Siden 			if (zpool_prop_get_feature(zhp, pl->pl_user_prop,
4668*ad135b5dSChristopher Siden 			    value, sizeof (value)) == 0) {
4669*ad135b5dSChristopher Siden 				zprop_print_one_property(zpool_get_name(zhp),
4670*ad135b5dSChristopher Siden 				    cbp, pl->pl_user_prop, value, srctype,
4671*ad135b5dSChristopher Siden 				    NULL, NULL);
4672*ad135b5dSChristopher Siden 			}
4673*ad135b5dSChristopher Siden 		} else {
4674*ad135b5dSChristopher Siden 			if (zpool_get_prop(zhp, pl->pl_prop, value,
4675*ad135b5dSChristopher Siden 			    sizeof (value), &srctype) != 0)
4676*ad135b5dSChristopher Siden 				continue;
4677*ad135b5dSChristopher Siden 
4678*ad135b5dSChristopher Siden 			zprop_print_one_property(zpool_get_name(zhp), cbp,
4679*ad135b5dSChristopher Siden 			    zpool_prop_to_name(pl->pl_prop), value, srctype,
4680*ad135b5dSChristopher Siden 			    NULL, NULL);
4681*ad135b5dSChristopher Siden 		}
4682b1b8ab34Slling 	}
4683b1b8ab34Slling 	return (0);
4684b1b8ab34Slling }
4685b1b8ab34Slling 
4686b1b8ab34Slling int
4687b1b8ab34Slling zpool_do_get(int argc, char **argv)
4688b1b8ab34Slling {
4689990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
4690990b4856Slling 	zprop_list_t fake_name = { 0 };
4691b1b8ab34Slling 	int ret;
4692b1b8ab34Slling 
4693*ad135b5dSChristopher Siden 	if (argc < 2) {
4694*ad135b5dSChristopher Siden 		(void) fprintf(stderr, gettext("missing property "
4695*ad135b5dSChristopher Siden 		    "argument\n"));
4696b1b8ab34Slling 		usage(B_FALSE);
4697*ad135b5dSChristopher Siden 	}
4698b1b8ab34Slling 
4699b1b8ab34Slling 	cb.cb_first = B_TRUE;
4700990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
4701b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
4702b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
4703b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
4704b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
4705990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
4706b1b8ab34Slling 
4707*ad135b5dSChristopher Siden 	if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist,
4708990b4856Slling 	    ZFS_TYPE_POOL) != 0)
4709b1b8ab34Slling 		usage(B_FALSE);
4710b1b8ab34Slling 
4711b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
4712990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
4713b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
4714b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
4715b1b8ab34Slling 		cb.cb_proplist = &fake_name;
4716b1b8ab34Slling 	}
4717b1b8ab34Slling 
4718b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
4719b1b8ab34Slling 	    get_callback, &cb);
4720b1b8ab34Slling 
4721b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
4722990b4856Slling 		zprop_free_list(fake_name.pl_next);
4723b1b8ab34Slling 	else
4724990b4856Slling 		zprop_free_list(cb.cb_proplist);
4725b1b8ab34Slling 
4726b1b8ab34Slling 	return (ret);
4727b1b8ab34Slling }
4728b1b8ab34Slling 
4729b1b8ab34Slling typedef struct set_cbdata {
4730b1b8ab34Slling 	char *cb_propname;
4731b1b8ab34Slling 	char *cb_value;
4732b1b8ab34Slling 	boolean_t cb_any_successful;
4733b1b8ab34Slling } set_cbdata_t;
4734b1b8ab34Slling 
4735b1b8ab34Slling int
4736b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
4737b1b8ab34Slling {
4738b1b8ab34Slling 	int error;
4739b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
4740b1b8ab34Slling 
4741b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
4742b1b8ab34Slling 
4743b1b8ab34Slling 	if (!error)
4744b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
4745b1b8ab34Slling 
4746b1b8ab34Slling 	return (error);
4747b1b8ab34Slling }
4748b1b8ab34Slling 
4749b1b8ab34Slling int
4750b1b8ab34Slling zpool_do_set(int argc, char **argv)
4751b1b8ab34Slling {
4752b1b8ab34Slling 	set_cbdata_t cb = { 0 };
4753b1b8ab34Slling 	int error;
4754b1b8ab34Slling 
4755b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
4756b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4757b1b8ab34Slling 		    argv[1][1]);
4758b1b8ab34Slling 		usage(B_FALSE);
4759b1b8ab34Slling 	}
4760b1b8ab34Slling 
4761b1b8ab34Slling 	if (argc < 2) {
4762b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
4763b1b8ab34Slling 		    "argument\n"));
4764b1b8ab34Slling 		usage(B_FALSE);
4765b1b8ab34Slling 	}
4766b1b8ab34Slling 
4767b1b8ab34Slling 	if (argc < 3) {
4768b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
4769b1b8ab34Slling 		usage(B_FALSE);
4770b1b8ab34Slling 	}
4771b1b8ab34Slling 
4772b1b8ab34Slling 	if (argc > 3) {
4773b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
4774b1b8ab34Slling 		usage(B_FALSE);
4775b1b8ab34Slling 	}
4776b1b8ab34Slling 
4777b1b8ab34Slling 	cb.cb_propname = argv[1];
4778b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
4779b1b8ab34Slling 	if (cb.cb_value == NULL) {
4780b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
4781b1b8ab34Slling 		    "property=value argument\n"));
4782b1b8ab34Slling 		usage(B_FALSE);
4783b1b8ab34Slling 	}
4784b1b8ab34Slling 
4785b1b8ab34Slling 	*(cb.cb_value) = '\0';
4786b1b8ab34Slling 	cb.cb_value++;
4787b1b8ab34Slling 
4788b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
4789b1b8ab34Slling 	    set_callback, &cb);
4790b1b8ab34Slling 
4791b1b8ab34Slling 	return (error);
4792b1b8ab34Slling }
4793b1b8ab34Slling 
4794b1b8ab34Slling static int
4795b1b8ab34Slling find_command_idx(char *command, int *idx)
4796b1b8ab34Slling {
4797b1b8ab34Slling 	int i;
4798b1b8ab34Slling 
4799b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
4800b1b8ab34Slling 		if (command_table[i].name == NULL)
4801b1b8ab34Slling 			continue;
4802b1b8ab34Slling 
4803b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
4804b1b8ab34Slling 			*idx = i;
4805b1b8ab34Slling 			return (0);
4806b1b8ab34Slling 		}
4807b1b8ab34Slling 	}
4808b1b8ab34Slling 	return (1);
4809b1b8ab34Slling }
4810b1b8ab34Slling 
4811fa9e4066Sahrens int
4812fa9e4066Sahrens main(int argc, char **argv)
4813fa9e4066Sahrens {
4814fa9e4066Sahrens 	int ret;
4815fa9e4066Sahrens 	int i;
4816fa9e4066Sahrens 	char *cmdname;
4817fa9e4066Sahrens 
4818fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
4819fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
4820fa9e4066Sahrens 
482199653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
482299653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
4823203a47d8Snd 		    "initialize ZFS library\n"));
482499653d4eSeschrock 		return (1);
482599653d4eSeschrock 	}
482699653d4eSeschrock 
482799653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
482899653d4eSeschrock 
4829fa9e4066Sahrens 	opterr = 0;
4830fa9e4066Sahrens 
4831fa9e4066Sahrens 	/*
4832fa9e4066Sahrens 	 * Make sure the user has specified some command.
4833fa9e4066Sahrens 	 */
4834fa9e4066Sahrens 	if (argc < 2) {
4835fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
483699653d4eSeschrock 		usage(B_FALSE);
4837fa9e4066Sahrens 	}
4838fa9e4066Sahrens 
4839fa9e4066Sahrens 	cmdname = argv[1];
4840fa9e4066Sahrens 
4841fa9e4066Sahrens 	/*
4842fa9e4066Sahrens 	 * Special case '-?'
4843fa9e4066Sahrens 	 */
4844fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
484599653d4eSeschrock 		usage(B_TRUE);
4846fa9e4066Sahrens 
48472a6b87f0Sek 	zpool_set_history_str("zpool", argc, argv, history_str);
48482a6b87f0Sek 	verify(zpool_stage_history(g_zfs, history_str) == 0);
48492a6b87f0Sek 
4850fa9e4066Sahrens 	/*
4851fa9e4066Sahrens 	 * Run the appropriate command.
4852fa9e4066Sahrens 	 */
4853b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
4854b1b8ab34Slling 		current_command = &command_table[i];
4855b1b8ab34Slling 		ret = command_table[i].func(argc - 1, argv + 1);
485691ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
485791ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
485891ebeef5Sahrens 		current_command = &command_table[i];
485991ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
486091ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
486191ebeef5Sahrens 		/*
486291ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
486391ebeef5Sahrens 		 * it as such.
486491ebeef5Sahrens 		 */
4865ea8dc4b6Seschrock 		char buf[16384];
4866ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
4867fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
4868fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
486991ebeef5Sahrens 	} else {
4870fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
4871fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
487299653d4eSeschrock 		usage(B_FALSE);
4873fa9e4066Sahrens 	}
4874fa9e4066Sahrens 
487599653d4eSeschrock 	libzfs_fini(g_zfs);
487699653d4eSeschrock 
4877fa9e4066Sahrens 	/*
4878fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
4879fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
4880fa9e4066Sahrens 	 */
4881fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
4882fa9e4066Sahrens 		(void) printf("dumping core by request\n");
4883fa9e4066Sahrens 		abort();
4884fa9e4066Sahrens 	}
4885fa9e4066Sahrens 
4886fa9e4066Sahrens 	return (ret);
4887fa9e4066Sahrens }
4888