xref: /titanic_53/usr/src/cmd/zpool/zpool_main.c (revision 4445fffbbb1ea25fd0e9ea68b9380dd7a6709025)
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"
54ad135b5dSChristopher 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 
8706eeb2adSek110237 static int zpool_do_history(int, char **);
8806eeb2adSek110237 
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  */
9629ab75c9Srm160521 
9729ab75c9Srm160521 #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 }
10929ab75c9Srm160521 #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,
11906eeb2adSek110237 	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		},
17806eeb2adSek110237 	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
179e9103aaeSGarrett D'Amore 	{ "reguid",	zpool_do_reguid,	HELP_REGUID		},
18006eeb2adSek110237 	{ 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 
188*4445fffbSMatthew Ahrens static zpool_command_t *current_command;
1892a6b87f0Sek110237 static char history_str[HIS_MAX_RECORD_LEN];
190*4445fffbSMatthew Ahrens static boolean_t log_history = B_TRUE;
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:
204ad135b5dSChristopher 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"));
21306eeb2adSek110237 	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 
269fa9e4066Sahrens /*
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
282990b4856Slling 		(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 
292b1b8ab34Slling /*
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);
335ad135b5dSChristopher Siden 
336ad135b5dSChristopher Siden 		(void) fprintf(fp, "\t%-15s   ", "feature@...");
337ad135b5dSChristopher Siden 		(void) fprintf(fp, "YES   disabled | enabled | active\n");
338ad135b5dSChristopher Siden 
339ad135b5dSChristopher Siden 		(void) fprintf(fp, gettext("\nThe feature@ properties must be "
340ad135b5dSChristopher 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 
384fa9e4066Sahrens /*
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) {
407ad135b5dSChristopher Siden 		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
408ad135b5dSChristopher Siden 		    !zpool_prop_feature(propname)) {
409990b4856Slling 			(void) fprintf(stderr, gettext("property '%s' is "
410990b4856Slling 			    "not a valid pool property\n"), propname);
411990b4856Slling 			return (2);
412990b4856Slling 		}
413ad135b5dSChristopher Siden 		if (zpool_prop_feature(propname))
414ad135b5dSChristopher Siden 			normnm = propname;
415ad135b5dSChristopher Siden 		else
4160a48a24eStimh 			normnm = zpool_prop_to_name(prop);
4170a48a24eStimh 	} else {
41814843421SMatthew Ahrens 		if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
4190a48a24eStimh 			normnm = zfs_prop_to_name(fprop);
42014843421SMatthew Ahrens 		} else {
42114843421SMatthew Ahrens 			normnm = propname;
42214843421SMatthew Ahrens 		}
4230a48a24eStimh 	}
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 
441990b4856Slling /*
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 /*
549fa94a07fSbrendan  * 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 /*
588ad135b5dSChristopher 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
597fa9e4066Sahrens  *		'/<pool>'
598990b4856Slling  *	-o	Set property=value.
599ad135b5dSChristopher Siden  *	-d	Don't automatically enable all supported pool features
600ad135b5dSChristopher 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;
613ad135b5dSChristopher 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 */
625ad135b5dSChristopher 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;
633ad135b5dSChristopher Siden 		case 'd':
634ad135b5dSChristopher Siden 			enable_all_pool_feat = B_FALSE;
635ad135b5dSChristopher 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;
663ad135b5dSChristopher Siden 
664ad135b5dSChristopher Siden 			/*
665ad135b5dSChristopher Siden 			 * If the user is creating a pool that doesn't support
666ad135b5dSChristopher Siden 			 * feature flags, don't enable any features.
667ad135b5dSChristopher Siden 			 */
668ad135b5dSChristopher Siden 			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) {
669ad135b5dSChristopher Siden 				char *end;
670ad135b5dSChristopher Siden 				u_longlong_t ver;
671ad135b5dSChristopher Siden 
672ad135b5dSChristopher Siden 				ver = strtoull(propval, &end, 10);
673ad135b5dSChristopher Siden 				if (*end == '\0' &&
674ad135b5dSChristopher Siden 				    ver < SPA_VERSION_FEATURES) {
675ad135b5dSChristopher Siden 					enable_all_pool_feat = B_FALSE;
676ad135b5dSChristopher Siden 				}
677ad135b5dSChristopher 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 		 */
824ad135b5dSChristopher Siden 		if (enable_all_pool_feat) {
825ad135b5dSChristopher Siden 			int i;
826ad135b5dSChristopher Siden 			for (i = 0; i < SPA_FEATURES; i++) {
827ad135b5dSChristopher Siden 				char propname[MAXPATHLEN];
828ad135b5dSChristopher Siden 				zfeature_info_t *feat = &spa_feature_table[i];
829ad135b5dSChristopher Siden 
830ad135b5dSChristopher Siden 				(void) snprintf(propname, sizeof (propname),
831ad135b5dSChristopher Siden 				    "feature@%s", feat->fi_uname);
832ad135b5dSChristopher Siden 
833ad135b5dSChristopher Siden 				/*
834ad135b5dSChristopher Siden 				 * Skip feature if user specified it manually
835ad135b5dSChristopher Siden 				 * on the command line.
836ad135b5dSChristopher Siden 				 */
837ad135b5dSChristopher Siden 				if (nvlist_exists(props, propname))
838ad135b5dSChristopher Siden 					continue;
839ad135b5dSChristopher Siden 
840ad135b5dSChristopher Siden 				if (add_prop_list(propname, ZFS_FEATURE_ENABLED,
841ad135b5dSChristopher Siden 				    &props, B_TRUE) != 0)
842ad135b5dSChristopher Siden 					goto errout;
843ad135b5dSChristopher Siden 			}
844ad135b5dSChristopher 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:
866fa9e4066Sahrens 	nvlist_free(nvroot);
8670a48a24eStimh 	nvlist_free(fsprops);
868990b4856Slling 	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 
938*4445fffbSMatthew Ahrens 	/* The history must be logged as part of the export */
939*4445fffbSMatthew Ahrens 	log_history = B_FALSE;
940*4445fffbSMatthew Ahrens 
941*4445fffbSMatthew Ahrens 	ret = (zpool_destroy(zhp, history_str) != 0);
942fa9e4066Sahrens 
943fa9e4066Sahrens 	zpool_close(zhp);
944fa9e4066Sahrens 
945fa9e4066Sahrens 	return (ret);
946fa9e4066Sahrens }
947fa9e4066Sahrens 
948fa9e4066Sahrens /*
949fa9e4066Sahrens  * zpool export [-f] <pool> ...
950fa9e4066Sahrens  *
951fa9e4066Sahrens  *	-f	Forcefully unmount datasets
952fa9e4066Sahrens  *
953b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
954fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
955fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
956fa9e4066Sahrens  */
957fa9e4066Sahrens int
958fa9e4066Sahrens zpool_do_export(int argc, char **argv)
959fa9e4066Sahrens {
96099653d4eSeschrock 	boolean_t force = B_FALSE;
961394ab0cbSGeorge Wilson 	boolean_t hardforce = B_FALSE;
962fa9e4066Sahrens 	int c;
963fa9e4066Sahrens 	zpool_handle_t *zhp;
964fa9e4066Sahrens 	int ret;
965fa9e4066Sahrens 	int i;
966fa9e4066Sahrens 
967fa9e4066Sahrens 	/* check options */
968394ab0cbSGeorge Wilson 	while ((c = getopt(argc, argv, "fF")) != -1) {
969fa9e4066Sahrens 		switch (c) {
970fa9e4066Sahrens 		case 'f':
97199653d4eSeschrock 			force = B_TRUE;
972fa9e4066Sahrens 			break;
973394ab0cbSGeorge Wilson 		case 'F':
974394ab0cbSGeorge Wilson 			hardforce = B_TRUE;
975394ab0cbSGeorge Wilson 			break;
976fa9e4066Sahrens 		case '?':
977fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
978fa9e4066Sahrens 			    optopt);
97999653d4eSeschrock 			usage(B_FALSE);
980fa9e4066Sahrens 		}
981fa9e4066Sahrens 	}
982fa9e4066Sahrens 
983fa9e4066Sahrens 	argc -= optind;
984fa9e4066Sahrens 	argv += optind;
985fa9e4066Sahrens 
986fa9e4066Sahrens 	/* check arguments */
987fa9e4066Sahrens 	if (argc < 1) {
988fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
98999653d4eSeschrock 		usage(B_FALSE);
990fa9e4066Sahrens 	}
991fa9e4066Sahrens 
992fa9e4066Sahrens 	ret = 0;
993fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
99499653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
995fa9e4066Sahrens 			ret = 1;
996fa9e4066Sahrens 			continue;
997fa9e4066Sahrens 		}
998fa9e4066Sahrens 
999f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
1000fa9e4066Sahrens 			ret = 1;
1001fa9e4066Sahrens 			zpool_close(zhp);
1002fa9e4066Sahrens 			continue;
1003fa9e4066Sahrens 		}
1004fa9e4066Sahrens 
1005*4445fffbSMatthew Ahrens 		/* The history must be logged as part of the export */
1006*4445fffbSMatthew Ahrens 		log_history = B_FALSE;
1007*4445fffbSMatthew Ahrens 
1008394ab0cbSGeorge Wilson 		if (hardforce) {
1009*4445fffbSMatthew Ahrens 			if (zpool_export_force(zhp, history_str) != 0)
1010fa9e4066Sahrens 				ret = 1;
1011*4445fffbSMatthew Ahrens 		} else if (zpool_export(zhp, force, history_str) != 0) {
1012394ab0cbSGeorge Wilson 			ret = 1;
1013394ab0cbSGeorge Wilson 		}
1014fa9e4066Sahrens 
1015fa9e4066Sahrens 		zpool_close(zhp);
1016fa9e4066Sahrens 	}
1017fa9e4066Sahrens 
1018fa9e4066Sahrens 	return (ret);
1019fa9e4066Sahrens }
1020fa9e4066Sahrens 
1021fa9e4066Sahrens /*
1022fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
1023fa9e4066Sahrens  * name column.
1024fa9e4066Sahrens  */
1025fa9e4066Sahrens static int
1026c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
1027fa9e4066Sahrens {
102888ecc943SGeorge Wilson 	char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
1029fa9e4066Sahrens 	nvlist_t **child;
1030fa9e4066Sahrens 	uint_t c, children;
1031fa9e4066Sahrens 	int ret;
1032fa9e4066Sahrens 
1033fa9e4066Sahrens 	if (strlen(name) + depth > max)
1034fa9e4066Sahrens 		max = strlen(name) + depth;
1035fa9e4066Sahrens 
1036afefbcddSeschrock 	free(name);
1037afefbcddSeschrock 
103899653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
103999653d4eSeschrock 	    &child, &children) == 0) {
1040fa9e4066Sahrens 		for (c = 0; c < children; c++)
104199653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
104299653d4eSeschrock 			    max)) > max)
1043fa9e4066Sahrens 				max = ret;
104499653d4eSeschrock 	}
104599653d4eSeschrock 
1046fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1047fa94a07fSbrendan 	    &child, &children) == 0) {
1048fa94a07fSbrendan 		for (c = 0; c < children; c++)
1049fa94a07fSbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
1050fa94a07fSbrendan 			    max)) > max)
1051fa94a07fSbrendan 				max = ret;
1052fa94a07fSbrendan 	}
1053fa94a07fSbrendan 
105499653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
105599653d4eSeschrock 	    &child, &children) == 0) {
105699653d4eSeschrock 		for (c = 0; c < children; c++)
105799653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
105899653d4eSeschrock 			    max)) > max)
105999653d4eSeschrock 				max = ret;
106099653d4eSeschrock 	}
106199653d4eSeschrock 
1062fa9e4066Sahrens 
1063fa9e4066Sahrens 	return (max);
1064fa9e4066Sahrens }
1065fa9e4066Sahrens 
1066e6ca193dSGeorge Wilson typedef struct spare_cbdata {
1067e6ca193dSGeorge Wilson 	uint64_t	cb_guid;
1068e6ca193dSGeorge Wilson 	zpool_handle_t	*cb_zhp;
1069e6ca193dSGeorge Wilson } spare_cbdata_t;
1070e6ca193dSGeorge Wilson 
1071e6ca193dSGeorge Wilson static boolean_t
1072e6ca193dSGeorge Wilson find_vdev(nvlist_t *nv, uint64_t search)
1073e6ca193dSGeorge Wilson {
1074e6ca193dSGeorge Wilson 	uint64_t guid;
1075e6ca193dSGeorge Wilson 	nvlist_t **child;
1076e6ca193dSGeorge Wilson 	uint_t c, children;
1077e6ca193dSGeorge Wilson 
1078e6ca193dSGeorge Wilson 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
1079e6ca193dSGeorge Wilson 	    search == guid)
1080e6ca193dSGeorge Wilson 		return (B_TRUE);
1081e6ca193dSGeorge Wilson 
1082e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1083e6ca193dSGeorge Wilson 	    &child, &children) == 0) {
1084e6ca193dSGeorge Wilson 		for (c = 0; c < children; c++)
1085e6ca193dSGeorge Wilson 			if (find_vdev(child[c], search))
1086e6ca193dSGeorge Wilson 				return (B_TRUE);
1087e6ca193dSGeorge Wilson 	}
1088e6ca193dSGeorge Wilson 
1089e6ca193dSGeorge Wilson 	return (B_FALSE);
1090e6ca193dSGeorge Wilson }
1091e6ca193dSGeorge Wilson 
1092e6ca193dSGeorge Wilson static int
1093e6ca193dSGeorge Wilson find_spare(zpool_handle_t *zhp, void *data)
1094e6ca193dSGeorge Wilson {
1095e6ca193dSGeorge Wilson 	spare_cbdata_t *cbp = data;
1096e6ca193dSGeorge Wilson 	nvlist_t *config, *nvroot;
1097e6ca193dSGeorge Wilson 
1098e6ca193dSGeorge Wilson 	config = zpool_get_config(zhp, NULL);
1099e6ca193dSGeorge Wilson 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1100e6ca193dSGeorge Wilson 	    &nvroot) == 0);
1101e6ca193dSGeorge Wilson 
1102e6ca193dSGeorge Wilson 	if (find_vdev(nvroot, cbp->cb_guid)) {
1103e6ca193dSGeorge Wilson 		cbp->cb_zhp = zhp;
1104e6ca193dSGeorge Wilson 		return (1);
1105e6ca193dSGeorge Wilson 	}
1106e6ca193dSGeorge Wilson 
1107e6ca193dSGeorge Wilson 	zpool_close(zhp);
1108e6ca193dSGeorge Wilson 	return (0);
1109e6ca193dSGeorge Wilson }
1110e6ca193dSGeorge Wilson 
1111e6ca193dSGeorge Wilson /*
1112e6ca193dSGeorge Wilson  * Print out configuration state as requested by status_callback.
1113e6ca193dSGeorge Wilson  */
1114e6ca193dSGeorge Wilson void
1115e6ca193dSGeorge Wilson print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
1116e6ca193dSGeorge Wilson     int namewidth, int depth, boolean_t isspare)
1117e6ca193dSGeorge Wilson {
1118e6ca193dSGeorge Wilson 	nvlist_t **child;
1119e6ca193dSGeorge Wilson 	uint_t c, children;
11203f9d6ad7SLin Ling 	pool_scan_stat_t *ps = NULL;
1121e6ca193dSGeorge Wilson 	vdev_stat_t *vs;
11223f9d6ad7SLin Ling 	char rbuf[6], wbuf[6], cbuf[6];
1123e6ca193dSGeorge Wilson 	char *vname;
1124e6ca193dSGeorge Wilson 	uint64_t notpresent;
1125e6ca193dSGeorge Wilson 	spare_cbdata_t cb;
1126e6ca193dSGeorge Wilson 	char *state;
1127e6ca193dSGeorge Wilson 
1128e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1129e6ca193dSGeorge Wilson 	    &child, &children) != 0)
1130e6ca193dSGeorge Wilson 		children = 0;
1131e6ca193dSGeorge Wilson 
11323f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
11333f9d6ad7SLin Ling 	    (uint64_t **)&vs, &c) == 0);
11343f9d6ad7SLin Ling 
1135e6ca193dSGeorge Wilson 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1136e6ca193dSGeorge Wilson 	if (isspare) {
1137e6ca193dSGeorge Wilson 		/*
1138e6ca193dSGeorge Wilson 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
1139e6ca193dSGeorge Wilson 		 * online drives.
1140e6ca193dSGeorge Wilson 		 */
1141e6ca193dSGeorge Wilson 		if (vs->vs_aux == VDEV_AUX_SPARED)
1142e6ca193dSGeorge Wilson 			state = "INUSE";
1143e6ca193dSGeorge Wilson 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
1144e6ca193dSGeorge Wilson 			state = "AVAIL";
1145e6ca193dSGeorge Wilson 	}
1146e6ca193dSGeorge Wilson 
1147e6ca193dSGeorge Wilson 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
1148e6ca193dSGeorge Wilson 	    name, state);
1149e6ca193dSGeorge Wilson 
1150e6ca193dSGeorge Wilson 	if (!isspare) {
1151e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
1152e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
1153e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
1154e6ca193dSGeorge Wilson 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
1155e6ca193dSGeorge Wilson 	}
1156e6ca193dSGeorge Wilson 
1157e6ca193dSGeorge Wilson 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1158e6ca193dSGeorge Wilson 	    &notpresent) == 0) {
1159e6ca193dSGeorge Wilson 		char *path;
1160e6ca193dSGeorge Wilson 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
1161e6ca193dSGeorge Wilson 		(void) printf("  was %s", path);
1162e6ca193dSGeorge Wilson 	} else if (vs->vs_aux != 0) {
1163e6ca193dSGeorge Wilson 		(void) printf("  ");
1164e6ca193dSGeorge Wilson 
1165e6ca193dSGeorge Wilson 		switch (vs->vs_aux) {
1166e6ca193dSGeorge Wilson 		case VDEV_AUX_OPEN_FAILED:
1167e6ca193dSGeorge Wilson 			(void) printf(gettext("cannot open"));
1168e6ca193dSGeorge Wilson 			break;
1169e6ca193dSGeorge Wilson 
1170e6ca193dSGeorge Wilson 		case VDEV_AUX_BAD_GUID_SUM:
1171e6ca193dSGeorge Wilson 			(void) printf(gettext("missing device"));
1172e6ca193dSGeorge Wilson 			break;
1173e6ca193dSGeorge Wilson 
1174e6ca193dSGeorge Wilson 		case VDEV_AUX_NO_REPLICAS:
1175e6ca193dSGeorge Wilson 			(void) printf(gettext("insufficient replicas"));
1176e6ca193dSGeorge Wilson 			break;
1177e6ca193dSGeorge Wilson 
1178e6ca193dSGeorge Wilson 		case VDEV_AUX_VERSION_NEWER:
1179e6ca193dSGeorge Wilson 			(void) printf(gettext("newer version"));
1180e6ca193dSGeorge Wilson 			break;
1181e6ca193dSGeorge Wilson 
1182ad135b5dSChristopher Siden 		case VDEV_AUX_UNSUP_FEAT:
1183ad135b5dSChristopher Siden 			(void) printf(gettext("unsupported feature(s)"));
1184ad135b5dSChristopher Siden 			break;
1185ad135b5dSChristopher Siden 
1186e6ca193dSGeorge Wilson 		case VDEV_AUX_SPARED:
1187e6ca193dSGeorge Wilson 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1188e6ca193dSGeorge Wilson 			    &cb.cb_guid) == 0);
1189e6ca193dSGeorge Wilson 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
1190e6ca193dSGeorge Wilson 				if (strcmp(zpool_get_name(cb.cb_zhp),
1191e6ca193dSGeorge Wilson 				    zpool_get_name(zhp)) == 0)
1192e6ca193dSGeorge Wilson 					(void) printf(gettext("currently in "
1193e6ca193dSGeorge Wilson 					    "use"));
1194e6ca193dSGeorge Wilson 				else
1195e6ca193dSGeorge Wilson 					(void) printf(gettext("in use by "
1196e6ca193dSGeorge Wilson 					    "pool '%s'"),
1197e6ca193dSGeorge Wilson 					    zpool_get_name(cb.cb_zhp));
1198e6ca193dSGeorge Wilson 				zpool_close(cb.cb_zhp);
1199e6ca193dSGeorge Wilson 			} else {
1200e6ca193dSGeorge Wilson 				(void) printf(gettext("currently in use"));
1201e6ca193dSGeorge Wilson 			}
1202e6ca193dSGeorge Wilson 			break;
1203e6ca193dSGeorge Wilson 
1204e6ca193dSGeorge Wilson 		case VDEV_AUX_ERR_EXCEEDED:
1205e6ca193dSGeorge Wilson 			(void) printf(gettext("too many errors"));
1206e6ca193dSGeorge Wilson 			break;
1207e6ca193dSGeorge Wilson 
1208e6ca193dSGeorge Wilson 		case VDEV_AUX_IO_FAILURE:
1209e6ca193dSGeorge Wilson 			(void) printf(gettext("experienced I/O failures"));
1210e6ca193dSGeorge Wilson 			break;
1211e6ca193dSGeorge Wilson 
1212e6ca193dSGeorge Wilson 		case VDEV_AUX_BAD_LOG:
1213e6ca193dSGeorge Wilson 			(void) printf(gettext("bad intent log"));
1214e6ca193dSGeorge Wilson 			break;
1215e6ca193dSGeorge Wilson 
1216069f55e2SEric Schrock 		case VDEV_AUX_EXTERNAL:
1217069f55e2SEric Schrock 			(void) printf(gettext("external device fault"));
1218069f55e2SEric Schrock 			break;
1219069f55e2SEric Schrock 
12201195e687SMark J Musante 		case VDEV_AUX_SPLIT_POOL:
12211195e687SMark J Musante 			(void) printf(gettext("split into new pool"));
12221195e687SMark J Musante 			break;
12231195e687SMark J Musante 
1224e6ca193dSGeorge Wilson 		default:
1225e6ca193dSGeorge Wilson 			(void) printf(gettext("corrupted data"));
1226e6ca193dSGeorge Wilson 			break;
1227e6ca193dSGeorge Wilson 		}
12283f9d6ad7SLin Ling 	}
12293f9d6ad7SLin Ling 
12303f9d6ad7SLin Ling 	(void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS,
12313f9d6ad7SLin Ling 	    (uint64_t **)&ps, &c);
12323f9d6ad7SLin Ling 
12333f9d6ad7SLin Ling 	if (ps && ps->pss_state == DSS_SCANNING &&
12343f9d6ad7SLin Ling 	    vs->vs_scan_processed != 0 && children == 0) {
12353f9d6ad7SLin Ling 		(void) printf(gettext("  (%s)"),
12363f9d6ad7SLin Ling 		    (ps->pss_func == POOL_SCAN_RESILVER) ?
12373f9d6ad7SLin Ling 		    "resilvering" : "repairing");
1238e6ca193dSGeorge Wilson 	}
1239e6ca193dSGeorge Wilson 
1240e6ca193dSGeorge Wilson 	(void) printf("\n");
1241e6ca193dSGeorge Wilson 
1242e6ca193dSGeorge Wilson 	for (c = 0; c < children; c++) {
124388ecc943SGeorge Wilson 		uint64_t islog = B_FALSE, ishole = B_FALSE;
1244e6ca193dSGeorge Wilson 
124588ecc943SGeorge Wilson 		/* Don't print logs or holes here */
1246e6ca193dSGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
124788ecc943SGeorge Wilson 		    &islog);
124888ecc943SGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
124988ecc943SGeorge Wilson 		    &ishole);
125088ecc943SGeorge Wilson 		if (islog || ishole)
1251e6ca193dSGeorge Wilson 			continue;
125288ecc943SGeorge Wilson 		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1253e6ca193dSGeorge Wilson 		print_status_config(zhp, vname, child[c],
1254e6ca193dSGeorge Wilson 		    namewidth, depth + 2, isspare);
1255e6ca193dSGeorge Wilson 		free(vname);
1256e6ca193dSGeorge Wilson 	}
1257e6ca193dSGeorge Wilson }
1258e6ca193dSGeorge Wilson 
1259fa9e4066Sahrens 
1260fa9e4066Sahrens /*
1261fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
1262fa9e4066Sahrens  * pool, printing out the name and status for each one.
1263fa9e4066Sahrens  */
1264fa9e4066Sahrens void
1265e6ca193dSGeorge Wilson print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
1266fa9e4066Sahrens {
1267fa9e4066Sahrens 	nvlist_t **child;
1268fa9e4066Sahrens 	uint_t c, children;
1269fa9e4066Sahrens 	vdev_stat_t *vs;
1270afefbcddSeschrock 	char *type, *vname;
1271fa9e4066Sahrens 
1272fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
127388ecc943SGeorge Wilson 	if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
127488ecc943SGeorge Wilson 	    strcmp(type, VDEV_TYPE_HOLE) == 0)
1275fa9e4066Sahrens 		return;
1276fa9e4066Sahrens 
12773f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1278fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
1279fa9e4066Sahrens 
1280fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
1281990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1282fa9e4066Sahrens 
1283fa9e4066Sahrens 	if (vs->vs_aux != 0) {
12843d7072f8Seschrock 		(void) printf("  ");
1285fa9e4066Sahrens 
1286fa9e4066Sahrens 		switch (vs->vs_aux) {
1287fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
1288fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
1289fa9e4066Sahrens 			break;
1290fa9e4066Sahrens 
1291fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
1292fa9e4066Sahrens 			(void) printf(gettext("missing device"));
1293fa9e4066Sahrens 			break;
1294fa9e4066Sahrens 
1295fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
1296fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
1297fa9e4066Sahrens 			break;
1298fa9e4066Sahrens 
1299eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
1300eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
1301eaca9bbdSeschrock 			break;
1302eaca9bbdSeschrock 
1303ad135b5dSChristopher Siden 		case VDEV_AUX_UNSUP_FEAT:
1304ad135b5dSChristopher Siden 			(void) printf(gettext("unsupported feature(s)"));
1305ad135b5dSChristopher Siden 			break;
1306ad135b5dSChristopher Siden 
13073d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
13083d7072f8Seschrock 			(void) printf(gettext("too many errors"));
13093d7072f8Seschrock 			break;
13103d7072f8Seschrock 
1311fa9e4066Sahrens 		default:
1312fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
1313fa9e4066Sahrens 			break;
1314fa9e4066Sahrens 		}
1315fa9e4066Sahrens 	}
1316fa9e4066Sahrens 	(void) printf("\n");
1317fa9e4066Sahrens 
1318fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1319fa9e4066Sahrens 	    &child, &children) != 0)
1320fa9e4066Sahrens 		return;
1321fa9e4066Sahrens 
1322afefbcddSeschrock 	for (c = 0; c < children; c++) {
13238654d025Sperrin 		uint64_t is_log = B_FALSE;
13248654d025Sperrin 
13258654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
13268654d025Sperrin 		    &is_log);
1327e6ca193dSGeorge Wilson 		if (is_log)
13288654d025Sperrin 			continue;
13298654d025Sperrin 
133088ecc943SGeorge Wilson 		vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
1331e6ca193dSGeorge Wilson 		print_import_config(vname, child[c], namewidth, depth + 2);
1332afefbcddSeschrock 		free(vname);
1333afefbcddSeschrock 	}
133499653d4eSeschrock 
1335fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1336fa94a07fSbrendan 	    &child, &children) == 0) {
1337fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
1338fa94a07fSbrendan 		for (c = 0; c < children; c++) {
133988ecc943SGeorge Wilson 			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1340fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1341fa94a07fSbrendan 			free(vname);
1342fa94a07fSbrendan 		}
1343fa94a07fSbrendan 	}
134499653d4eSeschrock 
1345fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1346fa94a07fSbrendan 	    &child, &children) == 0) {
134799653d4eSeschrock 		(void) printf(gettext("\tspares\n"));
134899653d4eSeschrock 		for (c = 0; c < children; c++) {
134988ecc943SGeorge Wilson 			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
135099653d4eSeschrock 			(void) printf("\t  %s\n", vname);
135199653d4eSeschrock 			free(vname);
135299653d4eSeschrock 		}
1353fa9e4066Sahrens 	}
1354fa94a07fSbrendan }
1355fa9e4066Sahrens 
1356fa9e4066Sahrens /*
1357e6ca193dSGeorge Wilson  * Print log vdevs.
1358e6ca193dSGeorge Wilson  * Logs are recorded as top level vdevs in the main pool child array
1359e6ca193dSGeorge Wilson  * but with "is_log" set to 1. We use either print_status_config() or
1360e6ca193dSGeorge Wilson  * print_import_config() to print the top level logs then any log
1361e6ca193dSGeorge Wilson  * children (eg mirrored slogs) are printed recursively - which
1362e6ca193dSGeorge Wilson  * works because only the top level vdev is marked "is_log"
1363e6ca193dSGeorge Wilson  */
1364e6ca193dSGeorge Wilson static void
1365e6ca193dSGeorge Wilson print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
1366e6ca193dSGeorge Wilson {
1367e6ca193dSGeorge Wilson 	uint_t c, children;
1368e6ca193dSGeorge Wilson 	nvlist_t **child;
1369e6ca193dSGeorge Wilson 
1370e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1371e6ca193dSGeorge Wilson 	    &children) != 0)
1372e6ca193dSGeorge Wilson 		return;
1373e6ca193dSGeorge Wilson 
1374e6ca193dSGeorge Wilson 	(void) printf(gettext("\tlogs\n"));
1375e6ca193dSGeorge Wilson 
1376e6ca193dSGeorge Wilson 	for (c = 0; c < children; c++) {
1377e6ca193dSGeorge Wilson 		uint64_t is_log = B_FALSE;
1378e6ca193dSGeorge Wilson 		char *name;
1379e6ca193dSGeorge Wilson 
1380e6ca193dSGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1381e6ca193dSGeorge Wilson 		    &is_log);
1382e6ca193dSGeorge Wilson 		if (!is_log)
1383e6ca193dSGeorge Wilson 			continue;
138488ecc943SGeorge Wilson 		name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1385e6ca193dSGeorge Wilson 		if (verbose)
1386e6ca193dSGeorge Wilson 			print_status_config(zhp, name, child[c], namewidth,
1387e6ca193dSGeorge Wilson 			    2, B_FALSE);
1388e6ca193dSGeorge Wilson 		else
1389e6ca193dSGeorge Wilson 			print_import_config(name, child[c], namewidth, 2);
1390e6ca193dSGeorge Wilson 		free(name);
1391e6ca193dSGeorge Wilson 	}
1392e6ca193dSGeorge Wilson }
1393468c413aSTim Haley 
1394e6ca193dSGeorge Wilson /*
1395fa9e4066Sahrens  * Display the status for the given pool.
1396fa9e4066Sahrens  */
1397fa9e4066Sahrens static void
1398fa9e4066Sahrens show_import(nvlist_t *config)
1399fa9e4066Sahrens {
1400fa9e4066Sahrens 	uint64_t pool_state;
1401fa9e4066Sahrens 	vdev_stat_t *vs;
1402fa9e4066Sahrens 	char *name;
1403fa9e4066Sahrens 	uint64_t guid;
1404fa9e4066Sahrens 	char *msgid;
1405fa9e4066Sahrens 	nvlist_t *nvroot;
1406fa9e4066Sahrens 	int reason;
140746657f8dSmmusante 	const char *health;
1408fa9e4066Sahrens 	uint_t vsc;
1409fa9e4066Sahrens 	int namewidth;
14108704186eSDan McDonald 	char *comment;
1411fa9e4066Sahrens 
1412fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1413fa9e4066Sahrens 	    &name) == 0);
1414fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1415fa9e4066Sahrens 	    &guid) == 0);
1416fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1417fa9e4066Sahrens 	    &pool_state) == 0);
1418fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1419fa9e4066Sahrens 	    &nvroot) == 0);
1420fa9e4066Sahrens 
14213f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
1422fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1423990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1424fa9e4066Sahrens 
1425fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1426fa9e4066Sahrens 
142746657f8dSmmusante 	(void) printf(gettext("   pool: %s\n"), name);
142846657f8dSmmusante 	(void) printf(gettext("     id: %llu\n"), (u_longlong_t)guid);
142946657f8dSmmusante 	(void) printf(gettext("  state: %s"), health);
14304c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
143146657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
14324c58d714Sdarrenm 	(void) printf("\n");
1433fa9e4066Sahrens 
1434fa9e4066Sahrens 	switch (reason) {
1435fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1436fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1437fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
14388704186eSDan McDonald 		(void) printf(gettext(" status: One or more devices are "
14398704186eSDan McDonald 		    "missing from the system.\n"));
1440fa9e4066Sahrens 		break;
1441fa9e4066Sahrens 
1442fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1443fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1444fa9e4066Sahrens 		(void) printf(gettext(" status: One or more devices contains "
1445fa9e4066Sahrens 		    "corrupted data.\n"));
1446fa9e4066Sahrens 		break;
1447fa9e4066Sahrens 
1448fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
14498704186eSDan McDonald 		(void) printf(
14508704186eSDan McDonald 		    gettext(" status: The pool data is corrupted.\n"));
1451fa9e4066Sahrens 		break;
1452fa9e4066Sahrens 
1453441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1454441d80aaSlling 		(void) printf(gettext(" status: One or more devices "
1455441d80aaSlling 		    "are offlined.\n"));
1456441d80aaSlling 		break;
1457441d80aaSlling 
1458ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1459ea8dc4b6Seschrock 		(void) printf(gettext(" status: The pool metadata is "
1460ea8dc4b6Seschrock 		    "corrupted.\n"));
1461ea8dc4b6Seschrock 		break;
1462ea8dc4b6Seschrock 
1463eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1464eaca9bbdSeschrock 		(void) printf(gettext(" status: The pool is formatted using an "
1465eaca9bbdSeschrock 		    "older on-disk version.\n"));
1466eaca9bbdSeschrock 		break;
1467eaca9bbdSeschrock 
1468eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1469eaca9bbdSeschrock 		(void) printf(gettext(" status: The pool is formatted using an "
1470eaca9bbdSeschrock 		    "incompatible version.\n"));
1471eaca9bbdSeschrock 		break;
1472b87f3af3Sperrin 
1473ad135b5dSChristopher Siden 	case ZPOOL_STATUS_UNSUP_FEAT_READ:
1474ad135b5dSChristopher Siden 		(void) printf(gettext("status: The pool uses the following "
1475ad135b5dSChristopher Siden 		    "feature(s) not supported on this sytem:\n"));
1476ad135b5dSChristopher Siden 		zpool_print_unsup_feat(config);
1477ad135b5dSChristopher Siden 		break;
1478ad135b5dSChristopher Siden 
1479ad135b5dSChristopher Siden 	case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
1480ad135b5dSChristopher Siden 		(void) printf(gettext("status: The pool can only be accessed "
1481ad135b5dSChristopher Siden 		    "in read-only mode on this system. It\n\tcannot be "
1482ad135b5dSChristopher Siden 		    "accessed in read-write mode because it uses the "
1483ad135b5dSChristopher Siden 		    "following\n\tfeature(s) not supported on this system:\n"));
1484ad135b5dSChristopher Siden 		zpool_print_unsup_feat(config);
1485ad135b5dSChristopher Siden 		break;
1486ad135b5dSChristopher Siden 
148795173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
148895173954Sek110237 		(void) printf(gettext(" status: The pool was last accessed by "
148995173954Sek110237 		    "another system.\n"));
149095173954Sek110237 		break;
1491b87f3af3Sperrin 
14923d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
14933d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
14943d7072f8Seschrock 		(void) printf(gettext(" status: One or more devices are "
14953d7072f8Seschrock 		    "faulted.\n"));
14963d7072f8Seschrock 		break;
14973d7072f8Seschrock 
1498b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
1499b87f3af3Sperrin 		(void) printf(gettext(" status: An intent log record cannot be "
1500b87f3af3Sperrin 		    "read.\n"));
1501b87f3af3Sperrin 		break;
1502b87f3af3Sperrin 
15033f9d6ad7SLin Ling 	case ZPOOL_STATUS_RESILVERING:
15043f9d6ad7SLin Ling 		(void) printf(gettext(" status: One or more devices were being "
15053f9d6ad7SLin Ling 		    "resilvered.\n"));
15063f9d6ad7SLin Ling 		break;
15073f9d6ad7SLin Ling 
1508fa9e4066Sahrens 	default:
1509fa9e4066Sahrens 		/*
1510fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1511fa9e4066Sahrens 		 */
1512fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1513fa9e4066Sahrens 	}
1514fa9e4066Sahrens 
1515fa9e4066Sahrens 	/*
1516fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1517fa9e4066Sahrens 	 */
151846657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1519eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1520eaca9bbdSeschrock 			(void) printf(gettext(" action: The pool can be "
1521eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1522eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1523eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
152495173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
152595173954Sek110237 			(void) printf(gettext(" action: The pool can be "
152695173954Sek110237 			    "imported using its name or numeric "
152795173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1528fa9e4066Sahrens 		else
1529eaca9bbdSeschrock 			(void) printf(gettext(" action: The pool can be "
1530eaca9bbdSeschrock 			    "imported using its name or numeric "
1531eaca9bbdSeschrock 			    "identifier.\n"));
153246657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1533fa9e4066Sahrens 		(void) printf(gettext(" action: The pool can be imported "
1534fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1535eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1536fa9e4066Sahrens 	} else {
1537eaca9bbdSeschrock 		switch (reason) {
1538eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1539eaca9bbdSeschrock 			(void) printf(gettext(" action: The pool cannot be "
1540eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1541eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1542eaca9bbdSeschrock 			    "backup.\n"));
1543eaca9bbdSeschrock 			break;
1544ad135b5dSChristopher Siden 		case ZPOOL_STATUS_UNSUP_FEAT_READ:
1545ad135b5dSChristopher Siden 			(void) printf(gettext("action: The pool cannot be "
1546ad135b5dSChristopher Siden 			    "imported. Access the pool on a system that "
1547ad135b5dSChristopher Siden 			    "supports\n\tthe required feature(s), or recreate "
1548ad135b5dSChristopher Siden 			    "the pool from backup.\n"));
1549ad135b5dSChristopher Siden 			break;
1550ad135b5dSChristopher Siden 		case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
1551ad135b5dSChristopher Siden 			(void) printf(gettext("action: The pool cannot be "
1552ad135b5dSChristopher Siden 			    "imported in read-write mode. Import the pool "
1553ad135b5dSChristopher Siden 			    "with\n"
1554ad135b5dSChristopher Siden 			    "\t\"-o readonly=on\", access the pool on a system "
1555ad135b5dSChristopher Siden 			    "that supports the\n\trequired feature(s), or "
1556ad135b5dSChristopher Siden 			    "recreate the pool from backup.\n"));
1557ad135b5dSChristopher Siden 			break;
1558eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1559eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1560eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1561fa9e4066Sahrens 			(void) printf(gettext(" action: The pool cannot be "
1562fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1563fa9e4066Sahrens 			    "again.\n"));
1564eaca9bbdSeschrock 			break;
1565eaca9bbdSeschrock 		default:
1566fa9e4066Sahrens 			(void) printf(gettext(" action: The pool cannot be "
1567fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1568fa9e4066Sahrens 		}
1569eaca9bbdSeschrock 	}
1570eaca9bbdSeschrock 
15718704186eSDan McDonald 	/* Print the comment attached to the pool. */
15728704186eSDan McDonald 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
15738704186eSDan McDonald 		(void) printf(gettext("comment: %s\n"), comment);
15748704186eSDan McDonald 
157546657f8dSmmusante 	/*
157646657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
157746657f8dSmmusante 	 * is "corrupt data":
157846657f8dSmmusante 	 */
157946657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
158046657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
158146657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1582eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1583eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1584eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1585eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1586eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
158718ce54dfSek110237 			    "another system, but can be imported using\n\t"
1588eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1589eaca9bbdSeschrock 	}
1590fa9e4066Sahrens 
1591fa9e4066Sahrens 	if (msgid != NULL)
1592654b400cSJoshua M. Clulow 		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
1593fa9e4066Sahrens 		    msgid);
1594fa9e4066Sahrens 
1595fa9e4066Sahrens 	(void) printf(gettext(" config:\n\n"));
1596fa9e4066Sahrens 
1597c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1598fa9e4066Sahrens 	if (namewidth < 10)
1599fa9e4066Sahrens 		namewidth = 10;
16008654d025Sperrin 
1601e6ca193dSGeorge Wilson 	print_import_config(name, nvroot, namewidth, 0);
1602e6ca193dSGeorge Wilson 	if (num_logs(nvroot) > 0)
1603e6ca193dSGeorge Wilson 		print_logs(NULL, nvroot, namewidth, B_FALSE);
1604fa9e4066Sahrens 
1605fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
160646657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1607fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
160846657f8dSmmusante 		    "configuration cannot be determined.\n"));
1609fa9e4066Sahrens 	}
1610fa9e4066Sahrens }
1611fa9e4066Sahrens 
1612fa9e4066Sahrens /*
1613fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1614990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1615990b4856Slling  * within the pool.
1616fa9e4066Sahrens  */
1617fa9e4066Sahrens static int
1618fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
16194b964adaSGeorge Wilson     nvlist_t *props, int flags)
1620fa9e4066Sahrens {
1621fa9e4066Sahrens 	zpool_handle_t *zhp;
1622fa9e4066Sahrens 	char *name;
1623fa9e4066Sahrens 	uint64_t state;
1624eaca9bbdSeschrock 	uint64_t version;
1625fa9e4066Sahrens 
1626fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1627fa9e4066Sahrens 	    &name) == 0);
1628fa9e4066Sahrens 
1629fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1630fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1631eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1632eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1633ad135b5dSChristopher Siden 	if (!SPA_VERSION_IS_SUPPORTED(version)) {
1634eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1635ad135b5dSChristopher Siden 		    "is formatted using an unsupported ZFS version\n"), name);
1636eaca9bbdSeschrock 		return (1);
16374b964adaSGeorge Wilson 	} else if (state != POOL_STATE_EXPORTED &&
16384b964adaSGeorge Wilson 	    !(flags & ZFS_IMPORT_ANY_HOST)) {
163995173954Sek110237 		uint64_t hostid;
164095173954Sek110237 
164195173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
164295173954Sek110237 		    &hostid) == 0) {
164395173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
164495173954Sek110237 				char *hostname;
164595173954Sek110237 				uint64_t timestamp;
164695173954Sek110237 				time_t t;
164795173954Sek110237 
164895173954Sek110237 				verify(nvlist_lookup_string(config,
164995173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
165095173954Sek110237 				verify(nvlist_lookup_uint64(config,
165195173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
165295173954Sek110237 				t = timestamp;
165395173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
165495173954Sek110237 				    "'%s': pool may be in use from other "
165595173954Sek110237 				    "system, it was last accessed by %s "
165695173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
165795173954Sek110237 				    (unsigned long)hostid,
165895173954Sek110237 				    asctime(localtime(&t)));
165995173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
166095173954Sek110237 				    "import anyway\n"));
1661fa9e4066Sahrens 				return (1);
1662fa9e4066Sahrens 			}
166395173954Sek110237 		} else {
166495173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
166595173954Sek110237 			    "pool may be in use from other system\n"), name);
166695173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
166795173954Sek110237 			    "anyway\n"));
166895173954Sek110237 			return (1);
166995173954Sek110237 		}
167095173954Sek110237 	}
1671fa9e4066Sahrens 
16724b964adaSGeorge Wilson 	if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
1673fa9e4066Sahrens 		return (1);
1674fa9e4066Sahrens 
1675fa9e4066Sahrens 	if (newname != NULL)
1676fa9e4066Sahrens 		name = (char *)newname;
1677fa9e4066Sahrens 
16784f0f5e5bSVictor Latushkin 	if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
16794f0f5e5bSVictor Latushkin 		return (1);
1680fa9e4066Sahrens 
1681379c004dSEric Schrock 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
1682f9af39baSGeorge Wilson 	    !(flags & ZFS_IMPORT_ONLY) &&
1683379c004dSEric Schrock 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1684fa9e4066Sahrens 		zpool_close(zhp);
1685fa9e4066Sahrens 		return (1);
1686fa9e4066Sahrens 	}
1687fa9e4066Sahrens 
1688fa9e4066Sahrens 	zpool_close(zhp);
1689468c413aSTim Haley 	return (0);
1690fa9e4066Sahrens }
1691fa9e4066Sahrens 
1692fa9e4066Sahrens /*
16934c58d714Sdarrenm  * zpool import [-d dir] [-D]
16942f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
16952f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
16962f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
1697468c413aSTim Haley  *              [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool]
16982f8aaab3Seschrock  *
16992f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
17002f8aaab3Seschrock  *		devices.
1701fa9e4066Sahrens  *
1702fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1703fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1704fa9e4066Sahrens  *
17054c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
17064c58d714Sdarrenm  *              specified destroyed pools.
17074c58d714Sdarrenm  *
1708fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1709fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1710fa9e4066Sahrens  *		is rebooted.
1711fa9e4066Sahrens  *
1712468c413aSTim Haley  *       -V	Import even in the presence of faulted vdevs.  This is an
1713c5904d13Seschrock  *       	intentionally undocumented option for testing purposes, and
1714c5904d13Seschrock  *       	treats the pool configuration as complete, leaving any bad
17154f0f5e5bSVictor Latushkin  *		vdevs in the FAULTED state. In other words, it does verbatim
17164f0f5e5bSVictor Latushkin  *		import.
1717c5904d13Seschrock  *
1718468c413aSTim Haley  *       -f	Force import, even if it appears that the pool is active.
1719468c413aSTim Haley  *
1720468c413aSTim Haley  *       -F     Attempt rewind if necessary.
1721468c413aSTim Haley  *
1722468c413aSTim Haley  *       -n     See if rewind would work, but don't actually rewind.
1723468c413aSTim Haley  *
1724f9af39baSGeorge Wilson  *       -N     Import the pool but don't mount datasets.
1725f9af39baSGeorge Wilson  *
1726f9af39baSGeorge Wilson  *       -T     Specify a starting txg to use for import. This option is
1727f9af39baSGeorge Wilson  *       	intentionally undocumented option for testing purposes.
1728f9af39baSGeorge Wilson  *
1729fa9e4066Sahrens  *       -a	Import all pools found.
1730fa9e4066Sahrens  *
1731990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1732ecd6cf80Smarks  *
1733fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1734fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1735fa9e4066Sahrens  */
1736fa9e4066Sahrens int
1737fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1738fa9e4066Sahrens {
1739fa9e4066Sahrens 	char **searchdirs = NULL;
1740fa9e4066Sahrens 	int nsearch = 0;
1741fa9e4066Sahrens 	int c;
1742d41c4376SMark J Musante 	int err = 0;
17432f8aaab3Seschrock 	nvlist_t *pools = NULL;
174499653d4eSeschrock 	boolean_t do_all = B_FALSE;
174599653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1746fa9e4066Sahrens 	char *mntopts = NULL;
1747fa9e4066Sahrens 	nvpair_t *elem;
1748fa9e4066Sahrens 	nvlist_t *config;
174924e697d4Sck153898 	uint64_t searchguid = 0;
175024e697d4Sck153898 	char *searchname = NULL;
1751990b4856Slling 	char *propval;
1752fa9e4066Sahrens 	nvlist_t *found_config;
1753468c413aSTim Haley 	nvlist_t *policy = NULL;
1754ecd6cf80Smarks 	nvlist_t *props = NULL;
175599653d4eSeschrock 	boolean_t first;
17564b964adaSGeorge Wilson 	int flags = ZFS_IMPORT_NORMAL;
1757468c413aSTim Haley 	uint32_t rewind_policy = ZPOOL_NO_REWIND;
1758468c413aSTim Haley 	boolean_t dryrun = B_FALSE;
1759468c413aSTim Haley 	boolean_t do_rewind = B_FALSE;
1760468c413aSTim Haley 	boolean_t xtreme_rewind = B_FALSE;
1761f9af39baSGeorge Wilson 	uint64_t pool_state, txg = -1ULL;
17622f8aaab3Seschrock 	char *cachefile = NULL;
1763d41c4376SMark J Musante 	importargs_t idata = { 0 };
1764f9af39baSGeorge Wilson 	char *endptr;
1765fa9e4066Sahrens 
1766fa9e4066Sahrens 	/* check options */
1767f9af39baSGeorge Wilson 	while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) {
1768fa9e4066Sahrens 		switch (c) {
1769fa9e4066Sahrens 		case 'a':
177099653d4eSeschrock 			do_all = B_TRUE;
1771fa9e4066Sahrens 			break;
17722f8aaab3Seschrock 		case 'c':
17732f8aaab3Seschrock 			cachefile = optarg;
17742f8aaab3Seschrock 			break;
1775fa9e4066Sahrens 		case 'd':
1776fa9e4066Sahrens 			if (searchdirs == NULL) {
1777fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1778fa9e4066Sahrens 			} else {
1779fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1780fa9e4066Sahrens 				    sizeof (char *));
1781fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1782fa9e4066Sahrens 				    sizeof (char *));
1783fa9e4066Sahrens 				free(searchdirs);
1784fa9e4066Sahrens 				searchdirs = tmp;
1785fa9e4066Sahrens 			}
1786fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1787fa9e4066Sahrens 			break;
17884c58d714Sdarrenm 		case 'D':
178999653d4eSeschrock 			do_destroyed = B_TRUE;
17904c58d714Sdarrenm 			break;
1791fa9e4066Sahrens 		case 'f':
17924b964adaSGeorge Wilson 			flags |= ZFS_IMPORT_ANY_HOST;
1793fa9e4066Sahrens 			break;
1794c5904d13Seschrock 		case 'F':
1795468c413aSTim Haley 			do_rewind = B_TRUE;
1796468c413aSTim Haley 			break;
17974b964adaSGeorge Wilson 		case 'm':
17984b964adaSGeorge Wilson 			flags |= ZFS_IMPORT_MISSING_LOG;
17994b964adaSGeorge Wilson 			break;
1800468c413aSTim Haley 		case 'n':
1801468c413aSTim Haley 			dryrun = B_TRUE;
1802c5904d13Seschrock 			break;
1803f9af39baSGeorge Wilson 		case 'N':
1804f9af39baSGeorge Wilson 			flags |= ZFS_IMPORT_ONLY;
1805f9af39baSGeorge Wilson 			break;
1806fa9e4066Sahrens 		case 'o':
1807990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1808990b4856Slling 				*propval = '\0';
1809990b4856Slling 				propval++;
18100a48a24eStimh 				if (add_prop_list(optarg, propval,
18110a48a24eStimh 				    &props, B_TRUE))
1812990b4856Slling 					goto error;
1813990b4856Slling 			} else {
1814fa9e4066Sahrens 				mntopts = optarg;
1815990b4856Slling 			}
1816fa9e4066Sahrens 			break;
1817fa9e4066Sahrens 		case 'R':
1818990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
18190a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1820990b4856Slling 				goto error;
18212f8aaab3Seschrock 			if (nvlist_lookup_string(props,
18222f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
18232f8aaab3Seschrock 			    &propval) == 0)
18242f8aaab3Seschrock 				break;
1825990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
18260a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1827990b4856Slling 				goto error;
1828fa9e4066Sahrens 			break;
1829f9af39baSGeorge Wilson 		case 'T':
1830f9af39baSGeorge Wilson 			errno = 0;
1831f9af39baSGeorge Wilson 			txg = strtoull(optarg, &endptr, 10);
1832f9af39baSGeorge Wilson 			if (errno != 0 || *endptr != '\0') {
1833f9af39baSGeorge Wilson 				(void) fprintf(stderr,
1834f9af39baSGeorge Wilson 				    gettext("invalid txg value\n"));
1835f9af39baSGeorge Wilson 				usage(B_FALSE);
1836f9af39baSGeorge Wilson 			}
1837f9af39baSGeorge Wilson 			rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
1838f9af39baSGeorge Wilson 			break;
1839468c413aSTim Haley 		case 'V':
18404b964adaSGeorge Wilson 			flags |= ZFS_IMPORT_VERBATIM;
1841468c413aSTim Haley 			break;
1842468c413aSTim Haley 		case 'X':
1843468c413aSTim Haley 			xtreme_rewind = B_TRUE;
1844468c413aSTim Haley 			break;
1845fa9e4066Sahrens 		case ':':
1846fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1847fa9e4066Sahrens 			    "'%c' option\n"), optopt);
184899653d4eSeschrock 			usage(B_FALSE);
1849fa9e4066Sahrens 			break;
1850fa9e4066Sahrens 		case '?':
1851fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1852fa9e4066Sahrens 			    optopt);
185399653d4eSeschrock 			usage(B_FALSE);
1854fa9e4066Sahrens 		}
1855fa9e4066Sahrens 	}
1856fa9e4066Sahrens 
1857fa9e4066Sahrens 	argc -= optind;
1858fa9e4066Sahrens 	argv += optind;
1859fa9e4066Sahrens 
18602f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
18612f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
18622f8aaab3Seschrock 		usage(B_FALSE);
18632f8aaab3Seschrock 	}
18642f8aaab3Seschrock 
1865468c413aSTim Haley 	if ((dryrun || xtreme_rewind) && !do_rewind) {
1866468c413aSTim Haley 		(void) fprintf(stderr,
1867468c413aSTim Haley 		    gettext("-n or -X only meaningful with -F\n"));
1868468c413aSTim Haley 		usage(B_FALSE);
1869468c413aSTim Haley 	}
1870468c413aSTim Haley 	if (dryrun)
1871468c413aSTim Haley 		rewind_policy = ZPOOL_TRY_REWIND;
1872468c413aSTim Haley 	else if (do_rewind)
1873468c413aSTim Haley 		rewind_policy = ZPOOL_DO_REWIND;
1874468c413aSTim Haley 	if (xtreme_rewind)
1875468c413aSTim Haley 		rewind_policy |= ZPOOL_EXTREME_REWIND;
1876468c413aSTim Haley 
1877468c413aSTim Haley 	/* In the future, we can capture further policy and include it here */
1878468c413aSTim Haley 	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
1879f9af39baSGeorge Wilson 	    nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 ||
1880468c413aSTim Haley 	    nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
1881468c413aSTim Haley 		goto error;
1882468c413aSTim Haley 
1883fa9e4066Sahrens 	if (searchdirs == NULL) {
1884fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1885fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1886fa9e4066Sahrens 		nsearch = 1;
1887fa9e4066Sahrens 	}
1888fa9e4066Sahrens 
1889fa9e4066Sahrens 	/* check argument count */
1890fa9e4066Sahrens 	if (do_all) {
1891fa9e4066Sahrens 		if (argc != 0) {
1892fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
189399653d4eSeschrock 			usage(B_FALSE);
1894fa9e4066Sahrens 		}
1895fa9e4066Sahrens 	} else {
1896fa9e4066Sahrens 		if (argc > 2) {
1897fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
189899653d4eSeschrock 			usage(B_FALSE);
1899fa9e4066Sahrens 		}
1900fa9e4066Sahrens 
1901fa9e4066Sahrens 		/*
1902fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1903fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1904fa9e4066Sahrens 		 * silently fail.
1905fa9e4066Sahrens 		 */
1906fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1907fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1908fa9e4066Sahrens 			    "discover pools: permission denied\n"));
190999653d4eSeschrock 			free(searchdirs);
1910468c413aSTim Haley 			nvlist_free(policy);
1911fa9e4066Sahrens 			return (1);
1912fa9e4066Sahrens 		}
1913fa9e4066Sahrens 	}
1914fa9e4066Sahrens 
1915fa9e4066Sahrens 	/*
1916fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1917fa9e4066Sahrens 	 *
1918fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1919fa9e4066Sahrens 	 *		each one.
1920fa9e4066Sahrens 	 *
1921fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1922fa9e4066Sahrens 	 *
1923fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1924fa9e4066Sahrens 	 *		name and import that one.
19254c58d714Sdarrenm 	 *
19264c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1927fa9e4066Sahrens 	 */
1928fa9e4066Sahrens 	if (argc != 0) {
1929fa9e4066Sahrens 		char *endptr;
1930fa9e4066Sahrens 
1931fa9e4066Sahrens 		errno = 0;
1932fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1933fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1934fa9e4066Sahrens 			searchname = argv[0];
1935fa9e4066Sahrens 		found_config = NULL;
1936fa9e4066Sahrens 
193724e697d4Sck153898 		/*
1938d41c4376SMark J Musante 		 * User specified a name or guid.  Ensure it's unique.
193924e697d4Sck153898 		 */
1940d41c4376SMark J Musante 		idata.unique = B_TRUE;
194124e697d4Sck153898 	}
194224e697d4Sck153898 
1943d41c4376SMark J Musante 
1944d41c4376SMark J Musante 	idata.path = searchdirs;
1945d41c4376SMark J Musante 	idata.paths = nsearch;
1946d41c4376SMark J Musante 	idata.poolname = searchname;
1947d41c4376SMark J Musante 	idata.guid = searchguid;
1948d41c4376SMark J Musante 	idata.cachefile = cachefile;
1949d41c4376SMark J Musante 
1950d41c4376SMark J Musante 	pools = zpool_search_import(g_zfs, &idata);
1951d41c4376SMark J Musante 
1952d41c4376SMark J Musante 	if (pools != NULL && idata.exists &&
1953d41c4376SMark J Musante 	    (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
1954d41c4376SMark J Musante 		(void) fprintf(stderr, gettext("cannot import '%s': "
1955d41c4376SMark J Musante 		    "a pool with that name already exists\n"),
1956d41c4376SMark J Musante 		    argv[0]);
1957d41c4376SMark J Musante 		(void) fprintf(stderr, gettext("use the form '%s "
1958d41c4376SMark J Musante 		    "<pool | id> <newpool>' to give it a new name\n"),
1959d41c4376SMark J Musante 		    "zpool import");
1960d41c4376SMark J Musante 		err = 1;
1961d41c4376SMark J Musante 	} else if (pools == NULL && idata.exists) {
1962d41c4376SMark J Musante 		(void) fprintf(stderr, gettext("cannot import '%s': "
1963d41c4376SMark J Musante 		    "a pool with that name is already created/imported,\n"),
1964d41c4376SMark J Musante 		    argv[0]);
1965d41c4376SMark J Musante 		(void) fprintf(stderr, gettext("and no additional pools "
1966d41c4376SMark J Musante 		    "with that name were found\n"));
1967d41c4376SMark J Musante 		err = 1;
1968d41c4376SMark J Musante 	} else if (pools == NULL) {
196924e697d4Sck153898 		if (argc != 0) {
197024e697d4Sck153898 			(void) fprintf(stderr, gettext("cannot import '%s': "
197124e697d4Sck153898 			    "no such pool available\n"), argv[0]);
197224e697d4Sck153898 		}
1973d41c4376SMark J Musante 		err = 1;
1974d41c4376SMark J Musante 	}
1975d41c4376SMark J Musante 
1976d41c4376SMark J Musante 	if (err == 1) {
197724e697d4Sck153898 		free(searchdirs);
1978468c413aSTim Haley 		nvlist_free(policy);
197924e697d4Sck153898 		return (1);
198024e697d4Sck153898 	}
198124e697d4Sck153898 
198224e697d4Sck153898 	/*
198324e697d4Sck153898 	 * At this point we have a list of import candidate configs. Even if
198424e697d4Sck153898 	 * we were searching by pool name or guid, we still need to
198524e697d4Sck153898 	 * post-process the list to deal with pool state and possible
198624e697d4Sck153898 	 * duplicate names.
198724e697d4Sck153898 	 */
1988fa9e4066Sahrens 	err = 0;
1989fa9e4066Sahrens 	elem = NULL;
199099653d4eSeschrock 	first = B_TRUE;
1991fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1992fa9e4066Sahrens 
1993fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1994fa9e4066Sahrens 
19954c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
19964c58d714Sdarrenm 		    &pool_state) == 0);
19974c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
19984c58d714Sdarrenm 			continue;
19994c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
20004c58d714Sdarrenm 			continue;
20014c58d714Sdarrenm 
2002468c413aSTim Haley 		verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY,
2003468c413aSTim Haley 		    policy) == 0);
2004468c413aSTim Haley 
2005fa9e4066Sahrens 		if (argc == 0) {
2006fa9e4066Sahrens 			if (first)
200799653d4eSeschrock 				first = B_FALSE;
20083bb79becSeschrock 			else if (!do_all)
2009fa9e4066Sahrens 				(void) printf("\n");
2010fa9e4066Sahrens 
2011468c413aSTim Haley 			if (do_all) {
2012fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
20134b964adaSGeorge Wilson 				    props, flags);
2014468c413aSTim Haley 			} else {
2015fa9e4066Sahrens 				show_import(config);
2016468c413aSTim Haley 			}
2017fa9e4066Sahrens 		} else if (searchname != NULL) {
2018fa9e4066Sahrens 			char *name;
2019fa9e4066Sahrens 
2020fa9e4066Sahrens 			/*
2021fa9e4066Sahrens 			 * We are searching for a pool based on name.
2022fa9e4066Sahrens 			 */
2023fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
2024fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
2025fa9e4066Sahrens 
2026fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
2027fa9e4066Sahrens 				if (found_config != NULL) {
2028fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
2029fa9e4066Sahrens 					    "cannot import '%s': more than "
2030fa9e4066Sahrens 					    "one matching pool\n"), searchname);
2031fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
2032fa9e4066Sahrens 					    "import by numeric ID instead\n"));
203399653d4eSeschrock 					err = B_TRUE;
2034fa9e4066Sahrens 				}
2035fa9e4066Sahrens 				found_config = config;
2036fa9e4066Sahrens 			}
2037fa9e4066Sahrens 		} else {
2038fa9e4066Sahrens 			uint64_t guid;
2039fa9e4066Sahrens 
2040fa9e4066Sahrens 			/*
2041fa9e4066Sahrens 			 * Search for a pool by guid.
2042fa9e4066Sahrens 			 */
2043fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
2044fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
2045fa9e4066Sahrens 
2046fa9e4066Sahrens 			if (guid == searchguid)
2047fa9e4066Sahrens 				found_config = config;
2048fa9e4066Sahrens 		}
2049fa9e4066Sahrens 	}
2050fa9e4066Sahrens 
2051fa9e4066Sahrens 	/*
2052fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
2053fa9e4066Sahrens 	 * pool, and then do the import.
2054fa9e4066Sahrens 	 */
2055fa9e4066Sahrens 	if (argc != 0 && err == 0) {
2056fa9e4066Sahrens 		if (found_config == NULL) {
2057fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
2058fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
205999653d4eSeschrock 			err = B_TRUE;
2060fa9e4066Sahrens 		} else {
2061fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
20624b964adaSGeorge Wilson 			    argv[1], mntopts, props, flags);
2063fa9e4066Sahrens 		}
2064fa9e4066Sahrens 	}
2065fa9e4066Sahrens 
2066fa9e4066Sahrens 	/*
2067fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
2068fa9e4066Sahrens 	 * found.
2069fa9e4066Sahrens 	 */
2070fa9e4066Sahrens 	if (argc == 0 && first)
2071fa9e4066Sahrens 		(void) fprintf(stderr,
2072fa9e4066Sahrens 		    gettext("no pools available to import\n"));
2073fa9e4066Sahrens 
2074ecd6cf80Smarks error:
2075ecd6cf80Smarks 	nvlist_free(props);
2076fa9e4066Sahrens 	nvlist_free(pools);
2077468c413aSTim Haley 	nvlist_free(policy);
207899653d4eSeschrock 	free(searchdirs);
2079fa9e4066Sahrens 
2080fa9e4066Sahrens 	return (err ? 1 : 0);
2081fa9e4066Sahrens }
2082fa9e4066Sahrens 
2083fa9e4066Sahrens typedef struct iostat_cbdata {
20844263d13fSGeorge Wilson 	boolean_t cb_verbose;
2085fa9e4066Sahrens 	int cb_namewidth;
20864263d13fSGeorge Wilson 	int cb_iteration;
20874263d13fSGeorge Wilson 	zpool_list_t *cb_list;
2088fa9e4066Sahrens } iostat_cbdata_t;
2089fa9e4066Sahrens 
2090fa9e4066Sahrens static void
2091fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
2092fa9e4066Sahrens {
2093fa9e4066Sahrens 	int i = 0;
2094fa9e4066Sahrens 
2095fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
2096fa9e4066Sahrens 		(void) printf("-");
2097fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
2098fa9e4066Sahrens }
2099fa9e4066Sahrens 
2100fa9e4066Sahrens static void
2101fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
2102fa9e4066Sahrens {
2103fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
2104fa9e4066Sahrens 	    cb->cb_namewidth, "");
2105485bbbf5SGeorge Wilson 	(void) printf("%-*s  alloc   free   read  write   read  write\n",
2106fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
2107fa9e4066Sahrens 	print_iostat_separator(cb);
2108fa9e4066Sahrens }
2109fa9e4066Sahrens 
2110fa9e4066Sahrens /*
2111fa9e4066Sahrens  * Display a single statistic.
2112fa9e4066Sahrens  */
2113990b4856Slling static void
2114fa9e4066Sahrens print_one_stat(uint64_t value)
2115fa9e4066Sahrens {
2116fa9e4066Sahrens 	char buf[64];
2117fa9e4066Sahrens 
2118fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
2119fa9e4066Sahrens 	(void) printf("  %5s", buf);
2120fa9e4066Sahrens }
2121fa9e4066Sahrens 
2122fa9e4066Sahrens /*
2123fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
2124fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
2125fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
2126fa9e4066Sahrens  */
2127fa9e4066Sahrens void
2128c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
2129c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
2130fa9e4066Sahrens {
2131fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
2132fa9e4066Sahrens 	uint_t c, children;
2133fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
2134fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
2135fa9e4066Sahrens 	uint64_t tdelta;
2136fa9e4066Sahrens 	double scale;
2137afefbcddSeschrock 	char *vname;
2138fa9e4066Sahrens 
2139fa9e4066Sahrens 	if (oldnv != NULL) {
21403f9d6ad7SLin Ling 		verify(nvlist_lookup_uint64_array(oldnv,
21413f9d6ad7SLin Ling 		    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
2142fa9e4066Sahrens 	} else {
2143fa9e4066Sahrens 		oldvs = &zerovs;
2144fa9e4066Sahrens 	}
2145fa9e4066Sahrens 
21463f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
2147fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
2148fa9e4066Sahrens 
2149fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
2150fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
2151fa9e4066Sahrens 	else
2152fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
2153fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
2154fa9e4066Sahrens 
2155fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
2156fa9e4066Sahrens 
2157fa9e4066Sahrens 	if (tdelta == 0)
2158fa9e4066Sahrens 		scale = 1.0;
2159fa9e4066Sahrens 	else
2160fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
2161fa9e4066Sahrens 
2162fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
2163fa9e4066Sahrens 	if (newvs->vs_space == 0) {
2164fa9e4066Sahrens 		(void) printf("      -      -");
2165fa9e4066Sahrens 	} else {
2166fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
2167fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
2168fa9e4066Sahrens 	}
2169fa9e4066Sahrens 
2170fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
2171fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
2172fa9e4066Sahrens 
2173fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
2174fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
2175fa9e4066Sahrens 
2176fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
2177fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
2178fa9e4066Sahrens 
2179fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
2180fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
2181fa9e4066Sahrens 
2182fa9e4066Sahrens 	(void) printf("\n");
2183fa9e4066Sahrens 
2184fa9e4066Sahrens 	if (!cb->cb_verbose)
2185fa9e4066Sahrens 		return;
2186fa9e4066Sahrens 
2187fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
2188fa9e4066Sahrens 	    &newchild, &children) != 0)
2189fa9e4066Sahrens 		return;
2190fa9e4066Sahrens 
2191fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
2192fa9e4066Sahrens 	    &oldchild, &c) != 0)
2193fa9e4066Sahrens 		return;
2194fa9e4066Sahrens 
2195afefbcddSeschrock 	for (c = 0; c < children; c++) {
21969d439f90SMike Harsch 		uint64_t ishole = B_FALSE, islog = B_FALSE;
21973f9d6ad7SLin Ling 
21989d439f90SMike Harsch 		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
21999d439f90SMike Harsch 		    &ishole);
22009d439f90SMike Harsch 
22019d439f90SMike Harsch 		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
22029d439f90SMike Harsch 		    &islog);
22039d439f90SMike Harsch 
22049d439f90SMike Harsch 		if (ishole || islog)
22053f9d6ad7SLin Ling 			continue;
22063f9d6ad7SLin Ling 
220788ecc943SGeorge Wilson 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
2208c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2209afefbcddSeschrock 		    newchild[c], cb, depth + 2);
2210afefbcddSeschrock 		free(vname);
2211afefbcddSeschrock 	}
2212fa94a07fSbrendan 
2213fa94a07fSbrendan 	/*
22149d439f90SMike Harsch 	 * Log device section
22159d439f90SMike Harsch 	 */
22169d439f90SMike Harsch 
22179d439f90SMike Harsch 	if (num_logs(newnv) > 0) {
22189d439f90SMike Harsch 		(void) printf("%-*s      -      -      -      -      -      "
22199d439f90SMike Harsch 		    "-\n", cb->cb_namewidth, "logs");
22209d439f90SMike Harsch 
22219d439f90SMike Harsch 		for (c = 0; c < children; c++) {
22229d439f90SMike Harsch 			uint64_t islog = B_FALSE;
22239d439f90SMike Harsch 			(void) nvlist_lookup_uint64(newchild[c],
22249d439f90SMike Harsch 			    ZPOOL_CONFIG_IS_LOG, &islog);
22259d439f90SMike Harsch 
22269d439f90SMike Harsch 			if (islog) {
22279d439f90SMike Harsch 				vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
22289d439f90SMike Harsch 				    B_FALSE);
22299d439f90SMike Harsch 				print_vdev_stats(zhp, vname, oldnv ?
22309d439f90SMike Harsch 				    oldchild[c] : NULL, newchild[c],
22319d439f90SMike Harsch 				    cb, depth + 2);
22329d439f90SMike Harsch 				free(vname);
22339d439f90SMike Harsch 			}
22349d439f90SMike Harsch 		}
22359d439f90SMike Harsch 
22369d439f90SMike Harsch 	}
22379d439f90SMike Harsch 
22389d439f90SMike Harsch 	/*
2239fa94a07fSbrendan 	 * Include level 2 ARC devices in iostat output
2240fa94a07fSbrendan 	 */
2241fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
2242fa94a07fSbrendan 	    &newchild, &children) != 0)
2243fa94a07fSbrendan 		return;
2244fa94a07fSbrendan 
2245fa94a07fSbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
2246fa94a07fSbrendan 	    &oldchild, &c) != 0)
2247fa94a07fSbrendan 		return;
2248fa94a07fSbrendan 
2249fa94a07fSbrendan 	if (children > 0) {
2250fa94a07fSbrendan 		(void) printf("%-*s      -      -      -      -      -      "
2251fa94a07fSbrendan 		    "-\n", cb->cb_namewidth, "cache");
2252fa94a07fSbrendan 		for (c = 0; c < children; c++) {
225388ecc943SGeorge Wilson 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
225488ecc943SGeorge Wilson 			    B_FALSE);
2255fa94a07fSbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2256fa94a07fSbrendan 			    newchild[c], cb, depth + 2);
2257fa94a07fSbrendan 			free(vname);
2258fa94a07fSbrendan 		}
2259fa94a07fSbrendan 	}
2260fa9e4066Sahrens }
2261fa9e4066Sahrens 
2262088e9d47Seschrock static int
2263088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
2264088e9d47Seschrock {
2265088e9d47Seschrock 	iostat_cbdata_t *cb = data;
226694de1d4cSeschrock 	boolean_t missing;
2267088e9d47Seschrock 
2268088e9d47Seschrock 	/*
2269088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
2270088e9d47Seschrock 	 */
227194de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
227294de1d4cSeschrock 		return (-1);
227394de1d4cSeschrock 
227494de1d4cSeschrock 	if (missing)
2275088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
2276088e9d47Seschrock 
2277088e9d47Seschrock 	return (0);
2278088e9d47Seschrock }
2279088e9d47Seschrock 
2280fa9e4066Sahrens /*
2281fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
2282fa9e4066Sahrens  */
2283fa9e4066Sahrens int
2284fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
2285fa9e4066Sahrens {
2286fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
2287fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
2288fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
2289fa9e4066Sahrens 
2290088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
2291fa9e4066Sahrens 
2292088e9d47Seschrock 	if (cb->cb_iteration == 1)
2293fa9e4066Sahrens 		oldconfig = NULL;
2294fa9e4066Sahrens 
2295fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
2296fa9e4066Sahrens 	    &newnvroot) == 0);
2297fa9e4066Sahrens 
2298088e9d47Seschrock 	if (oldconfig == NULL)
2299fa9e4066Sahrens 		oldnvroot = NULL;
2300088e9d47Seschrock 	else
2301088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
2302088e9d47Seschrock 		    &oldnvroot) == 0);
2303fa9e4066Sahrens 
2304fa9e4066Sahrens 	/*
2305fa9e4066Sahrens 	 * Print out the statistics for the pool.
2306fa9e4066Sahrens 	 */
2307c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
2308fa9e4066Sahrens 
2309fa9e4066Sahrens 	if (cb->cb_verbose)
2310fa9e4066Sahrens 		print_iostat_separator(cb);
2311fa9e4066Sahrens 
2312fa9e4066Sahrens 	return (0);
2313fa9e4066Sahrens }
2314fa9e4066Sahrens 
2315fa9e4066Sahrens int
2316fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
2317fa9e4066Sahrens {
2318fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
2319fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2320fa9e4066Sahrens 
2321088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
2322fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2323fa9e4066Sahrens 		    &nvroot) == 0);
2324fa9e4066Sahrens 		if (!cb->cb_verbose)
2325fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
2326fa9e4066Sahrens 		else
2327e1d5e507SFrederik Wessels 			cb->cb_namewidth = max_width(zhp, nvroot, 0,
2328e1d5e507SFrederik Wessels 			    cb->cb_namewidth);
2329fa9e4066Sahrens 	}
2330fa9e4066Sahrens 
2331fa9e4066Sahrens 	/*
2332fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
2333fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
2334fa9e4066Sahrens 	 */
2335fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
2336fa9e4066Sahrens 		cb->cb_namewidth = 10;
2337fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
2338fa9e4066Sahrens 		cb->cb_namewidth = 38;
2339fa9e4066Sahrens 
2340fa9e4066Sahrens 	return (0);
2341fa9e4066Sahrens }
2342fa9e4066Sahrens 
2343fa9e4066Sahrens /*
23443f9d6ad7SLin Ling  * Parse the input string, get the 'interval' and 'count' value if there is one.
2345fa9e4066Sahrens  */
23463f9d6ad7SLin Ling static void
23473f9d6ad7SLin Ling get_interval_count(int *argcp, char **argv, unsigned long *iv,
23483f9d6ad7SLin Ling     unsigned long *cnt)
2349fa9e4066Sahrens {
2350fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
23513f9d6ad7SLin Ling 	int argc = *argcp, errno;
2352fa9e4066Sahrens 
2353fa9e4066Sahrens 	/*
2354fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
2355fa9e4066Sahrens 	 */
2356fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2357fa9e4066Sahrens 		char *end;
2358fa9e4066Sahrens 
2359fa9e4066Sahrens 		errno = 0;
2360fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
2361fa9e4066Sahrens 
2362fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
2363fa9e4066Sahrens 			if (interval == 0) {
2364fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
2365fa9e4066Sahrens 				    "cannot be zero\n"));
236699653d4eSeschrock 				usage(B_FALSE);
2367fa9e4066Sahrens 			}
2368fa9e4066Sahrens 			/*
2369fa9e4066Sahrens 			 * Ignore the last parameter
2370fa9e4066Sahrens 			 */
2371fa9e4066Sahrens 			argc--;
2372fa9e4066Sahrens 		} else {
2373fa9e4066Sahrens 			/*
2374fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
2375fa9e4066Sahrens 			 * user will get a more informative error message later
2376fa9e4066Sahrens 			 * on.
2377fa9e4066Sahrens 			 */
2378fa9e4066Sahrens 			interval = 0;
2379fa9e4066Sahrens 		}
2380fa9e4066Sahrens 	}
2381fa9e4066Sahrens 
2382fa9e4066Sahrens 	/*
2383fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
23843f9d6ad7SLin Ling 	 * and an interval.
2385fa9e4066Sahrens 	 */
2386fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2387fa9e4066Sahrens 		char *end;
2388fa9e4066Sahrens 
2389fa9e4066Sahrens 		errno = 0;
2390fa9e4066Sahrens 		count = interval;
2391fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
2392fa9e4066Sahrens 
2393fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
2394fa9e4066Sahrens 			if (interval == 0) {
2395fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
2396fa9e4066Sahrens 				    "cannot be zero\n"));
239799653d4eSeschrock 				usage(B_FALSE);
2398fa9e4066Sahrens 			}
2399fa9e4066Sahrens 
2400fa9e4066Sahrens 			/*
2401fa9e4066Sahrens 			 * Ignore the last parameter
2402fa9e4066Sahrens 			 */
2403fa9e4066Sahrens 			argc--;
2404fa9e4066Sahrens 		} else {
2405fa9e4066Sahrens 			interval = 0;
2406fa9e4066Sahrens 		}
2407fa9e4066Sahrens 	}
2408fa9e4066Sahrens 
24093f9d6ad7SLin Ling 	*iv = interval;
24103f9d6ad7SLin Ling 	*cnt = count;
24113f9d6ad7SLin Ling 	*argcp = argc;
24123f9d6ad7SLin Ling }
24133f9d6ad7SLin Ling 
24143f9d6ad7SLin Ling static void
24153f9d6ad7SLin Ling get_timestamp_arg(char c)
24163f9d6ad7SLin Ling {
24173f9d6ad7SLin Ling 	if (c == 'u')
24183f9d6ad7SLin Ling 		timestamp_fmt = UDATE;
24193f9d6ad7SLin Ling 	else if (c == 'd')
24203f9d6ad7SLin Ling 		timestamp_fmt = DDATE;
24213f9d6ad7SLin Ling 	else
24223f9d6ad7SLin Ling 		usage(B_FALSE);
24233f9d6ad7SLin Ling }
24243f9d6ad7SLin Ling 
24253f9d6ad7SLin Ling /*
24263f9d6ad7SLin Ling  * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]]
24273f9d6ad7SLin Ling  *
24283f9d6ad7SLin Ling  *	-v	Display statistics for individual vdevs
24293f9d6ad7SLin Ling  *	-T	Display a timestamp in date(1) or Unix format
24303f9d6ad7SLin Ling  *
24313f9d6ad7SLin Ling  * This command can be tricky because we want to be able to deal with pool
24323f9d6ad7SLin Ling  * creation/destruction as well as vdev configuration changes.  The bulk of this
24333f9d6ad7SLin Ling  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
24343f9d6ad7SLin Ling  * on pool_list_update() to detect the addition of new pools.  Configuration
24353f9d6ad7SLin Ling  * changes are all handled within libzfs.
24363f9d6ad7SLin Ling  */
24373f9d6ad7SLin Ling int
24383f9d6ad7SLin Ling zpool_do_iostat(int argc, char **argv)
24393f9d6ad7SLin Ling {
24403f9d6ad7SLin Ling 	int c;
24413f9d6ad7SLin Ling 	int ret;
24423f9d6ad7SLin Ling 	int npools;
24433f9d6ad7SLin Ling 	unsigned long interval = 0, count = 0;
24443f9d6ad7SLin Ling 	zpool_list_t *list;
24453f9d6ad7SLin Ling 	boolean_t verbose = B_FALSE;
24463f9d6ad7SLin Ling 	iostat_cbdata_t cb;
24473f9d6ad7SLin Ling 
24483f9d6ad7SLin Ling 	/* check options */
24493f9d6ad7SLin Ling 	while ((c = getopt(argc, argv, "T:v")) != -1) {
24503f9d6ad7SLin Ling 		switch (c) {
24513f9d6ad7SLin Ling 		case 'T':
24523f9d6ad7SLin Ling 			get_timestamp_arg(*optarg);
24533f9d6ad7SLin Ling 			break;
24543f9d6ad7SLin Ling 		case 'v':
24553f9d6ad7SLin Ling 			verbose = B_TRUE;
24563f9d6ad7SLin Ling 			break;
24573f9d6ad7SLin Ling 		case '?':
24583f9d6ad7SLin Ling 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
24593f9d6ad7SLin Ling 			    optopt);
24603f9d6ad7SLin Ling 			usage(B_FALSE);
24613f9d6ad7SLin Ling 		}
24623f9d6ad7SLin Ling 	}
24633f9d6ad7SLin Ling 
24643f9d6ad7SLin Ling 	argc -= optind;
24653f9d6ad7SLin Ling 	argv += optind;
24663f9d6ad7SLin Ling 
24673f9d6ad7SLin Ling 	get_interval_count(&argc, argv, &interval, &count);
24683f9d6ad7SLin Ling 
2469fa9e4066Sahrens 	/*
2470fa9e4066Sahrens 	 * Construct the list of all interesting pools.
2471fa9e4066Sahrens 	 */
2472fa9e4066Sahrens 	ret = 0;
2473b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
2474fa9e4066Sahrens 		return (1);
2475fa9e4066Sahrens 
247699653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
247799653d4eSeschrock 		pool_list_free(list);
2478fa9e4066Sahrens 		return (1);
247999653d4eSeschrock 	}
2480fa9e4066Sahrens 
2481fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
248299653d4eSeschrock 		pool_list_free(list);
2483fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
2484fa9e4066Sahrens 		return (1);
2485fa9e4066Sahrens 	}
2486fa9e4066Sahrens 
2487fa9e4066Sahrens 	/*
2488fa9e4066Sahrens 	 * Enter the main iostat loop.
2489fa9e4066Sahrens 	 */
2490fa9e4066Sahrens 	cb.cb_list = list;
2491fa9e4066Sahrens 	cb.cb_verbose = verbose;
2492fa9e4066Sahrens 	cb.cb_iteration = 0;
2493fa9e4066Sahrens 	cb.cb_namewidth = 0;
2494fa9e4066Sahrens 
2495fa9e4066Sahrens 	for (;;) {
2496fa9e4066Sahrens 		pool_list_update(list);
2497fa9e4066Sahrens 
2498fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
2499fa9e4066Sahrens 			break;
2500fa9e4066Sahrens 
2501fa9e4066Sahrens 		/*
2502088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
2503088e9d47Seschrock 		 * before calculating the maximum name width, so that any
2504088e9d47Seschrock 		 * configuration changes are properly accounted for.
2505088e9d47Seschrock 		 */
250699653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
2507088e9d47Seschrock 
2508088e9d47Seschrock 		/*
2509fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
2510fa9e4066Sahrens 		 * for the pool / device name column across all pools.
2511fa9e4066Sahrens 		 */
2512fa9e4066Sahrens 		cb.cb_namewidth = 0;
251399653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2514fa9e4066Sahrens 
251526fd7700SKrishnendu Sadhukhan - Sun Microsystems 		if (timestamp_fmt != NODATE)
251626fd7700SKrishnendu Sadhukhan - Sun Microsystems 			print_timestamp(timestamp_fmt);
251726fd7700SKrishnendu Sadhukhan - Sun Microsystems 
2518fa9e4066Sahrens 		/*
2519fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
2520fa9e4066Sahrens 		 */
2521fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
2522fa9e4066Sahrens 			print_iostat_header(&cb);
2523fa9e4066Sahrens 
252499653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2525fa9e4066Sahrens 
2526fa9e4066Sahrens 		/*
2527fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
2528fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
2529fa9e4066Sahrens 		 */
2530fa9e4066Sahrens 		if (npools > 1 && !verbose)
2531fa9e4066Sahrens 			print_iostat_separator(&cb);
2532fa9e4066Sahrens 
2533fa9e4066Sahrens 		if (verbose)
2534fa9e4066Sahrens 			(void) printf("\n");
2535fa9e4066Sahrens 
253639c23413Seschrock 		/*
253739c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
253839c23413Seschrock 		 * indefinitely.
253939c23413Seschrock 		 */
254039c23413Seschrock 		(void) fflush(stdout);
254139c23413Seschrock 
2542fa9e4066Sahrens 		if (interval == 0)
2543fa9e4066Sahrens 			break;
2544fa9e4066Sahrens 
2545fa9e4066Sahrens 		if (count != 0 && --count == 0)
2546fa9e4066Sahrens 			break;
2547fa9e4066Sahrens 
2548fa9e4066Sahrens 		(void) sleep(interval);
2549fa9e4066Sahrens 	}
2550fa9e4066Sahrens 
2551fa9e4066Sahrens 	pool_list_free(list);
2552fa9e4066Sahrens 
2553fa9e4066Sahrens 	return (ret);
2554fa9e4066Sahrens }
2555fa9e4066Sahrens 
2556fa9e4066Sahrens typedef struct list_cbdata {
25574263d13fSGeorge Wilson 	boolean_t	cb_verbose;
25584263d13fSGeorge Wilson 	int		cb_namewidth;
255999653d4eSeschrock 	boolean_t	cb_scripted;
2560990b4856Slling 	zprop_list_t	*cb_proplist;
2561fa9e4066Sahrens } list_cbdata_t;
2562fa9e4066Sahrens 
2563fa9e4066Sahrens /*
2564fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
2565fa9e4066Sahrens  */
2566990b4856Slling static void
25674263d13fSGeorge Wilson print_header(list_cbdata_t *cb)
2568fa9e4066Sahrens {
25694263d13fSGeorge Wilson 	zprop_list_t *pl = cb->cb_proplist;
2570ad135b5dSChristopher Siden 	char headerbuf[ZPOOL_MAXPROPLEN];
2571990b4856Slling 	const char *header;
2572990b4856Slling 	boolean_t first = B_TRUE;
2573990b4856Slling 	boolean_t right_justify;
25744263d13fSGeorge Wilson 	size_t width = 0;
2575fa9e4066Sahrens 
2576990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
25774263d13fSGeorge Wilson 		width = pl->pl_width;
25784263d13fSGeorge Wilson 		if (first && cb->cb_verbose) {
25794263d13fSGeorge Wilson 			/*
25804263d13fSGeorge Wilson 			 * Reset the width to accommodate the verbose listing
25814263d13fSGeorge Wilson 			 * of devices.
25824263d13fSGeorge Wilson 			 */
25834263d13fSGeorge Wilson 			width = cb->cb_namewidth;
25844263d13fSGeorge Wilson 		}
25854263d13fSGeorge Wilson 
2586990b4856Slling 		if (!first)
2587fa9e4066Sahrens 			(void) printf("  ");
2588fa9e4066Sahrens 		else
2589990b4856Slling 			first = B_FALSE;
2590fa9e4066Sahrens 
2591ad135b5dSChristopher Siden 		right_justify = B_FALSE;
2592ad135b5dSChristopher Siden 		if (pl->pl_prop != ZPROP_INVAL) {
2593990b4856Slling 			header = zpool_prop_column_name(pl->pl_prop);
2594990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2595ad135b5dSChristopher Siden 		} else {
2596ad135b5dSChristopher Siden 			int i;
2597ad135b5dSChristopher Siden 
2598ad135b5dSChristopher Siden 			for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
2599ad135b5dSChristopher Siden 				headerbuf[i] = toupper(pl->pl_user_prop[i]);
2600ad135b5dSChristopher Siden 			headerbuf[i] = '\0';
2601ad135b5dSChristopher Siden 			header = headerbuf;
2602ad135b5dSChristopher Siden 		}
2603990b4856Slling 
2604990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
2605990b4856Slling 			(void) printf("%s", header);
2606990b4856Slling 		else if (right_justify)
26074263d13fSGeorge Wilson 			(void) printf("%*s", width, header);
2608990b4856Slling 		else
26094263d13fSGeorge Wilson 			(void) printf("%-*s", width, header);
26104263d13fSGeorge Wilson 
2611fa9e4066Sahrens 	}
2612fa9e4066Sahrens 
2613fa9e4066Sahrens 	(void) printf("\n");
2614fa9e4066Sahrens }
2615fa9e4066Sahrens 
2616990b4856Slling /*
2617990b4856Slling  * Given a pool and a list of properties, print out all the properties according
2618990b4856Slling  * to the described layout.
2619990b4856Slling  */
2620990b4856Slling static void
26214263d13fSGeorge Wilson print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
2622990b4856Slling {
26234263d13fSGeorge Wilson 	zprop_list_t *pl = cb->cb_proplist;
2624990b4856Slling 	boolean_t first = B_TRUE;
2625990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
2626990b4856Slling 	char *propstr;
2627990b4856Slling 	boolean_t right_justify;
26284263d13fSGeorge Wilson 	size_t width;
2629990b4856Slling 
2630990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
26314263d13fSGeorge Wilson 
26324263d13fSGeorge Wilson 		width = pl->pl_width;
26334263d13fSGeorge Wilson 		if (first && cb->cb_verbose) {
26344263d13fSGeorge Wilson 			/*
26354263d13fSGeorge Wilson 			 * Reset the width to accommodate the verbose listing
26364263d13fSGeorge Wilson 			 * of devices.
26374263d13fSGeorge Wilson 			 */
26384263d13fSGeorge Wilson 			width = cb->cb_namewidth;
26394263d13fSGeorge Wilson 		}
26404263d13fSGeorge Wilson 
2641990b4856Slling 		if (!first) {
26424263d13fSGeorge Wilson 			if (cb->cb_scripted)
2643990b4856Slling 				(void) printf("\t");
2644990b4856Slling 			else
2645990b4856Slling 				(void) printf("  ");
2646990b4856Slling 		} else {
2647990b4856Slling 			first = B_FALSE;
2648990b4856Slling 		}
2649990b4856Slling 
2650990b4856Slling 		right_justify = B_FALSE;
2651990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
26524263d13fSGeorge Wilson 			if (pl->pl_prop == ZPOOL_PROP_EXPANDSZ &&
26534263d13fSGeorge Wilson 			    zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0)
26544263d13fSGeorge Wilson 				propstr = "-";
26554263d13fSGeorge Wilson 			else if (zpool_get_prop(zhp, pl->pl_prop, property,
2656990b4856Slling 			    sizeof (property), NULL) != 0)
2657990b4856Slling 				propstr = "-";
2658990b4856Slling 			else
2659990b4856Slling 				propstr = property;
2660990b4856Slling 
2661990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2662ad135b5dSChristopher Siden 		} else if ((zpool_prop_feature(pl->pl_user_prop) ||
2663ad135b5dSChristopher Siden 		    zpool_prop_unsupported(pl->pl_user_prop)) &&
2664ad135b5dSChristopher Siden 		    zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
2665ad135b5dSChristopher Siden 		    sizeof (property)) == 0) {
2666ad135b5dSChristopher Siden 			propstr = property;
2667990b4856Slling 		} else {
2668990b4856Slling 			propstr = "-";
2669990b4856Slling 		}
2670990b4856Slling 
2671990b4856Slling 
2672990b4856Slling 		/*
2673990b4856Slling 		 * If this is being called in scripted mode, or if this is the
2674990b4856Slling 		 * last column and it is left-justified, don't include a width
2675990b4856Slling 		 * format specifier.
2676990b4856Slling 		 */
26774263d13fSGeorge Wilson 		if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
2678990b4856Slling 			(void) printf("%s", propstr);
2679990b4856Slling 		else if (right_justify)
2680990b4856Slling 			(void) printf("%*s", width, propstr);
2681990b4856Slling 		else
2682990b4856Slling 			(void) printf("%-*s", width, propstr);
2683990b4856Slling 	}
2684990b4856Slling 
2685990b4856Slling 	(void) printf("\n");
2686990b4856Slling }
2687990b4856Slling 
26884263d13fSGeorge Wilson static void
26894263d13fSGeorge Wilson print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted)
26904263d13fSGeorge Wilson {
26914263d13fSGeorge Wilson 	char propval[64];
26924263d13fSGeorge Wilson 	boolean_t fixed;
26934263d13fSGeorge Wilson 	size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
26944263d13fSGeorge Wilson 
26954263d13fSGeorge Wilson 	zfs_nicenum(value, propval, sizeof (propval));
26964263d13fSGeorge Wilson 
26974263d13fSGeorge Wilson 	if (prop == ZPOOL_PROP_EXPANDSZ && value == 0)
26984263d13fSGeorge Wilson 		(void) strlcpy(propval, "-", sizeof (propval));
26994263d13fSGeorge Wilson 
27004263d13fSGeorge Wilson 	if (scripted)
27014263d13fSGeorge Wilson 		(void) printf("\t%s", propval);
27024263d13fSGeorge Wilson 	else
27034263d13fSGeorge Wilson 		(void) printf("  %*s", width, propval);
27044263d13fSGeorge Wilson }
27054263d13fSGeorge Wilson 
27064263d13fSGeorge Wilson void
27074263d13fSGeorge Wilson print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
27084263d13fSGeorge Wilson     list_cbdata_t *cb, int depth)
27094263d13fSGeorge Wilson {
27104263d13fSGeorge Wilson 	nvlist_t **child;
27114263d13fSGeorge Wilson 	vdev_stat_t *vs;
27124263d13fSGeorge Wilson 	uint_t c, children;
27134263d13fSGeorge Wilson 	char *vname;
27144263d13fSGeorge Wilson 	boolean_t scripted = cb->cb_scripted;
27154263d13fSGeorge Wilson 
27164263d13fSGeorge Wilson 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
27174263d13fSGeorge Wilson 	    (uint64_t **)&vs, &c) == 0);
27184263d13fSGeorge Wilson 
27194263d13fSGeorge Wilson 	if (name != NULL) {
27204263d13fSGeorge Wilson 		if (scripted)
27214263d13fSGeorge Wilson 			(void) printf("\t%s", name);
27224263d13fSGeorge Wilson 		else if (strlen(name) + depth > cb->cb_namewidth)
27234263d13fSGeorge Wilson 			(void) printf("%*s%s", depth, "", name);
27244263d13fSGeorge Wilson 		else
27254263d13fSGeorge Wilson 			(void) printf("%*s%s%*s", depth, "", name,
27264263d13fSGeorge Wilson 			    (int)(cb->cb_namewidth - strlen(name) - depth), "");
27274263d13fSGeorge Wilson 
27284263d13fSGeorge Wilson 		/* only toplevel vdevs have capacity stats */
27294263d13fSGeorge Wilson 		if (vs->vs_space == 0) {
27304263d13fSGeorge Wilson 			if (scripted)
27314263d13fSGeorge Wilson 				(void) printf("\t-\t-\t-");
27324263d13fSGeorge Wilson 			else
27334263d13fSGeorge Wilson 				(void) printf("      -      -      -");
27344263d13fSGeorge Wilson 		} else {
27354263d13fSGeorge Wilson 			print_one_column(ZPOOL_PROP_SIZE, vs->vs_space,
27364263d13fSGeorge Wilson 			    scripted);
27374263d13fSGeorge Wilson 			print_one_column(ZPOOL_PROP_CAPACITY, vs->vs_alloc,
27384263d13fSGeorge Wilson 			    scripted);
27394263d13fSGeorge Wilson 			print_one_column(ZPOOL_PROP_FREE,
27404263d13fSGeorge Wilson 			    vs->vs_space - vs->vs_alloc, scripted);
27414263d13fSGeorge Wilson 		}
27424263d13fSGeorge Wilson 		print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize,
27434263d13fSGeorge Wilson 		    scripted);
27444263d13fSGeorge Wilson 		(void) printf("\n");
27454263d13fSGeorge Wilson 	}
27464263d13fSGeorge Wilson 
27474263d13fSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
27484263d13fSGeorge Wilson 	    &child, &children) != 0)
27494263d13fSGeorge Wilson 		return;
27504263d13fSGeorge Wilson 
27514263d13fSGeorge Wilson 	for (c = 0; c < children; c++) {
27524263d13fSGeorge Wilson 		uint64_t ishole = B_FALSE;
27534263d13fSGeorge Wilson 
27544263d13fSGeorge Wilson 		if (nvlist_lookup_uint64(child[c],
27554263d13fSGeorge Wilson 		    ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
27564263d13fSGeorge Wilson 			continue;
27574263d13fSGeorge Wilson 
27584263d13fSGeorge Wilson 		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
27594263d13fSGeorge Wilson 		print_list_stats(zhp, vname, child[c], cb, depth + 2);
27604263d13fSGeorge Wilson 		free(vname);
27614263d13fSGeorge Wilson 	}
27624263d13fSGeorge Wilson 
27634263d13fSGeorge Wilson 	/*
27644263d13fSGeorge Wilson 	 * Include level 2 ARC devices in iostat output
27654263d13fSGeorge Wilson 	 */
27664263d13fSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
27674263d13fSGeorge Wilson 	    &child, &children) != 0)
27684263d13fSGeorge Wilson 		return;
27694263d13fSGeorge Wilson 
27704263d13fSGeorge Wilson 	if (children > 0) {
27714263d13fSGeorge Wilson 		(void) printf("%-*s      -      -      -      -      -      "
27724263d13fSGeorge Wilson 		    "-\n", cb->cb_namewidth, "cache");
27734263d13fSGeorge Wilson 		for (c = 0; c < children; c++) {
27744263d13fSGeorge Wilson 			vname = zpool_vdev_name(g_zfs, zhp, child[c],
27754263d13fSGeorge Wilson 			    B_FALSE);
27764263d13fSGeorge Wilson 			print_list_stats(zhp, vname, child[c], cb, depth + 2);
27774263d13fSGeorge Wilson 			free(vname);
27784263d13fSGeorge Wilson 		}
27794263d13fSGeorge Wilson 	}
27804263d13fSGeorge Wilson }
27814263d13fSGeorge Wilson 
27824263d13fSGeorge Wilson 
2783990b4856Slling /*
2784990b4856Slling  * Generic callback function to list a pool.
2785990b4856Slling  */
2786fa9e4066Sahrens int
2787fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2788fa9e4066Sahrens {
2789fa9e4066Sahrens 	list_cbdata_t *cbp = data;
27904263d13fSGeorge Wilson 	nvlist_t *config;
27914263d13fSGeorge Wilson 	nvlist_t *nvroot;
2792fa9e4066Sahrens 
27934263d13fSGeorge Wilson 	config = zpool_get_config(zhp, NULL);
2794fa9e4066Sahrens 
27954263d13fSGeorge Wilson 	print_pool(zhp, cbp);
27964263d13fSGeorge Wilson 	if (!cbp->cb_verbose)
27974263d13fSGeorge Wilson 		return (0);
27984263d13fSGeorge Wilson 
27994263d13fSGeorge Wilson 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
28004263d13fSGeorge Wilson 	    &nvroot) == 0);
28014263d13fSGeorge Wilson 	print_list_stats(zhp, NULL, nvroot, cbp, 0);
2802fa9e4066Sahrens 
2803fa9e4066Sahrens 	return (0);
2804fa9e4066Sahrens }
2805fa9e4066Sahrens 
2806fa9e4066Sahrens /*
28073f9d6ad7SLin Ling  * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
2808fa9e4066Sahrens  *
2809990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2810990b4856Slling  *		by a single tab.
2811990b4856Slling  *	-o	List of properties to display.  Defaults to
2812485bbbf5SGeorge Wilson  *		"name,size,allocated,free,capacity,health,altroot"
28133f9d6ad7SLin Ling  *	-T	Display a timestamp in date(1) or Unix format
2814fa9e4066Sahrens  *
2815fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2816fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2817fa9e4066Sahrens  */
2818fa9e4066Sahrens int
2819fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2820fa9e4066Sahrens {
2821fa9e4066Sahrens 	int c;
2822fa9e4066Sahrens 	int ret;
2823fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2824990b4856Slling 	static char default_props[] =
28254263d13fSGeorge Wilson 	    "name,size,allocated,free,expandsize,capacity,dedupratio,"
28264263d13fSGeorge Wilson 	    "health,altroot";
2827990b4856Slling 	char *props = default_props;
28283f9d6ad7SLin Ling 	unsigned long interval = 0, count = 0;
28294263d13fSGeorge Wilson 	zpool_list_t *list;
28304263d13fSGeorge Wilson 	boolean_t first = B_TRUE;
2831fa9e4066Sahrens 
2832fa9e4066Sahrens 	/* check options */
28334263d13fSGeorge Wilson 	while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) {
2834fa9e4066Sahrens 		switch (c) {
2835fa9e4066Sahrens 		case 'H':
283699653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2837fa9e4066Sahrens 			break;
2838fa9e4066Sahrens 		case 'o':
2839990b4856Slling 			props = optarg;
2840fa9e4066Sahrens 			break;
28413f9d6ad7SLin Ling 		case 'T':
28423f9d6ad7SLin Ling 			get_timestamp_arg(*optarg);
28433f9d6ad7SLin Ling 			break;
28444263d13fSGeorge Wilson 		case 'v':
28454263d13fSGeorge Wilson 			cb.cb_verbose = B_TRUE;
28464263d13fSGeorge Wilson 			break;
2847fa9e4066Sahrens 		case ':':
2848fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2849fa9e4066Sahrens 			    "'%c' option\n"), optopt);
285099653d4eSeschrock 			usage(B_FALSE);
2851fa9e4066Sahrens 			break;
2852fa9e4066Sahrens 		case '?':
2853fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2854fa9e4066Sahrens 			    optopt);
285599653d4eSeschrock 			usage(B_FALSE);
2856fa9e4066Sahrens 		}
2857fa9e4066Sahrens 	}
2858fa9e4066Sahrens 
2859fa9e4066Sahrens 	argc -= optind;
2860fa9e4066Sahrens 	argv += optind;
2861fa9e4066Sahrens 
28623f9d6ad7SLin Ling 	get_interval_count(&argc, argv, &interval, &count);
28633f9d6ad7SLin Ling 
2864990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
286599653d4eSeschrock 		usage(B_FALSE);
2866fa9e4066Sahrens 
28674263d13fSGeorge Wilson 	if ((list = pool_list_get(argc, argv, &cb.cb_proplist, &ret)) == NULL)
28684263d13fSGeorge Wilson 		return (1);
2869fa9e4066Sahrens 
28704263d13fSGeorge Wilson 	if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
2871fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
28723f9d6ad7SLin Ling 		zprop_free_list(cb.cb_proplist);
2873fa9e4066Sahrens 		return (0);
2874fa9e4066Sahrens 	}
2875fa9e4066Sahrens 
28764263d13fSGeorge Wilson 	for (;;) {
28774263d13fSGeorge Wilson 		pool_list_update(list);
28784263d13fSGeorge Wilson 
28794263d13fSGeorge Wilson 		if (pool_list_count(list) == 0)
28804263d13fSGeorge Wilson 			break;
28814263d13fSGeorge Wilson 
28824263d13fSGeorge Wilson 		cb.cb_namewidth = 0;
28834263d13fSGeorge Wilson 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
28844263d13fSGeorge Wilson 
28854263d13fSGeorge Wilson 		if (timestamp_fmt != NODATE)
28864263d13fSGeorge Wilson 			print_timestamp(timestamp_fmt);
28874263d13fSGeorge Wilson 
28884263d13fSGeorge Wilson 		if (!cb.cb_scripted && (first || cb.cb_verbose)) {
28894263d13fSGeorge Wilson 			print_header(&cb);
28904263d13fSGeorge Wilson 			first = B_FALSE;
28914263d13fSGeorge Wilson 		}
28924263d13fSGeorge Wilson 		ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
28934263d13fSGeorge Wilson 
28943f9d6ad7SLin Ling 		if (interval == 0)
28953f9d6ad7SLin Ling 			break;
28963f9d6ad7SLin Ling 
28973f9d6ad7SLin Ling 		if (count != 0 && --count == 0)
28983f9d6ad7SLin Ling 			break;
28993f9d6ad7SLin Ling 
29003f9d6ad7SLin Ling 		(void) sleep(interval);
29013f9d6ad7SLin Ling 	}
29023f9d6ad7SLin Ling 
29033f9d6ad7SLin Ling 	zprop_free_list(cb.cb_proplist);
2904fa9e4066Sahrens 	return (ret);
2905fa9e4066Sahrens }
2906fa9e4066Sahrens 
2907fa9e4066Sahrens static nvlist_t *
2908fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2909fa9e4066Sahrens {
2910fa9e4066Sahrens 	nvlist_t **child;
2911fa9e4066Sahrens 	uint_t c, children;
2912fa9e4066Sahrens 	nvlist_t *match;
2913fa9e4066Sahrens 	char *path;
2914fa9e4066Sahrens 
2915fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2916fa9e4066Sahrens 	    &child, &children) != 0) {
2917fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2918fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2919fa9e4066Sahrens 			name += 9;
2920fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2921fa9e4066Sahrens 			path += 9;
2922fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2923fa9e4066Sahrens 			return (nv);
2924fa9e4066Sahrens 		return (NULL);
2925fa9e4066Sahrens 	}
2926fa9e4066Sahrens 
2927fa9e4066Sahrens 	for (c = 0; c < children; c++)
2928fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2929fa9e4066Sahrens 			return (match);
2930fa9e4066Sahrens 
2931fa9e4066Sahrens 	return (NULL);
2932fa9e4066Sahrens }
2933fa9e4066Sahrens 
2934fa9e4066Sahrens static int
2935fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2936fa9e4066Sahrens {
293799653d4eSeschrock 	boolean_t force = B_FALSE;
2938fa9e4066Sahrens 	int c;
2939fa9e4066Sahrens 	nvlist_t *nvroot;
2940fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2941fa9e4066Sahrens 	zpool_handle_t *zhp;
294299653d4eSeschrock 	int ret;
2943fa9e4066Sahrens 
2944fa9e4066Sahrens 	/* check options */
2945fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2946fa9e4066Sahrens 		switch (c) {
2947fa9e4066Sahrens 		case 'f':
294899653d4eSeschrock 			force = B_TRUE;
2949fa9e4066Sahrens 			break;
2950fa9e4066Sahrens 		case '?':
2951fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2952fa9e4066Sahrens 			    optopt);
295399653d4eSeschrock 			usage(B_FALSE);
2954fa9e4066Sahrens 		}
2955fa9e4066Sahrens 	}
2956fa9e4066Sahrens 
2957fa9e4066Sahrens 	argc -= optind;
2958fa9e4066Sahrens 	argv += optind;
2959fa9e4066Sahrens 
2960fa9e4066Sahrens 	/* get pool name and check number of arguments */
2961fa9e4066Sahrens 	if (argc < 1) {
2962fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
296399653d4eSeschrock 		usage(B_FALSE);
2964fa9e4066Sahrens 	}
2965fa9e4066Sahrens 
2966fa9e4066Sahrens 	poolname = argv[0];
2967fa9e4066Sahrens 
2968fa9e4066Sahrens 	if (argc < 2) {
2969fa9e4066Sahrens 		(void) fprintf(stderr,
2970fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
297199653d4eSeschrock 		usage(B_FALSE);
2972fa9e4066Sahrens 	}
2973fa9e4066Sahrens 
2974fa9e4066Sahrens 	old_disk = argv[1];
2975fa9e4066Sahrens 
2976fa9e4066Sahrens 	if (argc < 3) {
2977fa9e4066Sahrens 		if (!replacing) {
2978fa9e4066Sahrens 			(void) fprintf(stderr,
2979fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
298099653d4eSeschrock 			usage(B_FALSE);
2981fa9e4066Sahrens 		}
2982fa9e4066Sahrens 		new_disk = old_disk;
2983fa9e4066Sahrens 		argc -= 1;
2984fa9e4066Sahrens 		argv += 1;
2985fa9e4066Sahrens 	} else {
2986fa9e4066Sahrens 		new_disk = argv[2];
2987fa9e4066Sahrens 		argc -= 2;
2988fa9e4066Sahrens 		argv += 2;
2989fa9e4066Sahrens 	}
2990fa9e4066Sahrens 
2991fa9e4066Sahrens 	if (argc > 1) {
2992fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
299399653d4eSeschrock 		usage(B_FALSE);
2994fa9e4066Sahrens 	}
2995fa9e4066Sahrens 
299699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2997fa9e4066Sahrens 		return (1);
2998fa9e4066Sahrens 
29998488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
3000fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
3001fa9e4066Sahrens 		    poolname);
3002fa9e4066Sahrens 		zpool_close(zhp);
3003fa9e4066Sahrens 		return (1);
3004fa9e4066Sahrens 	}
3005fa9e4066Sahrens 
3006705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
3007705040edSEric Taylor 	    argc, argv);
3008fa9e4066Sahrens 	if (nvroot == NULL) {
3009fa9e4066Sahrens 		zpool_close(zhp);
3010fa9e4066Sahrens 		return (1);
3011fa9e4066Sahrens 	}
3012fa9e4066Sahrens 
301399653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
301499653d4eSeschrock 
301599653d4eSeschrock 	nvlist_free(nvroot);
301699653d4eSeschrock 	zpool_close(zhp);
301799653d4eSeschrock 
301899653d4eSeschrock 	return (ret);
3019fa9e4066Sahrens }
3020fa9e4066Sahrens 
3021fa9e4066Sahrens /*
3022fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
3023fa9e4066Sahrens  *
3024fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
3025fa9e4066Sahrens  *
3026fa9e4066Sahrens  * Replace <device> with <new_device>.
3027fa9e4066Sahrens  */
3028fa9e4066Sahrens /* ARGSUSED */
3029fa9e4066Sahrens int
3030fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
3031fa9e4066Sahrens {
3032fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
3033fa9e4066Sahrens }
3034fa9e4066Sahrens 
3035fa9e4066Sahrens /*
3036fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
3037fa9e4066Sahrens  *
3038fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
3039fa9e4066Sahrens  *
3040fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
3041fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
3042fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
3043fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
3044fa9e4066Sahrens  */
3045fa9e4066Sahrens int
3046fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
3047fa9e4066Sahrens {
3048fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
3049fa9e4066Sahrens }
3050fa9e4066Sahrens 
3051fa9e4066Sahrens /*
3052fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
3053fa9e4066Sahrens  *
3054fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
3055fa9e4066Sahrens  *		(not supported yet)
3056fa9e4066Sahrens  *
3057fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
3058fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
3059fa9e4066Sahrens  * has the only valid copy of some data.
3060fa9e4066Sahrens  */
3061fa9e4066Sahrens /* ARGSUSED */
3062fa9e4066Sahrens int
3063fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
3064fa9e4066Sahrens {
3065fa9e4066Sahrens 	int c;
3066fa9e4066Sahrens 	char *poolname, *path;
3067fa9e4066Sahrens 	zpool_handle_t *zhp;
306899653d4eSeschrock 	int ret;
3069fa9e4066Sahrens 
3070fa9e4066Sahrens 	/* check options */
3071fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
3072fa9e4066Sahrens 		switch (c) {
3073fa9e4066Sahrens 		case 'f':
3074fa9e4066Sahrens 		case '?':
3075fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3076fa9e4066Sahrens 			    optopt);
307799653d4eSeschrock 			usage(B_FALSE);
3078fa9e4066Sahrens 		}
3079fa9e4066Sahrens 	}
3080fa9e4066Sahrens 
3081fa9e4066Sahrens 	argc -= optind;
3082fa9e4066Sahrens 	argv += optind;
3083fa9e4066Sahrens 
3084fa9e4066Sahrens 	/* get pool name and check number of arguments */
3085fa9e4066Sahrens 	if (argc < 1) {
3086fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
308799653d4eSeschrock 		usage(B_FALSE);
3088fa9e4066Sahrens 	}
3089fa9e4066Sahrens 
3090fa9e4066Sahrens 	if (argc < 2) {
3091fa9e4066Sahrens 		(void) fprintf(stderr,
3092fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
309399653d4eSeschrock 		usage(B_FALSE);
3094fa9e4066Sahrens 	}
3095fa9e4066Sahrens 
3096fa9e4066Sahrens 	poolname = argv[0];
3097fa9e4066Sahrens 	path = argv[1];
3098fa9e4066Sahrens 
309999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3100fa9e4066Sahrens 		return (1);
3101fa9e4066Sahrens 
310299653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
310399653d4eSeschrock 
310499653d4eSeschrock 	zpool_close(zhp);
310599653d4eSeschrock 
310699653d4eSeschrock 	return (ret);
3107fa9e4066Sahrens }
3108fa9e4066Sahrens 
3109fa9e4066Sahrens /*
31101195e687SMark J Musante  * zpool split [-n] [-o prop=val] ...
31111195e687SMark J Musante  *		[-o mntopt] ...
31121195e687SMark J Musante  *		[-R altroot] <pool> <newpool> [<device> ...]
31131195e687SMark J Musante  *
31141195e687SMark J Musante  *	-n	Do not split the pool, but display the resulting layout if
31151195e687SMark J Musante  *		it were to be split.
31161195e687SMark J Musante  *	-o	Set property=value, or set mount options.
31171195e687SMark J Musante  *	-R	Mount the split-off pool under an alternate root.
31181195e687SMark J Musante  *
31191195e687SMark J Musante  * Splits the named pool and gives it the new pool name.  Devices to be split
31201195e687SMark J Musante  * off may be listed, provided that no more than one device is specified
31211195e687SMark J Musante  * per top-level vdev mirror.  The newly split pool is left in an exported
31221195e687SMark J Musante  * state unless -R is specified.
31231195e687SMark J Musante  *
31241195e687SMark J Musante  * Restrictions: the top-level of the pool pool must only be made up of
31251195e687SMark J Musante  * mirrors; all devices in the pool must be healthy; no device may be
31261195e687SMark J Musante  * undergoing a resilvering operation.
31271195e687SMark J Musante  */
31281195e687SMark J Musante int
31291195e687SMark J Musante zpool_do_split(int argc, char **argv)
31301195e687SMark J Musante {
31311195e687SMark J Musante 	char *srcpool, *newpool, *propval;
31321195e687SMark J Musante 	char *mntopts = NULL;
31331195e687SMark J Musante 	splitflags_t flags;
31341195e687SMark J Musante 	int c, ret = 0;
31351195e687SMark J Musante 	zpool_handle_t *zhp;
31361195e687SMark J Musante 	nvlist_t *config, *props = NULL;
31371195e687SMark J Musante 
31381195e687SMark J Musante 	flags.dryrun = B_FALSE;
31391195e687SMark J Musante 	flags.import = B_FALSE;
31401195e687SMark J Musante 
31411195e687SMark J Musante 	/* check options */
31421195e687SMark J Musante 	while ((c = getopt(argc, argv, ":R:no:")) != -1) {
31431195e687SMark J Musante 		switch (c) {
31441195e687SMark J Musante 		case 'R':
31451195e687SMark J Musante 			flags.import = B_TRUE;
31461195e687SMark J Musante 			if (add_prop_list(
31471195e687SMark J Musante 			    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
31481195e687SMark J Musante 			    &props, B_TRUE) != 0) {
31491195e687SMark J Musante 				if (props)
31501195e687SMark J Musante 					nvlist_free(props);
31511195e687SMark J Musante 				usage(B_FALSE);
31521195e687SMark J Musante 			}
31531195e687SMark J Musante 			break;
31541195e687SMark J Musante 		case 'n':
31551195e687SMark J Musante 			flags.dryrun = B_TRUE;
31561195e687SMark J Musante 			break;
31571195e687SMark J Musante 		case 'o':
31581195e687SMark J Musante 			if ((propval = strchr(optarg, '=')) != NULL) {
31591195e687SMark J Musante 				*propval = '\0';
31601195e687SMark J Musante 				propval++;
31611195e687SMark J Musante 				if (add_prop_list(optarg, propval,
31621195e687SMark J Musante 				    &props, B_TRUE) != 0) {
31631195e687SMark J Musante 					if (props)
31641195e687SMark J Musante 						nvlist_free(props);
31651195e687SMark J Musante 					usage(B_FALSE);
31661195e687SMark J Musante 				}
31671195e687SMark J Musante 			} else {
31681195e687SMark J Musante 				mntopts = optarg;
31691195e687SMark J Musante 			}
31701195e687SMark J Musante 			break;
31711195e687SMark J Musante 		case ':':
31721195e687SMark J Musante 			(void) fprintf(stderr, gettext("missing argument for "
31731195e687SMark J Musante 			    "'%c' option\n"), optopt);
31741195e687SMark J Musante 			usage(B_FALSE);
31751195e687SMark J Musante 			break;
31761195e687SMark J Musante 		case '?':
31771195e687SMark J Musante 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
31781195e687SMark J Musante 			    optopt);
31791195e687SMark J Musante 			usage(B_FALSE);
31801195e687SMark J Musante 			break;
31811195e687SMark J Musante 		}
31821195e687SMark J Musante 	}
31831195e687SMark J Musante 
31841195e687SMark J Musante 	if (!flags.import && mntopts != NULL) {
31851195e687SMark J Musante 		(void) fprintf(stderr, gettext("setting mntopts is only "
31861195e687SMark J Musante 		    "valid when importing the pool\n"));
31871195e687SMark J Musante 		usage(B_FALSE);
31881195e687SMark J Musante 	}
31891195e687SMark J Musante 
31901195e687SMark J Musante 	argc -= optind;
31911195e687SMark J Musante 	argv += optind;
31921195e687SMark J Musante 
31931195e687SMark J Musante 	if (argc < 1) {
31941195e687SMark J Musante 		(void) fprintf(stderr, gettext("Missing pool name\n"));
31951195e687SMark J Musante 		usage(B_FALSE);
31961195e687SMark J Musante 	}
31971195e687SMark J Musante 	if (argc < 2) {
31981195e687SMark J Musante 		(void) fprintf(stderr, gettext("Missing new pool name\n"));
31991195e687SMark J Musante 		usage(B_FALSE);
32001195e687SMark J Musante 	}
32011195e687SMark J Musante 
32021195e687SMark J Musante 	srcpool = argv[0];
32031195e687SMark J Musante 	newpool = argv[1];
32041195e687SMark J Musante 
32051195e687SMark J Musante 	argc -= 2;
32061195e687SMark J Musante 	argv += 2;
32071195e687SMark J Musante 
32081195e687SMark J Musante 	if ((zhp = zpool_open(g_zfs, srcpool)) == NULL)
32091195e687SMark J Musante 		return (1);
32101195e687SMark J Musante 
32111195e687SMark J Musante 	config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
32121195e687SMark J Musante 	if (config == NULL) {
32131195e687SMark J Musante 		ret = 1;
32141195e687SMark J Musante 	} else {
32151195e687SMark J Musante 		if (flags.dryrun) {
32161195e687SMark J Musante 			(void) printf(gettext("would create '%s' with the "
32171195e687SMark J Musante 			    "following layout:\n\n"), newpool);
32181195e687SMark J Musante 			print_vdev_tree(NULL, newpool, config, 0, B_FALSE);
32191195e687SMark J Musante 		}
32201195e687SMark J Musante 		nvlist_free(config);
32211195e687SMark J Musante 	}
32221195e687SMark J Musante 
32231195e687SMark J Musante 	zpool_close(zhp);
32241195e687SMark J Musante 
32251195e687SMark J Musante 	if (ret != 0 || flags.dryrun || !flags.import)
32261195e687SMark J Musante 		return (ret);
32271195e687SMark J Musante 
32281195e687SMark J Musante 	/*
32291195e687SMark J Musante 	 * The split was successful. Now we need to open the new
32301195e687SMark J Musante 	 * pool and import it.
32311195e687SMark J Musante 	 */
32321195e687SMark J Musante 	if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
32331195e687SMark J Musante 		return (1);
32341195e687SMark J Musante 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
32351195e687SMark J Musante 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
32361195e687SMark J Musante 		ret = 1;
32371195e687SMark J Musante 		(void) fprintf(stderr, gettext("Split was succssful, but "
32381195e687SMark J Musante 		    "the datasets could not all be mounted\n"));
32391195e687SMark J Musante 		(void) fprintf(stderr, gettext("Try doing '%s' with a "
32401195e687SMark J Musante 		    "different altroot\n"), "zpool import");
32411195e687SMark J Musante 	}
32421195e687SMark J Musante 	zpool_close(zhp);
32431195e687SMark J Musante 
32441195e687SMark J Musante 	return (ret);
32451195e687SMark J Musante }
32461195e687SMark J Musante 
32471195e687SMark J Musante 
32481195e687SMark J Musante 
32491195e687SMark J Musante /*
3250441d80aaSlling  * zpool online <pool> <device> ...
3251fa9e4066Sahrens  */
3252fa9e4066Sahrens int
3253fa9e4066Sahrens zpool_do_online(int argc, char **argv)
3254fa9e4066Sahrens {
3255fa9e4066Sahrens 	int c, i;
3256fa9e4066Sahrens 	char *poolname;
3257fa9e4066Sahrens 	zpool_handle_t *zhp;
3258fa9e4066Sahrens 	int ret = 0;
32593d7072f8Seschrock 	vdev_state_t newstate;
3260573ca77eSGeorge Wilson 	int flags = 0;
3261fa9e4066Sahrens 
3262fa9e4066Sahrens 	/* check options */
3263573ca77eSGeorge Wilson 	while ((c = getopt(argc, argv, "et")) != -1) {
3264fa9e4066Sahrens 		switch (c) {
3265573ca77eSGeorge Wilson 		case 'e':
3266573ca77eSGeorge Wilson 			flags |= ZFS_ONLINE_EXPAND;
3267573ca77eSGeorge Wilson 			break;
3268fa9e4066Sahrens 		case 't':
3269fa9e4066Sahrens 		case '?':
3270fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3271fa9e4066Sahrens 			    optopt);
327299653d4eSeschrock 			usage(B_FALSE);
3273fa9e4066Sahrens 		}
3274fa9e4066Sahrens 	}
3275fa9e4066Sahrens 
3276fa9e4066Sahrens 	argc -= optind;
3277fa9e4066Sahrens 	argv += optind;
3278fa9e4066Sahrens 
3279fa9e4066Sahrens 	/* get pool name and check number of arguments */
3280fa9e4066Sahrens 	if (argc < 1) {
3281fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
328299653d4eSeschrock 		usage(B_FALSE);
3283fa9e4066Sahrens 	}
3284fa9e4066Sahrens 	if (argc < 2) {
3285fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
328699653d4eSeschrock 		usage(B_FALSE);
3287fa9e4066Sahrens 	}
3288fa9e4066Sahrens 
3289fa9e4066Sahrens 	poolname = argv[0];
3290fa9e4066Sahrens 
329199653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3292fa9e4066Sahrens 		return (1);
3293fa9e4066Sahrens 
32943d7072f8Seschrock 	for (i = 1; i < argc; i++) {
3295573ca77eSGeorge Wilson 		if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
32963d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
32973d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
32983d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
3299fa9e4066Sahrens 				    argv[i]);
33003d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
33013d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
33023d7072f8Seschrock 					    "clear' to restore a faulted "
33033d7072f8Seschrock 					    "device\n"));
3304fa9e4066Sahrens 				else
33053d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
33063d7072f8Seschrock 					    "replace' to replace devices "
33073d7072f8Seschrock 					    "that are no longer present\n"));
33083d7072f8Seschrock 			}
33093d7072f8Seschrock 		} else {
3310fa9e4066Sahrens 			ret = 1;
33113d7072f8Seschrock 		}
33123d7072f8Seschrock 	}
3313fa9e4066Sahrens 
331499653d4eSeschrock 	zpool_close(zhp);
331599653d4eSeschrock 
3316fa9e4066Sahrens 	return (ret);
3317fa9e4066Sahrens }
3318fa9e4066Sahrens 
3319fa9e4066Sahrens /*
3320441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
3321fa9e4066Sahrens  *
3322fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
3323fa9e4066Sahrens  *		so would appear to compromise pool availability.
3324fa9e4066Sahrens  *		(not supported yet)
3325fa9e4066Sahrens  *
3326fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
3327fa9e4066Sahrens  *		state will not be persistent across reboots.
3328fa9e4066Sahrens  */
3329fa9e4066Sahrens /* ARGSUSED */
3330fa9e4066Sahrens int
3331fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
3332fa9e4066Sahrens {
3333fa9e4066Sahrens 	int c, i;
3334fa9e4066Sahrens 	char *poolname;
3335fa9e4066Sahrens 	zpool_handle_t *zhp;
333699653d4eSeschrock 	int ret = 0;
333799653d4eSeschrock 	boolean_t istmp = B_FALSE;
3338fa9e4066Sahrens 
3339fa9e4066Sahrens 	/* check options */
3340fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
3341fa9e4066Sahrens 		switch (c) {
3342fa9e4066Sahrens 		case 't':
334399653d4eSeschrock 			istmp = B_TRUE;
3344441d80aaSlling 			break;
3345441d80aaSlling 		case 'f':
3346fa9e4066Sahrens 		case '?':
3347fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3348fa9e4066Sahrens 			    optopt);
334999653d4eSeschrock 			usage(B_FALSE);
3350fa9e4066Sahrens 		}
3351fa9e4066Sahrens 	}
3352fa9e4066Sahrens 
3353fa9e4066Sahrens 	argc -= optind;
3354fa9e4066Sahrens 	argv += optind;
3355fa9e4066Sahrens 
3356fa9e4066Sahrens 	/* get pool name and check number of arguments */
3357fa9e4066Sahrens 	if (argc < 1) {
3358fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
335999653d4eSeschrock 		usage(B_FALSE);
3360fa9e4066Sahrens 	}
3361fa9e4066Sahrens 	if (argc < 2) {
3362fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
336399653d4eSeschrock 		usage(B_FALSE);
3364fa9e4066Sahrens 	}
3365fa9e4066Sahrens 
3366fa9e4066Sahrens 	poolname = argv[0];
3367fa9e4066Sahrens 
336899653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3369fa9e4066Sahrens 		return (1);
3370fa9e4066Sahrens 
33713d7072f8Seschrock 	for (i = 1; i < argc; i++) {
33723d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
3373fa9e4066Sahrens 			ret = 1;
33743d7072f8Seschrock 	}
3375fa9e4066Sahrens 
337699653d4eSeschrock 	zpool_close(zhp);
337799653d4eSeschrock 
3378fa9e4066Sahrens 	return (ret);
3379fa9e4066Sahrens }
3380fa9e4066Sahrens 
3381ea8dc4b6Seschrock /*
3382ea8dc4b6Seschrock  * zpool clear <pool> [device]
3383ea8dc4b6Seschrock  *
3384ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
3385ea8dc4b6Seschrock  */
3386ea8dc4b6Seschrock int
3387ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
3388ea8dc4b6Seschrock {
3389468c413aSTim Haley 	int c;
3390ea8dc4b6Seschrock 	int ret = 0;
3391468c413aSTim Haley 	boolean_t dryrun = B_FALSE;
3392468c413aSTim Haley 	boolean_t do_rewind = B_FALSE;
3393468c413aSTim Haley 	boolean_t xtreme_rewind = B_FALSE;
3394468c413aSTim Haley 	uint32_t rewind_policy = ZPOOL_NO_REWIND;
3395468c413aSTim Haley 	nvlist_t *policy = NULL;
3396ea8dc4b6Seschrock 	zpool_handle_t *zhp;
3397ea8dc4b6Seschrock 	char *pool, *device;
3398ea8dc4b6Seschrock 
3399468c413aSTim Haley 	/* check options */
3400468c413aSTim Haley 	while ((c = getopt(argc, argv, "FnX")) != -1) {
3401468c413aSTim Haley 		switch (c) {
3402468c413aSTim Haley 		case 'F':
3403468c413aSTim Haley 			do_rewind = B_TRUE;
3404468c413aSTim Haley 			break;
3405468c413aSTim Haley 		case 'n':
3406468c413aSTim Haley 			dryrun = B_TRUE;
3407468c413aSTim Haley 			break;
3408468c413aSTim Haley 		case 'X':
3409468c413aSTim Haley 			xtreme_rewind = B_TRUE;
3410468c413aSTim Haley 			break;
3411468c413aSTim Haley 		case '?':
3412468c413aSTim Haley 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3413468c413aSTim Haley 			    optopt);
3414468c413aSTim Haley 			usage(B_FALSE);
3415468c413aSTim Haley 		}
3416468c413aSTim Haley 	}
3417468c413aSTim Haley 
3418468c413aSTim Haley 	argc -= optind;
3419468c413aSTim Haley 	argv += optind;
3420468c413aSTim Haley 
3421468c413aSTim Haley 	if (argc < 1) {
3422ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
342399653d4eSeschrock 		usage(B_FALSE);
3424ea8dc4b6Seschrock 	}
3425ea8dc4b6Seschrock 
3426468c413aSTim Haley 	if (argc > 2) {
3427ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
342899653d4eSeschrock 		usage(B_FALSE);
3429ea8dc4b6Seschrock 	}
3430ea8dc4b6Seschrock 
3431468c413aSTim Haley 	if ((dryrun || xtreme_rewind) && !do_rewind) {
3432468c413aSTim Haley 		(void) fprintf(stderr,
3433468c413aSTim Haley 		    gettext("-n or -X only meaningful with -F\n"));
3434468c413aSTim Haley 		usage(B_FALSE);
3435468c413aSTim Haley 	}
3436468c413aSTim Haley 	if (dryrun)
3437468c413aSTim Haley 		rewind_policy = ZPOOL_TRY_REWIND;
3438468c413aSTim Haley 	else if (do_rewind)
3439468c413aSTim Haley 		rewind_policy = ZPOOL_DO_REWIND;
3440468c413aSTim Haley 	if (xtreme_rewind)
3441468c413aSTim Haley 		rewind_policy |= ZPOOL_EXTREME_REWIND;
3442ea8dc4b6Seschrock 
3443468c413aSTim Haley 	/* In future, further rewind policy choices can be passed along here */
3444468c413aSTim Haley 	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
3445468c413aSTim Haley 	    nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
3446ea8dc4b6Seschrock 		return (1);
3447ea8dc4b6Seschrock 
3448468c413aSTim Haley 	pool = argv[0];
3449468c413aSTim Haley 	device = argc == 2 ? argv[1] : NULL;
3450468c413aSTim Haley 
3451468c413aSTim Haley 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
3452468c413aSTim Haley 		nvlist_free(policy);
3453468c413aSTim Haley 		return (1);
3454468c413aSTim Haley 	}
3455468c413aSTim Haley 
3456468c413aSTim Haley 	if (zpool_clear(zhp, device, policy) != 0)
3457ea8dc4b6Seschrock 		ret = 1;
3458ea8dc4b6Seschrock 
3459ea8dc4b6Seschrock 	zpool_close(zhp);
3460ea8dc4b6Seschrock 
3461468c413aSTim Haley 	nvlist_free(policy);
3462468c413aSTim Haley 
3463ea8dc4b6Seschrock 	return (ret);
3464ea8dc4b6Seschrock }
3465ea8dc4b6Seschrock 
3466e9103aaeSGarrett D'Amore /*
3467e9103aaeSGarrett D'Amore  * zpool reguid <pool>
3468e9103aaeSGarrett D'Amore  */
3469e9103aaeSGarrett D'Amore int
3470e9103aaeSGarrett D'Amore zpool_do_reguid(int argc, char **argv)
3471e9103aaeSGarrett D'Amore {
3472e9103aaeSGarrett D'Amore 	int c;
3473e9103aaeSGarrett D'Amore 	char *poolname;
3474e9103aaeSGarrett D'Amore 	zpool_handle_t *zhp;
3475e9103aaeSGarrett D'Amore 	int ret = 0;
3476e9103aaeSGarrett D'Amore 
3477e9103aaeSGarrett D'Amore 	/* check options */
3478e9103aaeSGarrett D'Amore 	while ((c = getopt(argc, argv, "")) != -1) {
3479e9103aaeSGarrett D'Amore 		switch (c) {
3480e9103aaeSGarrett D'Amore 		case '?':
3481e9103aaeSGarrett D'Amore 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3482e9103aaeSGarrett D'Amore 			    optopt);
3483e9103aaeSGarrett D'Amore 			usage(B_FALSE);
3484e9103aaeSGarrett D'Amore 		}
3485e9103aaeSGarrett D'Amore 	}
3486e9103aaeSGarrett D'Amore 
3487e9103aaeSGarrett D'Amore 	argc -= optind;
3488e9103aaeSGarrett D'Amore 	argv += optind;
3489e9103aaeSGarrett D'Amore 
3490e9103aaeSGarrett D'Amore 	/* get pool name and check number of arguments */
3491e9103aaeSGarrett D'Amore 	if (argc < 1) {
3492e9103aaeSGarrett D'Amore 		(void) fprintf(stderr, gettext("missing pool name\n"));
3493e9103aaeSGarrett D'Amore 		usage(B_FALSE);
3494e9103aaeSGarrett D'Amore 	}
3495e9103aaeSGarrett D'Amore 
3496e9103aaeSGarrett D'Amore 	if (argc > 1) {
3497e9103aaeSGarrett D'Amore 		(void) fprintf(stderr, gettext("too many arguments\n"));
3498e9103aaeSGarrett D'Amore 		usage(B_FALSE);
3499e9103aaeSGarrett D'Amore 	}
3500e9103aaeSGarrett D'Amore 
3501e9103aaeSGarrett D'Amore 	poolname = argv[0];
3502e9103aaeSGarrett D'Amore 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3503e9103aaeSGarrett D'Amore 		return (1);
3504e9103aaeSGarrett D'Amore 
3505e9103aaeSGarrett D'Amore 	ret = zpool_reguid(zhp);
3506e9103aaeSGarrett D'Amore 
3507e9103aaeSGarrett D'Amore 	zpool_close(zhp);
3508e9103aaeSGarrett D'Amore 	return (ret);
3509e9103aaeSGarrett D'Amore }
3510e9103aaeSGarrett D'Amore 
3511e9103aaeSGarrett D'Amore 
35124263d13fSGeorge Wilson /*
35134263d13fSGeorge Wilson  * zpool reopen <pool>
35144263d13fSGeorge Wilson  *
35154263d13fSGeorge Wilson  * Reopen the pool so that the kernel can update the sizes of all vdevs.
35164263d13fSGeorge Wilson  *
35174263d13fSGeorge Wilson  * NOTE: This command is currently undocumented.  If the command is ever
35184263d13fSGeorge Wilson  * exposed then the appropriate usage() messages will need to be made.
35194263d13fSGeorge Wilson  */
35204263d13fSGeorge Wilson int
35214263d13fSGeorge Wilson zpool_do_reopen(int argc, char **argv)
35224263d13fSGeorge Wilson {
35234263d13fSGeorge Wilson 	int ret = 0;
35244263d13fSGeorge Wilson 	zpool_handle_t *zhp;
35254263d13fSGeorge Wilson 	char *pool;
35264263d13fSGeorge Wilson 
35274263d13fSGeorge Wilson 	argc--;
35284263d13fSGeorge Wilson 	argv++;
35294263d13fSGeorge Wilson 
35304263d13fSGeorge Wilson 	if (argc != 1)
35314263d13fSGeorge Wilson 		return (2);
35324263d13fSGeorge Wilson 
35334263d13fSGeorge Wilson 	pool = argv[0];
35344263d13fSGeorge Wilson 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
35354263d13fSGeorge Wilson 		return (1);
35364263d13fSGeorge Wilson 
35374263d13fSGeorge Wilson 	ret = zpool_reopen(zhp);
35384263d13fSGeorge Wilson 	zpool_close(zhp);
35394263d13fSGeorge Wilson 	return (ret);
35404263d13fSGeorge Wilson }
35414263d13fSGeorge Wilson 
3542fa9e4066Sahrens typedef struct scrub_cbdata {
3543fa9e4066Sahrens 	int	cb_type;
354406eeb2adSek110237 	int	cb_argc;
354506eeb2adSek110237 	char	**cb_argv;
3546fa9e4066Sahrens } scrub_cbdata_t;
3547fa9e4066Sahrens 
3548fa9e4066Sahrens int
3549fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
3550fa9e4066Sahrens {
3551fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
355206eeb2adSek110237 	int err;
3553fa9e4066Sahrens 
3554ea8dc4b6Seschrock 	/*
3555ea8dc4b6Seschrock 	 * Ignore faulted pools.
3556ea8dc4b6Seschrock 	 */
3557ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
3558ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
3559ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
3560ea8dc4b6Seschrock 		return (1);
3561ea8dc4b6Seschrock 	}
3562ea8dc4b6Seschrock 
35633f9d6ad7SLin Ling 	err = zpool_scan(zhp, cb->cb_type);
356406eeb2adSek110237 
356506eeb2adSek110237 	return (err != 0);
3566fa9e4066Sahrens }
3567fa9e4066Sahrens 
3568fa9e4066Sahrens /*
3569fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
3570fa9e4066Sahrens  *
3571fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
3572fa9e4066Sahrens  */
3573fa9e4066Sahrens int
3574fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
3575fa9e4066Sahrens {
3576fa9e4066Sahrens 	int c;
3577fa9e4066Sahrens 	scrub_cbdata_t cb;
3578fa9e4066Sahrens 
35793f9d6ad7SLin Ling 	cb.cb_type = POOL_SCAN_SCRUB;
3580fa9e4066Sahrens 
3581fa9e4066Sahrens 	/* check options */
3582fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
3583fa9e4066Sahrens 		switch (c) {
3584fa9e4066Sahrens 		case 's':
35853f9d6ad7SLin Ling 			cb.cb_type = POOL_SCAN_NONE;
3586fa9e4066Sahrens 			break;
3587fa9e4066Sahrens 		case '?':
3588fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3589fa9e4066Sahrens 			    optopt);
359099653d4eSeschrock 			usage(B_FALSE);
3591fa9e4066Sahrens 		}
3592fa9e4066Sahrens 	}
3593fa9e4066Sahrens 
359406eeb2adSek110237 	cb.cb_argc = argc;
359506eeb2adSek110237 	cb.cb_argv = argv;
3596fa9e4066Sahrens 	argc -= optind;
3597fa9e4066Sahrens 	argv += optind;
3598fa9e4066Sahrens 
3599fa9e4066Sahrens 	if (argc < 1) {
3600fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
360199653d4eSeschrock 		usage(B_FALSE);
3602fa9e4066Sahrens 	}
3603fa9e4066Sahrens 
3604b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
3605fa9e4066Sahrens }
3606fa9e4066Sahrens 
3607fa9e4066Sahrens typedef struct status_cbdata {
3608fa9e4066Sahrens 	int		cb_count;
3609e9dbad6fSeschrock 	boolean_t	cb_allpools;
361099653d4eSeschrock 	boolean_t	cb_verbose;
361199653d4eSeschrock 	boolean_t	cb_explain;
361299653d4eSeschrock 	boolean_t	cb_first;
36139eb19f4dSGeorge Wilson 	boolean_t	cb_dedup_stats;
3614fa9e4066Sahrens } status_cbdata_t;
3615fa9e4066Sahrens 
3616fa9e4066Sahrens /*
3617fa9e4066Sahrens  * Print out detailed scrub status.
3618fa9e4066Sahrens  */
3619fa9e4066Sahrens void
36203f9d6ad7SLin Ling print_scan_status(pool_scan_stat_t *ps)
3621fa9e4066Sahrens {
36223f9d6ad7SLin Ling 	time_t start, end;
362373d314ceSLin Ling 	uint64_t elapsed, mins_left, hours_left;
36243f9d6ad7SLin Ling 	uint64_t pass_exam, examined, total;
36253f9d6ad7SLin Ling 	uint_t rate;
3626fa9e4066Sahrens 	double fraction_done;
36273f9d6ad7SLin Ling 	char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
3628fa9e4066Sahrens 
36293f9d6ad7SLin Ling 	(void) printf(gettext("  scan: "));
3630fa9e4066Sahrens 
36313f9d6ad7SLin Ling 	/* If there's never been a scan, there's not much to say. */
36323f9d6ad7SLin Ling 	if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
36333f9d6ad7SLin Ling 	    ps->pss_func >= POOL_SCAN_FUNCS) {
3634fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
3635fa9e4066Sahrens 		return;
3636fa9e4066Sahrens 	}
3637fa9e4066Sahrens 
36383f9d6ad7SLin Ling 	start = ps->pss_start_time;
36393f9d6ad7SLin Ling 	end = ps->pss_end_time;
36403f9d6ad7SLin Ling 	zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
3641fa9e4066Sahrens 
36423f9d6ad7SLin Ling 	assert(ps->pss_func == POOL_SCAN_SCRUB ||
36433f9d6ad7SLin Ling 	    ps->pss_func == POOL_SCAN_RESILVER);
36443f9d6ad7SLin Ling 	/*
36453f9d6ad7SLin Ling 	 * Scan is finished or canceled.
36463f9d6ad7SLin Ling 	 */
36473f9d6ad7SLin Ling 	if (ps->pss_state == DSS_FINISHED) {
36483f9d6ad7SLin Ling 		uint64_t minutes_taken = (end - start) / 60;
36493f9d6ad7SLin Ling 		char *fmt;
3650fa9e4066Sahrens 
36513f9d6ad7SLin Ling 		if (ps->pss_func == POOL_SCAN_SCRUB) {
36523f9d6ad7SLin Ling 			fmt = gettext("scrub repaired %s in %lluh%um with "
36533f9d6ad7SLin Ling 			    "%llu errors on %s");
36543f9d6ad7SLin Ling 		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
36553f9d6ad7SLin Ling 			fmt = gettext("resilvered %s in %lluh%um with "
36563f9d6ad7SLin Ling 			    "%llu errors on %s");
36573f9d6ad7SLin Ling 		}
36583f9d6ad7SLin Ling 		/* LINTED */
36593f9d6ad7SLin Ling 		(void) printf(fmt, processed_buf,
366018ce54dfSek110237 		    (u_longlong_t)(minutes_taken / 60),
366118ce54dfSek110237 		    (uint_t)(minutes_taken % 60),
36623f9d6ad7SLin Ling 		    (u_longlong_t)ps->pss_errors,
36633f9d6ad7SLin Ling 		    ctime((time_t *)&end));
36643f9d6ad7SLin Ling 		return;
36653f9d6ad7SLin Ling 	} else if (ps->pss_state == DSS_CANCELED) {
36663f9d6ad7SLin Ling 		if (ps->pss_func == POOL_SCAN_SCRUB) {
36673f9d6ad7SLin Ling 			(void) printf(gettext("scrub canceled on %s"),
36683f9d6ad7SLin Ling 			    ctime(&end));
36693f9d6ad7SLin Ling 		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
36703f9d6ad7SLin Ling 			(void) printf(gettext("resilver canceled on %s"),
36713f9d6ad7SLin Ling 			    ctime(&end));
36723f9d6ad7SLin Ling 		}
3673fa9e4066Sahrens 		return;
3674fa9e4066Sahrens 	}
3675fa9e4066Sahrens 
36763f9d6ad7SLin Ling 	assert(ps->pss_state == DSS_SCANNING);
3677fa9e4066Sahrens 
36783f9d6ad7SLin Ling 	/*
36793f9d6ad7SLin Ling 	 * Scan is in progress.
36803f9d6ad7SLin Ling 	 */
36813f9d6ad7SLin Ling 	if (ps->pss_func == POOL_SCAN_SCRUB) {
36823f9d6ad7SLin Ling 		(void) printf(gettext("scrub in progress since %s"),
36833f9d6ad7SLin Ling 		    ctime(&start));
36843f9d6ad7SLin Ling 	} else if (ps->pss_func == POOL_SCAN_RESILVER) {
36853f9d6ad7SLin Ling 		(void) printf(gettext("resilver in progress since %s"),
36863f9d6ad7SLin Ling 		    ctime(&start));
36873f9d6ad7SLin Ling 	}
36883f9d6ad7SLin Ling 
36893f9d6ad7SLin Ling 	examined = ps->pss_examined ? ps->pss_examined : 1;
36903f9d6ad7SLin Ling 	total = ps->pss_to_examine;
3691fa9e4066Sahrens 	fraction_done = (double)examined / total;
3692fa9e4066Sahrens 
36933f9d6ad7SLin Ling 	/* elapsed time for this pass */
36943f9d6ad7SLin Ling 	elapsed = time(NULL) - ps->pss_pass_start;
36953f9d6ad7SLin Ling 	elapsed = elapsed ? elapsed : 1;
36963f9d6ad7SLin Ling 	pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1;
36973f9d6ad7SLin Ling 	rate = pass_exam / elapsed;
36983f9d6ad7SLin Ling 	rate = rate ? rate : 1;
36993f9d6ad7SLin Ling 	mins_left = ((total - examined) / rate) / 60;
370073d314ceSLin Ling 	hours_left = mins_left / 60;
37013f9d6ad7SLin Ling 
37023f9d6ad7SLin Ling 	zfs_nicenum(examined, examined_buf, sizeof (examined_buf));
37033f9d6ad7SLin Ling 	zfs_nicenum(total, total_buf, sizeof (total_buf));
37043f9d6ad7SLin Ling 	zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
37053f9d6ad7SLin Ling 
370673d314ceSLin Ling 	/*
370773d314ceSLin Ling 	 * do not print estimated time if hours_left is more than 30 days
370873d314ceSLin Ling 	 */
370973d314ceSLin Ling 	(void) printf(gettext("    %s scanned out of %s at %s/s"),
371073d314ceSLin Ling 	    examined_buf, total_buf, rate_buf);
371173d314ceSLin Ling 	if (hours_left < (30 * 24)) {
371273d314ceSLin Ling 		(void) printf(gettext(", %lluh%um to go\n"),
371373d314ceSLin Ling 		    (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
371473d314ceSLin Ling 	} else {
371573d314ceSLin Ling 		(void) printf(gettext(
371673d314ceSLin Ling 		    ", (scan is slow, no estimated time)\n"));
371773d314ceSLin Ling 	}
37183f9d6ad7SLin Ling 
37193f9d6ad7SLin Ling 	if (ps->pss_func == POOL_SCAN_RESILVER) {
37203f9d6ad7SLin Ling 		(void) printf(gettext("    %s resilvered, %.2f%% done\n"),
37213f9d6ad7SLin Ling 		    processed_buf, 100 * fraction_done);
37223f9d6ad7SLin Ling 	} else if (ps->pss_func == POOL_SCAN_SCRUB) {
37233f9d6ad7SLin Ling 		(void) printf(gettext("    %s repaired, %.2f%% done\n"),
37243f9d6ad7SLin Ling 		    processed_buf, 100 * fraction_done);
37253f9d6ad7SLin Ling 	}
3726fa9e4066Sahrens }
3727fa9e4066Sahrens 
3728ea8dc4b6Seschrock static void
3729ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
3730ea8dc4b6Seschrock {
373175519f38Sek110237 	nvlist_t *nverrlist = NULL;
373255434c77Sek110237 	nvpair_t *elem;
373355434c77Sek110237 	char *pathname;
373455434c77Sek110237 	size_t len = MAXPATHLEN * 2;
3735ea8dc4b6Seschrock 
373655434c77Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
3737ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
3738ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
3739ea8dc4b6Seschrock 		return;
3740ea8dc4b6Seschrock 	}
3741ea8dc4b6Seschrock 
374255434c77Sek110237 	(void) printf("errors: Permanent errors have been "
374355434c77Sek110237 	    "detected in the following files:\n\n");
3744ea8dc4b6Seschrock 
374555434c77Sek110237 	pathname = safe_malloc(len);
374655434c77Sek110237 	elem = NULL;
374755434c77Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
374855434c77Sek110237 		nvlist_t *nv;
374955434c77Sek110237 		uint64_t dsobj, obj;
3750ea8dc4b6Seschrock 
375155434c77Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
375255434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
375355434c77Sek110237 		    &dsobj) == 0);
375455434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
375555434c77Sek110237 		    &obj) == 0);
375655434c77Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
375755434c77Sek110237 		(void) printf("%7s %s\n", "", pathname);
3758ea8dc4b6Seschrock 	}
375955434c77Sek110237 	free(pathname);
376055434c77Sek110237 	nvlist_free(nverrlist);
3761ea8dc4b6Seschrock }
3762ea8dc4b6Seschrock 
376399653d4eSeschrock static void
376499653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
376599653d4eSeschrock     int namewidth)
376699653d4eSeschrock {
376799653d4eSeschrock 	uint_t i;
376899653d4eSeschrock 	char *name;
376999653d4eSeschrock 
377099653d4eSeschrock 	if (nspares == 0)
377199653d4eSeschrock 		return;
377299653d4eSeschrock 
377399653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
377499653d4eSeschrock 
377599653d4eSeschrock 	for (i = 0; i < nspares; i++) {
377688ecc943SGeorge Wilson 		name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE);
377799653d4eSeschrock 		print_status_config(zhp, name, spares[i],
3778aa8cf21aSNeil Perrin 		    namewidth, 2, B_TRUE);
377999653d4eSeschrock 		free(name);
378099653d4eSeschrock 	}
378199653d4eSeschrock }
378299653d4eSeschrock 
3783fa94a07fSbrendan static void
3784fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
3785fa94a07fSbrendan     int namewidth)
3786fa94a07fSbrendan {
3787fa94a07fSbrendan 	uint_t i;
3788fa94a07fSbrendan 	char *name;
3789fa94a07fSbrendan 
3790fa94a07fSbrendan 	if (nl2cache == 0)
3791fa94a07fSbrendan 		return;
3792fa94a07fSbrendan 
3793fa94a07fSbrendan 	(void) printf(gettext("\tcache\n"));
3794fa94a07fSbrendan 
3795fa94a07fSbrendan 	for (i = 0; i < nl2cache; i++) {
379688ecc943SGeorge Wilson 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE);
3797fa94a07fSbrendan 		print_status_config(zhp, name, l2cache[i],
3798aa8cf21aSNeil Perrin 		    namewidth, 2, B_FALSE);
3799aa8cf21aSNeil Perrin 		free(name);
3800aa8cf21aSNeil Perrin 	}
3801aa8cf21aSNeil Perrin }
3802aa8cf21aSNeil Perrin 
38039eb19f4dSGeorge Wilson static void
38049eb19f4dSGeorge Wilson print_dedup_stats(nvlist_t *config)
38059eb19f4dSGeorge Wilson {
38069eb19f4dSGeorge Wilson 	ddt_histogram_t *ddh;
38079eb19f4dSGeorge Wilson 	ddt_stat_t *dds;
38089eb19f4dSGeorge Wilson 	ddt_object_t *ddo;
38099eb19f4dSGeorge Wilson 	uint_t c;
38109eb19f4dSGeorge Wilson 
38119eb19f4dSGeorge Wilson 	/*
38129eb19f4dSGeorge Wilson 	 * If the pool was faulted then we may not have been able to
38132384d9f8SGeorge Wilson 	 * obtain the config. Otherwise, if we have anything in the dedup
38149eb19f4dSGeorge Wilson 	 * table continue processing the stats.
38159eb19f4dSGeorge Wilson 	 */
38169eb19f4dSGeorge Wilson 	if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
3817ce72e614SYuri Pankov 	    (uint64_t **)&ddo, &c) != 0)
38189eb19f4dSGeorge Wilson 		return;
38199eb19f4dSGeorge Wilson 
38209eb19f4dSGeorge Wilson 	(void) printf("\n");
3821ce72e614SYuri Pankov 	(void) printf(gettext(" dedup: "));
3822ce72e614SYuri Pankov 	if (ddo->ddo_count == 0) {
3823ce72e614SYuri Pankov 		(void) printf(gettext("no DDT entries\n"));
3824ce72e614SYuri Pankov 		return;
3825ce72e614SYuri Pankov 	}
3826ce72e614SYuri Pankov 
38279eb19f4dSGeorge Wilson 	(void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
38289eb19f4dSGeorge Wilson 	    (u_longlong_t)ddo->ddo_count,
38299eb19f4dSGeorge Wilson 	    (u_longlong_t)ddo->ddo_dspace,
38309eb19f4dSGeorge Wilson 	    (u_longlong_t)ddo->ddo_mspace);
38319eb19f4dSGeorge Wilson 
38329eb19f4dSGeorge Wilson 	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
38339eb19f4dSGeorge Wilson 	    (uint64_t **)&dds, &c) == 0);
38349eb19f4dSGeorge Wilson 	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
38359eb19f4dSGeorge Wilson 	    (uint64_t **)&ddh, &c) == 0);
38369eb19f4dSGeorge Wilson 	zpool_dump_ddt(dds, ddh);
38379eb19f4dSGeorge Wilson }
38389eb19f4dSGeorge Wilson 
3839aa8cf21aSNeil Perrin /*
3840fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
3841fa9e4066Sahrens  *
3842fa9e4066Sahrens  *        pool: tank
3843fa9e4066Sahrens  *	status: DEGRADED
3844fa9e4066Sahrens  *	reason: One or more devices ...
3845654b400cSJoshua M. Clulow  *         see: http://illumos.org/msg/ZFS-xxxx-01
3846fa9e4066Sahrens  *	config:
3847fa9e4066Sahrens  *		mirror		DEGRADED
3848fa9e4066Sahrens  *                c1t0d0	OK
3849ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
3850fa9e4066Sahrens  *
3851fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
3852fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
3853fa9e4066Sahrens  */
3854fa9e4066Sahrens int
3855fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
3856fa9e4066Sahrens {
3857fa9e4066Sahrens 	status_cbdata_t *cbp = data;
3858fa9e4066Sahrens 	nvlist_t *config, *nvroot;
3859fa9e4066Sahrens 	char *msgid;
3860fa9e4066Sahrens 	int reason;
386146657f8dSmmusante 	const char *health;
386246657f8dSmmusante 	uint_t c;
386346657f8dSmmusante 	vdev_stat_t *vs;
3864fa9e4066Sahrens 
3865088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
3866fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
3867fa9e4066Sahrens 
3868fa9e4066Sahrens 	cbp->cb_count++;
3869fa9e4066Sahrens 
3870fa9e4066Sahrens 	/*
3871fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
3872fa9e4066Sahrens 	 * problems.
3873fa9e4066Sahrens 	 */
3874e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
3875e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
3876e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
3877e9dbad6fSeschrock 			    zpool_get_name(zhp));
3878e9dbad6fSeschrock 			if (cbp->cb_first)
3879e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
3880e9dbad6fSeschrock 		}
3881fa9e4066Sahrens 		return (0);
3882e9dbad6fSeschrock 	}
3883fa9e4066Sahrens 
3884fa9e4066Sahrens 	if (cbp->cb_first)
388599653d4eSeschrock 		cbp->cb_first = B_FALSE;
3886fa9e4066Sahrens 	else
3887fa9e4066Sahrens 		(void) printf("\n");
3888fa9e4066Sahrens 
388946657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
389046657f8dSmmusante 	    &nvroot) == 0);
38913f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
389246657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
3893990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3894fa9e4066Sahrens 
3895fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
3896fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
3897fa9e4066Sahrens 
3898fa9e4066Sahrens 	switch (reason) {
3899fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
3900fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3901fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
3902fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
3903fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3904fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3905fa9e4066Sahrens 		break;
3906fa9e4066Sahrens 
3907fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
3908fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3909fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
3910fa9e4066Sahrens 		    "pool to continue functioning.\n"));
3911fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3912fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3913fa9e4066Sahrens 		break;
3914fa9e4066Sahrens 
3915fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
3916fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3917fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
3918fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
3919fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
3920fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
3921fa9e4066Sahrens 		    "'zpool replace'.\n"));
3922fa9e4066Sahrens 		break;
3923fa9e4066Sahrens 
3924fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3925fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3926b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
3927fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
3928fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
3929468c413aSTim Haley 		zpool_explain_recover(zpool_get_handle(zhp),
3930468c413aSTim Haley 		    zpool_get_name(zhp), reason, config);
3931fa9e4066Sahrens 		break;
3932fa9e4066Sahrens 
3933fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
3934fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3935fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
3936fa9e4066Sahrens 		    "made to correct the error.  Applications are "
3937fa9e4066Sahrens 		    "unaffected.\n"));
3938fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
3939fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
3940ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
3941fa9e4066Sahrens 		    "replace'.\n"));
3942fa9e4066Sahrens 		break;
3943fa9e4066Sahrens 
3944fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
3945fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3946d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
3947fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
3948fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
3949fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
3950fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
3951fa9e4066Sahrens 		    "replace'.\n"));
3952fa9e4066Sahrens 		break;
3953fa9e4066Sahrens 
3954c25309d4SGeorge Wilson 	case ZPOOL_STATUS_REMOVED_DEV:
3955c25309d4SGeorge Wilson 		(void) printf(gettext("status: One or more devices has "
3956c25309d4SGeorge Wilson 		    "been removed by the administrator.\n\tSufficient "
3957c25309d4SGeorge Wilson 		    "replicas exist for the pool to continue functioning in "
3958c25309d4SGeorge Wilson 		    "a\n\tdegraded state.\n"));
3959c25309d4SGeorge Wilson 		(void) printf(gettext("action: Online the device using "
3960c25309d4SGeorge Wilson 		    "'zpool online' or replace the device with\n\t'zpool "
3961c25309d4SGeorge Wilson 		    "replace'.\n"));
3962c25309d4SGeorge Wilson 		break;
3963c25309d4SGeorge Wilson 
3964fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
3965fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
3966fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3967fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
3968fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3969fa9e4066Sahrens 		    "complete.\n"));
3970fa9e4066Sahrens 		break;
3971fa9e4066Sahrens 
3972ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3973ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3974ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3975ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3976ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3977ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3978ea8dc4b6Seschrock 		    "backup.\n"));
3979ea8dc4b6Seschrock 		break;
3980ea8dc4b6Seschrock 
3981ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3982ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3983ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3984468c413aSTim Haley 		zpool_explain_recover(zpool_get_handle(zhp),
3985468c413aSTim Haley 		    zpool_get_name(zhp), reason, config);
3986ea8dc4b6Seschrock 		break;
3987ea8dc4b6Seschrock 
3988eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3989eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3990eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3991eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3992eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3993eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3994eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3995eaca9bbdSeschrock 		break;
3996eaca9bbdSeschrock 
3997eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3998eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3999eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
4000eaca9bbdSeschrock 		    "be accessed on this system.\n"));
4001eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
4002eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
4003eaca9bbdSeschrock 		    "backup.\n"));
4004eaca9bbdSeschrock 		break;
4005eaca9bbdSeschrock 
4006ad135b5dSChristopher Siden 	case ZPOOL_STATUS_UNSUP_FEAT_READ:
4007ad135b5dSChristopher Siden 		(void) printf(gettext("status: The pool cannot be accessed on "
4008ad135b5dSChristopher Siden 		    "this system because it uses the\n\tfollowing feature(s) "
4009ad135b5dSChristopher Siden 		    "not supported on this system:\n"));
4010ad135b5dSChristopher Siden 		zpool_print_unsup_feat(config);
4011ad135b5dSChristopher Siden 		(void) printf("\n");
4012ad135b5dSChristopher Siden 		(void) printf(gettext("action: Access the pool from a system "
4013ad135b5dSChristopher Siden 		    "that supports the required feature(s),\n\tor restore the "
4014ad135b5dSChristopher Siden 		    "pool from backup.\n"));
4015ad135b5dSChristopher Siden 		break;
4016ad135b5dSChristopher Siden 
4017ad135b5dSChristopher Siden 	case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
4018ad135b5dSChristopher Siden 		(void) printf(gettext("status: The pool can only be accessed "
4019ad135b5dSChristopher Siden 		    "in read-only mode on this system. It\n\tcannot be "
4020ad135b5dSChristopher Siden 		    "accessed in read-write mode because it uses the "
4021ad135b5dSChristopher Siden 		    "following\n\tfeature(s) not supported on this system:\n"));
4022ad135b5dSChristopher Siden 		zpool_print_unsup_feat(config);
4023ad135b5dSChristopher Siden 		(void) printf("\n");
4024ad135b5dSChristopher Siden 		(void) printf(gettext("action: The pool cannot be accessed in "
4025ad135b5dSChristopher Siden 		    "read-write mode. Import the pool with\n"
4026ad135b5dSChristopher Siden 		    "\t\"-o readonly=on\", access the pool from a system that "
4027ad135b5dSChristopher Siden 		    "supports the\n\trequired feature(s), or restore the "
4028ad135b5dSChristopher Siden 		    "pool from backup.\n"));
4029ad135b5dSChristopher Siden 		break;
4030ad135b5dSChristopher Siden 
40313d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
40323d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
40333d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
40343d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
40353d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
40363d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
40373d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
40383d7072f8Seschrock 		break;
40393d7072f8Seschrock 
40403d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
40413d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
40423d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
40433d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
40443d7072f8Seschrock 		    "functioning.\n"));
40453d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
40463d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
40473d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
40483d7072f8Seschrock 		    "to be recovered.\n"));
40493d7072f8Seschrock 		break;
40503d7072f8Seschrock 
405132b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_WAIT:
405232b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
405332b87932Sek110237 		(void) printf(gettext("status: One or more devices are "
40548a79c1b5Sek110237 		    "faulted in response to IO failures.\n"));
405532b87932Sek110237 		(void) printf(gettext("action: Make sure the affected devices "
405632b87932Sek110237 		    "are connected, then run 'zpool clear'.\n"));
405732b87932Sek110237 		break;
405832b87932Sek110237 
4059b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
4060b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record "
4061b87f3af3Sperrin 		    "could not be read.\n"
4062b87f3af3Sperrin 		    "\tWaiting for adminstrator intervention to fix the "
4063b87f3af3Sperrin 		    "faulted pool.\n"));
4064b87f3af3Sperrin 		(void) printf(gettext("action: Either restore the affected "
4065b87f3af3Sperrin 		    "device(s) and run 'zpool online',\n"
4066b87f3af3Sperrin 		    "\tor ignore the intent log records by running "
4067b87f3af3Sperrin 		    "'zpool clear'.\n"));
4068b87f3af3Sperrin 		break;
4069b87f3af3Sperrin 
4070fa9e4066Sahrens 	default:
4071fa9e4066Sahrens 		/*
4072fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
4073fa9e4066Sahrens 		 */
4074fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
4075fa9e4066Sahrens 	}
4076fa9e4066Sahrens 
4077fa9e4066Sahrens 	if (msgid != NULL)
4078654b400cSJoshua M. Clulow 		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
4079fa9e4066Sahrens 		    msgid);
4080fa9e4066Sahrens 
4081fa9e4066Sahrens 	if (config != NULL) {
4082fa9e4066Sahrens 		int namewidth;
4083ea8dc4b6Seschrock 		uint64_t nerr;
4084fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
4085fa94a07fSbrendan 		uint_t nspares, nl2cache;
40863f9d6ad7SLin Ling 		pool_scan_stat_t *ps = NULL;
4087fa9e4066Sahrens 
40883f9d6ad7SLin Ling 		(void) nvlist_lookup_uint64_array(nvroot,
40893f9d6ad7SLin Ling 		    ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
40903f9d6ad7SLin Ling 		print_scan_status(ps);
4091fa9e4066Sahrens 
4092c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
4093fa9e4066Sahrens 		if (namewidth < 10)
4094fa9e4066Sahrens 			namewidth = 10;
4095fa9e4066Sahrens 
4096fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
4097fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
4098fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
4099c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
4100aa8cf21aSNeil Perrin 		    namewidth, 0, B_FALSE);
410199653d4eSeschrock 
41024dea40f0SNeil Perrin 		if (num_logs(nvroot) > 0)
4103e6ca193dSGeorge Wilson 			print_logs(zhp, nvroot, namewidth, B_TRUE);
4104fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
4105fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
4106fa94a07fSbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
4107fa94a07fSbrendan 
410899653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
410999653d4eSeschrock 		    &spares, &nspares) == 0)
411099653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
4111ea8dc4b6Seschrock 
4112ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
4113ea8dc4b6Seschrock 		    &nerr) == 0) {
411455434c77Sek110237 			nvlist_t *nverrlist = NULL;
411555434c77Sek110237 
4116ea8dc4b6Seschrock 			/*
4117ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
4118ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
4119ea8dc4b6Seschrock 			 * uniquifying the results.
4120ea8dc4b6Seschrock 			 */
412175519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
412255434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
412355434c77Sek110237 				nvpair_t *elem;
412455434c77Sek110237 
412555434c77Sek110237 				elem = NULL;
412655434c77Sek110237 				nerr = 0;
412755434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
412855434c77Sek110237 				    elem)) != NULL) {
412955434c77Sek110237 					nerr++;
413055434c77Sek110237 				}
413155434c77Sek110237 			}
413255434c77Sek110237 			nvlist_free(nverrlist);
4133ea8dc4b6Seschrock 
4134ea8dc4b6Seschrock 			(void) printf("\n");
413599653d4eSeschrock 
4136ea8dc4b6Seschrock 			if (nerr == 0)
4137ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
4138ea8dc4b6Seschrock 				    "errors\n"));
4139ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
4140e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
41415ad82045Snd150628 				    "errors, use '-v' for a list\n"),
41425ad82045Snd150628 				    (u_longlong_t)nerr);
4143ea8dc4b6Seschrock 			else
4144ea8dc4b6Seschrock 				print_error_log(zhp);
4145ea8dc4b6Seschrock 		}
41469eb19f4dSGeorge Wilson 
41479eb19f4dSGeorge Wilson 		if (cbp->cb_dedup_stats)
41489eb19f4dSGeorge Wilson 			print_dedup_stats(config);
4149fa9e4066Sahrens 	} else {
4150fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
4151fa9e4066Sahrens 		    "determined.\n"));
4152fa9e4066Sahrens 	}
4153fa9e4066Sahrens 
4154fa9e4066Sahrens 	return (0);
4155fa9e4066Sahrens }
4156fa9e4066Sahrens 
4157fa9e4066Sahrens /*
41583f9d6ad7SLin Ling  * zpool status [-vx] [-T d|u] [pool] ... [interval [count]]
4159fa9e4066Sahrens  *
4160fa9e4066Sahrens  *	-v	Display complete error logs
4161fa9e4066Sahrens  *	-x	Display only pools with potential problems
41629eb19f4dSGeorge Wilson  *	-D	Display dedup status (undocumented)
41633f9d6ad7SLin Ling  *	-T	Display a timestamp in date(1) or Unix format
4164fa9e4066Sahrens  *
4165fa9e4066Sahrens  * Describes the health status of all pools or some subset.
4166fa9e4066Sahrens  */
4167fa9e4066Sahrens int
4168fa9e4066Sahrens zpool_do_status(int argc, char **argv)
4169fa9e4066Sahrens {
4170fa9e4066Sahrens 	int c;
4171fa9e4066Sahrens 	int ret;
41723f9d6ad7SLin Ling 	unsigned long interval = 0, count = 0;
4173fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
4174fa9e4066Sahrens 
4175fa9e4066Sahrens 	/* check options */
41763f9d6ad7SLin Ling 	while ((c = getopt(argc, argv, "vxDT:")) != -1) {
4177fa9e4066Sahrens 		switch (c) {
4178fa9e4066Sahrens 		case 'v':
417999653d4eSeschrock 			cb.cb_verbose = B_TRUE;
4180fa9e4066Sahrens 			break;
4181fa9e4066Sahrens 		case 'x':
418299653d4eSeschrock 			cb.cb_explain = B_TRUE;
4183fa9e4066Sahrens 			break;
41849eb19f4dSGeorge Wilson 		case 'D':
41859eb19f4dSGeorge Wilson 			cb.cb_dedup_stats = B_TRUE;
41869eb19f4dSGeorge Wilson 			break;
41873f9d6ad7SLin Ling 		case 'T':
41883f9d6ad7SLin Ling 			get_timestamp_arg(*optarg);
41893f9d6ad7SLin Ling 			break;
4190fa9e4066Sahrens 		case '?':
4191fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4192fa9e4066Sahrens 			    optopt);
419399653d4eSeschrock 			usage(B_FALSE);
4194fa9e4066Sahrens 		}
4195fa9e4066Sahrens 	}
4196fa9e4066Sahrens 
4197fa9e4066Sahrens 	argc -= optind;
4198fa9e4066Sahrens 	argv += optind;
4199fa9e4066Sahrens 
42003f9d6ad7SLin Ling 	get_interval_count(&argc, argv, &interval, &count);
4201fa9e4066Sahrens 
4202e9dbad6fSeschrock 	if (argc == 0)
4203e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
4204e9dbad6fSeschrock 
42053f9d6ad7SLin Ling 	cb.cb_first = B_TRUE;
42063f9d6ad7SLin Ling 
42073f9d6ad7SLin Ling 	for (;;) {
42083f9d6ad7SLin Ling 		if (timestamp_fmt != NODATE)
42093f9d6ad7SLin Ling 			print_timestamp(timestamp_fmt);
42103f9d6ad7SLin Ling 
42113f9d6ad7SLin Ling 		ret = for_each_pool(argc, argv, B_TRUE, NULL,
42123f9d6ad7SLin Ling 		    status_callback, &cb);
4213fa9e4066Sahrens 
4214fa9e4066Sahrens 		if (argc == 0 && cb.cb_count == 0)
4215fa9e4066Sahrens 			(void) printf(gettext("no pools available\n"));
4216e9dbad6fSeschrock 		else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
4217fa9e4066Sahrens 			(void) printf(gettext("all pools are healthy\n"));
4218fa9e4066Sahrens 
42193f9d6ad7SLin Ling 		if (ret != 0)
4220fa9e4066Sahrens 			return (ret);
42213f9d6ad7SLin Ling 
42223f9d6ad7SLin Ling 		if (interval == 0)
42233f9d6ad7SLin Ling 			break;
42243f9d6ad7SLin Ling 
42253f9d6ad7SLin Ling 		if (count != 0 && --count == 0)
42263f9d6ad7SLin Ling 			break;
42273f9d6ad7SLin Ling 
42283f9d6ad7SLin Ling 		(void) sleep(interval);
42293f9d6ad7SLin Ling 	}
42303f9d6ad7SLin Ling 
42313f9d6ad7SLin Ling 	return (0);
4232fa9e4066Sahrens }
4233fa9e4066Sahrens 
4234eaca9bbdSeschrock typedef struct upgrade_cbdata {
4235eaca9bbdSeschrock 	int	cb_all;
4236eaca9bbdSeschrock 	int	cb_first;
4237eaca9bbdSeschrock 	int	cb_newer;
423806eeb2adSek110237 	int	cb_argc;
4239990b4856Slling 	uint64_t cb_version;
424006eeb2adSek110237 	char	**cb_argv;
4241eaca9bbdSeschrock } upgrade_cbdata_t;
4242eaca9bbdSeschrock 
4243eaca9bbdSeschrock static int
4244eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
4245eaca9bbdSeschrock {
4246eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
4247eaca9bbdSeschrock 	nvlist_t *config;
4248eaca9bbdSeschrock 	uint64_t version;
4249eaca9bbdSeschrock 	int ret = 0;
4250eaca9bbdSeschrock 
4251eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
4252eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
4253eaca9bbdSeschrock 	    &version) == 0);
4254eaca9bbdSeschrock 
4255ad135b5dSChristopher Siden 	if (!cbp->cb_newer && SPA_VERSION_IS_SUPPORTED(version) &&
4256ad135b5dSChristopher Siden 	    version != SPA_VERSION) {
4257eaca9bbdSeschrock 		if (!cbp->cb_all) {
4258eaca9bbdSeschrock 			if (cbp->cb_first) {
4259eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
4260eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
4261eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
4262eaca9bbdSeschrock 				    "longer be accessible by older software "
4263eaca9bbdSeschrock 				    "versions.\n\n"));
4264eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
4265eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
426699653d4eSeschrock 				cbp->cb_first = B_FALSE;
4267eaca9bbdSeschrock 			}
4268eaca9bbdSeschrock 
42695ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
4270eaca9bbdSeschrock 			    zpool_get_name(zhp));
4271eaca9bbdSeschrock 		} else {
427299653d4eSeschrock 			cbp->cb_first = B_FALSE;
4273990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
427406eeb2adSek110237 			if (!ret) {
4275eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
4276990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
4277eaca9bbdSeschrock 			}
4278*4445fffbSMatthew Ahrens 			/*
4279*4445fffbSMatthew Ahrens 			 * If they did "zpool upgrade -a", then we could
4280*4445fffbSMatthew Ahrens 			 * be doing ioctls to different pools.  We need
4281*4445fffbSMatthew Ahrens 			 * to log this history once to each pool, and bypass
4282*4445fffbSMatthew Ahrens 			 * the normal history logging that happens in main().
4283*4445fffbSMatthew Ahrens 			 */
4284*4445fffbSMatthew Ahrens 			(void) zpool_log_history(g_zfs, history_str);
4285*4445fffbSMatthew Ahrens 			log_history = B_FALSE;
428606eeb2adSek110237 		}
4287ad135b5dSChristopher Siden 	} else if (cbp->cb_newer && !SPA_VERSION_IS_SUPPORTED(version)) {
4288eaca9bbdSeschrock 		assert(!cbp->cb_all);
4289eaca9bbdSeschrock 
4290eaca9bbdSeschrock 		if (cbp->cb_first) {
4291eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
4292ad135b5dSChristopher Siden 			    "formatted using an unsupported software version "
4293ad135b5dSChristopher Siden 			    "and\ncannot be accessed on the current "
4294ad135b5dSChristopher Siden 			    "system.\n\n"));
4295eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
4296eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
429799653d4eSeschrock 			cbp->cb_first = B_FALSE;
4298eaca9bbdSeschrock 		}
4299eaca9bbdSeschrock 
43005ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
4301eaca9bbdSeschrock 		    zpool_get_name(zhp));
4302eaca9bbdSeschrock 	}
4303eaca9bbdSeschrock 
4304eaca9bbdSeschrock 	zpool_close(zhp);
4305eaca9bbdSeschrock 	return (ret);
4306eaca9bbdSeschrock }
4307eaca9bbdSeschrock 
4308eaca9bbdSeschrock /* ARGSUSED */
4309eaca9bbdSeschrock static int
431006eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
4311eaca9bbdSeschrock {
4312990b4856Slling 	upgrade_cbdata_t *cbp = data;
4313990b4856Slling 	uint64_t cur_version;
4314eaca9bbdSeschrock 	int ret;
4315eaca9bbdSeschrock 
43168654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
43178654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
43188654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
43198654d025Sperrin 		    " to upgrade.\n"));
43208654d025Sperrin 		return (1);
43218654d025Sperrin 	}
4322990b4856Slling 
4323990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
4324e6c728e1Sbrendan 	if (cur_version > cbp->cb_version) {
4325eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
4326e6c728e1Sbrendan 		    "using more current version '%llu'.\n"),
4327e6c728e1Sbrendan 		    zpool_get_name(zhp), cur_version);
4328e6c728e1Sbrendan 		return (0);
4329e6c728e1Sbrendan 	}
4330e6c728e1Sbrendan 	if (cur_version == cbp->cb_version) {
4331e6c728e1Sbrendan 		(void) printf(gettext("Pool '%s' is already formatted "
4332e6c728e1Sbrendan 		    "using the current version.\n"), zpool_get_name(zhp));
4333eaca9bbdSeschrock 		return (0);
4334eaca9bbdSeschrock 	}
4335eaca9bbdSeschrock 
4336990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
433706eeb2adSek110237 
433806eeb2adSek110237 	if (!ret) {
433944cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
4340990b4856Slling 		    "from version %llu to version %llu\n\n"),
4341990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
4342990b4856Slling 		    (u_longlong_t)cbp->cb_version);
434306eeb2adSek110237 	}
4344eaca9bbdSeschrock 
4345eaca9bbdSeschrock 	return (ret != 0);
4346eaca9bbdSeschrock }
4347eaca9bbdSeschrock 
4348eaca9bbdSeschrock /*
4349eaca9bbdSeschrock  * zpool upgrade
4350eaca9bbdSeschrock  * zpool upgrade -v
4351990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
4352eaca9bbdSeschrock  *
4353eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
4354eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
4355eaca9bbdSeschrock  * upgrade all pools.
4356eaca9bbdSeschrock  */
4357eaca9bbdSeschrock int
4358eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
4359eaca9bbdSeschrock {
4360eaca9bbdSeschrock 	int c;
4361eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
4362eaca9bbdSeschrock 	int ret = 0;
4363eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
4364990b4856Slling 	char *end;
4365990b4856Slling 
4366eaca9bbdSeschrock 
4367eaca9bbdSeschrock 	/* check options */
4368478ed9adSEric Taylor 	while ((c = getopt(argc, argv, ":avV:")) != -1) {
4369eaca9bbdSeschrock 		switch (c) {
4370eaca9bbdSeschrock 		case 'a':
437199653d4eSeschrock 			cb.cb_all = B_TRUE;
4372eaca9bbdSeschrock 			break;
4373eaca9bbdSeschrock 		case 'v':
4374eaca9bbdSeschrock 			showversions = B_TRUE;
4375eaca9bbdSeschrock 			break;
4376990b4856Slling 		case 'V':
4377990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
4378ad135b5dSChristopher Siden 			if (*end != '\0' ||
4379ad135b5dSChristopher Siden 			    !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) {
4380990b4856Slling 				(void) fprintf(stderr,
4381990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
4382990b4856Slling 				usage(B_FALSE);
4383990b4856Slling 			}
4384990b4856Slling 			break;
4385478ed9adSEric Taylor 		case ':':
4386478ed9adSEric Taylor 			(void) fprintf(stderr, gettext("missing argument for "
4387478ed9adSEric Taylor 			    "'%c' option\n"), optopt);
4388478ed9adSEric Taylor 			usage(B_FALSE);
4389478ed9adSEric Taylor 			break;
4390eaca9bbdSeschrock 		case '?':
4391eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4392eaca9bbdSeschrock 			    optopt);
439399653d4eSeschrock 			usage(B_FALSE);
4394eaca9bbdSeschrock 		}
4395eaca9bbdSeschrock 	}
4396eaca9bbdSeschrock 
439706eeb2adSek110237 	cb.cb_argc = argc;
439806eeb2adSek110237 	cb.cb_argv = argv;
4399eaca9bbdSeschrock 	argc -= optind;
4400eaca9bbdSeschrock 	argv += optind;
4401eaca9bbdSeschrock 
4402351420b3Slling 	if (cb.cb_version == 0) {
4403351420b3Slling 		cb.cb_version = SPA_VERSION;
4404351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
4405351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
4406351420b3Slling 		    "incompatible with other arguments\n"));
4407351420b3Slling 		usage(B_FALSE);
4408351420b3Slling 	}
4409351420b3Slling 
4410eaca9bbdSeschrock 	if (showversions) {
4411eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
4412eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
4413eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
441499653d4eSeschrock 			usage(B_FALSE);
4415eaca9bbdSeschrock 		}
4416eaca9bbdSeschrock 	} else if (cb.cb_all) {
4417eaca9bbdSeschrock 		if (argc != 0) {
4418351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
4419351420b3Slling 			    "be used along with a pool name\n"));
442099653d4eSeschrock 			usage(B_FALSE);
4421eaca9bbdSeschrock 		}
4422eaca9bbdSeschrock 	}
4423eaca9bbdSeschrock 
4424ad135b5dSChristopher Siden 	(void) printf(gettext("This system supports ZFS pool feature "
4425ad135b5dSChristopher Siden 	    "flags.\n\n"));
442699653d4eSeschrock 	cb.cb_first = B_TRUE;
4427eaca9bbdSeschrock 	if (showversions) {
4428eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
4429d7d4af51Smmusante 		    "supported:\n\n"));
4430eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
4431eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
4432eaca9bbdSeschrock 		    "---------------\n");
443399653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
443444cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
443544cd46caSbillm 		    "(replicated metadata)\n"));
443699653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
443799653d4eSeschrock 		    "RAID-Z\n"));
4438d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
4439c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
4440c9431fa1Sahl 		    "algorithm\n"));
4441990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
44428654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
4443ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
4444a9799022Sck153898 		(void) printf(gettext(" 9   refquota and refreservation "
4445a9799022Sck153898 		    "properties\n"));
4446fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
4447088f3894Sahrens 		(void) printf(gettext(" 11  Improved scrub performance\n"));
4448bb0ade09Sahrens 		(void) printf(gettext(" 12  Snapshot properties\n"));
444974e7dc98SMatthew Ahrens 		(void) printf(gettext(" 13  snapused property\n"));
445014843421SMatthew Ahrens 		(void) printf(gettext(" 14  passthrough-x aclinherit\n"));
445114843421SMatthew Ahrens 		(void) printf(gettext(" 15  user/group space accounting\n"));
4452478ed9adSEric Taylor 		(void) printf(gettext(" 16  stmf property support\n"));
44537aeab329SAdam Leventhal 		(void) printf(gettext(" 17  Triple-parity RAID-Z\n"));
4454b24ab676SJeff Bonwick 		(void) printf(gettext(" 18  Snapshot user holds\n"));
445588ecc943SGeorge Wilson 		(void) printf(gettext(" 19  Log device removal\n"));
4456b24ab676SJeff Bonwick 		(void) printf(gettext(" 20  Compression using zle "
4457b24ab676SJeff Bonwick 		    "(zero-length encoding)\n"));
4458b24ab676SJeff Bonwick 		(void) printf(gettext(" 21  Deduplication\n"));
445992241e0bSTom Erickson 		(void) printf(gettext(" 22  Received properties\n"));
44606e1f5caaSNeil Perrin 		(void) printf(gettext(" 23  Slim ZIL\n"));
44610a586ceaSMark Shellenbaum 		(void) printf(gettext(" 24  System attributes\n"));
44623f9d6ad7SLin Ling 		(void) printf(gettext(" 25  Improved scrub stats\n"));
4463cde58dbcSMatthew Ahrens 		(void) printf(gettext(" 26  Improved snapshot deletion "
4464cde58dbcSMatthew Ahrens 		    "performance\n"));
44656e0cbcaaSMatthew Ahrens 		(void) printf(gettext(" 27  Improved snapshot creation "
44666e0cbcaaSMatthew Ahrens 		    "performance\n"));
4467cb04b873SMark J Musante 		(void) printf(gettext(" 28  Multiple vdev replacements\n"));
4468b24ab676SJeff Bonwick 		(void) printf(gettext("\nFor more information on a particular "
44699a8685acSstephanie scheffler 		    "version, including supported releases,\n"));
44709a8685acSstephanie scheffler 		(void) printf(gettext("see the ZFS Administration Guide.\n\n"));
4471eaca9bbdSeschrock 	} else if (argc == 0) {
4472eaca9bbdSeschrock 		int notfound;
4473eaca9bbdSeschrock 
447499653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
4475eaca9bbdSeschrock 		notfound = cb.cb_first;
4476eaca9bbdSeschrock 
4477eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
4478eaca9bbdSeschrock 			if (!cb.cb_first)
4479eaca9bbdSeschrock 				(void) printf("\n");
4480eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
4481eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
448299653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
4483eaca9bbdSeschrock 			if (!cb.cb_first) {
4484eaca9bbdSeschrock 				notfound = B_FALSE;
4485eaca9bbdSeschrock 				(void) printf("\n");
4486eaca9bbdSeschrock 			}
4487eaca9bbdSeschrock 		}
4488eaca9bbdSeschrock 
4489eaca9bbdSeschrock 		if (ret == 0) {
4490eaca9bbdSeschrock 			if (notfound)
4491eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
4492eaca9bbdSeschrock 				    "using this version.\n"));
4493eaca9bbdSeschrock 			else if (!cb.cb_all)
4494eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
4495eaca9bbdSeschrock 				    "for a list of available versions and "
4496eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
4497eaca9bbdSeschrock 		}
4498eaca9bbdSeschrock 	} else {
4499b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
4500b1b8ab34Slling 		    upgrade_one, &cb);
450106eeb2adSek110237 	}
450206eeb2adSek110237 
450306eeb2adSek110237 	return (ret);
450406eeb2adSek110237 }
450506eeb2adSek110237 
4506ecd6cf80Smarks typedef struct hist_cbdata {
4507ecd6cf80Smarks 	boolean_t first;
4508*4445fffbSMatthew Ahrens 	boolean_t longfmt;
4509*4445fffbSMatthew Ahrens 	boolean_t internal;
4510ecd6cf80Smarks } hist_cbdata_t;
4511ecd6cf80Smarks 
451206eeb2adSek110237 /*
451306eeb2adSek110237  * Print out the command history for a specific pool.
451406eeb2adSek110237  */
451506eeb2adSek110237 static int
451606eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
451706eeb2adSek110237 {
451806eeb2adSek110237 	nvlist_t *nvhis;
451906eeb2adSek110237 	nvlist_t **records;
452006eeb2adSek110237 	uint_t numrecords;
452106eeb2adSek110237 	int ret, i;
4522ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
452306eeb2adSek110237 
4524ecd6cf80Smarks 	cb->first = B_FALSE;
452506eeb2adSek110237 
452606eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
452706eeb2adSek110237 
452806eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
452906eeb2adSek110237 		return (ret);
453006eeb2adSek110237 
453106eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
453206eeb2adSek110237 	    &records, &numrecords) == 0);
453306eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
4534*4445fffbSMatthew Ahrens 		nvlist_t *rec = records[i];
4535*4445fffbSMatthew Ahrens 		char tbuf[30] = "";
4536ecd6cf80Smarks 
4537*4445fffbSMatthew Ahrens 		if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
4538*4445fffbSMatthew Ahrens 			time_t tsec;
4539*4445fffbSMatthew Ahrens 			struct tm t;
4540ecd6cf80Smarks 
4541*4445fffbSMatthew Ahrens 			tsec = fnvlist_lookup_uint64(records[i],
4542*4445fffbSMatthew Ahrens 			    ZPOOL_HIST_TIME);
454306eeb2adSek110237 			(void) localtime_r(&tsec, &t);
454406eeb2adSek110237 			(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
4545*4445fffbSMatthew Ahrens 		}
4546*4445fffbSMatthew Ahrens 
4547*4445fffbSMatthew Ahrens 		if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
4548*4445fffbSMatthew Ahrens 			(void) printf("%s %s", tbuf,
4549*4445fffbSMatthew Ahrens 			    fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
4550*4445fffbSMatthew Ahrens 		} else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
4551*4445fffbSMatthew Ahrens 			int ievent =
4552*4445fffbSMatthew Ahrens 			    fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
4553*4445fffbSMatthew Ahrens 			if (!cb->internal)
4554*4445fffbSMatthew Ahrens 				continue;
4555*4445fffbSMatthew Ahrens 			if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
4556*4445fffbSMatthew Ahrens 				(void) printf("%s unrecognized record:\n",
4557*4445fffbSMatthew Ahrens 				    tbuf);
4558*4445fffbSMatthew Ahrens 				dump_nvlist(rec, 4);
4559*4445fffbSMatthew Ahrens 				continue;
4560*4445fffbSMatthew Ahrens 			}
4561*4445fffbSMatthew Ahrens 			(void) printf("%s [internal %s txg:%lld] %s", tbuf,
4562*4445fffbSMatthew Ahrens 			    zfs_history_event_names[ievent],
4563*4445fffbSMatthew Ahrens 			    fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
4564*4445fffbSMatthew Ahrens 			    fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
4565*4445fffbSMatthew Ahrens 		} else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
4566*4445fffbSMatthew Ahrens 			if (!cb->internal)
4567*4445fffbSMatthew Ahrens 				continue;
4568*4445fffbSMatthew Ahrens 			(void) printf("%s [txg:%lld] %s", tbuf,
4569*4445fffbSMatthew Ahrens 			    fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
4570*4445fffbSMatthew Ahrens 			    fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
4571*4445fffbSMatthew Ahrens 			if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
4572*4445fffbSMatthew Ahrens 				(void) printf(" %s (%llu)",
4573*4445fffbSMatthew Ahrens 				    fnvlist_lookup_string(rec,
4574*4445fffbSMatthew Ahrens 				    ZPOOL_HIST_DSNAME),
4575*4445fffbSMatthew Ahrens 				    fnvlist_lookup_uint64(rec,
4576*4445fffbSMatthew Ahrens 				    ZPOOL_HIST_DSID));
4577*4445fffbSMatthew Ahrens 			}
4578*4445fffbSMatthew Ahrens 			(void) printf(" %s", fnvlist_lookup_string(rec,
4579*4445fffbSMatthew Ahrens 			    ZPOOL_HIST_INT_STR));
4580*4445fffbSMatthew Ahrens 		} else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
4581*4445fffbSMatthew Ahrens 			if (!cb->internal)
4582*4445fffbSMatthew Ahrens 				continue;
4583*4445fffbSMatthew Ahrens 			(void) printf("%s ioctl %s\n", tbuf,
4584*4445fffbSMatthew Ahrens 			    fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
4585*4445fffbSMatthew Ahrens 			if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
4586*4445fffbSMatthew Ahrens 				(void) printf("    input:\n");
4587*4445fffbSMatthew Ahrens 				dump_nvlist(fnvlist_lookup_nvlist(rec,
4588*4445fffbSMatthew Ahrens 				    ZPOOL_HIST_INPUT_NVL), 8);
4589*4445fffbSMatthew Ahrens 			}
4590*4445fffbSMatthew Ahrens 			if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
4591*4445fffbSMatthew Ahrens 				(void) printf("    output:\n");
4592*4445fffbSMatthew Ahrens 				dump_nvlist(fnvlist_lookup_nvlist(rec,
4593*4445fffbSMatthew Ahrens 				    ZPOOL_HIST_OUTPUT_NVL), 8);
4594*4445fffbSMatthew Ahrens 			}
4595*4445fffbSMatthew Ahrens 		} else {
4596*4445fffbSMatthew Ahrens 			if (!cb->internal)
4597*4445fffbSMatthew Ahrens 				continue;
4598*4445fffbSMatthew Ahrens 			(void) printf("%s unrecognized record:\n", tbuf);
4599*4445fffbSMatthew Ahrens 			dump_nvlist(rec, 4);
4600*4445fffbSMatthew Ahrens 		}
4601ecd6cf80Smarks 
4602ecd6cf80Smarks 		if (!cb->longfmt) {
4603ecd6cf80Smarks 			(void) printf("\n");
4604ecd6cf80Smarks 			continue;
460506eeb2adSek110237 		}
4606ecd6cf80Smarks 		(void) printf(" [");
4607*4445fffbSMatthew Ahrens 		if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
4608*4445fffbSMatthew Ahrens 			uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
4609*4445fffbSMatthew Ahrens 			struct passwd *pwd = getpwuid(who);
4610*4445fffbSMatthew Ahrens 			(void) printf("user %d ", (int)who);
4611*4445fffbSMatthew Ahrens 			if (pwd != NULL)
4612*4445fffbSMatthew Ahrens 				(void) printf("(%s) ", pwd->pw_name);
4613ecd6cf80Smarks 		}
4614*4445fffbSMatthew Ahrens 		if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
4615*4445fffbSMatthew Ahrens 			(void) printf("on %s",
4616*4445fffbSMatthew Ahrens 			    fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
4617ecd6cf80Smarks 		}
4618*4445fffbSMatthew Ahrens 		if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
4619*4445fffbSMatthew Ahrens 			(void) printf(":%s",
4620*4445fffbSMatthew Ahrens 			    fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
4621ecd6cf80Smarks 		}
4622ecd6cf80Smarks 		(void) printf("]");
4623ecd6cf80Smarks 		(void) printf("\n");
462406eeb2adSek110237 	}
462506eeb2adSek110237 	(void) printf("\n");
462606eeb2adSek110237 	nvlist_free(nvhis);
462706eeb2adSek110237 
462806eeb2adSek110237 	return (ret);
462906eeb2adSek110237 }
463006eeb2adSek110237 
463106eeb2adSek110237 /*
463206eeb2adSek110237  * zpool history <pool>
463306eeb2adSek110237  *
463406eeb2adSek110237  * Displays the history of commands that modified pools.
463506eeb2adSek110237  */
463606eeb2adSek110237 int
463706eeb2adSek110237 zpool_do_history(int argc, char **argv)
463806eeb2adSek110237 {
4639ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
464006eeb2adSek110237 	int ret;
4641ecd6cf80Smarks 	int c;
464206eeb2adSek110237 
4643ecd6cf80Smarks 	cbdata.first = B_TRUE;
4644ecd6cf80Smarks 	/* check options */
4645ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
4646ecd6cf80Smarks 		switch (c) {
4647ecd6cf80Smarks 		case 'l':
4648*4445fffbSMatthew Ahrens 			cbdata.longfmt = B_TRUE;
4649ecd6cf80Smarks 			break;
4650ecd6cf80Smarks 		case 'i':
4651*4445fffbSMatthew Ahrens 			cbdata.internal = B_TRUE;
4652ecd6cf80Smarks 			break;
4653ecd6cf80Smarks 		case '?':
4654ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4655ecd6cf80Smarks 			    optopt);
4656ecd6cf80Smarks 			usage(B_FALSE);
4657ecd6cf80Smarks 		}
4658ecd6cf80Smarks 	}
465906eeb2adSek110237 	argc -= optind;
466006eeb2adSek110237 	argv += optind;
466106eeb2adSek110237 
4662b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
4663ecd6cf80Smarks 	    &cbdata);
466406eeb2adSek110237 
4665ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
466606eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
466706eeb2adSek110237 		return (0);
4668eaca9bbdSeschrock 	}
4669eaca9bbdSeschrock 
4670eaca9bbdSeschrock 	return (ret);
4671eaca9bbdSeschrock }
4672eaca9bbdSeschrock 
4673b1b8ab34Slling static int
4674b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
4675b1b8ab34Slling {
4676990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
4677b1b8ab34Slling 	char value[MAXNAMELEN];
4678990b4856Slling 	zprop_source_t srctype;
4679990b4856Slling 	zprop_list_t *pl;
4680b1b8ab34Slling 
4681b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
4682b1b8ab34Slling 
4683b1b8ab34Slling 		/*
4684990b4856Slling 		 * Skip the special fake placeholder. This will also skip
4685990b4856Slling 		 * over the name property when 'all' is specified.
4686b1b8ab34Slling 		 */
4687990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
4688b1b8ab34Slling 		    pl == cbp->cb_proplist)
4689b1b8ab34Slling 			continue;
4690b1b8ab34Slling 
4691ad135b5dSChristopher Siden 		if (pl->pl_prop == ZPROP_INVAL &&
4692ad135b5dSChristopher Siden 		    (zpool_prop_feature(pl->pl_user_prop) ||
4693ad135b5dSChristopher Siden 		    zpool_prop_unsupported(pl->pl_user_prop))) {
4694ad135b5dSChristopher Siden 			srctype = ZPROP_SRC_LOCAL;
4695ad135b5dSChristopher Siden 
4696ad135b5dSChristopher Siden 			if (zpool_prop_get_feature(zhp, pl->pl_user_prop,
4697ad135b5dSChristopher Siden 			    value, sizeof (value)) == 0) {
4698ad135b5dSChristopher Siden 				zprop_print_one_property(zpool_get_name(zhp),
4699ad135b5dSChristopher Siden 				    cbp, pl->pl_user_prop, value, srctype,
4700ad135b5dSChristopher Siden 				    NULL, NULL);
4701ad135b5dSChristopher Siden 			}
4702ad135b5dSChristopher Siden 		} else {
4703ad135b5dSChristopher Siden 			if (zpool_get_prop(zhp, pl->pl_prop, value,
4704ad135b5dSChristopher Siden 			    sizeof (value), &srctype) != 0)
4705b1b8ab34Slling 				continue;
4706b1b8ab34Slling 
4707990b4856Slling 			zprop_print_one_property(zpool_get_name(zhp), cbp,
4708ad135b5dSChristopher Siden 			    zpool_prop_to_name(pl->pl_prop), value, srctype,
4709ad135b5dSChristopher Siden 			    NULL, NULL);
4710ad135b5dSChristopher Siden 		}
4711b1b8ab34Slling 	}
4712b1b8ab34Slling 	return (0);
4713b1b8ab34Slling }
4714b1b8ab34Slling 
4715b1b8ab34Slling int
4716b1b8ab34Slling zpool_do_get(int argc, char **argv)
4717b1b8ab34Slling {
4718990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
4719990b4856Slling 	zprop_list_t fake_name = { 0 };
4720b1b8ab34Slling 	int ret;
4721b1b8ab34Slling 
4722ad135b5dSChristopher Siden 	if (argc < 2) {
4723ad135b5dSChristopher Siden 		(void) fprintf(stderr, gettext("missing property "
4724ad135b5dSChristopher Siden 		    "argument\n"));
4725b1b8ab34Slling 		usage(B_FALSE);
4726ad135b5dSChristopher Siden 	}
4727b1b8ab34Slling 
4728b1b8ab34Slling 	cb.cb_first = B_TRUE;
4729990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
4730b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
4731b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
4732b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
4733b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
4734990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
4735b1b8ab34Slling 
4736990b4856Slling 	if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist,
4737990b4856Slling 	    ZFS_TYPE_POOL) != 0)
4738b1b8ab34Slling 		usage(B_FALSE);
4739b1b8ab34Slling 
4740b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
4741990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
4742b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
4743b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
4744b1b8ab34Slling 		cb.cb_proplist = &fake_name;
4745b1b8ab34Slling 	}
4746b1b8ab34Slling 
4747b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
4748b1b8ab34Slling 	    get_callback, &cb);
4749b1b8ab34Slling 
4750b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
4751990b4856Slling 		zprop_free_list(fake_name.pl_next);
4752b1b8ab34Slling 	else
4753990b4856Slling 		zprop_free_list(cb.cb_proplist);
4754b1b8ab34Slling 
4755b1b8ab34Slling 	return (ret);
4756b1b8ab34Slling }
4757b1b8ab34Slling 
4758b1b8ab34Slling typedef struct set_cbdata {
4759b1b8ab34Slling 	char *cb_propname;
4760b1b8ab34Slling 	char *cb_value;
4761b1b8ab34Slling 	boolean_t cb_any_successful;
4762b1b8ab34Slling } set_cbdata_t;
4763b1b8ab34Slling 
4764b1b8ab34Slling int
4765b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
4766b1b8ab34Slling {
4767b1b8ab34Slling 	int error;
4768b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
4769b1b8ab34Slling 
4770b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
4771b1b8ab34Slling 
4772b1b8ab34Slling 	if (!error)
4773b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
4774b1b8ab34Slling 
4775b1b8ab34Slling 	return (error);
4776b1b8ab34Slling }
4777b1b8ab34Slling 
4778b1b8ab34Slling int
4779b1b8ab34Slling zpool_do_set(int argc, char **argv)
4780b1b8ab34Slling {
4781b1b8ab34Slling 	set_cbdata_t cb = { 0 };
4782b1b8ab34Slling 	int error;
4783b1b8ab34Slling 
4784b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
4785b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4786b1b8ab34Slling 		    argv[1][1]);
4787b1b8ab34Slling 		usage(B_FALSE);
4788b1b8ab34Slling 	}
4789b1b8ab34Slling 
4790b1b8ab34Slling 	if (argc < 2) {
4791b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
4792b1b8ab34Slling 		    "argument\n"));
4793b1b8ab34Slling 		usage(B_FALSE);
4794b1b8ab34Slling 	}
4795b1b8ab34Slling 
4796b1b8ab34Slling 	if (argc < 3) {
4797b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
4798b1b8ab34Slling 		usage(B_FALSE);
4799b1b8ab34Slling 	}
4800b1b8ab34Slling 
4801b1b8ab34Slling 	if (argc > 3) {
4802b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
4803b1b8ab34Slling 		usage(B_FALSE);
4804b1b8ab34Slling 	}
4805b1b8ab34Slling 
4806b1b8ab34Slling 	cb.cb_propname = argv[1];
4807b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
4808b1b8ab34Slling 	if (cb.cb_value == NULL) {
4809b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
4810b1b8ab34Slling 		    "property=value argument\n"));
4811b1b8ab34Slling 		usage(B_FALSE);
4812b1b8ab34Slling 	}
4813b1b8ab34Slling 
4814b1b8ab34Slling 	*(cb.cb_value) = '\0';
4815b1b8ab34Slling 	cb.cb_value++;
4816b1b8ab34Slling 
4817b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
4818b1b8ab34Slling 	    set_callback, &cb);
4819b1b8ab34Slling 
4820b1b8ab34Slling 	return (error);
4821b1b8ab34Slling }
4822b1b8ab34Slling 
4823b1b8ab34Slling static int
4824b1b8ab34Slling find_command_idx(char *command, int *idx)
4825b1b8ab34Slling {
4826b1b8ab34Slling 	int i;
4827b1b8ab34Slling 
4828b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
4829b1b8ab34Slling 		if (command_table[i].name == NULL)
4830b1b8ab34Slling 			continue;
4831b1b8ab34Slling 
4832b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
4833b1b8ab34Slling 			*idx = i;
4834b1b8ab34Slling 			return (0);
4835b1b8ab34Slling 		}
4836b1b8ab34Slling 	}
4837b1b8ab34Slling 	return (1);
4838b1b8ab34Slling }
4839b1b8ab34Slling 
4840fa9e4066Sahrens int
4841fa9e4066Sahrens main(int argc, char **argv)
4842fa9e4066Sahrens {
4843fa9e4066Sahrens 	int ret;
4844fa9e4066Sahrens 	int i;
4845fa9e4066Sahrens 	char *cmdname;
4846fa9e4066Sahrens 
4847fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
4848fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
4849fa9e4066Sahrens 
485099653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
485199653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
4852203a47d8Snd150628 		    "initialize ZFS library\n"));
485399653d4eSeschrock 		return (1);
485499653d4eSeschrock 	}
485599653d4eSeschrock 
485699653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
485799653d4eSeschrock 
4858fa9e4066Sahrens 	opterr = 0;
4859fa9e4066Sahrens 
4860fa9e4066Sahrens 	/*
4861fa9e4066Sahrens 	 * Make sure the user has specified some command.
4862fa9e4066Sahrens 	 */
4863fa9e4066Sahrens 	if (argc < 2) {
4864fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
486599653d4eSeschrock 		usage(B_FALSE);
4866fa9e4066Sahrens 	}
4867fa9e4066Sahrens 
4868fa9e4066Sahrens 	cmdname = argv[1];
4869fa9e4066Sahrens 
4870fa9e4066Sahrens 	/*
4871fa9e4066Sahrens 	 * Special case '-?'
4872fa9e4066Sahrens 	 */
4873fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
487499653d4eSeschrock 		usage(B_TRUE);
4875fa9e4066Sahrens 
4876*4445fffbSMatthew Ahrens 	zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
48772a6b87f0Sek110237 
4878fa9e4066Sahrens 	/*
4879fa9e4066Sahrens 	 * Run the appropriate command.
4880fa9e4066Sahrens 	 */
4881b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
4882fa9e4066Sahrens 		current_command = &command_table[i];
4883fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
488491ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
488591ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
488691ebeef5Sahrens 		current_command = &command_table[i];
488791ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
488891ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
4889fa9e4066Sahrens 		/*
489091ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
489191ebeef5Sahrens 		 * it as such.
4892fa9e4066Sahrens 		 */
4893ea8dc4b6Seschrock 		char buf[16384];
4894ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
4895fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
4896fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
489791ebeef5Sahrens 	} else {
4898fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
4899fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
490099653d4eSeschrock 		usage(B_FALSE);
4901fa9e4066Sahrens 	}
4902fa9e4066Sahrens 
4903*4445fffbSMatthew Ahrens 	if (ret == 0 && log_history)
4904*4445fffbSMatthew Ahrens 		(void) zpool_log_history(g_zfs, history_str);
4905*4445fffbSMatthew Ahrens 
490699653d4eSeschrock 	libzfs_fini(g_zfs);
490799653d4eSeschrock 
4908fa9e4066Sahrens 	/*
4909fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
4910fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
4911fa9e4066Sahrens 	 */
4912fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
4913fa9e4066Sahrens 		(void) printf("dumping core by request\n");
4914fa9e4066Sahrens 		abort();
4915fa9e4066Sahrens 	}
4916fa9e4066Sahrens 
4917fa9e4066Sahrens 	return (ret);
4918fa9e4066Sahrens }
4919