xref: /titanic_54/usr/src/cmd/zpool/zpool_main.c (revision 88ecc943b4eb72f7c4fbbd8435997b85ef171fc3)
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 /*
23379c004dSEric Schrock  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #include <assert.h>
28fa9e4066Sahrens #include <ctype.h>
29fa9e4066Sahrens #include <dirent.h>
30fa9e4066Sahrens #include <errno.h>
31fa9e4066Sahrens #include <fcntl.h>
32fa9e4066Sahrens #include <libgen.h>
33fa9e4066Sahrens #include <libintl.h>
34fa9e4066Sahrens #include <libuutil.h>
35fa9e4066Sahrens #include <locale.h>
36fa9e4066Sahrens #include <stdio.h>
37fa9e4066Sahrens #include <stdlib.h>
38fa9e4066Sahrens #include <string.h>
39fa9e4066Sahrens #include <strings.h>
40fa9e4066Sahrens #include <unistd.h>
41fa9e4066Sahrens #include <priv.h>
42ecd6cf80Smarks #include <pwd.h>
43ecd6cf80Smarks #include <zone.h>
44b1b8ab34Slling #include <sys/fs/zfs.h>
45fa9e4066Sahrens 
46fa9e4066Sahrens #include <sys/stat.h>
47fa9e4066Sahrens 
48fa9e4066Sahrens #include <libzfs.h>
49fa9e4066Sahrens 
50fa9e4066Sahrens #include "zpool_util.h"
51b7b97454Sperrin #include "zfs_comutil.h"
52fa9e4066Sahrens 
5326fd7700SKrishnendu Sadhukhan - Sun Microsystems #include "statcommon.h"
5426fd7700SKrishnendu Sadhukhan - Sun Microsystems 
55fa9e4066Sahrens static int zpool_do_create(int, char **);
56fa9e4066Sahrens static int zpool_do_destroy(int, char **);
57fa9e4066Sahrens 
58fa9e4066Sahrens static int zpool_do_add(int, char **);
5999653d4eSeschrock static int zpool_do_remove(int, char **);
60fa9e4066Sahrens 
61fa9e4066Sahrens static int zpool_do_list(int, char **);
62fa9e4066Sahrens static int zpool_do_iostat(int, char **);
63fa9e4066Sahrens static int zpool_do_status(int, char **);
64fa9e4066Sahrens 
65fa9e4066Sahrens static int zpool_do_online(int, char **);
66fa9e4066Sahrens static int zpool_do_offline(int, char **);
67ea8dc4b6Seschrock static int zpool_do_clear(int, char **);
68fa9e4066Sahrens 
69fa9e4066Sahrens static int zpool_do_attach(int, char **);
70fa9e4066Sahrens static int zpool_do_detach(int, char **);
71fa9e4066Sahrens static int zpool_do_replace(int, char **);
72fa9e4066Sahrens 
73fa9e4066Sahrens static int zpool_do_scrub(int, char **);
74fa9e4066Sahrens 
75fa9e4066Sahrens static int zpool_do_import(int, char **);
76fa9e4066Sahrens static int zpool_do_export(int, char **);
77fa9e4066Sahrens 
78eaca9bbdSeschrock static int zpool_do_upgrade(int, char **);
79eaca9bbdSeschrock 
8006eeb2adSek110237 static int zpool_do_history(int, char **);
8106eeb2adSek110237 
82b1b8ab34Slling static int zpool_do_get(int, char **);
83b1b8ab34Slling static int zpool_do_set(int, char **);
84b1b8ab34Slling 
85fa9e4066Sahrens /*
86fa9e4066Sahrens  * These libumem hooks provide a reasonable set of defaults for the allocator's
87fa9e4066Sahrens  * debugging facilities.
88fa9e4066Sahrens  */
8929ab75c9Srm160521 
9029ab75c9Srm160521 #ifdef DEBUG
91fa9e4066Sahrens const char *
9299653d4eSeschrock _umem_debug_init(void)
93fa9e4066Sahrens {
94fa9e4066Sahrens 	return ("default,verbose"); /* $UMEM_DEBUG setting */
95fa9e4066Sahrens }
96fa9e4066Sahrens 
97fa9e4066Sahrens const char *
98fa9e4066Sahrens _umem_logging_init(void)
99fa9e4066Sahrens {
100fa9e4066Sahrens 	return ("fail,contents"); /* $UMEM_LOGGING setting */
101fa9e4066Sahrens }
10229ab75c9Srm160521 #endif
103fa9e4066Sahrens 
10465cd9f28Seschrock typedef enum {
10565cd9f28Seschrock 	HELP_ADD,
10665cd9f28Seschrock 	HELP_ATTACH,
107ea8dc4b6Seschrock 	HELP_CLEAR,
10865cd9f28Seschrock 	HELP_CREATE,
10965cd9f28Seschrock 	HELP_DESTROY,
11065cd9f28Seschrock 	HELP_DETACH,
11165cd9f28Seschrock 	HELP_EXPORT,
11206eeb2adSek110237 	HELP_HISTORY,
11365cd9f28Seschrock 	HELP_IMPORT,
11465cd9f28Seschrock 	HELP_IOSTAT,
11565cd9f28Seschrock 	HELP_LIST,
11665cd9f28Seschrock 	HELP_OFFLINE,
11765cd9f28Seschrock 	HELP_ONLINE,
11865cd9f28Seschrock 	HELP_REPLACE,
11999653d4eSeschrock 	HELP_REMOVE,
12065cd9f28Seschrock 	HELP_SCRUB,
121eaca9bbdSeschrock 	HELP_STATUS,
122b1b8ab34Slling 	HELP_UPGRADE,
123b1b8ab34Slling 	HELP_GET,
124b1b8ab34Slling 	HELP_SET
12565cd9f28Seschrock } zpool_help_t;
12665cd9f28Seschrock 
12765cd9f28Seschrock 
128fa9e4066Sahrens typedef struct zpool_command {
129fa9e4066Sahrens 	const char	*name;
130fa9e4066Sahrens 	int		(*func)(int, char **);
13165cd9f28Seschrock 	zpool_help_t	usage;
132fa9e4066Sahrens } zpool_command_t;
133fa9e4066Sahrens 
134fa9e4066Sahrens /*
135fa9e4066Sahrens  * Master command table.  Each ZFS command has a name, associated function, and
136ea8dc4b6Seschrock  * usage message.  The usage messages need to be internationalized, so we have
137ea8dc4b6Seschrock  * to have a function to return the usage message based on a command index.
13865cd9f28Seschrock  *
13965cd9f28Seschrock  * These commands are organized according to how they are displayed in the usage
14065cd9f28Seschrock  * message.  An empty command (one with a NULL name) indicates an empty line in
14165cd9f28Seschrock  * the generic usage message.
142fa9e4066Sahrens  */
143fa9e4066Sahrens static zpool_command_t command_table[] = {
14465cd9f28Seschrock 	{ "create",	zpool_do_create,	HELP_CREATE		},
14565cd9f28Seschrock 	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
146fa9e4066Sahrens 	{ NULL },
14765cd9f28Seschrock 	{ "add",	zpool_do_add,		HELP_ADD		},
14899653d4eSeschrock 	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
149fa9e4066Sahrens 	{ NULL },
15065cd9f28Seschrock 	{ "list",	zpool_do_list,		HELP_LIST		},
15165cd9f28Seschrock 	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
15265cd9f28Seschrock 	{ "status",	zpool_do_status,	HELP_STATUS		},
153fa9e4066Sahrens 	{ NULL },
15465cd9f28Seschrock 	{ "online",	zpool_do_online,	HELP_ONLINE		},
15565cd9f28Seschrock 	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
156ea8dc4b6Seschrock 	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
157fa9e4066Sahrens 	{ NULL },
15865cd9f28Seschrock 	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
15965cd9f28Seschrock 	{ "detach",	zpool_do_detach,	HELP_DETACH		},
16065cd9f28Seschrock 	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
161fa9e4066Sahrens 	{ NULL },
16265cd9f28Seschrock 	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
163fa9e4066Sahrens 	{ NULL },
16465cd9f28Seschrock 	{ "import",	zpool_do_import,	HELP_IMPORT		},
16565cd9f28Seschrock 	{ "export",	zpool_do_export,	HELP_EXPORT		},
16606eeb2adSek110237 	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
16706eeb2adSek110237 	{ NULL },
168b1b8ab34Slling 	{ "history",	zpool_do_history,	HELP_HISTORY		},
169b1b8ab34Slling 	{ "get",	zpool_do_get,		HELP_GET		},
170b1b8ab34Slling 	{ "set",	zpool_do_set,		HELP_SET		},
171fa9e4066Sahrens };
172fa9e4066Sahrens 
173fa9e4066Sahrens #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
174fa9e4066Sahrens 
175fa9e4066Sahrens zpool_command_t *current_command;
1762a6b87f0Sek110237 static char history_str[HIS_MAX_RECORD_LEN];
177fa9e4066Sahrens 
17826fd7700SKrishnendu Sadhukhan - Sun Microsystems static uint_t timestamp_fmt = NODATE;
17926fd7700SKrishnendu Sadhukhan - Sun Microsystems 
18065cd9f28Seschrock static const char *
18165cd9f28Seschrock get_usage(zpool_help_t idx) {
18265cd9f28Seschrock 	switch (idx) {
18365cd9f28Seschrock 	case HELP_ADD:
18465cd9f28Seschrock 		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
18565cd9f28Seschrock 	case HELP_ATTACH:
18665cd9f28Seschrock 		return (gettext("\tattach [-f] <pool> <device> "
187e45ce728Sahrens 		    "<new-device>\n"));
188ea8dc4b6Seschrock 	case HELP_CLEAR:
189ea8dc4b6Seschrock 		return (gettext("\tclear <pool> [device]\n"));
19065cd9f28Seschrock 	case HELP_CREATE:
191990b4856Slling 		return (gettext("\tcreate [-fn] [-o property=value] ... \n"
1920a48a24eStimh 		    "\t    [-O file-system-property=value] ... \n"
193990b4856Slling 		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
19465cd9f28Seschrock 	case HELP_DESTROY:
19565cd9f28Seschrock 		return (gettext("\tdestroy [-f] <pool>\n"));
19665cd9f28Seschrock 	case HELP_DETACH:
19765cd9f28Seschrock 		return (gettext("\tdetach <pool> <device>\n"));
19865cd9f28Seschrock 	case HELP_EXPORT:
19965cd9f28Seschrock 		return (gettext("\texport [-f] <pool> ...\n"));
20006eeb2adSek110237 	case HELP_HISTORY:
201ecd6cf80Smarks 		return (gettext("\thistory [-il] [<pool>] ...\n"));
20265cd9f28Seschrock 	case HELP_IMPORT:
2034c58d714Sdarrenm 		return (gettext("\timport [-d dir] [-D]\n"
2042f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
2052f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n"
2062f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
2072f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] "
2082f8aaab3Seschrock 		    "<pool | id> [newpool]\n"));
20965cd9f28Seschrock 	case HELP_IOSTAT:
21026fd7700SKrishnendu Sadhukhan - Sun Microsystems 		return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
21165cd9f28Seschrock 		    "[count]]\n"));
21265cd9f28Seschrock 	case HELP_LIST:
213990b4856Slling 		return (gettext("\tlist [-H] [-o property[,...]] "
214990b4856Slling 		    "[pool] ...\n"));
21565cd9f28Seschrock 	case HELP_OFFLINE:
216441d80aaSlling 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
21765cd9f28Seschrock 	case HELP_ONLINE:
218441d80aaSlling 		return (gettext("\tonline <pool> <device> ...\n"));
21965cd9f28Seschrock 	case HELP_REPLACE:
22065cd9f28Seschrock 		return (gettext("\treplace [-f] <pool> <device> "
221e45ce728Sahrens 		    "[new-device]\n"));
22299653d4eSeschrock 	case HELP_REMOVE:
223fa94a07fSbrendan 		return (gettext("\tremove <pool> <device> ...\n"));
22465cd9f28Seschrock 	case HELP_SCRUB:
22565cd9f28Seschrock 		return (gettext("\tscrub [-s] <pool> ...\n"));
22665cd9f28Seschrock 	case HELP_STATUS:
22765cd9f28Seschrock 		return (gettext("\tstatus [-vx] [pool] ...\n"));
228eaca9bbdSeschrock 	case HELP_UPGRADE:
229eaca9bbdSeschrock 		return (gettext("\tupgrade\n"
230eaca9bbdSeschrock 		    "\tupgrade -v\n"
231990b4856Slling 		    "\tupgrade [-V version] <-a | pool ...>\n"));
232b1b8ab34Slling 	case HELP_GET:
233e45ce728Sahrens 		return (gettext("\tget <\"all\" | property[,...]> "
234b1b8ab34Slling 		    "<pool> ...\n"));
235b1b8ab34Slling 	case HELP_SET:
236b1b8ab34Slling 		return (gettext("\tset <property=value> <pool> \n"));
23765cd9f28Seschrock 	}
23865cd9f28Seschrock 
23965cd9f28Seschrock 	abort();
24065cd9f28Seschrock 	/* NOTREACHED */
24165cd9f28Seschrock }
24265cd9f28Seschrock 
243fa9e4066Sahrens 
244fa9e4066Sahrens /*
245b1b8ab34Slling  * Callback routine that will print out a pool property value.
246b1b8ab34Slling  */
247990b4856Slling static int
248990b4856Slling print_prop_cb(int prop, void *cb)
249b1b8ab34Slling {
250b1b8ab34Slling 	FILE *fp = cb;
251b1b8ab34Slling 
252b1b8ab34Slling 	(void) fprintf(fp, "\t%-13s  ", zpool_prop_to_name(prop));
253b1b8ab34Slling 
254990b4856Slling 	if (zpool_prop_readonly(prop))
255990b4856Slling 		(void) fprintf(fp, "  NO   ");
256990b4856Slling 	else
257990b4856Slling 		(void) fprintf(fp, " YES    ");
258990b4856Slling 
259b1b8ab34Slling 	if (zpool_prop_values(prop) == NULL)
260b1b8ab34Slling 		(void) fprintf(fp, "-\n");
261b1b8ab34Slling 	else
262b1b8ab34Slling 		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
263b1b8ab34Slling 
264990b4856Slling 	return (ZPROP_CONT);
265b1b8ab34Slling }
266b1b8ab34Slling 
267b1b8ab34Slling /*
268fa9e4066Sahrens  * Display usage message.  If we're inside a command, display only the usage for
269fa9e4066Sahrens  * that command.  Otherwise, iterate over the entire command table and display
270fa9e4066Sahrens  * a complete usage message.
271fa9e4066Sahrens  */
272fa9e4066Sahrens void
27399653d4eSeschrock usage(boolean_t requested)
274fa9e4066Sahrens {
275fa9e4066Sahrens 	FILE *fp = requested ? stdout : stderr;
276fa9e4066Sahrens 
277fa9e4066Sahrens 	if (current_command == NULL) {
278fa9e4066Sahrens 		int i;
279fa9e4066Sahrens 
280fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
281fa9e4066Sahrens 		(void) fprintf(fp,
282fa9e4066Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
283fa9e4066Sahrens 
284fa9e4066Sahrens 		for (i = 0; i < NCOMMAND; i++) {
285fa9e4066Sahrens 			if (command_table[i].name == NULL)
286fa9e4066Sahrens 				(void) fprintf(fp, "\n");
287fa9e4066Sahrens 			else
288fa9e4066Sahrens 				(void) fprintf(fp, "%s",
28965cd9f28Seschrock 				    get_usage(command_table[i].usage));
290fa9e4066Sahrens 		}
291fa9e4066Sahrens 	} else {
292fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
29365cd9f28Seschrock 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
294fa9e4066Sahrens 	}
295fa9e4066Sahrens 
296b1b8ab34Slling 	if (current_command != NULL &&
297b1b8ab34Slling 	    ((strcmp(current_command->name, "set") == 0) ||
298990b4856Slling 	    (strcmp(current_command->name, "get") == 0) ||
299990b4856Slling 	    (strcmp(current_command->name, "list") == 0))) {
300b1b8ab34Slling 
301b1b8ab34Slling 		(void) fprintf(fp,
302b1b8ab34Slling 		    gettext("\nthe following properties are supported:\n"));
303b1b8ab34Slling 
304990b4856Slling 		(void) fprintf(fp, "\n\t%-13s  %s  %s\n\n",
305990b4856Slling 		    "PROPERTY", "EDIT", "VALUES");
306b1b8ab34Slling 
307b1b8ab34Slling 		/* Iterate over all properties */
308990b4856Slling 		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
309990b4856Slling 		    ZFS_TYPE_POOL);
310b1b8ab34Slling 	}
311b1b8ab34Slling 
312e9dbad6fSeschrock 	/*
313e9dbad6fSeschrock 	 * See comments at end of main().
314e9dbad6fSeschrock 	 */
315e9dbad6fSeschrock 	if (getenv("ZFS_ABORT") != NULL) {
316e9dbad6fSeschrock 		(void) printf("dumping core by request\n");
317e9dbad6fSeschrock 		abort();
318e9dbad6fSeschrock 	}
319e9dbad6fSeschrock 
320fa9e4066Sahrens 	exit(requested ? 0 : 2);
321fa9e4066Sahrens }
322fa9e4066Sahrens 
323fa9e4066Sahrens void
3248654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
3258654d025Sperrin     boolean_t print_logs)
326fa9e4066Sahrens {
327fa9e4066Sahrens 	nvlist_t **child;
328fa9e4066Sahrens 	uint_t c, children;
329afefbcddSeschrock 	char *vname;
330fa9e4066Sahrens 
331fa9e4066Sahrens 	if (name != NULL)
332fa9e4066Sahrens 		(void) printf("\t%*s%s\n", indent, "", name);
333fa9e4066Sahrens 
334fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
335fa9e4066Sahrens 	    &child, &children) != 0)
336fa9e4066Sahrens 		return;
337fa9e4066Sahrens 
338afefbcddSeschrock 	for (c = 0; c < children; c++) {
3398654d025Sperrin 		uint64_t is_log = B_FALSE;
3408654d025Sperrin 
3418654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3428654d025Sperrin 		    &is_log);
3438654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
3448654d025Sperrin 			continue;
3458654d025Sperrin 
346*88ecc943SGeorge Wilson 		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
3478654d025Sperrin 		print_vdev_tree(zhp, vname, child[c], indent + 2,
3488654d025Sperrin 		    B_FALSE);
349afefbcddSeschrock 		free(vname);
350afefbcddSeschrock 	}
351fa9e4066Sahrens }
352fa9e4066Sahrens 
353fa9e4066Sahrens /*
354990b4856Slling  * Add a property pair (name, string-value) into a property nvlist.
355990b4856Slling  */
356990b4856Slling static int
3570a48a24eStimh add_prop_list(const char *propname, char *propval, nvlist_t **props,
3580a48a24eStimh     boolean_t poolprop)
359990b4856Slling {
3600a48a24eStimh 	zpool_prop_t prop = ZPROP_INVAL;
3610a48a24eStimh 	zfs_prop_t fprop;
362990b4856Slling 	nvlist_t *proplist;
3630a48a24eStimh 	const char *normnm;
3640a48a24eStimh 	char *strval;
365990b4856Slling 
366990b4856Slling 	if (*props == NULL &&
367990b4856Slling 	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
368990b4856Slling 		(void) fprintf(stderr,
369990b4856Slling 		    gettext("internal error: out of memory\n"));
370990b4856Slling 		return (1);
371990b4856Slling 	}
372990b4856Slling 
373990b4856Slling 	proplist = *props;
374990b4856Slling 
3750a48a24eStimh 	if (poolprop) {
376990b4856Slling 		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
377990b4856Slling 			(void) fprintf(stderr, gettext("property '%s' is "
378990b4856Slling 			    "not a valid pool property\n"), propname);
379990b4856Slling 			return (2);
380990b4856Slling 		}
3810a48a24eStimh 		normnm = zpool_prop_to_name(prop);
3820a48a24eStimh 	} else {
38314843421SMatthew Ahrens 		if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
3840a48a24eStimh 			normnm = zfs_prop_to_name(fprop);
38514843421SMatthew Ahrens 		} else {
38614843421SMatthew Ahrens 			normnm = propname;
38714843421SMatthew Ahrens 		}
3880a48a24eStimh 	}
389990b4856Slling 
3900a48a24eStimh 	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
3910a48a24eStimh 	    prop != ZPOOL_PROP_CACHEFILE) {
392990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' "
393990b4856Slling 		    "specified multiple times\n"), propname);
394990b4856Slling 		return (2);
395990b4856Slling 	}
396990b4856Slling 
3970a48a24eStimh 	if (nvlist_add_string(proplist, normnm, propval) != 0) {
398990b4856Slling 		(void) fprintf(stderr, gettext("internal "
399990b4856Slling 		    "error: out of memory\n"));
400990b4856Slling 		return (1);
401990b4856Slling 	}
402990b4856Slling 
403990b4856Slling 	return (0);
404990b4856Slling }
405990b4856Slling 
406990b4856Slling /*
407fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
408fa9e4066Sahrens  *
409fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
410fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
411fa9e4066Sahrens  *		they were to be added.
412fa9e4066Sahrens  *
413fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
414fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
415fa9e4066Sahrens  * libzfs.
416fa9e4066Sahrens  */
417fa9e4066Sahrens int
418fa9e4066Sahrens zpool_do_add(int argc, char **argv)
419fa9e4066Sahrens {
42099653d4eSeschrock 	boolean_t force = B_FALSE;
42199653d4eSeschrock 	boolean_t dryrun = B_FALSE;
422fa9e4066Sahrens 	int c;
423fa9e4066Sahrens 	nvlist_t *nvroot;
424fa9e4066Sahrens 	char *poolname;
425fa9e4066Sahrens 	int ret;
426fa9e4066Sahrens 	zpool_handle_t *zhp;
427fa9e4066Sahrens 	nvlist_t *config;
428fa9e4066Sahrens 
429fa9e4066Sahrens 	/* check options */
430fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
431fa9e4066Sahrens 		switch (c) {
432fa9e4066Sahrens 		case 'f':
43399653d4eSeschrock 			force = B_TRUE;
434fa9e4066Sahrens 			break;
435fa9e4066Sahrens 		case 'n':
43699653d4eSeschrock 			dryrun = B_TRUE;
437fa9e4066Sahrens 			break;
438fa9e4066Sahrens 		case '?':
439fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
440fa9e4066Sahrens 			    optopt);
44199653d4eSeschrock 			usage(B_FALSE);
442fa9e4066Sahrens 		}
443fa9e4066Sahrens 	}
444fa9e4066Sahrens 
445fa9e4066Sahrens 	argc -= optind;
446fa9e4066Sahrens 	argv += optind;
447fa9e4066Sahrens 
448fa9e4066Sahrens 	/* get pool name and check number of arguments */
449fa9e4066Sahrens 	if (argc < 1) {
450fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
45199653d4eSeschrock 		usage(B_FALSE);
452fa9e4066Sahrens 	}
453fa9e4066Sahrens 	if (argc < 2) {
454fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
45599653d4eSeschrock 		usage(B_FALSE);
456fa9e4066Sahrens 	}
457fa9e4066Sahrens 
458fa9e4066Sahrens 	poolname = argv[0];
459fa9e4066Sahrens 
460fa9e4066Sahrens 	argc--;
461fa9e4066Sahrens 	argv++;
462fa9e4066Sahrens 
46399653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
464fa9e4066Sahrens 		return (1);
465fa9e4066Sahrens 
466088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
467fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
468fa9e4066Sahrens 		    poolname);
469fa9e4066Sahrens 		zpool_close(zhp);
470fa9e4066Sahrens 		return (1);
471fa9e4066Sahrens 	}
472fa9e4066Sahrens 
473fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
474705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
475705040edSEric Taylor 	    argc, argv);
476fa9e4066Sahrens 	if (nvroot == NULL) {
477fa9e4066Sahrens 		zpool_close(zhp);
478fa9e4066Sahrens 		return (1);
479fa9e4066Sahrens 	}
480fa9e4066Sahrens 
481fa9e4066Sahrens 	if (dryrun) {
482fa9e4066Sahrens 		nvlist_t *poolnvroot;
483fa9e4066Sahrens 
484fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
485fa9e4066Sahrens 		    &poolnvroot) == 0);
486fa9e4066Sahrens 
487fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
488fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
489fa9e4066Sahrens 
4908654d025Sperrin 		/* print original main pool and new tree */
4918654d025Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
4928654d025Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
4938654d025Sperrin 
4948654d025Sperrin 		/* Do the same for the logs */
4958654d025Sperrin 		if (num_logs(poolnvroot) > 0) {
4968654d025Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
4978654d025Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
4988654d025Sperrin 		} else if (num_logs(nvroot) > 0) {
4998654d025Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
5008654d025Sperrin 		}
501fa9e4066Sahrens 
502fa9e4066Sahrens 		ret = 0;
503fa9e4066Sahrens 	} else {
504fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
505fa9e4066Sahrens 	}
506fa9e4066Sahrens 
50799653d4eSeschrock 	nvlist_free(nvroot);
50899653d4eSeschrock 	zpool_close(zhp);
50999653d4eSeschrock 
51099653d4eSeschrock 	return (ret);
51199653d4eSeschrock }
51299653d4eSeschrock 
51399653d4eSeschrock /*
514fa94a07fSbrendan  * zpool remove <pool> <vdev> ...
51599653d4eSeschrock  *
51699653d4eSeschrock  * Removes the given vdev from the pool.  Currently, this only supports removing
517fa94a07fSbrendan  * spares and cache devices from the pool.  Eventually, we'll want to support
518fa94a07fSbrendan  * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs.
51999653d4eSeschrock  */
52099653d4eSeschrock int
52199653d4eSeschrock zpool_do_remove(int argc, char **argv)
52299653d4eSeschrock {
52399653d4eSeschrock 	char *poolname;
524fa94a07fSbrendan 	int i, ret = 0;
52599653d4eSeschrock 	zpool_handle_t *zhp;
52699653d4eSeschrock 
52799653d4eSeschrock 	argc--;
52899653d4eSeschrock 	argv++;
52999653d4eSeschrock 
53099653d4eSeschrock 	/* get pool name and check number of arguments */
53199653d4eSeschrock 	if (argc < 1) {
53299653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
53399653d4eSeschrock 		usage(B_FALSE);
53499653d4eSeschrock 	}
53599653d4eSeschrock 	if (argc < 2) {
53699653d4eSeschrock 		(void) fprintf(stderr, gettext("missing device\n"));
53799653d4eSeschrock 		usage(B_FALSE);
53899653d4eSeschrock 	}
53999653d4eSeschrock 
54099653d4eSeschrock 	poolname = argv[0];
54199653d4eSeschrock 
54299653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
54399653d4eSeschrock 		return (1);
54499653d4eSeschrock 
545fa94a07fSbrendan 	for (i = 1; i < argc; i++) {
546fa94a07fSbrendan 		if (zpool_vdev_remove(zhp, argv[i]) != 0)
547fa94a07fSbrendan 			ret = 1;
548fa94a07fSbrendan 	}
54999653d4eSeschrock 
550fa9e4066Sahrens 	return (ret);
551fa9e4066Sahrens }
552fa9e4066Sahrens 
553fa9e4066Sahrens /*
5540a48a24eStimh  * zpool create [-fn] [-o property=value] ...
5550a48a24eStimh  *		[-O file-system-property=value] ...
5560a48a24eStimh  *		[-R root] [-m mountpoint] <pool> <dev> ...
557fa9e4066Sahrens  *
558fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
559fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
560fa9e4066Sahrens  *		were to be created.
561fa9e4066Sahrens  *      -R	Create a pool under an alternate root
562fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
563fa9e4066Sahrens  *      	'/<pool>'
564990b4856Slling  *	-o	Set property=value.
5650a48a24eStimh  *	-O	Set fsproperty=value in the pool's root file system
566fa9e4066Sahrens  *
567b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
568fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
569fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
570fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
571fa9e4066Sahrens  */
572fa9e4066Sahrens int
573fa9e4066Sahrens zpool_do_create(int argc, char **argv)
574fa9e4066Sahrens {
57599653d4eSeschrock 	boolean_t force = B_FALSE;
57699653d4eSeschrock 	boolean_t dryrun = B_FALSE;
577fa9e4066Sahrens 	int c;
578990b4856Slling 	nvlist_t *nvroot = NULL;
579fa9e4066Sahrens 	char *poolname;
580990b4856Slling 	int ret = 1;
581fa9e4066Sahrens 	char *altroot = NULL;
582fa9e4066Sahrens 	char *mountpoint = NULL;
5830a48a24eStimh 	nvlist_t *fsprops = NULL;
584990b4856Slling 	nvlist_t *props = NULL;
5852f8aaab3Seschrock 	char *propval;
586fa9e4066Sahrens 
587fa9e4066Sahrens 	/* check options */
5880a48a24eStimh 	while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) {
589fa9e4066Sahrens 		switch (c) {
590fa9e4066Sahrens 		case 'f':
59199653d4eSeschrock 			force = B_TRUE;
592fa9e4066Sahrens 			break;
593fa9e4066Sahrens 		case 'n':
59499653d4eSeschrock 			dryrun = B_TRUE;
595fa9e4066Sahrens 			break;
596fa9e4066Sahrens 		case 'R':
597fa9e4066Sahrens 			altroot = optarg;
598990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
5990a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
600990b4856Slling 				goto errout;
6012f8aaab3Seschrock 			if (nvlist_lookup_string(props,
6022f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
6032f8aaab3Seschrock 			    &propval) == 0)
6042f8aaab3Seschrock 				break;
605990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
6060a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
607990b4856Slling 				goto errout;
608fa9e4066Sahrens 			break;
609fa9e4066Sahrens 		case 'm':
610fa9e4066Sahrens 			mountpoint = optarg;
611fa9e4066Sahrens 			break;
612990b4856Slling 		case 'o':
613990b4856Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
614990b4856Slling 				(void) fprintf(stderr, gettext("missing "
615990b4856Slling 				    "'=' for -o option\n"));
616990b4856Slling 				goto errout;
617990b4856Slling 			}
618990b4856Slling 			*propval = '\0';
619990b4856Slling 			propval++;
620990b4856Slling 
6210a48a24eStimh 			if (add_prop_list(optarg, propval, &props, B_TRUE))
6220a48a24eStimh 				goto errout;
6230a48a24eStimh 			break;
6240a48a24eStimh 		case 'O':
6250a48a24eStimh 			if ((propval = strchr(optarg, '=')) == NULL) {
6260a48a24eStimh 				(void) fprintf(stderr, gettext("missing "
6270a48a24eStimh 				    "'=' for -O option\n"));
6280a48a24eStimh 				goto errout;
6290a48a24eStimh 			}
6300a48a24eStimh 			*propval = '\0';
6310a48a24eStimh 			propval++;
6320a48a24eStimh 
6330a48a24eStimh 			if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
634990b4856Slling 				goto errout;
635990b4856Slling 			break;
636fa9e4066Sahrens 		case ':':
637fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
638fa9e4066Sahrens 			    "'%c' option\n"), optopt);
639990b4856Slling 			goto badusage;
640fa9e4066Sahrens 		case '?':
641fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
642fa9e4066Sahrens 			    optopt);
643990b4856Slling 			goto badusage;
644fa9e4066Sahrens 		}
645fa9e4066Sahrens 	}
646fa9e4066Sahrens 
647fa9e4066Sahrens 	argc -= optind;
648fa9e4066Sahrens 	argv += optind;
649fa9e4066Sahrens 
650fa9e4066Sahrens 	/* get pool name and check number of arguments */
651fa9e4066Sahrens 	if (argc < 1) {
652fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
653990b4856Slling 		goto badusage;
654fa9e4066Sahrens 	}
655fa9e4066Sahrens 	if (argc < 2) {
656fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
657990b4856Slling 		goto badusage;
658fa9e4066Sahrens 	}
659fa9e4066Sahrens 
660fa9e4066Sahrens 	poolname = argv[0];
661fa9e4066Sahrens 
662fa9e4066Sahrens 	/*
663fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
664fa9e4066Sahrens 	 * user to use 'zfs create' instead.
665fa9e4066Sahrens 	 */
666fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
667fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
668fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
669fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
670fa9e4066Sahrens 		    "create a dataset\n"));
671990b4856Slling 		goto errout;
672fa9e4066Sahrens 	}
673fa9e4066Sahrens 
674fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
675705040edSEric Taylor 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
676705040edSEric Taylor 	    argc - 1, argv + 1);
677fa9e4066Sahrens 	if (nvroot == NULL)
6780a48a24eStimh 		goto errout;
679fa9e4066Sahrens 
68099653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
681b7b97454Sperrin 	if (!zfs_allocatable_devs(nvroot)) {
68299653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
68399653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
68499653d4eSeschrock 		    "specified\n"));
685990b4856Slling 		goto errout;
68699653d4eSeschrock 	}
68799653d4eSeschrock 
68899653d4eSeschrock 
689fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
690fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
691e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
692990b4856Slling 		goto errout;
693fa9e4066Sahrens 	}
694fa9e4066Sahrens 
695fa9e4066Sahrens 	/*
696fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
697fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
698fa9e4066Sahrens 	 */
699fa9e4066Sahrens 	if (mountpoint == NULL ||
700fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
701fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
702fa9e4066Sahrens 		char buf[MAXPATHLEN];
70311022c7cStimh 		DIR *dirp;
704fa9e4066Sahrens 
705fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
706fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
707fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
708fa9e4066Sahrens 			    "'none'\n"), mountpoint);
709990b4856Slling 			goto errout;
710fa9e4066Sahrens 		}
711fa9e4066Sahrens 
712fa9e4066Sahrens 		if (mountpoint == NULL) {
713fa9e4066Sahrens 			if (altroot != NULL)
714fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
715fa9e4066Sahrens 				    altroot, poolname);
716fa9e4066Sahrens 			else
717fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
718fa9e4066Sahrens 				    poolname);
719fa9e4066Sahrens 		} else {
720fa9e4066Sahrens 			if (altroot != NULL)
721fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
722fa9e4066Sahrens 				    altroot, mountpoint);
723fa9e4066Sahrens 			else
724fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
725fa9e4066Sahrens 				    mountpoint);
726fa9e4066Sahrens 		}
727fa9e4066Sahrens 
72811022c7cStimh 		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
72911022c7cStimh 			(void) fprintf(stderr, gettext("mountpoint '%s' : "
73011022c7cStimh 			    "%s\n"), buf, strerror(errno));
731fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
732fa9e4066Sahrens 			    "option to provide a different default\n"));
733990b4856Slling 			goto errout;
73411022c7cStimh 		} else if (dirp) {
73511022c7cStimh 			int count = 0;
73611022c7cStimh 
73711022c7cStimh 			while (count < 3 && readdir(dirp) != NULL)
73811022c7cStimh 				count++;
73911022c7cStimh 			(void) closedir(dirp);
74011022c7cStimh 
74111022c7cStimh 			if (count > 2) {
74211022c7cStimh 				(void) fprintf(stderr, gettext("mountpoint "
74311022c7cStimh 				    "'%s' exists and is not empty\n"), buf);
74411022c7cStimh 				(void) fprintf(stderr, gettext("use '-m' "
74511022c7cStimh 				    "option to provide a "
74611022c7cStimh 				    "different default\n"));
74711022c7cStimh 				goto errout;
74811022c7cStimh 			}
749fa9e4066Sahrens 		}
750fa9e4066Sahrens 	}
751fa9e4066Sahrens 
752fa9e4066Sahrens 	if (dryrun) {
753fa9e4066Sahrens 		/*
754fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
755fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
756fa9e4066Sahrens 		 * appropriate hierarchy.
757fa9e4066Sahrens 		 */
758fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
759fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
760fa9e4066Sahrens 
7618654d025Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7628654d025Sperrin 		if (num_logs(nvroot) > 0)
7638654d025Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
764fa9e4066Sahrens 
765fa9e4066Sahrens 		ret = 0;
766fa9e4066Sahrens 	} else {
767fa9e4066Sahrens 		/*
768fa9e4066Sahrens 		 * Hand off to libzfs.
769fa9e4066Sahrens 		 */
7700a48a24eStimh 		if (zpool_create(g_zfs, poolname,
7710a48a24eStimh 		    nvroot, props, fsprops) == 0) {
77299653d4eSeschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
773fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
774fa9e4066Sahrens 			if (pool != NULL) {
775fa9e4066Sahrens 				if (mountpoint != NULL)
776fa9e4066Sahrens 					verify(zfs_prop_set(pool,
777e9dbad6fSeschrock 					    zfs_prop_to_name(
778e9dbad6fSeschrock 					    ZFS_PROP_MOUNTPOINT),
779fa9e4066Sahrens 					    mountpoint) == 0);
780fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
781da6c28aaSamw 					ret = zfs_shareall(pool);
782fa9e4066Sahrens 				zfs_close(pool);
783fa9e4066Sahrens 			}
78499653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
78599653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
78699653d4eSeschrock 			    "been omitted\n"));
787fa9e4066Sahrens 		}
788fa9e4066Sahrens 	}
789fa9e4066Sahrens 
790990b4856Slling errout:
791fa9e4066Sahrens 	nvlist_free(nvroot);
7920a48a24eStimh 	nvlist_free(fsprops);
793990b4856Slling 	nvlist_free(props);
794fa9e4066Sahrens 	return (ret);
795990b4856Slling badusage:
7960a48a24eStimh 	nvlist_free(fsprops);
797990b4856Slling 	nvlist_free(props);
798990b4856Slling 	usage(B_FALSE);
799990b4856Slling 	return (2);
800fa9e4066Sahrens }
801fa9e4066Sahrens 
802fa9e4066Sahrens /*
803fa9e4066Sahrens  * zpool destroy <pool>
804fa9e4066Sahrens  *
805fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
806fa9e4066Sahrens  *
807fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
808fa9e4066Sahrens  */
809fa9e4066Sahrens int
810fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
811fa9e4066Sahrens {
81299653d4eSeschrock 	boolean_t force = B_FALSE;
813fa9e4066Sahrens 	int c;
814fa9e4066Sahrens 	char *pool;
815fa9e4066Sahrens 	zpool_handle_t *zhp;
816fa9e4066Sahrens 	int ret;
817fa9e4066Sahrens 
818fa9e4066Sahrens 	/* check options */
819fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
820fa9e4066Sahrens 		switch (c) {
821fa9e4066Sahrens 		case 'f':
82299653d4eSeschrock 			force = B_TRUE;
823fa9e4066Sahrens 			break;
824fa9e4066Sahrens 		case '?':
825fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
826fa9e4066Sahrens 			    optopt);
82799653d4eSeschrock 			usage(B_FALSE);
828fa9e4066Sahrens 		}
829fa9e4066Sahrens 	}
830fa9e4066Sahrens 
831fa9e4066Sahrens 	argc -= optind;
832fa9e4066Sahrens 	argv += optind;
833fa9e4066Sahrens 
834fa9e4066Sahrens 	/* check arguments */
835fa9e4066Sahrens 	if (argc < 1) {
836fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
83799653d4eSeschrock 		usage(B_FALSE);
838fa9e4066Sahrens 	}
839fa9e4066Sahrens 	if (argc > 1) {
840fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
84199653d4eSeschrock 		usage(B_FALSE);
842fa9e4066Sahrens 	}
843fa9e4066Sahrens 
844fa9e4066Sahrens 	pool = argv[0];
845fa9e4066Sahrens 
84699653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
847fa9e4066Sahrens 		/*
848fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
849fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
850fa9e4066Sahrens 		 */
851fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
852fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
853fa9e4066Sahrens 			    "destroy a dataset\n"));
854fa9e4066Sahrens 		return (1);
855fa9e4066Sahrens 	}
856fa9e4066Sahrens 
857f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
858fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
859fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
860fa9e4066Sahrens 		return (1);
861fa9e4066Sahrens 	}
862fa9e4066Sahrens 
863fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
864fa9e4066Sahrens 
865fa9e4066Sahrens 	zpool_close(zhp);
866fa9e4066Sahrens 
867fa9e4066Sahrens 	return (ret);
868fa9e4066Sahrens }
869fa9e4066Sahrens 
870fa9e4066Sahrens /*
871fa9e4066Sahrens  * zpool export [-f] <pool> ...
872fa9e4066Sahrens  *
873fa9e4066Sahrens  *	-f	Forcefully unmount datasets
874fa9e4066Sahrens  *
875b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
876fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
877fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
878fa9e4066Sahrens  */
879fa9e4066Sahrens int
880fa9e4066Sahrens zpool_do_export(int argc, char **argv)
881fa9e4066Sahrens {
88299653d4eSeschrock 	boolean_t force = B_FALSE;
883394ab0cbSGeorge Wilson 	boolean_t hardforce = B_FALSE;
884fa9e4066Sahrens 	int c;
885fa9e4066Sahrens 	zpool_handle_t *zhp;
886fa9e4066Sahrens 	int ret;
887fa9e4066Sahrens 	int i;
888fa9e4066Sahrens 
889fa9e4066Sahrens 	/* check options */
890394ab0cbSGeorge Wilson 	while ((c = getopt(argc, argv, "fF")) != -1) {
891fa9e4066Sahrens 		switch (c) {
892fa9e4066Sahrens 		case 'f':
89399653d4eSeschrock 			force = B_TRUE;
894fa9e4066Sahrens 			break;
895394ab0cbSGeorge Wilson 		case 'F':
896394ab0cbSGeorge Wilson 			hardforce = B_TRUE;
897394ab0cbSGeorge Wilson 			break;
898fa9e4066Sahrens 		case '?':
899fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
900fa9e4066Sahrens 			    optopt);
90199653d4eSeschrock 			usage(B_FALSE);
902fa9e4066Sahrens 		}
903fa9e4066Sahrens 	}
904fa9e4066Sahrens 
905fa9e4066Sahrens 	argc -= optind;
906fa9e4066Sahrens 	argv += optind;
907fa9e4066Sahrens 
908fa9e4066Sahrens 	/* check arguments */
909fa9e4066Sahrens 	if (argc < 1) {
910fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
91199653d4eSeschrock 		usage(B_FALSE);
912fa9e4066Sahrens 	}
913fa9e4066Sahrens 
914fa9e4066Sahrens 	ret = 0;
915fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
91699653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
917fa9e4066Sahrens 			ret = 1;
918fa9e4066Sahrens 			continue;
919fa9e4066Sahrens 		}
920fa9e4066Sahrens 
921f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
922fa9e4066Sahrens 			ret = 1;
923fa9e4066Sahrens 			zpool_close(zhp);
924fa9e4066Sahrens 			continue;
925fa9e4066Sahrens 		}
926fa9e4066Sahrens 
927394ab0cbSGeorge Wilson 		if (hardforce) {
928394ab0cbSGeorge Wilson 			if (zpool_export_force(zhp) != 0)
929fa9e4066Sahrens 				ret = 1;
930394ab0cbSGeorge Wilson 		} else if (zpool_export(zhp, force) != 0) {
931394ab0cbSGeorge Wilson 			ret = 1;
932394ab0cbSGeorge Wilson 		}
933fa9e4066Sahrens 
934fa9e4066Sahrens 		zpool_close(zhp);
935fa9e4066Sahrens 	}
936fa9e4066Sahrens 
937fa9e4066Sahrens 	return (ret);
938fa9e4066Sahrens }
939fa9e4066Sahrens 
940fa9e4066Sahrens /*
941fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
942fa9e4066Sahrens  * name column.
943fa9e4066Sahrens  */
944fa9e4066Sahrens static int
945c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
946fa9e4066Sahrens {
947*88ecc943SGeorge Wilson 	char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
948fa9e4066Sahrens 	nvlist_t **child;
949fa9e4066Sahrens 	uint_t c, children;
950fa9e4066Sahrens 	int ret;
951fa9e4066Sahrens 
952fa9e4066Sahrens 	if (strlen(name) + depth > max)
953fa9e4066Sahrens 		max = strlen(name) + depth;
954fa9e4066Sahrens 
955afefbcddSeschrock 	free(name);
956afefbcddSeschrock 
95799653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
95899653d4eSeschrock 	    &child, &children) == 0) {
959fa9e4066Sahrens 		for (c = 0; c < children; c++)
96099653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
96199653d4eSeschrock 			    max)) > max)
962fa9e4066Sahrens 				max = ret;
96399653d4eSeschrock 	}
96499653d4eSeschrock 
965fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
966fa94a07fSbrendan 	    &child, &children) == 0) {
967fa94a07fSbrendan 		for (c = 0; c < children; c++)
968fa94a07fSbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
969fa94a07fSbrendan 			    max)) > max)
970fa94a07fSbrendan 				max = ret;
971fa94a07fSbrendan 	}
972fa94a07fSbrendan 
97399653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
97499653d4eSeschrock 	    &child, &children) == 0) {
97599653d4eSeschrock 		for (c = 0; c < children; c++)
97699653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
97799653d4eSeschrock 			    max)) > max)
97899653d4eSeschrock 				max = ret;
97999653d4eSeschrock 	}
98099653d4eSeschrock 
981fa9e4066Sahrens 
982fa9e4066Sahrens 	return (max);
983fa9e4066Sahrens }
984fa9e4066Sahrens 
985e6ca193dSGeorge Wilson typedef struct spare_cbdata {
986e6ca193dSGeorge Wilson 	uint64_t	cb_guid;
987e6ca193dSGeorge Wilson 	zpool_handle_t	*cb_zhp;
988e6ca193dSGeorge Wilson } spare_cbdata_t;
989e6ca193dSGeorge Wilson 
990e6ca193dSGeorge Wilson static boolean_t
991e6ca193dSGeorge Wilson find_vdev(nvlist_t *nv, uint64_t search)
992e6ca193dSGeorge Wilson {
993e6ca193dSGeorge Wilson 	uint64_t guid;
994e6ca193dSGeorge Wilson 	nvlist_t **child;
995e6ca193dSGeorge Wilson 	uint_t c, children;
996e6ca193dSGeorge Wilson 
997e6ca193dSGeorge Wilson 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
998e6ca193dSGeorge Wilson 	    search == guid)
999e6ca193dSGeorge Wilson 		return (B_TRUE);
1000e6ca193dSGeorge Wilson 
1001e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1002e6ca193dSGeorge Wilson 	    &child, &children) == 0) {
1003e6ca193dSGeorge Wilson 		for (c = 0; c < children; c++)
1004e6ca193dSGeorge Wilson 			if (find_vdev(child[c], search))
1005e6ca193dSGeorge Wilson 				return (B_TRUE);
1006e6ca193dSGeorge Wilson 	}
1007e6ca193dSGeorge Wilson 
1008e6ca193dSGeorge Wilson 	return (B_FALSE);
1009e6ca193dSGeorge Wilson }
1010e6ca193dSGeorge Wilson 
1011e6ca193dSGeorge Wilson static int
1012e6ca193dSGeorge Wilson find_spare(zpool_handle_t *zhp, void *data)
1013e6ca193dSGeorge Wilson {
1014e6ca193dSGeorge Wilson 	spare_cbdata_t *cbp = data;
1015e6ca193dSGeorge Wilson 	nvlist_t *config, *nvroot;
1016e6ca193dSGeorge Wilson 
1017e6ca193dSGeorge Wilson 	config = zpool_get_config(zhp, NULL);
1018e6ca193dSGeorge Wilson 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1019e6ca193dSGeorge Wilson 	    &nvroot) == 0);
1020e6ca193dSGeorge Wilson 
1021e6ca193dSGeorge Wilson 	if (find_vdev(nvroot, cbp->cb_guid)) {
1022e6ca193dSGeorge Wilson 		cbp->cb_zhp = zhp;
1023e6ca193dSGeorge Wilson 		return (1);
1024e6ca193dSGeorge Wilson 	}
1025e6ca193dSGeorge Wilson 
1026e6ca193dSGeorge Wilson 	zpool_close(zhp);
1027e6ca193dSGeorge Wilson 	return (0);
1028e6ca193dSGeorge Wilson }
1029e6ca193dSGeorge Wilson 
1030e6ca193dSGeorge Wilson /*
1031e6ca193dSGeorge Wilson  * Print out configuration state as requested by status_callback.
1032e6ca193dSGeorge Wilson  */
1033e6ca193dSGeorge Wilson void
1034e6ca193dSGeorge Wilson print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
1035e6ca193dSGeorge Wilson     int namewidth, int depth, boolean_t isspare)
1036e6ca193dSGeorge Wilson {
1037e6ca193dSGeorge Wilson 	nvlist_t **child;
1038e6ca193dSGeorge Wilson 	uint_t c, children;
1039e6ca193dSGeorge Wilson 	vdev_stat_t *vs;
1040e6ca193dSGeorge Wilson 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
1041e6ca193dSGeorge Wilson 	char *vname;
1042e6ca193dSGeorge Wilson 	uint64_t notpresent;
1043e6ca193dSGeorge Wilson 	spare_cbdata_t cb;
1044e6ca193dSGeorge Wilson 	char *state;
1045e6ca193dSGeorge Wilson 
1046e6ca193dSGeorge Wilson 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
1047e6ca193dSGeorge Wilson 	    (uint64_t **)&vs, &c) == 0);
1048e6ca193dSGeorge Wilson 
1049e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1050e6ca193dSGeorge Wilson 	    &child, &children) != 0)
1051e6ca193dSGeorge Wilson 		children = 0;
1052e6ca193dSGeorge Wilson 
1053e6ca193dSGeorge Wilson 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1054e6ca193dSGeorge Wilson 	if (isspare) {
1055e6ca193dSGeorge Wilson 		/*
1056e6ca193dSGeorge Wilson 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
1057e6ca193dSGeorge Wilson 		 * online drives.
1058e6ca193dSGeorge Wilson 		 */
1059e6ca193dSGeorge Wilson 		if (vs->vs_aux == VDEV_AUX_SPARED)
1060e6ca193dSGeorge Wilson 			state = "INUSE";
1061e6ca193dSGeorge Wilson 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
1062e6ca193dSGeorge Wilson 			state = "AVAIL";
1063e6ca193dSGeorge Wilson 	}
1064e6ca193dSGeorge Wilson 
1065e6ca193dSGeorge Wilson 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
1066e6ca193dSGeorge Wilson 	    name, state);
1067e6ca193dSGeorge Wilson 
1068e6ca193dSGeorge Wilson 	if (!isspare) {
1069e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
1070e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
1071e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
1072e6ca193dSGeorge Wilson 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
1073e6ca193dSGeorge Wilson 	}
1074e6ca193dSGeorge Wilson 
1075e6ca193dSGeorge Wilson 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1076e6ca193dSGeorge Wilson 	    &notpresent) == 0) {
1077e6ca193dSGeorge Wilson 		char *path;
1078e6ca193dSGeorge Wilson 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
1079e6ca193dSGeorge Wilson 		(void) printf("  was %s", path);
1080e6ca193dSGeorge Wilson 	} else if (vs->vs_aux != 0) {
1081e6ca193dSGeorge Wilson 		(void) printf("  ");
1082e6ca193dSGeorge Wilson 
1083e6ca193dSGeorge Wilson 		switch (vs->vs_aux) {
1084e6ca193dSGeorge Wilson 		case VDEV_AUX_OPEN_FAILED:
1085e6ca193dSGeorge Wilson 			(void) printf(gettext("cannot open"));
1086e6ca193dSGeorge Wilson 			break;
1087e6ca193dSGeorge Wilson 
1088e6ca193dSGeorge Wilson 		case VDEV_AUX_BAD_GUID_SUM:
1089e6ca193dSGeorge Wilson 			(void) printf(gettext("missing device"));
1090e6ca193dSGeorge Wilson 			break;
1091e6ca193dSGeorge Wilson 
1092e6ca193dSGeorge Wilson 		case VDEV_AUX_NO_REPLICAS:
1093e6ca193dSGeorge Wilson 			(void) printf(gettext("insufficient replicas"));
1094e6ca193dSGeorge Wilson 			break;
1095e6ca193dSGeorge Wilson 
1096e6ca193dSGeorge Wilson 		case VDEV_AUX_VERSION_NEWER:
1097e6ca193dSGeorge Wilson 			(void) printf(gettext("newer version"));
1098e6ca193dSGeorge Wilson 			break;
1099e6ca193dSGeorge Wilson 
1100e6ca193dSGeorge Wilson 		case VDEV_AUX_SPARED:
1101e6ca193dSGeorge Wilson 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1102e6ca193dSGeorge Wilson 			    &cb.cb_guid) == 0);
1103e6ca193dSGeorge Wilson 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
1104e6ca193dSGeorge Wilson 				if (strcmp(zpool_get_name(cb.cb_zhp),
1105e6ca193dSGeorge Wilson 				    zpool_get_name(zhp)) == 0)
1106e6ca193dSGeorge Wilson 					(void) printf(gettext("currently in "
1107e6ca193dSGeorge Wilson 					    "use"));
1108e6ca193dSGeorge Wilson 				else
1109e6ca193dSGeorge Wilson 					(void) printf(gettext("in use by "
1110e6ca193dSGeorge Wilson 					    "pool '%s'"),
1111e6ca193dSGeorge Wilson 					    zpool_get_name(cb.cb_zhp));
1112e6ca193dSGeorge Wilson 				zpool_close(cb.cb_zhp);
1113e6ca193dSGeorge Wilson 			} else {
1114e6ca193dSGeorge Wilson 				(void) printf(gettext("currently in use"));
1115e6ca193dSGeorge Wilson 			}
1116e6ca193dSGeorge Wilson 			break;
1117e6ca193dSGeorge Wilson 
1118e6ca193dSGeorge Wilson 		case VDEV_AUX_ERR_EXCEEDED:
1119e6ca193dSGeorge Wilson 			(void) printf(gettext("too many errors"));
1120e6ca193dSGeorge Wilson 			break;
1121e6ca193dSGeorge Wilson 
1122e6ca193dSGeorge Wilson 		case VDEV_AUX_IO_FAILURE:
1123e6ca193dSGeorge Wilson 			(void) printf(gettext("experienced I/O failures"));
1124e6ca193dSGeorge Wilson 			break;
1125e6ca193dSGeorge Wilson 
1126e6ca193dSGeorge Wilson 		case VDEV_AUX_BAD_LOG:
1127e6ca193dSGeorge Wilson 			(void) printf(gettext("bad intent log"));
1128e6ca193dSGeorge Wilson 			break;
1129e6ca193dSGeorge Wilson 
1130e6ca193dSGeorge Wilson 		default:
1131e6ca193dSGeorge Wilson 			(void) printf(gettext("corrupted data"));
1132e6ca193dSGeorge Wilson 			break;
1133e6ca193dSGeorge Wilson 		}
1134e6ca193dSGeorge Wilson 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
1135e6ca193dSGeorge Wilson 		/*
1136e6ca193dSGeorge Wilson 		 * Report bytes resilvered/repaired on leaf devices.
1137e6ca193dSGeorge Wilson 		 */
1138e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
1139e6ca193dSGeorge Wilson 		(void) printf(gettext("  %s %s"), repaired,
1140e6ca193dSGeorge Wilson 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
1141e6ca193dSGeorge Wilson 		    "resilvered" : "repaired");
1142e6ca193dSGeorge Wilson 	}
1143e6ca193dSGeorge Wilson 
1144e6ca193dSGeorge Wilson 	(void) printf("\n");
1145e6ca193dSGeorge Wilson 
1146e6ca193dSGeorge Wilson 	for (c = 0; c < children; c++) {
1147*88ecc943SGeorge Wilson 		uint64_t islog = B_FALSE, ishole = B_FALSE;
1148e6ca193dSGeorge Wilson 
1149*88ecc943SGeorge Wilson 		/* Don't print logs or holes here */
1150e6ca193dSGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1151*88ecc943SGeorge Wilson 		    &islog);
1152*88ecc943SGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
1153*88ecc943SGeorge Wilson 		    &ishole);
1154*88ecc943SGeorge Wilson 		if (islog || ishole)
1155e6ca193dSGeorge Wilson 			continue;
1156*88ecc943SGeorge Wilson 		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1157e6ca193dSGeorge Wilson 		print_status_config(zhp, vname, child[c],
1158e6ca193dSGeorge Wilson 		    namewidth, depth + 2, isspare);
1159e6ca193dSGeorge Wilson 		free(vname);
1160e6ca193dSGeorge Wilson 	}
1161e6ca193dSGeorge Wilson }
1162e6ca193dSGeorge Wilson 
1163fa9e4066Sahrens 
1164fa9e4066Sahrens /*
1165fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
1166fa9e4066Sahrens  * pool, printing out the name and status for each one.
1167fa9e4066Sahrens  */
1168fa9e4066Sahrens void
1169e6ca193dSGeorge Wilson print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
1170fa9e4066Sahrens {
1171fa9e4066Sahrens 	nvlist_t **child;
1172fa9e4066Sahrens 	uint_t c, children;
1173fa9e4066Sahrens 	vdev_stat_t *vs;
1174afefbcddSeschrock 	char *type, *vname;
1175fa9e4066Sahrens 
1176fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
1177*88ecc943SGeorge Wilson 	if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
1178*88ecc943SGeorge Wilson 	    strcmp(type, VDEV_TYPE_HOLE) == 0)
1179fa9e4066Sahrens 		return;
1180fa9e4066Sahrens 
1181fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
1182fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
1183fa9e4066Sahrens 
1184fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
1185990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1186fa9e4066Sahrens 
1187fa9e4066Sahrens 	if (vs->vs_aux != 0) {
11883d7072f8Seschrock 		(void) printf("  ");
1189fa9e4066Sahrens 
1190fa9e4066Sahrens 		switch (vs->vs_aux) {
1191fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
1192fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
1193fa9e4066Sahrens 			break;
1194fa9e4066Sahrens 
1195fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
1196fa9e4066Sahrens 			(void) printf(gettext("missing device"));
1197fa9e4066Sahrens 			break;
1198fa9e4066Sahrens 
1199fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
1200fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
1201fa9e4066Sahrens 			break;
1202fa9e4066Sahrens 
1203eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
1204eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
1205eaca9bbdSeschrock 			break;
1206eaca9bbdSeschrock 
12073d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
12083d7072f8Seschrock 			(void) printf(gettext("too many errors"));
12093d7072f8Seschrock 			break;
12103d7072f8Seschrock 
1211fa9e4066Sahrens 		default:
1212fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
1213fa9e4066Sahrens 			break;
1214fa9e4066Sahrens 		}
1215fa9e4066Sahrens 	}
1216fa9e4066Sahrens 	(void) printf("\n");
1217fa9e4066Sahrens 
1218fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1219fa9e4066Sahrens 	    &child, &children) != 0)
1220fa9e4066Sahrens 		return;
1221fa9e4066Sahrens 
1222afefbcddSeschrock 	for (c = 0; c < children; c++) {
12238654d025Sperrin 		uint64_t is_log = B_FALSE;
12248654d025Sperrin 
12258654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
12268654d025Sperrin 		    &is_log);
1227e6ca193dSGeorge Wilson 		if (is_log)
12288654d025Sperrin 			continue;
12298654d025Sperrin 
1230*88ecc943SGeorge Wilson 		vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
1231e6ca193dSGeorge Wilson 		print_import_config(vname, child[c], namewidth, depth + 2);
1232afefbcddSeschrock 		free(vname);
1233afefbcddSeschrock 	}
123499653d4eSeschrock 
1235fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1236fa94a07fSbrendan 	    &child, &children) == 0) {
1237fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
1238fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1239*88ecc943SGeorge Wilson 			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1240fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1241fa94a07fSbrendan 			free(vname);
1242fa94a07fSbrendan 		}
1243fa94a07fSbrendan 	}
124499653d4eSeschrock 
1245fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1246fa94a07fSbrendan 	    &child, &children) == 0) {
124799653d4eSeschrock 		(void) printf(gettext("\tspares\n"));
124899653d4eSeschrock 		for (c = 0; c < children; c++) {
1249*88ecc943SGeorge Wilson 			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
125099653d4eSeschrock 			(void) printf("\t  %s\n", vname);
125199653d4eSeschrock 			free(vname);
125299653d4eSeschrock 		}
1253fa9e4066Sahrens 	}
1254fa94a07fSbrendan }
1255fa9e4066Sahrens 
1256fa9e4066Sahrens /*
1257e6ca193dSGeorge Wilson  * Print log vdevs.
1258e6ca193dSGeorge Wilson  * Logs are recorded as top level vdevs in the main pool child array
1259e6ca193dSGeorge Wilson  * but with "is_log" set to 1. We use either print_status_config() or
1260e6ca193dSGeorge Wilson  * print_import_config() to print the top level logs then any log
1261e6ca193dSGeorge Wilson  * children (eg mirrored slogs) are printed recursively - which
1262e6ca193dSGeorge Wilson  * works because only the top level vdev is marked "is_log"
1263e6ca193dSGeorge Wilson  */
1264e6ca193dSGeorge Wilson static void
1265e6ca193dSGeorge Wilson print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
1266e6ca193dSGeorge Wilson {
1267e6ca193dSGeorge Wilson 	uint_t c, children;
1268e6ca193dSGeorge Wilson 	nvlist_t **child;
1269e6ca193dSGeorge Wilson 
1270e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1271e6ca193dSGeorge Wilson 	    &children) != 0)
1272e6ca193dSGeorge Wilson 		return;
1273e6ca193dSGeorge Wilson 
1274e6ca193dSGeorge Wilson 	(void) printf(gettext("\tlogs\n"));
1275e6ca193dSGeorge Wilson 
1276e6ca193dSGeorge Wilson 	for (c = 0; c < children; c++) {
1277e6ca193dSGeorge Wilson 		uint64_t is_log = B_FALSE;
1278e6ca193dSGeorge Wilson 		char *name;
1279e6ca193dSGeorge Wilson 
1280e6ca193dSGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1281e6ca193dSGeorge Wilson 		    &is_log);
1282e6ca193dSGeorge Wilson 		if (!is_log)
1283e6ca193dSGeorge Wilson 			continue;
1284*88ecc943SGeorge Wilson 		name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1285e6ca193dSGeorge Wilson 		if (verbose)
1286e6ca193dSGeorge Wilson 			print_status_config(zhp, name, child[c], namewidth,
1287e6ca193dSGeorge Wilson 			    2, B_FALSE);
1288e6ca193dSGeorge Wilson 		else
1289e6ca193dSGeorge Wilson 			print_import_config(name, child[c], namewidth, 2);
1290e6ca193dSGeorge Wilson 		free(name);
1291e6ca193dSGeorge Wilson 	}
1292e6ca193dSGeorge Wilson }
1293e6ca193dSGeorge Wilson /*
1294fa9e4066Sahrens  * Display the status for the given pool.
1295fa9e4066Sahrens  */
1296fa9e4066Sahrens static void
1297fa9e4066Sahrens show_import(nvlist_t *config)
1298fa9e4066Sahrens {
1299fa9e4066Sahrens 	uint64_t pool_state;
1300fa9e4066Sahrens 	vdev_stat_t *vs;
1301fa9e4066Sahrens 	char *name;
1302fa9e4066Sahrens 	uint64_t guid;
1303fa9e4066Sahrens 	char *msgid;
1304fa9e4066Sahrens 	nvlist_t *nvroot;
1305fa9e4066Sahrens 	int reason;
130646657f8dSmmusante 	const char *health;
1307fa9e4066Sahrens 	uint_t vsc;
1308fa9e4066Sahrens 	int namewidth;
1309fa9e4066Sahrens 
1310fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1311fa9e4066Sahrens 	    &name) == 0);
1312fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1313fa9e4066Sahrens 	    &guid) == 0);
1314fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1315fa9e4066Sahrens 	    &pool_state) == 0);
1316fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1317fa9e4066Sahrens 	    &nvroot) == 0);
1318fa9e4066Sahrens 
1319fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1320fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1321990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1322fa9e4066Sahrens 
1323fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1324fa9e4066Sahrens 
132546657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
132646657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
132746657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
13284c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
132946657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
13304c58d714Sdarrenm 	(void) printf("\n");
1331fa9e4066Sahrens 
1332fa9e4066Sahrens 	switch (reason) {
1333fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1334fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1335fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1336fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1337fa9e4066Sahrens 		    "from the system.\n"));
1338fa9e4066Sahrens 		break;
1339fa9e4066Sahrens 
1340fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1341fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1342fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1343fa9e4066Sahrens 		    "corrupted data.\n"));
1344fa9e4066Sahrens 		break;
1345fa9e4066Sahrens 
1346fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1347fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1348fa9e4066Sahrens 		break;
1349fa9e4066Sahrens 
1350441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1351441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1352441d80aaSlling 		    "are offlined.\n"));
1353441d80aaSlling 		break;
1354441d80aaSlling 
1355ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1356ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1357ea8dc4b6Seschrock 		    "corrupted.\n"));
1358ea8dc4b6Seschrock 		break;
1359ea8dc4b6Seschrock 
1360eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1361eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1362eaca9bbdSeschrock 		    "older on-disk version.\n"));
1363eaca9bbdSeschrock 		break;
1364eaca9bbdSeschrock 
1365eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1366eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1367eaca9bbdSeschrock 		    "incompatible version.\n"));
1368eaca9bbdSeschrock 		break;
1369b87f3af3Sperrin 
137095173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
137195173954Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
137295173954Sek110237 		    "another system.\n"));
137395173954Sek110237 		break;
1374b87f3af3Sperrin 
13753d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
13763d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
13773d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
13783d7072f8Seschrock 		    "faulted.\n"));
13793d7072f8Seschrock 		break;
13803d7072f8Seschrock 
1381b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
1382b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record cannot be "
1383b87f3af3Sperrin 		    "read.\n"));
1384b87f3af3Sperrin 		break;
1385b87f3af3Sperrin 
1386fa9e4066Sahrens 	default:
1387fa9e4066Sahrens 		/*
1388fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1389fa9e4066Sahrens 		 */
1390fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1391fa9e4066Sahrens 	}
1392fa9e4066Sahrens 
1393fa9e4066Sahrens 	/*
1394fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1395fa9e4066Sahrens 	 */
139646657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1397eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1398eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1399eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1400eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1401eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
140295173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
140395173954Sek110237 			(void) printf(gettext("action: The pool can be "
140495173954Sek110237 			    "imported using its name or numeric "
140595173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1406fa9e4066Sahrens 		else
1407eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1408eaca9bbdSeschrock 			    "imported using its name or numeric "
1409eaca9bbdSeschrock 			    "identifier.\n"));
141046657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1411fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1412fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1413eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1414fa9e4066Sahrens 	} else {
1415eaca9bbdSeschrock 		switch (reason) {
1416eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1417eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1418eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1419eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1420eaca9bbdSeschrock 			    "backup.\n"));
1421eaca9bbdSeschrock 			break;
1422eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1423eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1424eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1425fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1426fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1427fa9e4066Sahrens 			    "again.\n"));
1428eaca9bbdSeschrock 			break;
1429eaca9bbdSeschrock 		default:
1430fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1431fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1432fa9e4066Sahrens 		}
1433eaca9bbdSeschrock 	}
1434eaca9bbdSeschrock 
143546657f8dSmmusante 	/*
143646657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
143746657f8dSmmusante 	 * is "corrupt data":
143846657f8dSmmusante 	 */
143946657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
144046657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
144146657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1442eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1443eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1444eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1445eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1446eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
144718ce54dfSek110237 			    "another system, but can be imported using\n\t"
1448eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1449eaca9bbdSeschrock 	}
1450fa9e4066Sahrens 
1451fa9e4066Sahrens 	if (msgid != NULL)
1452fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1453fa9e4066Sahrens 		    msgid);
1454fa9e4066Sahrens 
1455fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1456fa9e4066Sahrens 
1457c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1458fa9e4066Sahrens 	if (namewidth < 10)
1459fa9e4066Sahrens 		namewidth = 10;
14608654d025Sperrin 
1461e6ca193dSGeorge Wilson 	print_import_config(name, nvroot, namewidth, 0);
1462e6ca193dSGeorge Wilson 	if (num_logs(nvroot) > 0)
1463e6ca193dSGeorge Wilson 		print_logs(NULL, nvroot, namewidth, B_FALSE);
1464fa9e4066Sahrens 
1465fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
146646657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1467fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
146846657f8dSmmusante 		    "configuration cannot be determined.\n"));
1469fa9e4066Sahrens 	}
1470fa9e4066Sahrens }
1471fa9e4066Sahrens 
1472fa9e4066Sahrens /*
1473fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1474990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1475990b4856Slling  * within the pool.
1476fa9e4066Sahrens  */
1477fa9e4066Sahrens static int
1478fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
14794f0f5e5bSVictor Latushkin     int force, nvlist_t *props, boolean_t do_verbatim)
1480fa9e4066Sahrens {
1481fa9e4066Sahrens 	zpool_handle_t *zhp;
1482fa9e4066Sahrens 	char *name;
1483fa9e4066Sahrens 	uint64_t state;
1484eaca9bbdSeschrock 	uint64_t version;
1485ecd6cf80Smarks 	int error = 0;
1486fa9e4066Sahrens 
1487fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1488fa9e4066Sahrens 	    &name) == 0);
1489fa9e4066Sahrens 
1490fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1491fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1492eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1493eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1494e7437265Sahrens 	if (version > SPA_VERSION) {
1495eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1496eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1497eaca9bbdSeschrock 		return (1);
1498eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
149995173954Sek110237 		uint64_t hostid;
150095173954Sek110237 
150195173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
150295173954Sek110237 		    &hostid) == 0) {
150395173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
150495173954Sek110237 				char *hostname;
150595173954Sek110237 				uint64_t timestamp;
150695173954Sek110237 				time_t t;
150795173954Sek110237 
150895173954Sek110237 				verify(nvlist_lookup_string(config,
150995173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
151095173954Sek110237 				verify(nvlist_lookup_uint64(config,
151195173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
151295173954Sek110237 				t = timestamp;
151395173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
151495173954Sek110237 				    "'%s': pool may be in use from other "
151595173954Sek110237 				    "system, it was last accessed by %s "
151695173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
151795173954Sek110237 				    (unsigned long)hostid,
151895173954Sek110237 				    asctime(localtime(&t)));
151995173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
152095173954Sek110237 				    "import anyway\n"));
1521fa9e4066Sahrens 				return (1);
1522fa9e4066Sahrens 			}
152395173954Sek110237 		} else {
152495173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
152595173954Sek110237 			    "pool may be in use from other system\n"), name);
152695173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
152795173954Sek110237 			    "anyway\n"));
152895173954Sek110237 			return (1);
152995173954Sek110237 		}
153095173954Sek110237 	}
1531fa9e4066Sahrens 
15324f0f5e5bSVictor Latushkin 	if (zpool_import_props(g_zfs, config, newname, props, do_verbatim) != 0)
1533fa9e4066Sahrens 		return (1);
1534fa9e4066Sahrens 
1535fa9e4066Sahrens 	if (newname != NULL)
1536fa9e4066Sahrens 		name = (char *)newname;
1537fa9e4066Sahrens 
15384f0f5e5bSVictor Latushkin 	if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
15394f0f5e5bSVictor Latushkin 		return (1);
1540fa9e4066Sahrens 
1541379c004dSEric Schrock 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
1542379c004dSEric Schrock 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1543fa9e4066Sahrens 		zpool_close(zhp);
1544fa9e4066Sahrens 		return (1);
1545fa9e4066Sahrens 	}
1546fa9e4066Sahrens 
1547fa9e4066Sahrens 	zpool_close(zhp);
1548ecd6cf80Smarks 	return (error);
1549fa9e4066Sahrens }
1550fa9e4066Sahrens 
1551fa9e4066Sahrens /*
15524c58d714Sdarrenm  * zpool import [-d dir] [-D]
15532f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
15542f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
15552f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
15562f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] <pool | id> [newpool]
15572f8aaab3Seschrock  *
15582f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
15592f8aaab3Seschrock  *		devices.
1560fa9e4066Sahrens  *
1561fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1562fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1563fa9e4066Sahrens  *
15644c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
15654c58d714Sdarrenm  *              specified destroyed pools.
15664c58d714Sdarrenm  *
1567fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1568fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1569fa9e4066Sahrens  *		is rebooted.
1570fa9e4066Sahrens  *
1571fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1572fa9e4066Sahrens  *
1573c5904d13Seschrock  *       -F	Import even in the presence of faulted vdevs.  This is an
1574c5904d13Seschrock  *       	intentionally undocumented option for testing purposes, and
1575c5904d13Seschrock  *       	treats the pool configuration as complete, leaving any bad
15764f0f5e5bSVictor Latushkin  *		vdevs in the FAULTED state. In other words, it does verbatim
15774f0f5e5bSVictor Latushkin  *		import.
1578c5904d13Seschrock  *
1579fa9e4066Sahrens  *       -a	Import all pools found.
1580fa9e4066Sahrens  *
1581990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1582ecd6cf80Smarks  *
1583fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1584fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1585fa9e4066Sahrens  */
1586fa9e4066Sahrens int
1587fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1588fa9e4066Sahrens {
1589fa9e4066Sahrens 	char **searchdirs = NULL;
1590fa9e4066Sahrens 	int nsearch = 0;
1591fa9e4066Sahrens 	int c;
1592fa9e4066Sahrens 	int err;
15932f8aaab3Seschrock 	nvlist_t *pools = NULL;
159499653d4eSeschrock 	boolean_t do_all = B_FALSE;
159599653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1596fa9e4066Sahrens 	char *mntopts = NULL;
159799653d4eSeschrock 	boolean_t do_force = B_FALSE;
1598fa9e4066Sahrens 	nvpair_t *elem;
1599fa9e4066Sahrens 	nvlist_t *config;
160024e697d4Sck153898 	uint64_t searchguid = 0;
160124e697d4Sck153898 	char *searchname = NULL;
1602990b4856Slling 	char *propval;
1603fa9e4066Sahrens 	nvlist_t *found_config;
1604ecd6cf80Smarks 	nvlist_t *props = NULL;
160599653d4eSeschrock 	boolean_t first;
16064f0f5e5bSVictor Latushkin 	boolean_t do_verbatim = B_FALSE;
16074c58d714Sdarrenm 	uint64_t pool_state;
16082f8aaab3Seschrock 	char *cachefile = NULL;
1609fa9e4066Sahrens 
1610fa9e4066Sahrens 	/* check options */
1611c5904d13Seschrock 	while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) {
1612fa9e4066Sahrens 		switch (c) {
1613fa9e4066Sahrens 		case 'a':
161499653d4eSeschrock 			do_all = B_TRUE;
1615fa9e4066Sahrens 			break;
16162f8aaab3Seschrock 		case 'c':
16172f8aaab3Seschrock 			cachefile = optarg;
16182f8aaab3Seschrock 			break;
1619fa9e4066Sahrens 		case 'd':
1620fa9e4066Sahrens 			if (searchdirs == NULL) {
1621fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1622fa9e4066Sahrens 			} else {
1623fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1624fa9e4066Sahrens 				    sizeof (char *));
1625fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1626fa9e4066Sahrens 				    sizeof (char *));
1627fa9e4066Sahrens 				free(searchdirs);
1628fa9e4066Sahrens 				searchdirs = tmp;
1629fa9e4066Sahrens 			}
1630fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1631fa9e4066Sahrens 			break;
16324c58d714Sdarrenm 		case 'D':
163399653d4eSeschrock 			do_destroyed = B_TRUE;
16344c58d714Sdarrenm 			break;
1635fa9e4066Sahrens 		case 'f':
163699653d4eSeschrock 			do_force = B_TRUE;
1637fa9e4066Sahrens 			break;
1638c5904d13Seschrock 		case 'F':
16394f0f5e5bSVictor Latushkin 			do_verbatim = B_TRUE;
1640c5904d13Seschrock 			break;
1641fa9e4066Sahrens 		case 'o':
1642990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1643990b4856Slling 				*propval = '\0';
1644990b4856Slling 				propval++;
16450a48a24eStimh 				if (add_prop_list(optarg, propval,
16460a48a24eStimh 				    &props, B_TRUE))
1647990b4856Slling 					goto error;
1648990b4856Slling 			} else {
1649fa9e4066Sahrens 				mntopts = optarg;
1650990b4856Slling 			}
1651fa9e4066Sahrens 			break;
1652fa9e4066Sahrens 		case 'R':
1653990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
16540a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1655990b4856Slling 				goto error;
16562f8aaab3Seschrock 			if (nvlist_lookup_string(props,
16572f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
16582f8aaab3Seschrock 			    &propval) == 0)
16592f8aaab3Seschrock 				break;
1660990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
16610a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1662990b4856Slling 				goto error;
1663fa9e4066Sahrens 			break;
1664fa9e4066Sahrens 		case ':':
1665fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1666fa9e4066Sahrens 			    "'%c' option\n"), optopt);
166799653d4eSeschrock 			usage(B_FALSE);
1668fa9e4066Sahrens 			break;
1669fa9e4066Sahrens 		case '?':
1670fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1671fa9e4066Sahrens 			    optopt);
167299653d4eSeschrock 			usage(B_FALSE);
1673fa9e4066Sahrens 		}
1674fa9e4066Sahrens 	}
1675fa9e4066Sahrens 
1676fa9e4066Sahrens 	argc -= optind;
1677fa9e4066Sahrens 	argv += optind;
1678fa9e4066Sahrens 
16792f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
16802f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
16812f8aaab3Seschrock 		usage(B_FALSE);
16822f8aaab3Seschrock 	}
16832f8aaab3Seschrock 
1684fa9e4066Sahrens 	if (searchdirs == NULL) {
1685fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1686fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1687fa9e4066Sahrens 		nsearch = 1;
1688fa9e4066Sahrens 	}
1689fa9e4066Sahrens 
1690fa9e4066Sahrens 	/* check argument count */
1691fa9e4066Sahrens 	if (do_all) {
1692fa9e4066Sahrens 		if (argc != 0) {
1693fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
169499653d4eSeschrock 			usage(B_FALSE);
1695fa9e4066Sahrens 		}
1696fa9e4066Sahrens 	} else {
1697fa9e4066Sahrens 		if (argc > 2) {
1698fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
169999653d4eSeschrock 			usage(B_FALSE);
1700fa9e4066Sahrens 		}
1701fa9e4066Sahrens 
1702fa9e4066Sahrens 		/*
1703fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1704fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1705fa9e4066Sahrens 		 * silently fail.
1706fa9e4066Sahrens 		 */
1707fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1708fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1709fa9e4066Sahrens 			    "discover pools: permission denied\n"));
171099653d4eSeschrock 			free(searchdirs);
1711fa9e4066Sahrens 			return (1);
1712fa9e4066Sahrens 		}
1713fa9e4066Sahrens 	}
1714fa9e4066Sahrens 
1715fa9e4066Sahrens 	/*
1716fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1717fa9e4066Sahrens 	 *
1718fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1719fa9e4066Sahrens 	 *		each one.
1720fa9e4066Sahrens 	 *
1721fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1722fa9e4066Sahrens 	 *
1723fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1724fa9e4066Sahrens 	 *		name and import that one.
17254c58d714Sdarrenm 	 *
17264c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1727fa9e4066Sahrens 	 */
1728fa9e4066Sahrens 	if (argc != 0) {
1729fa9e4066Sahrens 		char *endptr;
1730fa9e4066Sahrens 
1731fa9e4066Sahrens 		errno = 0;
1732fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1733fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1734fa9e4066Sahrens 			searchname = argv[0];
1735fa9e4066Sahrens 		found_config = NULL;
1736fa9e4066Sahrens 	}
1737fa9e4066Sahrens 
173824e697d4Sck153898 	if (cachefile) {
1739e829d913Sck153898 		pools = zpool_find_import_cached(g_zfs, cachefile, searchname,
1740e829d913Sck153898 		    searchguid);
174124e697d4Sck153898 	} else if (searchname != NULL) {
174224e697d4Sck153898 		pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs,
174324e697d4Sck153898 		    searchname);
174424e697d4Sck153898 	} else {
174524e697d4Sck153898 		/*
174624e697d4Sck153898 		 * It's OK to search by guid even if searchguid is 0.
174724e697d4Sck153898 		 */
174824e697d4Sck153898 		pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs,
174924e697d4Sck153898 		    searchguid);
175024e697d4Sck153898 	}
175124e697d4Sck153898 
175224e697d4Sck153898 	if (pools == NULL) {
175324e697d4Sck153898 		if (argc != 0) {
175424e697d4Sck153898 			(void) fprintf(stderr, gettext("cannot import '%s': "
175524e697d4Sck153898 			    "no such pool available\n"), argv[0]);
175624e697d4Sck153898 		}
175724e697d4Sck153898 		free(searchdirs);
175824e697d4Sck153898 		return (1);
175924e697d4Sck153898 	}
176024e697d4Sck153898 
176124e697d4Sck153898 	/*
176224e697d4Sck153898 	 * At this point we have a list of import candidate configs. Even if
176324e697d4Sck153898 	 * we were searching by pool name or guid, we still need to
176424e697d4Sck153898 	 * post-process the list to deal with pool state and possible
176524e697d4Sck153898 	 * duplicate names.
176624e697d4Sck153898 	 */
1767fa9e4066Sahrens 	err = 0;
1768fa9e4066Sahrens 	elem = NULL;
176999653d4eSeschrock 	first = B_TRUE;
1770fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1771fa9e4066Sahrens 
1772fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1773fa9e4066Sahrens 
17744c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
17754c58d714Sdarrenm 		    &pool_state) == 0);
17764c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
17774c58d714Sdarrenm 			continue;
17784c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
17794c58d714Sdarrenm 			continue;
17804c58d714Sdarrenm 
1781fa9e4066Sahrens 		if (argc == 0) {
1782fa9e4066Sahrens 			if (first)
178399653d4eSeschrock 				first = B_FALSE;
17843bb79becSeschrock 			else if (!do_all)
1785fa9e4066Sahrens 				(void) printf("\n");
1786fa9e4066Sahrens 
1787fa9e4066Sahrens 			if (do_all)
1788fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
17894f0f5e5bSVictor Latushkin 				    do_force, props, do_verbatim);
1790fa9e4066Sahrens 			else
1791fa9e4066Sahrens 				show_import(config);
1792fa9e4066Sahrens 		} else if (searchname != NULL) {
1793fa9e4066Sahrens 			char *name;
1794fa9e4066Sahrens 
1795fa9e4066Sahrens 			/*
1796fa9e4066Sahrens 			 * We are searching for a pool based on name.
1797fa9e4066Sahrens 			 */
1798fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1799fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1800fa9e4066Sahrens 
1801fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1802fa9e4066Sahrens 				if (found_config != NULL) {
1803fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1804fa9e4066Sahrens 					    "cannot import '%s': more than "
1805fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1806fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1807fa9e4066Sahrens 					    "import by numeric ID instead\n"));
180899653d4eSeschrock 					err = B_TRUE;
1809fa9e4066Sahrens 				}
1810fa9e4066Sahrens 				found_config = config;
1811fa9e4066Sahrens 			}
1812fa9e4066Sahrens 		} else {
1813fa9e4066Sahrens 			uint64_t guid;
1814fa9e4066Sahrens 
1815fa9e4066Sahrens 			/*
1816fa9e4066Sahrens 			 * Search for a pool by guid.
1817fa9e4066Sahrens 			 */
1818fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1819fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1820fa9e4066Sahrens 
1821fa9e4066Sahrens 			if (guid == searchguid)
1822fa9e4066Sahrens 				found_config = config;
1823fa9e4066Sahrens 		}
1824fa9e4066Sahrens 	}
1825fa9e4066Sahrens 
1826fa9e4066Sahrens 	/*
1827fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1828fa9e4066Sahrens 	 * pool, and then do the import.
1829fa9e4066Sahrens 	 */
1830fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1831fa9e4066Sahrens 		if (found_config == NULL) {
1832fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1833fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
183499653d4eSeschrock 			err = B_TRUE;
1835fa9e4066Sahrens 		} else {
1836fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
18374f0f5e5bSVictor Latushkin 			    argv[1], mntopts, do_force, props, do_verbatim);
1838fa9e4066Sahrens 		}
1839fa9e4066Sahrens 	}
1840fa9e4066Sahrens 
1841fa9e4066Sahrens 	/*
1842fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1843fa9e4066Sahrens 	 * found.
1844fa9e4066Sahrens 	 */
1845fa9e4066Sahrens 	if (argc == 0 && first)
1846fa9e4066Sahrens 		(void) fprintf(stderr,
1847fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1848fa9e4066Sahrens 
1849ecd6cf80Smarks error:
1850ecd6cf80Smarks 	nvlist_free(props);
1851fa9e4066Sahrens 	nvlist_free(pools);
185299653d4eSeschrock 	free(searchdirs);
1853fa9e4066Sahrens 
1854fa9e4066Sahrens 	return (err ? 1 : 0);
1855fa9e4066Sahrens }
1856fa9e4066Sahrens 
1857fa9e4066Sahrens typedef struct iostat_cbdata {
1858fa9e4066Sahrens 	zpool_list_t *cb_list;
1859fa9e4066Sahrens 	int cb_verbose;
1860fa9e4066Sahrens 	int cb_iteration;
1861fa9e4066Sahrens 	int cb_namewidth;
1862fa9e4066Sahrens } iostat_cbdata_t;
1863fa9e4066Sahrens 
1864fa9e4066Sahrens static void
1865fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1866fa9e4066Sahrens {
1867fa9e4066Sahrens 	int i = 0;
1868fa9e4066Sahrens 
1869fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1870fa9e4066Sahrens 		(void) printf("-");
1871fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1872fa9e4066Sahrens }
1873fa9e4066Sahrens 
1874fa9e4066Sahrens static void
1875fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1876fa9e4066Sahrens {
1877fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1878fa9e4066Sahrens 	    cb->cb_namewidth, "");
1879fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1880fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1881fa9e4066Sahrens 	print_iostat_separator(cb);
1882fa9e4066Sahrens }
1883fa9e4066Sahrens 
1884fa9e4066Sahrens /*
1885fa9e4066Sahrens  * Display a single statistic.
1886fa9e4066Sahrens  */
1887990b4856Slling static void
1888fa9e4066Sahrens print_one_stat(uint64_t value)
1889fa9e4066Sahrens {
1890fa9e4066Sahrens 	char buf[64];
1891fa9e4066Sahrens 
1892fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1893fa9e4066Sahrens 	(void) printf("  %5s", buf);
1894fa9e4066Sahrens }
1895fa9e4066Sahrens 
1896fa9e4066Sahrens /*
1897fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1898fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1899fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1900fa9e4066Sahrens  */
1901fa9e4066Sahrens void
1902c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1903c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1904fa9e4066Sahrens {
1905fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1906fa9e4066Sahrens 	uint_t c, children;
1907fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1908fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1909fa9e4066Sahrens 	uint64_t tdelta;
1910fa9e4066Sahrens 	double scale;
1911afefbcddSeschrock 	char *vname;
1912fa9e4066Sahrens 
1913fa9e4066Sahrens 	if (oldnv != NULL) {
1914fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1915fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1916fa9e4066Sahrens 	} else {
1917fa9e4066Sahrens 		oldvs = &zerovs;
1918fa9e4066Sahrens 	}
1919fa9e4066Sahrens 
1920fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1921fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1922fa9e4066Sahrens 
1923fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1924fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1925fa9e4066Sahrens 	else
1926fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1927fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1928fa9e4066Sahrens 
1929fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1930fa9e4066Sahrens 
1931fa9e4066Sahrens 	if (tdelta == 0)
1932fa9e4066Sahrens 		scale = 1.0;
1933fa9e4066Sahrens 	else
1934fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1935fa9e4066Sahrens 
1936fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1937fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1938fa9e4066Sahrens 		(void) printf("      -      -");
1939fa9e4066Sahrens 	} else {
1940fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1941fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1942fa9e4066Sahrens 	}
1943fa9e4066Sahrens 
1944fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1945fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1946fa9e4066Sahrens 
1947fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1948fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1949fa9e4066Sahrens 
1950fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1951fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1952fa9e4066Sahrens 
1953fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1954fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1955fa9e4066Sahrens 
1956fa9e4066Sahrens 	(void) printf("\n");
1957fa9e4066Sahrens 
1958fa9e4066Sahrens 	if (!cb->cb_verbose)
1959fa9e4066Sahrens 		return;
1960fa9e4066Sahrens 
1961fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1962fa9e4066Sahrens 	    &newchild, &children) != 0)
1963fa9e4066Sahrens 		return;
1964fa9e4066Sahrens 
1965fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1966fa9e4066Sahrens 	    &oldchild, &c) != 0)
1967fa9e4066Sahrens 		return;
1968fa9e4066Sahrens 
1969afefbcddSeschrock 	for (c = 0; c < children; c++) {
1970*88ecc943SGeorge Wilson 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
1971c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1972afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1973afefbcddSeschrock 		free(vname);
1974afefbcddSeschrock 	}
1975fa94a07fSbrendan 
1976fa94a07fSbrendan 	/*
1977fa94a07fSbrendan 	 * Include level 2 ARC devices in iostat output
1978fa94a07fSbrendan 	 */
1979fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
1980fa94a07fSbrendan 	    &newchild, &children) != 0)
1981fa94a07fSbrendan 		return;
1982fa94a07fSbrendan 
1983fa94a07fSbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
1984fa94a07fSbrendan 	    &oldchild, &c) != 0)
1985fa94a07fSbrendan 		return;
1986fa94a07fSbrendan 
1987fa94a07fSbrendan 	if (children > 0) {
1988fa94a07fSbrendan 		(void) printf("%-*s      -      -      -      -      -      "
1989fa94a07fSbrendan 		    "-\n", cb->cb_namewidth, "cache");
1990fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1991*88ecc943SGeorge Wilson 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
1992*88ecc943SGeorge Wilson 			    B_FALSE);
1993fa94a07fSbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1994fa94a07fSbrendan 			    newchild[c], cb, depth + 2);
1995fa94a07fSbrendan 			free(vname);
1996fa94a07fSbrendan 		}
1997fa94a07fSbrendan 	}
1998fa9e4066Sahrens }
1999fa9e4066Sahrens 
2000088e9d47Seschrock static int
2001088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
2002088e9d47Seschrock {
2003088e9d47Seschrock 	iostat_cbdata_t *cb = data;
200494de1d4cSeschrock 	boolean_t missing;
2005088e9d47Seschrock 
2006088e9d47Seschrock 	/*
2007088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
2008088e9d47Seschrock 	 */
200994de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
201094de1d4cSeschrock 		return (-1);
201194de1d4cSeschrock 
201294de1d4cSeschrock 	if (missing)
2013088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
2014088e9d47Seschrock 
2015088e9d47Seschrock 	return (0);
2016088e9d47Seschrock }
2017088e9d47Seschrock 
2018fa9e4066Sahrens /*
2019fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
2020fa9e4066Sahrens  */
2021fa9e4066Sahrens int
2022fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
2023fa9e4066Sahrens {
2024fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
2025fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
2026fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
2027fa9e4066Sahrens 
2028088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
2029fa9e4066Sahrens 
2030088e9d47Seschrock 	if (cb->cb_iteration == 1)
2031fa9e4066Sahrens 		oldconfig = NULL;
2032fa9e4066Sahrens 
2033fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
2034fa9e4066Sahrens 	    &newnvroot) == 0);
2035fa9e4066Sahrens 
2036088e9d47Seschrock 	if (oldconfig == NULL)
2037fa9e4066Sahrens 		oldnvroot = NULL;
2038088e9d47Seschrock 	else
2039088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
2040088e9d47Seschrock 		    &oldnvroot) == 0);
2041fa9e4066Sahrens 
2042fa9e4066Sahrens 	/*
2043fa9e4066Sahrens 	 * Print out the statistics for the pool.
2044fa9e4066Sahrens 	 */
2045c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
2046fa9e4066Sahrens 
2047fa9e4066Sahrens 	if (cb->cb_verbose)
2048fa9e4066Sahrens 		print_iostat_separator(cb);
2049fa9e4066Sahrens 
2050fa9e4066Sahrens 	return (0);
2051fa9e4066Sahrens }
2052fa9e4066Sahrens 
2053fa9e4066Sahrens int
2054fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
2055fa9e4066Sahrens {
2056fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
2057fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2058fa9e4066Sahrens 
2059088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
2060fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2061fa9e4066Sahrens 		    &nvroot) == 0);
2062fa9e4066Sahrens 		if (!cb->cb_verbose)
2063fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
2064fa9e4066Sahrens 		else
2065c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
2066fa9e4066Sahrens 	}
2067fa9e4066Sahrens 
2068fa9e4066Sahrens 	/*
2069fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
2070fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
2071fa9e4066Sahrens 	 */
2072fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
2073fa9e4066Sahrens 		cb->cb_namewidth = 10;
2074fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
2075fa9e4066Sahrens 		cb->cb_namewidth = 38;
2076fa9e4066Sahrens 
2077fa9e4066Sahrens 	return (0);
2078fa9e4066Sahrens }
2079fa9e4066Sahrens 
2080fa9e4066Sahrens /*
208126fd7700SKrishnendu Sadhukhan - Sun Microsystems  * zpool iostat [-T d|u] [-v] [pool] ... [interval [count]]
2082fa9e4066Sahrens  *
208326fd7700SKrishnendu Sadhukhan - Sun Microsystems  *	-T	Display a timestamp in date(1) or Unix format
2084fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
2085fa9e4066Sahrens  *
2086fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
2087fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
2088fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
2089fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
2090fa9e4066Sahrens  * changes are all handled within libzfs.
2091fa9e4066Sahrens  */
2092fa9e4066Sahrens int
2093fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
2094fa9e4066Sahrens {
2095fa9e4066Sahrens 	int c;
2096fa9e4066Sahrens 	int ret;
2097fa9e4066Sahrens 	int npools;
2098fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
2099fa9e4066Sahrens 	zpool_list_t *list;
210099653d4eSeschrock 	boolean_t verbose = B_FALSE;
2101fa9e4066Sahrens 	iostat_cbdata_t cb;
2102fa9e4066Sahrens 
2103fa9e4066Sahrens 	/* check options */
210426fd7700SKrishnendu Sadhukhan - Sun Microsystems 	while ((c = getopt(argc, argv, "T:v")) != -1) {
2105fa9e4066Sahrens 		switch (c) {
210626fd7700SKrishnendu Sadhukhan - Sun Microsystems 		case 'T':
210726fd7700SKrishnendu Sadhukhan - Sun Microsystems 			if (optarg) {
210826fd7700SKrishnendu Sadhukhan - Sun Microsystems 				if (*optarg == 'u')
210926fd7700SKrishnendu Sadhukhan - Sun Microsystems 					timestamp_fmt = UDATE;
211026fd7700SKrishnendu Sadhukhan - Sun Microsystems 				else if (*optarg == 'd')
211126fd7700SKrishnendu Sadhukhan - Sun Microsystems 					timestamp_fmt = DDATE;
211226fd7700SKrishnendu Sadhukhan - Sun Microsystems 				else
211326fd7700SKrishnendu Sadhukhan - Sun Microsystems 					usage(B_FALSE);
211426fd7700SKrishnendu Sadhukhan - Sun Microsystems 			} else {
211526fd7700SKrishnendu Sadhukhan - Sun Microsystems 				usage(B_FALSE);
211626fd7700SKrishnendu Sadhukhan - Sun Microsystems 			}
211726fd7700SKrishnendu Sadhukhan - Sun Microsystems 			break;
2118fa9e4066Sahrens 		case 'v':
211999653d4eSeschrock 			verbose = B_TRUE;
2120fa9e4066Sahrens 			break;
2121fa9e4066Sahrens 		case '?':
2122fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2123fa9e4066Sahrens 			    optopt);
212499653d4eSeschrock 			usage(B_FALSE);
2125fa9e4066Sahrens 		}
2126fa9e4066Sahrens 	}
2127fa9e4066Sahrens 
2128fa9e4066Sahrens 	argc -= optind;
2129fa9e4066Sahrens 	argv += optind;
2130fa9e4066Sahrens 
2131fa9e4066Sahrens 	/*
2132fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
2133fa9e4066Sahrens 	 */
2134fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2135fa9e4066Sahrens 		char *end;
2136fa9e4066Sahrens 
2137fa9e4066Sahrens 		errno = 0;
2138fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
2139fa9e4066Sahrens 
2140fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
2141fa9e4066Sahrens 			if (interval == 0) {
2142fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
2143fa9e4066Sahrens 				    "cannot be zero\n"));
214499653d4eSeschrock 				usage(B_FALSE);
2145fa9e4066Sahrens 			}
2146fa9e4066Sahrens 
2147fa9e4066Sahrens 			/*
2148fa9e4066Sahrens 			 * Ignore the last parameter
2149fa9e4066Sahrens 			 */
2150fa9e4066Sahrens 			argc--;
2151fa9e4066Sahrens 		} else {
2152fa9e4066Sahrens 			/*
2153fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
2154fa9e4066Sahrens 			 * user will get a more informative error message later
2155fa9e4066Sahrens 			 * on.
2156fa9e4066Sahrens 			 */
2157fa9e4066Sahrens 			interval = 0;
2158fa9e4066Sahrens 		}
2159fa9e4066Sahrens 	}
2160fa9e4066Sahrens 
2161fa9e4066Sahrens 	/*
2162fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
2163fa9e4066Sahrens 	 * and an integer.
2164fa9e4066Sahrens 	 */
2165fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2166fa9e4066Sahrens 		char *end;
2167fa9e4066Sahrens 
2168fa9e4066Sahrens 		errno = 0;
2169fa9e4066Sahrens 		count = interval;
2170fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
2171fa9e4066Sahrens 
2172fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
2173fa9e4066Sahrens 			if (interval == 0) {
2174fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
2175fa9e4066Sahrens 				    "cannot be zero\n"));
217699653d4eSeschrock 				usage(B_FALSE);
2177fa9e4066Sahrens 			}
2178fa9e4066Sahrens 
2179fa9e4066Sahrens 			/*
2180fa9e4066Sahrens 			 * Ignore the last parameter
2181fa9e4066Sahrens 			 */
2182fa9e4066Sahrens 			argc--;
2183fa9e4066Sahrens 		} else {
2184fa9e4066Sahrens 			interval = 0;
2185fa9e4066Sahrens 		}
2186fa9e4066Sahrens 	}
2187fa9e4066Sahrens 
2188fa9e4066Sahrens 	/*
2189fa9e4066Sahrens 	 * Construct the list of all interesting pools.
2190fa9e4066Sahrens 	 */
2191fa9e4066Sahrens 	ret = 0;
2192b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
2193fa9e4066Sahrens 		return (1);
2194fa9e4066Sahrens 
219599653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
219699653d4eSeschrock 		pool_list_free(list);
2197fa9e4066Sahrens 		return (1);
219899653d4eSeschrock 	}
2199fa9e4066Sahrens 
2200fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
220199653d4eSeschrock 		pool_list_free(list);
2202fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
2203fa9e4066Sahrens 		return (1);
2204fa9e4066Sahrens 	}
2205fa9e4066Sahrens 
2206fa9e4066Sahrens 	/*
2207fa9e4066Sahrens 	 * Enter the main iostat loop.
2208fa9e4066Sahrens 	 */
2209fa9e4066Sahrens 	cb.cb_list = list;
2210fa9e4066Sahrens 	cb.cb_verbose = verbose;
2211fa9e4066Sahrens 	cb.cb_iteration = 0;
2212fa9e4066Sahrens 	cb.cb_namewidth = 0;
2213fa9e4066Sahrens 
2214fa9e4066Sahrens 	for (;;) {
2215fa9e4066Sahrens 		pool_list_update(list);
2216fa9e4066Sahrens 
2217fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
2218fa9e4066Sahrens 			break;
2219fa9e4066Sahrens 
2220fa9e4066Sahrens 		/*
2221088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
2222088e9d47Seschrock 		 * before calculating the maximum name width, so that any
2223088e9d47Seschrock 		 * configuration changes are properly accounted for.
2224088e9d47Seschrock 		 */
222599653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
2226088e9d47Seschrock 
2227088e9d47Seschrock 		/*
2228fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
2229fa9e4066Sahrens 		 * for the pool / device name column across all pools.
2230fa9e4066Sahrens 		 */
2231fa9e4066Sahrens 		cb.cb_namewidth = 0;
223299653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2233fa9e4066Sahrens 
223426fd7700SKrishnendu Sadhukhan - Sun Microsystems 		if (timestamp_fmt != NODATE)
223526fd7700SKrishnendu Sadhukhan - Sun Microsystems 			print_timestamp(timestamp_fmt);
223626fd7700SKrishnendu Sadhukhan - Sun Microsystems 
2237fa9e4066Sahrens 		/*
2238fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
2239fa9e4066Sahrens 		 */
2240fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
2241fa9e4066Sahrens 			print_iostat_header(&cb);
2242fa9e4066Sahrens 
224399653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2244fa9e4066Sahrens 
2245fa9e4066Sahrens 		/*
2246fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
2247fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
2248fa9e4066Sahrens 		 */
2249fa9e4066Sahrens 		if (npools > 1 && !verbose)
2250fa9e4066Sahrens 			print_iostat_separator(&cb);
2251fa9e4066Sahrens 
2252fa9e4066Sahrens 		if (verbose)
2253fa9e4066Sahrens 			(void) printf("\n");
2254fa9e4066Sahrens 
225539c23413Seschrock 		/*
225639c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
225739c23413Seschrock 		 * indefinitely.
225839c23413Seschrock 		 */
225939c23413Seschrock 		(void) fflush(stdout);
226039c23413Seschrock 
2261fa9e4066Sahrens 		if (interval == 0)
2262fa9e4066Sahrens 			break;
2263fa9e4066Sahrens 
2264fa9e4066Sahrens 		if (count != 0 && --count == 0)
2265fa9e4066Sahrens 			break;
2266fa9e4066Sahrens 
2267fa9e4066Sahrens 		(void) sleep(interval);
2268fa9e4066Sahrens 	}
2269fa9e4066Sahrens 
2270fa9e4066Sahrens 	pool_list_free(list);
2271fa9e4066Sahrens 
2272fa9e4066Sahrens 	return (ret);
2273fa9e4066Sahrens }
2274fa9e4066Sahrens 
2275fa9e4066Sahrens typedef struct list_cbdata {
227699653d4eSeschrock 	boolean_t	cb_scripted;
227799653d4eSeschrock 	boolean_t	cb_first;
2278990b4856Slling 	zprop_list_t	*cb_proplist;
2279fa9e4066Sahrens } list_cbdata_t;
2280fa9e4066Sahrens 
2281fa9e4066Sahrens /*
2282fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
2283fa9e4066Sahrens  */
2284990b4856Slling static void
2285990b4856Slling print_header(zprop_list_t *pl)
2286fa9e4066Sahrens {
2287990b4856Slling 	const char *header;
2288990b4856Slling 	boolean_t first = B_TRUE;
2289990b4856Slling 	boolean_t right_justify;
2290fa9e4066Sahrens 
2291990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2292990b4856Slling 		if (pl->pl_prop == ZPROP_INVAL)
2293990b4856Slling 			continue;
2294990b4856Slling 
2295990b4856Slling 		if (!first)
2296fa9e4066Sahrens 			(void) printf("  ");
2297fa9e4066Sahrens 		else
2298990b4856Slling 			first = B_FALSE;
2299fa9e4066Sahrens 
2300990b4856Slling 		header = zpool_prop_column_name(pl->pl_prop);
2301990b4856Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
2302990b4856Slling 
2303990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
2304990b4856Slling 			(void) printf("%s", header);
2305990b4856Slling 		else if (right_justify)
2306990b4856Slling 			(void) printf("%*s", pl->pl_width, header);
2307990b4856Slling 		else
2308990b4856Slling 			(void) printf("%-*s", pl->pl_width, header);
2309fa9e4066Sahrens 	}
2310fa9e4066Sahrens 
2311fa9e4066Sahrens 	(void) printf("\n");
2312fa9e4066Sahrens }
2313fa9e4066Sahrens 
2314990b4856Slling /*
2315990b4856Slling  * Given a pool and a list of properties, print out all the properties according
2316990b4856Slling  * to the described layout.
2317990b4856Slling  */
2318990b4856Slling static void
2319990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
2320990b4856Slling {
2321990b4856Slling 	boolean_t first = B_TRUE;
2322990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
2323990b4856Slling 	char *propstr;
2324990b4856Slling 	boolean_t right_justify;
2325990b4856Slling 	int width;
2326990b4856Slling 
2327990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2328990b4856Slling 		if (!first) {
2329990b4856Slling 			if (scripted)
2330990b4856Slling 				(void) printf("\t");
2331990b4856Slling 			else
2332990b4856Slling 				(void) printf("  ");
2333990b4856Slling 		} else {
2334990b4856Slling 			first = B_FALSE;
2335990b4856Slling 		}
2336990b4856Slling 
2337990b4856Slling 		right_justify = B_FALSE;
2338990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
2339990b4856Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
2340990b4856Slling 			    sizeof (property), NULL) != 0)
2341990b4856Slling 				propstr = "-";
2342990b4856Slling 			else
2343990b4856Slling 				propstr = property;
2344990b4856Slling 
2345990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2346990b4856Slling 		} else {
2347990b4856Slling 			propstr = "-";
2348990b4856Slling 		}
2349990b4856Slling 
2350990b4856Slling 		width = pl->pl_width;
2351990b4856Slling 
2352990b4856Slling 		/*
2353990b4856Slling 		 * If this is being called in scripted mode, or if this is the
2354990b4856Slling 		 * last column and it is left-justified, don't include a width
2355990b4856Slling 		 * format specifier.
2356990b4856Slling 		 */
2357990b4856Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
2358990b4856Slling 			(void) printf("%s", propstr);
2359990b4856Slling 		else if (right_justify)
2360990b4856Slling 			(void) printf("%*s", width, propstr);
2361990b4856Slling 		else
2362990b4856Slling 			(void) printf("%-*s", width, propstr);
2363990b4856Slling 	}
2364990b4856Slling 
2365990b4856Slling 	(void) printf("\n");
2366990b4856Slling }
2367990b4856Slling 
2368990b4856Slling /*
2369990b4856Slling  * Generic callback function to list a pool.
2370990b4856Slling  */
2371fa9e4066Sahrens int
2372fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2373fa9e4066Sahrens {
2374fa9e4066Sahrens 	list_cbdata_t *cbp = data;
2375fa9e4066Sahrens 
2376fa9e4066Sahrens 	if (cbp->cb_first) {
2377fa9e4066Sahrens 		if (!cbp->cb_scripted)
2378990b4856Slling 			print_header(cbp->cb_proplist);
237999653d4eSeschrock 		cbp->cb_first = B_FALSE;
2380fa9e4066Sahrens 	}
2381fa9e4066Sahrens 
2382990b4856Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2383fa9e4066Sahrens 
2384fa9e4066Sahrens 	return (0);
2385fa9e4066Sahrens }
2386fa9e4066Sahrens 
2387fa9e4066Sahrens /*
2388990b4856Slling  * zpool list [-H] [-o prop[,prop]*] [pool] ...
2389fa9e4066Sahrens  *
2390990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2391990b4856Slling  *		by a single tab.
2392990b4856Slling  *	-o	List of properties to display.  Defaults to
2393990b4856Slling  *		"name,size,used,available,capacity,health,altroot"
2394fa9e4066Sahrens  *
2395fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2396fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2397fa9e4066Sahrens  */
2398fa9e4066Sahrens int
2399fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2400fa9e4066Sahrens {
2401fa9e4066Sahrens 	int c;
2402fa9e4066Sahrens 	int ret;
2403fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2404990b4856Slling 	static char default_props[] =
2405990b4856Slling 	    "name,size,used,available,capacity,health,altroot";
2406990b4856Slling 	char *props = default_props;
2407fa9e4066Sahrens 
2408fa9e4066Sahrens 	/* check options */
2409fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2410fa9e4066Sahrens 		switch (c) {
2411fa9e4066Sahrens 		case 'H':
241299653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2413fa9e4066Sahrens 			break;
2414fa9e4066Sahrens 		case 'o':
2415990b4856Slling 			props = optarg;
2416fa9e4066Sahrens 			break;
2417fa9e4066Sahrens 		case ':':
2418fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2419fa9e4066Sahrens 			    "'%c' option\n"), optopt);
242099653d4eSeschrock 			usage(B_FALSE);
2421fa9e4066Sahrens 			break;
2422fa9e4066Sahrens 		case '?':
2423fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2424fa9e4066Sahrens 			    optopt);
242599653d4eSeschrock 			usage(B_FALSE);
2426fa9e4066Sahrens 		}
2427fa9e4066Sahrens 	}
2428fa9e4066Sahrens 
2429fa9e4066Sahrens 	argc -= optind;
2430fa9e4066Sahrens 	argv += optind;
2431fa9e4066Sahrens 
2432990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
243399653d4eSeschrock 		usage(B_FALSE);
2434fa9e4066Sahrens 
243599653d4eSeschrock 	cb.cb_first = B_TRUE;
2436fa9e4066Sahrens 
2437990b4856Slling 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2438990b4856Slling 	    list_callback, &cb);
2439990b4856Slling 
2440990b4856Slling 	zprop_free_list(cb.cb_proplist);
2441fa9e4066Sahrens 
2442fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2443fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2444fa9e4066Sahrens 		return (0);
2445fa9e4066Sahrens 	}
2446fa9e4066Sahrens 
2447fa9e4066Sahrens 	return (ret);
2448fa9e4066Sahrens }
2449fa9e4066Sahrens 
2450fa9e4066Sahrens static nvlist_t *
2451fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2452fa9e4066Sahrens {
2453fa9e4066Sahrens 	nvlist_t **child;
2454fa9e4066Sahrens 	uint_t c, children;
2455fa9e4066Sahrens 	nvlist_t *match;
2456fa9e4066Sahrens 	char *path;
2457fa9e4066Sahrens 
2458fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2459fa9e4066Sahrens 	    &child, &children) != 0) {
2460fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2461fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2462fa9e4066Sahrens 			name += 9;
2463fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2464fa9e4066Sahrens 			path += 9;
2465fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2466fa9e4066Sahrens 			return (nv);
2467fa9e4066Sahrens 		return (NULL);
2468fa9e4066Sahrens 	}
2469fa9e4066Sahrens 
2470fa9e4066Sahrens 	for (c = 0; c < children; c++)
2471fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2472fa9e4066Sahrens 			return (match);
2473fa9e4066Sahrens 
2474fa9e4066Sahrens 	return (NULL);
2475fa9e4066Sahrens }
2476fa9e4066Sahrens 
2477fa9e4066Sahrens static int
2478fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2479fa9e4066Sahrens {
248099653d4eSeschrock 	boolean_t force = B_FALSE;
2481fa9e4066Sahrens 	int c;
2482fa9e4066Sahrens 	nvlist_t *nvroot;
2483fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2484fa9e4066Sahrens 	zpool_handle_t *zhp;
248599653d4eSeschrock 	int ret;
2486fa9e4066Sahrens 
2487fa9e4066Sahrens 	/* check options */
2488fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2489fa9e4066Sahrens 		switch (c) {
2490fa9e4066Sahrens 		case 'f':
249199653d4eSeschrock 			force = B_TRUE;
2492fa9e4066Sahrens 			break;
2493fa9e4066Sahrens 		case '?':
2494fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2495fa9e4066Sahrens 			    optopt);
249699653d4eSeschrock 			usage(B_FALSE);
2497fa9e4066Sahrens 		}
2498fa9e4066Sahrens 	}
2499fa9e4066Sahrens 
2500fa9e4066Sahrens 	argc -= optind;
2501fa9e4066Sahrens 	argv += optind;
2502fa9e4066Sahrens 
2503fa9e4066Sahrens 	/* get pool name and check number of arguments */
2504fa9e4066Sahrens 	if (argc < 1) {
2505fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
250699653d4eSeschrock 		usage(B_FALSE);
2507fa9e4066Sahrens 	}
2508fa9e4066Sahrens 
2509fa9e4066Sahrens 	poolname = argv[0];
2510fa9e4066Sahrens 
2511fa9e4066Sahrens 	if (argc < 2) {
2512fa9e4066Sahrens 		(void) fprintf(stderr,
2513fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
251499653d4eSeschrock 		usage(B_FALSE);
2515fa9e4066Sahrens 	}
2516fa9e4066Sahrens 
2517fa9e4066Sahrens 	old_disk = argv[1];
2518fa9e4066Sahrens 
2519fa9e4066Sahrens 	if (argc < 3) {
2520fa9e4066Sahrens 		if (!replacing) {
2521fa9e4066Sahrens 			(void) fprintf(stderr,
2522fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
252399653d4eSeschrock 			usage(B_FALSE);
2524fa9e4066Sahrens 		}
2525fa9e4066Sahrens 		new_disk = old_disk;
2526fa9e4066Sahrens 		argc -= 1;
2527fa9e4066Sahrens 		argv += 1;
2528fa9e4066Sahrens 	} else {
2529fa9e4066Sahrens 		new_disk = argv[2];
2530fa9e4066Sahrens 		argc -= 2;
2531fa9e4066Sahrens 		argv += 2;
2532fa9e4066Sahrens 	}
2533fa9e4066Sahrens 
2534fa9e4066Sahrens 	if (argc > 1) {
2535fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
253699653d4eSeschrock 		usage(B_FALSE);
2537fa9e4066Sahrens 	}
2538fa9e4066Sahrens 
253999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2540fa9e4066Sahrens 		return (1);
2541fa9e4066Sahrens 
25428488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2543fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2544fa9e4066Sahrens 		    poolname);
2545fa9e4066Sahrens 		zpool_close(zhp);
2546fa9e4066Sahrens 		return (1);
2547fa9e4066Sahrens 	}
2548fa9e4066Sahrens 
2549705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
2550705040edSEric Taylor 	    argc, argv);
2551fa9e4066Sahrens 	if (nvroot == NULL) {
2552fa9e4066Sahrens 		zpool_close(zhp);
2553fa9e4066Sahrens 		return (1);
2554fa9e4066Sahrens 	}
2555fa9e4066Sahrens 
255699653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
255799653d4eSeschrock 
255899653d4eSeschrock 	nvlist_free(nvroot);
255999653d4eSeschrock 	zpool_close(zhp);
256099653d4eSeschrock 
256199653d4eSeschrock 	return (ret);
2562fa9e4066Sahrens }
2563fa9e4066Sahrens 
2564fa9e4066Sahrens /*
2565fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2566fa9e4066Sahrens  *
2567fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2568fa9e4066Sahrens  *
2569fa9e4066Sahrens  * Replace <device> with <new_device>.
2570fa9e4066Sahrens  */
2571fa9e4066Sahrens /* ARGSUSED */
2572fa9e4066Sahrens int
2573fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2574fa9e4066Sahrens {
2575fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2576fa9e4066Sahrens }
2577fa9e4066Sahrens 
2578fa9e4066Sahrens /*
2579fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2580fa9e4066Sahrens  *
2581fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2582fa9e4066Sahrens  *
2583fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2584fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2585fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2586fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2587fa9e4066Sahrens  */
2588fa9e4066Sahrens int
2589fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2590fa9e4066Sahrens {
2591fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2592fa9e4066Sahrens }
2593fa9e4066Sahrens 
2594fa9e4066Sahrens /*
2595fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2596fa9e4066Sahrens  *
2597fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2598fa9e4066Sahrens  *		(not supported yet)
2599fa9e4066Sahrens  *
2600fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2601fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2602fa9e4066Sahrens  * has the only valid copy of some data.
2603fa9e4066Sahrens  */
2604fa9e4066Sahrens /* ARGSUSED */
2605fa9e4066Sahrens int
2606fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2607fa9e4066Sahrens {
2608fa9e4066Sahrens 	int c;
2609fa9e4066Sahrens 	char *poolname, *path;
2610fa9e4066Sahrens 	zpool_handle_t *zhp;
261199653d4eSeschrock 	int ret;
2612fa9e4066Sahrens 
2613fa9e4066Sahrens 	/* check options */
2614fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2615fa9e4066Sahrens 		switch (c) {
2616fa9e4066Sahrens 		case 'f':
2617fa9e4066Sahrens 		case '?':
2618fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2619fa9e4066Sahrens 			    optopt);
262099653d4eSeschrock 			usage(B_FALSE);
2621fa9e4066Sahrens 		}
2622fa9e4066Sahrens 	}
2623fa9e4066Sahrens 
2624fa9e4066Sahrens 	argc -= optind;
2625fa9e4066Sahrens 	argv += optind;
2626fa9e4066Sahrens 
2627fa9e4066Sahrens 	/* get pool name and check number of arguments */
2628fa9e4066Sahrens 	if (argc < 1) {
2629fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
263099653d4eSeschrock 		usage(B_FALSE);
2631fa9e4066Sahrens 	}
2632fa9e4066Sahrens 
2633fa9e4066Sahrens 	if (argc < 2) {
2634fa9e4066Sahrens 		(void) fprintf(stderr,
2635fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
263699653d4eSeschrock 		usage(B_FALSE);
2637fa9e4066Sahrens 	}
2638fa9e4066Sahrens 
2639fa9e4066Sahrens 	poolname = argv[0];
2640fa9e4066Sahrens 	path = argv[1];
2641fa9e4066Sahrens 
264299653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2643fa9e4066Sahrens 		return (1);
2644fa9e4066Sahrens 
264599653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
264699653d4eSeschrock 
264799653d4eSeschrock 	zpool_close(zhp);
264899653d4eSeschrock 
264999653d4eSeschrock 	return (ret);
2650fa9e4066Sahrens }
2651fa9e4066Sahrens 
2652fa9e4066Sahrens /*
2653441d80aaSlling  * zpool online <pool> <device> ...
2654fa9e4066Sahrens  */
2655fa9e4066Sahrens int
2656fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2657fa9e4066Sahrens {
2658fa9e4066Sahrens 	int c, i;
2659fa9e4066Sahrens 	char *poolname;
2660fa9e4066Sahrens 	zpool_handle_t *zhp;
2661fa9e4066Sahrens 	int ret = 0;
26623d7072f8Seschrock 	vdev_state_t newstate;
2663573ca77eSGeorge Wilson 	int flags = 0;
2664fa9e4066Sahrens 
2665fa9e4066Sahrens 	/* check options */
2666573ca77eSGeorge Wilson 	while ((c = getopt(argc, argv, "et")) != -1) {
2667fa9e4066Sahrens 		switch (c) {
2668573ca77eSGeorge Wilson 		case 'e':
2669573ca77eSGeorge Wilson 			flags |= ZFS_ONLINE_EXPAND;
2670573ca77eSGeorge Wilson 			break;
2671fa9e4066Sahrens 		case 't':
2672fa9e4066Sahrens 		case '?':
2673fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2674fa9e4066Sahrens 			    optopt);
267599653d4eSeschrock 			usage(B_FALSE);
2676fa9e4066Sahrens 		}
2677fa9e4066Sahrens 	}
2678fa9e4066Sahrens 
2679fa9e4066Sahrens 	argc -= optind;
2680fa9e4066Sahrens 	argv += optind;
2681fa9e4066Sahrens 
2682fa9e4066Sahrens 	/* get pool name and check number of arguments */
2683fa9e4066Sahrens 	if (argc < 1) {
2684fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
268599653d4eSeschrock 		usage(B_FALSE);
2686fa9e4066Sahrens 	}
2687fa9e4066Sahrens 	if (argc < 2) {
2688fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
268999653d4eSeschrock 		usage(B_FALSE);
2690fa9e4066Sahrens 	}
2691fa9e4066Sahrens 
2692fa9e4066Sahrens 	poolname = argv[0];
2693fa9e4066Sahrens 
269499653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2695fa9e4066Sahrens 		return (1);
2696fa9e4066Sahrens 
26973d7072f8Seschrock 	for (i = 1; i < argc; i++) {
2698573ca77eSGeorge Wilson 		if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
26993d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
27003d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
27013d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
2702fa9e4066Sahrens 				    argv[i]);
27033d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
27043d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
27053d7072f8Seschrock 					    "clear' to restore a faulted "
27063d7072f8Seschrock 					    "device\n"));
2707fa9e4066Sahrens 				else
27083d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
27093d7072f8Seschrock 					    "replace' to replace devices "
27103d7072f8Seschrock 					    "that are no longer present\n"));
27113d7072f8Seschrock 			}
27123d7072f8Seschrock 		} else {
2713fa9e4066Sahrens 			ret = 1;
27143d7072f8Seschrock 		}
27153d7072f8Seschrock 	}
2716fa9e4066Sahrens 
271799653d4eSeschrock 	zpool_close(zhp);
271899653d4eSeschrock 
2719fa9e4066Sahrens 	return (ret);
2720fa9e4066Sahrens }
2721fa9e4066Sahrens 
2722fa9e4066Sahrens /*
2723441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2724fa9e4066Sahrens  *
2725fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2726fa9e4066Sahrens  *		so would appear to compromise pool availability.
2727fa9e4066Sahrens  *		(not supported yet)
2728fa9e4066Sahrens  *
2729fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2730fa9e4066Sahrens  *		state will not be persistent across reboots.
2731fa9e4066Sahrens  */
2732fa9e4066Sahrens /* ARGSUSED */
2733fa9e4066Sahrens int
2734fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2735fa9e4066Sahrens {
2736fa9e4066Sahrens 	int c, i;
2737fa9e4066Sahrens 	char *poolname;
2738fa9e4066Sahrens 	zpool_handle_t *zhp;
273999653d4eSeschrock 	int ret = 0;
274099653d4eSeschrock 	boolean_t istmp = B_FALSE;
2741fa9e4066Sahrens 
2742fa9e4066Sahrens 	/* check options */
2743fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2744fa9e4066Sahrens 		switch (c) {
2745fa9e4066Sahrens 		case 't':
274699653d4eSeschrock 			istmp = B_TRUE;
2747441d80aaSlling 			break;
2748441d80aaSlling 		case 'f':
2749fa9e4066Sahrens 		case '?':
2750fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2751fa9e4066Sahrens 			    optopt);
275299653d4eSeschrock 			usage(B_FALSE);
2753fa9e4066Sahrens 		}
2754fa9e4066Sahrens 	}
2755fa9e4066Sahrens 
2756fa9e4066Sahrens 	argc -= optind;
2757fa9e4066Sahrens 	argv += optind;
2758fa9e4066Sahrens 
2759fa9e4066Sahrens 	/* get pool name and check number of arguments */
2760fa9e4066Sahrens 	if (argc < 1) {
2761fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
276299653d4eSeschrock 		usage(B_FALSE);
2763fa9e4066Sahrens 	}
2764fa9e4066Sahrens 	if (argc < 2) {
2765fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
276699653d4eSeschrock 		usage(B_FALSE);
2767fa9e4066Sahrens 	}
2768fa9e4066Sahrens 
2769fa9e4066Sahrens 	poolname = argv[0];
2770fa9e4066Sahrens 
277199653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2772fa9e4066Sahrens 		return (1);
2773fa9e4066Sahrens 
27743d7072f8Seschrock 	for (i = 1; i < argc; i++) {
27753d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2776fa9e4066Sahrens 			ret = 1;
27773d7072f8Seschrock 	}
2778fa9e4066Sahrens 
277999653d4eSeschrock 	zpool_close(zhp);
278099653d4eSeschrock 
2781fa9e4066Sahrens 	return (ret);
2782fa9e4066Sahrens }
2783fa9e4066Sahrens 
2784ea8dc4b6Seschrock /*
2785ea8dc4b6Seschrock  * zpool clear <pool> [device]
2786ea8dc4b6Seschrock  *
2787ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2788ea8dc4b6Seschrock  */
2789ea8dc4b6Seschrock int
2790ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2791ea8dc4b6Seschrock {
2792ea8dc4b6Seschrock 	int ret = 0;
2793ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2794ea8dc4b6Seschrock 	char *pool, *device;
2795ea8dc4b6Seschrock 
2796ea8dc4b6Seschrock 	if (argc < 2) {
2797ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
279899653d4eSeschrock 		usage(B_FALSE);
2799ea8dc4b6Seschrock 	}
2800ea8dc4b6Seschrock 
2801ea8dc4b6Seschrock 	if (argc > 3) {
2802ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
280399653d4eSeschrock 		usage(B_FALSE);
2804ea8dc4b6Seschrock 	}
2805ea8dc4b6Seschrock 
2806ea8dc4b6Seschrock 	pool = argv[1];
2807ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2808ea8dc4b6Seschrock 
2809b87f3af3Sperrin 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
2810ea8dc4b6Seschrock 		return (1);
2811ea8dc4b6Seschrock 
2812ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2813ea8dc4b6Seschrock 		ret = 1;
2814ea8dc4b6Seschrock 
2815ea8dc4b6Seschrock 	zpool_close(zhp);
2816ea8dc4b6Seschrock 
2817ea8dc4b6Seschrock 	return (ret);
2818ea8dc4b6Seschrock }
2819ea8dc4b6Seschrock 
2820fa9e4066Sahrens typedef struct scrub_cbdata {
2821fa9e4066Sahrens 	int	cb_type;
282206eeb2adSek110237 	int	cb_argc;
282306eeb2adSek110237 	char	**cb_argv;
2824fa9e4066Sahrens } scrub_cbdata_t;
2825fa9e4066Sahrens 
2826fa9e4066Sahrens int
2827fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2828fa9e4066Sahrens {
2829fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
283006eeb2adSek110237 	int err;
2831fa9e4066Sahrens 
2832ea8dc4b6Seschrock 	/*
2833ea8dc4b6Seschrock 	 * Ignore faulted pools.
2834ea8dc4b6Seschrock 	 */
2835ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2836ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2837ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2838ea8dc4b6Seschrock 		return (1);
2839ea8dc4b6Seschrock 	}
2840ea8dc4b6Seschrock 
284106eeb2adSek110237 	err = zpool_scrub(zhp, cb->cb_type);
284206eeb2adSek110237 
284306eeb2adSek110237 	return (err != 0);
2844fa9e4066Sahrens }
2845fa9e4066Sahrens 
2846fa9e4066Sahrens /*
2847fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2848fa9e4066Sahrens  *
2849fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2850fa9e4066Sahrens  */
2851fa9e4066Sahrens int
2852fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2853fa9e4066Sahrens {
2854fa9e4066Sahrens 	int c;
2855fa9e4066Sahrens 	scrub_cbdata_t cb;
2856fa9e4066Sahrens 
2857fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2858fa9e4066Sahrens 
2859fa9e4066Sahrens 	/* check options */
2860fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2861fa9e4066Sahrens 		switch (c) {
2862fa9e4066Sahrens 		case 's':
2863fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2864fa9e4066Sahrens 			break;
2865fa9e4066Sahrens 		case '?':
2866fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2867fa9e4066Sahrens 			    optopt);
286899653d4eSeschrock 			usage(B_FALSE);
2869fa9e4066Sahrens 		}
2870fa9e4066Sahrens 	}
2871fa9e4066Sahrens 
287206eeb2adSek110237 	cb.cb_argc = argc;
287306eeb2adSek110237 	cb.cb_argv = argv;
2874fa9e4066Sahrens 	argc -= optind;
2875fa9e4066Sahrens 	argv += optind;
2876fa9e4066Sahrens 
2877fa9e4066Sahrens 	if (argc < 1) {
2878fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
287999653d4eSeschrock 		usage(B_FALSE);
2880fa9e4066Sahrens 	}
2881fa9e4066Sahrens 
2882b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2883fa9e4066Sahrens }
2884fa9e4066Sahrens 
2885fa9e4066Sahrens typedef struct status_cbdata {
2886fa9e4066Sahrens 	int		cb_count;
2887e9dbad6fSeschrock 	boolean_t	cb_allpools;
288899653d4eSeschrock 	boolean_t	cb_verbose;
288999653d4eSeschrock 	boolean_t	cb_explain;
289099653d4eSeschrock 	boolean_t	cb_first;
2891fa9e4066Sahrens } status_cbdata_t;
2892fa9e4066Sahrens 
2893fa9e4066Sahrens /*
2894fa9e4066Sahrens  * Print out detailed scrub status.
2895fa9e4066Sahrens  */
2896fa9e4066Sahrens void
2897fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2898fa9e4066Sahrens {
2899fa9e4066Sahrens 	vdev_stat_t *vs;
2900fa9e4066Sahrens 	uint_t vsc;
2901fa9e4066Sahrens 	time_t start, end, now;
2902fa9e4066Sahrens 	double fraction_done;
290318ce54dfSek110237 	uint64_t examined, total, minutes_left, minutes_taken;
2904fa9e4066Sahrens 	char *scrub_type;
2905fa9e4066Sahrens 
2906fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2907fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2908fa9e4066Sahrens 
2909fa9e4066Sahrens 	/*
2910fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2911fa9e4066Sahrens 	 */
2912fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2913fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2914fa9e4066Sahrens 		return;
2915fa9e4066Sahrens 	}
2916fa9e4066Sahrens 
2917fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2918fa9e4066Sahrens 	    "resilver" : "scrub";
2919fa9e4066Sahrens 
2920fa9e4066Sahrens 	start = vs->vs_scrub_start;
2921fa9e4066Sahrens 	end = vs->vs_scrub_end;
2922fa9e4066Sahrens 	now = time(NULL);
2923fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2924fa9e4066Sahrens 	total = vs->vs_alloc;
2925fa9e4066Sahrens 
2926fa9e4066Sahrens 	if (end != 0) {
292718ce54dfSek110237 		minutes_taken = (uint64_t)((end - start) / 60);
292818ce54dfSek110237 
292918ce54dfSek110237 		(void) printf(gettext("%s %s after %lluh%um with %llu errors "
293018ce54dfSek110237 		    "on %s"),
2931fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
293218ce54dfSek110237 		    (u_longlong_t)(minutes_taken / 60),
293318ce54dfSek110237 		    (uint_t)(minutes_taken % 60),
2934fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2935fa9e4066Sahrens 		return;
2936fa9e4066Sahrens 	}
2937fa9e4066Sahrens 
2938fa9e4066Sahrens 	if (examined == 0)
2939fa9e4066Sahrens 		examined = 1;
2940fa9e4066Sahrens 	if (examined > total)
2941fa9e4066Sahrens 		total = examined;
2942fa9e4066Sahrens 
2943fa9e4066Sahrens 	fraction_done = (double)examined / total;
2944fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2945fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
294618ce54dfSek110237 	minutes_taken = (uint64_t)((now - start) / 60);
2947fa9e4066Sahrens 
294818ce54dfSek110237 	(void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, "
294918ce54dfSek110237 	    "%lluh%um to go\n"),
295018ce54dfSek110237 	    scrub_type, (u_longlong_t)(minutes_taken / 60),
295118ce54dfSek110237 	    (uint_t)(minutes_taken % 60), 100 * fraction_done,
2952fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2953fa9e4066Sahrens }
2954fa9e4066Sahrens 
2955ea8dc4b6Seschrock static void
2956ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
2957ea8dc4b6Seschrock {
295875519f38Sek110237 	nvlist_t *nverrlist = NULL;
295955434c77Sek110237 	nvpair_t *elem;
296055434c77Sek110237 	char *pathname;
296155434c77Sek110237 	size_t len = MAXPATHLEN * 2;
2962ea8dc4b6Seschrock 
296355434c77Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2964ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
2965ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
2966ea8dc4b6Seschrock 		return;
2967ea8dc4b6Seschrock 	}
2968ea8dc4b6Seschrock 
296955434c77Sek110237 	(void) printf("errors: Permanent errors have been "
297055434c77Sek110237 	    "detected in the following files:\n\n");
2971ea8dc4b6Seschrock 
297255434c77Sek110237 	pathname = safe_malloc(len);
297355434c77Sek110237 	elem = NULL;
297455434c77Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
297555434c77Sek110237 		nvlist_t *nv;
297655434c77Sek110237 		uint64_t dsobj, obj;
2977ea8dc4b6Seschrock 
297855434c77Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
297955434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
298055434c77Sek110237 		    &dsobj) == 0);
298155434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
298255434c77Sek110237 		    &obj) == 0);
298355434c77Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
298455434c77Sek110237 		(void) printf("%7s %s\n", "", pathname);
2985ea8dc4b6Seschrock 	}
298655434c77Sek110237 	free(pathname);
298755434c77Sek110237 	nvlist_free(nverrlist);
2988ea8dc4b6Seschrock }
2989ea8dc4b6Seschrock 
299099653d4eSeschrock static void
299199653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
299299653d4eSeschrock     int namewidth)
299399653d4eSeschrock {
299499653d4eSeschrock 	uint_t i;
299599653d4eSeschrock 	char *name;
299699653d4eSeschrock 
299799653d4eSeschrock 	if (nspares == 0)
299899653d4eSeschrock 		return;
299999653d4eSeschrock 
300099653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
300199653d4eSeschrock 
300299653d4eSeschrock 	for (i = 0; i < nspares; i++) {
3003*88ecc943SGeorge Wilson 		name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE);
300499653d4eSeschrock 		print_status_config(zhp, name, spares[i],
3005aa8cf21aSNeil Perrin 		    namewidth, 2, B_TRUE);
300699653d4eSeschrock 		free(name);
300799653d4eSeschrock 	}
300899653d4eSeschrock }
300999653d4eSeschrock 
3010fa94a07fSbrendan static void
3011fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
3012fa94a07fSbrendan     int namewidth)
3013fa94a07fSbrendan {
3014fa94a07fSbrendan 	uint_t i;
3015fa94a07fSbrendan 	char *name;
3016fa94a07fSbrendan 
3017fa94a07fSbrendan 	if (nl2cache == 0)
3018fa94a07fSbrendan 		return;
3019fa94a07fSbrendan 
3020fa94a07fSbrendan 	(void) printf(gettext("\tcache\n"));
3021fa94a07fSbrendan 
3022fa94a07fSbrendan 	for (i = 0; i < nl2cache; i++) {
3023*88ecc943SGeorge Wilson 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE);
3024fa94a07fSbrendan 		print_status_config(zhp, name, l2cache[i],
3025aa8cf21aSNeil Perrin 		    namewidth, 2, B_FALSE);
3026aa8cf21aSNeil Perrin 		free(name);
3027aa8cf21aSNeil Perrin 	}
3028aa8cf21aSNeil Perrin }
3029aa8cf21aSNeil Perrin 
3030aa8cf21aSNeil Perrin /*
3031fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
3032fa9e4066Sahrens  *
3033fa9e4066Sahrens  *        pool: tank
3034fa9e4066Sahrens  *	status: DEGRADED
3035fa9e4066Sahrens  *	reason: One or more devices ...
3036fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
3037fa9e4066Sahrens  *	config:
3038fa9e4066Sahrens  *		mirror		DEGRADED
3039fa9e4066Sahrens  *                c1t0d0	OK
3040ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
3041fa9e4066Sahrens  *
3042fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
3043fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
3044fa9e4066Sahrens  */
3045fa9e4066Sahrens int
3046fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
3047fa9e4066Sahrens {
3048fa9e4066Sahrens 	status_cbdata_t *cbp = data;
3049fa9e4066Sahrens 	nvlist_t *config, *nvroot;
3050fa9e4066Sahrens 	char *msgid;
3051fa9e4066Sahrens 	int reason;
305246657f8dSmmusante 	const char *health;
305346657f8dSmmusante 	uint_t c;
305446657f8dSmmusante 	vdev_stat_t *vs;
3055fa9e4066Sahrens 
3056088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
3057fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
3058fa9e4066Sahrens 
3059fa9e4066Sahrens 	cbp->cb_count++;
3060fa9e4066Sahrens 
3061fa9e4066Sahrens 	/*
3062fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
3063fa9e4066Sahrens 	 * problems.
3064fa9e4066Sahrens 	 */
3065e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
3066e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
3067e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
3068e9dbad6fSeschrock 			    zpool_get_name(zhp));
3069e9dbad6fSeschrock 			if (cbp->cb_first)
3070e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
3071e9dbad6fSeschrock 		}
3072fa9e4066Sahrens 		return (0);
3073e9dbad6fSeschrock 	}
3074fa9e4066Sahrens 
3075fa9e4066Sahrens 	if (cbp->cb_first)
307699653d4eSeschrock 		cbp->cb_first = B_FALSE;
3077fa9e4066Sahrens 	else
3078fa9e4066Sahrens 		(void) printf("\n");
3079fa9e4066Sahrens 
308046657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
308146657f8dSmmusante 	    &nvroot) == 0);
308246657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
308346657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
3084990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3085fa9e4066Sahrens 
3086fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
3087fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
3088fa9e4066Sahrens 
3089fa9e4066Sahrens 	switch (reason) {
3090fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
3091fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3092fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
3093fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
3094fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3095fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3096fa9e4066Sahrens 		break;
3097fa9e4066Sahrens 
3098fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
3099fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3100fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
3101fa9e4066Sahrens 		    "pool to continue functioning.\n"));
3102fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3103fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3104fa9e4066Sahrens 		break;
3105fa9e4066Sahrens 
3106fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
3107fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3108fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
3109fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
3110fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
3111fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
3112fa9e4066Sahrens 		    "'zpool replace'.\n"));
3113fa9e4066Sahrens 		break;
3114fa9e4066Sahrens 
3115fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3116fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3117b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
3118fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
3119fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
3120fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
3121fa9e4066Sahrens 		    "from a backup source.\n"));
3122fa9e4066Sahrens 		break;
3123fa9e4066Sahrens 
3124fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
3125fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3126fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
3127fa9e4066Sahrens 		    "made to correct the error.  Applications are "
3128fa9e4066Sahrens 		    "unaffected.\n"));
3129fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
3130fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
3131ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
3132fa9e4066Sahrens 		    "replace'.\n"));
3133fa9e4066Sahrens 		break;
3134fa9e4066Sahrens 
3135fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
3136fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3137d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
3138fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
3139fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
3140fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
3141fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
3142fa9e4066Sahrens 		    "replace'.\n"));
3143fa9e4066Sahrens 		break;
3144fa9e4066Sahrens 
3145c25309d4SGeorge Wilson 	case ZPOOL_STATUS_REMOVED_DEV:
3146c25309d4SGeorge Wilson 		(void) printf(gettext("status: One or more devices has "
3147c25309d4SGeorge Wilson 		    "been removed by the administrator.\n\tSufficient "
3148c25309d4SGeorge Wilson 		    "replicas exist for the pool to continue functioning in "
3149c25309d4SGeorge Wilson 		    "a\n\tdegraded state.\n"));
3150c25309d4SGeorge Wilson 		(void) printf(gettext("action: Online the device using "
3151c25309d4SGeorge Wilson 		    "'zpool online' or replace the device with\n\t'zpool "
3152c25309d4SGeorge Wilson 		    "replace'.\n"));
3153c25309d4SGeorge Wilson 		break;
3154c25309d4SGeorge Wilson 
3155c25309d4SGeorge Wilson 
3156fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
3157fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
3158fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3159fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
3160fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3161fa9e4066Sahrens 		    "complete.\n"));
3162fa9e4066Sahrens 		break;
3163fa9e4066Sahrens 
3164ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3165ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3166ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3167ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3168ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3169ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3170ea8dc4b6Seschrock 		    "backup.\n"));
3171ea8dc4b6Seschrock 		break;
3172ea8dc4b6Seschrock 
3173ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3174ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3175ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3176ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
3177ea8dc4b6Seschrock 		    "from a backup source.\n"));
3178ea8dc4b6Seschrock 		break;
3179ea8dc4b6Seschrock 
3180eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3181eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3182eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3183eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3184eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3185eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3186eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3187eaca9bbdSeschrock 		break;
3188eaca9bbdSeschrock 
3189eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3190eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3191eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3192eaca9bbdSeschrock 		    "be accessed on this system.\n"));
3193eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
3194eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
3195eaca9bbdSeschrock 		    "backup.\n"));
3196eaca9bbdSeschrock 		break;
3197eaca9bbdSeschrock 
31983d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
31993d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
32003d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
32013d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
32023d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
32033d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
32043d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
32053d7072f8Seschrock 		break;
32063d7072f8Seschrock 
32073d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
32083d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
32093d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
32103d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
32113d7072f8Seschrock 		    "functioning.\n"));
32123d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
32133d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
32143d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
32153d7072f8Seschrock 		    "to be recovered.\n"));
32163d7072f8Seschrock 		break;
32173d7072f8Seschrock 
321832b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_WAIT:
321932b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
322032b87932Sek110237 		(void) printf(gettext("status: One or more devices are "
32218a79c1b5Sek110237 		    "faulted in response to IO failures.\n"));
322232b87932Sek110237 		(void) printf(gettext("action: Make sure the affected devices "
322332b87932Sek110237 		    "are connected, then run 'zpool clear'.\n"));
322432b87932Sek110237 		break;
322532b87932Sek110237 
3226b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
3227b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record "
3228b87f3af3Sperrin 		    "could not be read.\n"
3229b87f3af3Sperrin 		    "\tWaiting for adminstrator intervention to fix the "
3230b87f3af3Sperrin 		    "faulted pool.\n"));
3231b87f3af3Sperrin 		(void) printf(gettext("action: Either restore the affected "
3232b87f3af3Sperrin 		    "device(s) and run 'zpool online',\n"
3233b87f3af3Sperrin 		    "\tor ignore the intent log records by running "
3234b87f3af3Sperrin 		    "'zpool clear'.\n"));
3235b87f3af3Sperrin 		break;
3236b87f3af3Sperrin 
3237fa9e4066Sahrens 	default:
3238fa9e4066Sahrens 		/*
3239fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
3240fa9e4066Sahrens 		 */
3241fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
3242fa9e4066Sahrens 	}
3243fa9e4066Sahrens 
3244fa9e4066Sahrens 	if (msgid != NULL)
3245fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3246fa9e4066Sahrens 		    msgid);
3247fa9e4066Sahrens 
3248fa9e4066Sahrens 	if (config != NULL) {
3249fa9e4066Sahrens 		int namewidth;
3250ea8dc4b6Seschrock 		uint64_t nerr;
3251fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
3252fa94a07fSbrendan 		uint_t nspares, nl2cache;
3253fa9e4066Sahrens 
3254fa9e4066Sahrens 
3255fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
3256fa9e4066Sahrens 		print_scrub_status(nvroot);
3257fa9e4066Sahrens 
3258c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3259fa9e4066Sahrens 		if (namewidth < 10)
3260fa9e4066Sahrens 			namewidth = 10;
3261fa9e4066Sahrens 
3262fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
3263fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3264fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3265c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
3266aa8cf21aSNeil Perrin 		    namewidth, 0, B_FALSE);
326799653d4eSeschrock 
32684dea40f0SNeil Perrin 		if (num_logs(nvroot) > 0)
3269e6ca193dSGeorge Wilson 			print_logs(zhp, nvroot, namewidth, B_TRUE);
3270fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
3271fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
3272fa94a07fSbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
3273fa94a07fSbrendan 
327499653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
327599653d4eSeschrock 		    &spares, &nspares) == 0)
327699653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
3277ea8dc4b6Seschrock 
3278ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3279ea8dc4b6Seschrock 		    &nerr) == 0) {
328055434c77Sek110237 			nvlist_t *nverrlist = NULL;
328155434c77Sek110237 
3282ea8dc4b6Seschrock 			/*
3283ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3284ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3285ea8dc4b6Seschrock 			 * uniquifying the results.
3286ea8dc4b6Seschrock 			 */
328775519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
328855434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
328955434c77Sek110237 				nvpair_t *elem;
329055434c77Sek110237 
329155434c77Sek110237 				elem = NULL;
329255434c77Sek110237 				nerr = 0;
329355434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
329455434c77Sek110237 				    elem)) != NULL) {
329555434c77Sek110237 					nerr++;
329655434c77Sek110237 				}
329755434c77Sek110237 			}
329855434c77Sek110237 			nvlist_free(nverrlist);
3299ea8dc4b6Seschrock 
3300ea8dc4b6Seschrock 			(void) printf("\n");
330199653d4eSeschrock 
3302ea8dc4b6Seschrock 			if (nerr == 0)
3303ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3304ea8dc4b6Seschrock 				    "errors\n"));
3305ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3306e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
33075ad82045Snd150628 				    "errors, use '-v' for a list\n"),
33085ad82045Snd150628 				    (u_longlong_t)nerr);
3309ea8dc4b6Seschrock 			else
3310ea8dc4b6Seschrock 				print_error_log(zhp);
3311ea8dc4b6Seschrock 		}
3312fa9e4066Sahrens 	} else {
3313fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3314fa9e4066Sahrens 		    "determined.\n"));
3315fa9e4066Sahrens 	}
3316fa9e4066Sahrens 
3317fa9e4066Sahrens 	return (0);
3318fa9e4066Sahrens }
3319fa9e4066Sahrens 
3320fa9e4066Sahrens /*
3321fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3322fa9e4066Sahrens  *
3323fa9e4066Sahrens  *	-v	Display complete error logs
3324fa9e4066Sahrens  *	-x	Display only pools with potential problems
3325fa9e4066Sahrens  *
3326fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3327fa9e4066Sahrens  */
3328fa9e4066Sahrens int
3329fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3330fa9e4066Sahrens {
3331fa9e4066Sahrens 	int c;
3332fa9e4066Sahrens 	int ret;
3333fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3334fa9e4066Sahrens 
3335fa9e4066Sahrens 	/* check options */
3336fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3337fa9e4066Sahrens 		switch (c) {
3338fa9e4066Sahrens 		case 'v':
333999653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3340fa9e4066Sahrens 			break;
3341fa9e4066Sahrens 		case 'x':
334299653d4eSeschrock 			cb.cb_explain = B_TRUE;
3343fa9e4066Sahrens 			break;
3344fa9e4066Sahrens 		case '?':
3345fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3346fa9e4066Sahrens 			    optopt);
334799653d4eSeschrock 			usage(B_FALSE);
3348fa9e4066Sahrens 		}
3349fa9e4066Sahrens 	}
3350fa9e4066Sahrens 
3351fa9e4066Sahrens 	argc -= optind;
3352fa9e4066Sahrens 	argv += optind;
3353fa9e4066Sahrens 
335499653d4eSeschrock 	cb.cb_first = B_TRUE;
3355fa9e4066Sahrens 
3356e9dbad6fSeschrock 	if (argc == 0)
3357e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3358e9dbad6fSeschrock 
3359b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3360fa9e4066Sahrens 
3361fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3362fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3363e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3364fa9e4066Sahrens 		(void) printf(gettext("all pools are healthy\n"));
3365fa9e4066Sahrens 
3366fa9e4066Sahrens 	return (ret);
3367fa9e4066Sahrens }
3368fa9e4066Sahrens 
3369eaca9bbdSeschrock typedef struct upgrade_cbdata {
3370eaca9bbdSeschrock 	int	cb_all;
3371eaca9bbdSeschrock 	int	cb_first;
3372eaca9bbdSeschrock 	int	cb_newer;
337306eeb2adSek110237 	int	cb_argc;
3374990b4856Slling 	uint64_t cb_version;
337506eeb2adSek110237 	char	**cb_argv;
3376eaca9bbdSeschrock } upgrade_cbdata_t;
3377eaca9bbdSeschrock 
3378eaca9bbdSeschrock static int
3379eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3380eaca9bbdSeschrock {
3381eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3382eaca9bbdSeschrock 	nvlist_t *config;
3383eaca9bbdSeschrock 	uint64_t version;
3384eaca9bbdSeschrock 	int ret = 0;
3385eaca9bbdSeschrock 
3386eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3387eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3388eaca9bbdSeschrock 	    &version) == 0);
3389eaca9bbdSeschrock 
3390e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3391eaca9bbdSeschrock 		if (!cbp->cb_all) {
3392eaca9bbdSeschrock 			if (cbp->cb_first) {
3393eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3394eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3395eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3396eaca9bbdSeschrock 				    "longer be accessible by older software "
3397eaca9bbdSeschrock 				    "versions.\n\n"));
3398eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3399eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
340099653d4eSeschrock 				cbp->cb_first = B_FALSE;
3401eaca9bbdSeschrock 			}
3402eaca9bbdSeschrock 
34035ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3404eaca9bbdSeschrock 			    zpool_get_name(zhp));
3405eaca9bbdSeschrock 		} else {
340699653d4eSeschrock 			cbp->cb_first = B_FALSE;
3407990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
340806eeb2adSek110237 			if (!ret) {
3409eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3410990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
3411eaca9bbdSeschrock 			}
341206eeb2adSek110237 		}
3413e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3414eaca9bbdSeschrock 		assert(!cbp->cb_all);
3415eaca9bbdSeschrock 
3416eaca9bbdSeschrock 		if (cbp->cb_first) {
3417eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3418eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3419eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3420eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3421eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
342299653d4eSeschrock 			cbp->cb_first = B_FALSE;
3423eaca9bbdSeschrock 		}
3424eaca9bbdSeschrock 
34255ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3426eaca9bbdSeschrock 		    zpool_get_name(zhp));
3427eaca9bbdSeschrock 	}
3428eaca9bbdSeschrock 
3429eaca9bbdSeschrock 	zpool_close(zhp);
3430eaca9bbdSeschrock 	return (ret);
3431eaca9bbdSeschrock }
3432eaca9bbdSeschrock 
3433eaca9bbdSeschrock /* ARGSUSED */
3434eaca9bbdSeschrock static int
343506eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
3436eaca9bbdSeschrock {
3437990b4856Slling 	upgrade_cbdata_t *cbp = data;
3438990b4856Slling 	uint64_t cur_version;
3439eaca9bbdSeschrock 	int ret;
3440eaca9bbdSeschrock 
34418654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
34428654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
34438654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
34448654d025Sperrin 		    " to upgrade.\n"));
34458654d025Sperrin 		return (1);
34468654d025Sperrin 	}
3447990b4856Slling 
3448990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3449e6c728e1Sbrendan 	if (cur_version > cbp->cb_version) {
3450eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3451e6c728e1Sbrendan 		    "using more current version '%llu'.\n"),
3452e6c728e1Sbrendan 		    zpool_get_name(zhp), cur_version);
3453e6c728e1Sbrendan 		return (0);
3454e6c728e1Sbrendan 	}
3455e6c728e1Sbrendan 	if (cur_version == cbp->cb_version) {
3456e6c728e1Sbrendan 		(void) printf(gettext("Pool '%s' is already formatted "
3457e6c728e1Sbrendan 		    "using the current version.\n"), zpool_get_name(zhp));
3458eaca9bbdSeschrock 		return (0);
3459eaca9bbdSeschrock 	}
3460eaca9bbdSeschrock 
3461990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
346206eeb2adSek110237 
346306eeb2adSek110237 	if (!ret) {
346444cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
3465990b4856Slling 		    "from version %llu to version %llu\n\n"),
3466990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3467990b4856Slling 		    (u_longlong_t)cbp->cb_version);
346806eeb2adSek110237 	}
3469eaca9bbdSeschrock 
3470eaca9bbdSeschrock 	return (ret != 0);
3471eaca9bbdSeschrock }
3472eaca9bbdSeschrock 
3473eaca9bbdSeschrock /*
3474eaca9bbdSeschrock  * zpool upgrade
3475eaca9bbdSeschrock  * zpool upgrade -v
3476990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
3477eaca9bbdSeschrock  *
3478eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3479eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3480eaca9bbdSeschrock  * upgrade all pools.
3481eaca9bbdSeschrock  */
3482eaca9bbdSeschrock int
3483eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3484eaca9bbdSeschrock {
3485eaca9bbdSeschrock 	int c;
3486eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3487eaca9bbdSeschrock 	int ret = 0;
3488eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3489990b4856Slling 	char *end;
3490990b4856Slling 
3491eaca9bbdSeschrock 
3492eaca9bbdSeschrock 	/* check options */
3493478ed9adSEric Taylor 	while ((c = getopt(argc, argv, ":avV:")) != -1) {
3494eaca9bbdSeschrock 		switch (c) {
3495eaca9bbdSeschrock 		case 'a':
349699653d4eSeschrock 			cb.cb_all = B_TRUE;
3497eaca9bbdSeschrock 			break;
3498eaca9bbdSeschrock 		case 'v':
3499eaca9bbdSeschrock 			showversions = B_TRUE;
3500eaca9bbdSeschrock 			break;
3501990b4856Slling 		case 'V':
3502990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
3503351420b3Slling 			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
3504351420b3Slling 			    cb.cb_version < SPA_VERSION_1) {
3505990b4856Slling 				(void) fprintf(stderr,
3506990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
3507990b4856Slling 				usage(B_FALSE);
3508990b4856Slling 			}
3509990b4856Slling 			break;
3510478ed9adSEric Taylor 		case ':':
3511478ed9adSEric Taylor 			(void) fprintf(stderr, gettext("missing argument for "
3512478ed9adSEric Taylor 			    "'%c' option\n"), optopt);
3513478ed9adSEric Taylor 			usage(B_FALSE);
3514478ed9adSEric Taylor 			break;
3515eaca9bbdSeschrock 		case '?':
3516eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3517eaca9bbdSeschrock 			    optopt);
351899653d4eSeschrock 			usage(B_FALSE);
3519eaca9bbdSeschrock 		}
3520eaca9bbdSeschrock 	}
3521eaca9bbdSeschrock 
352206eeb2adSek110237 	cb.cb_argc = argc;
352306eeb2adSek110237 	cb.cb_argv = argv;
3524eaca9bbdSeschrock 	argc -= optind;
3525eaca9bbdSeschrock 	argv += optind;
3526eaca9bbdSeschrock 
3527351420b3Slling 	if (cb.cb_version == 0) {
3528351420b3Slling 		cb.cb_version = SPA_VERSION;
3529351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
3530351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
3531351420b3Slling 		    "incompatible with other arguments\n"));
3532351420b3Slling 		usage(B_FALSE);
3533351420b3Slling 	}
3534351420b3Slling 
3535eaca9bbdSeschrock 	if (showversions) {
3536eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3537eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3538eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
353999653d4eSeschrock 			usage(B_FALSE);
3540eaca9bbdSeschrock 		}
3541eaca9bbdSeschrock 	} else if (cb.cb_all) {
3542eaca9bbdSeschrock 		if (argc != 0) {
3543351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
3544351420b3Slling 			    "be used along with a pool name\n"));
354599653d4eSeschrock 			usage(B_FALSE);
3546eaca9bbdSeschrock 		}
3547eaca9bbdSeschrock 	}
3548eaca9bbdSeschrock 
3549e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3550e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
355199653d4eSeschrock 	cb.cb_first = B_TRUE;
3552eaca9bbdSeschrock 	if (showversions) {
3553eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3554d7d4af51Smmusante 		    "supported:\n\n"));
3555eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3556eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3557eaca9bbdSeschrock 		    "---------------\n");
355899653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
355944cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
356044cd46caSbillm 		    "(replicated metadata)\n"));
356199653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
356299653d4eSeschrock 		    "RAID-Z\n"));
3563d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
3564c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3565c9431fa1Sahl 		    "algorithm\n"));
3566990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
35678654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3568ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
3569a9799022Sck153898 		(void) printf(gettext(" 9   refquota and refreservation "
3570a9799022Sck153898 		    "properties\n"));
3571fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
3572088f3894Sahrens 		(void) printf(gettext(" 11  Improved scrub performance\n"));
3573bb0ade09Sahrens 		(void) printf(gettext(" 12  Snapshot properties\n"));
357474e7dc98SMatthew Ahrens 		(void) printf(gettext(" 13  snapused property\n"));
357514843421SMatthew Ahrens 		(void) printf(gettext(" 14  passthrough-x aclinherit\n"));
357614843421SMatthew Ahrens 		(void) printf(gettext(" 15  user/group space accounting\n"));
3577478ed9adSEric Taylor 		(void) printf(gettext(" 16  stmf property support\n"));
35787aeab329SAdam Leventhal 		(void) printf(gettext(" 17  Triple-parity RAID-Z\n"));
3579842727c2SChris Kirby 		(void) printf(gettext(" 18  snapshot user holds\n"));
3580*88ecc943SGeorge Wilson 		(void) printf(gettext(" 19  Log device removal\n"));
35818654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3582eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3583eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3584eaca9bbdSeschrock 		    "version/N\n\n");
3585eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3586eaca9bbdSeschrock 	} else if (argc == 0) {
3587eaca9bbdSeschrock 		int notfound;
3588eaca9bbdSeschrock 
358999653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3590eaca9bbdSeschrock 		notfound = cb.cb_first;
3591eaca9bbdSeschrock 
3592eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3593eaca9bbdSeschrock 			if (!cb.cb_first)
3594eaca9bbdSeschrock 				(void) printf("\n");
3595eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3596eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
359799653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3598eaca9bbdSeschrock 			if (!cb.cb_first) {
3599eaca9bbdSeschrock 				notfound = B_FALSE;
3600eaca9bbdSeschrock 				(void) printf("\n");
3601eaca9bbdSeschrock 			}
3602eaca9bbdSeschrock 		}
3603eaca9bbdSeschrock 
3604eaca9bbdSeschrock 		if (ret == 0) {
3605eaca9bbdSeschrock 			if (notfound)
3606eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3607eaca9bbdSeschrock 				    "using this version.\n"));
3608eaca9bbdSeschrock 			else if (!cb.cb_all)
3609eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3610eaca9bbdSeschrock 				    "for a list of available versions and "
3611eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3612eaca9bbdSeschrock 		}
3613eaca9bbdSeschrock 	} else {
3614b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3615b1b8ab34Slling 		    upgrade_one, &cb);
361606eeb2adSek110237 	}
361706eeb2adSek110237 
361806eeb2adSek110237 	return (ret);
361906eeb2adSek110237 }
362006eeb2adSek110237 
3621ecd6cf80Smarks typedef struct hist_cbdata {
3622ecd6cf80Smarks 	boolean_t first;
3623ecd6cf80Smarks 	int longfmt;
3624ecd6cf80Smarks 	int internal;
3625ecd6cf80Smarks } hist_cbdata_t;
3626ecd6cf80Smarks 
3627ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3628ecd6cf80Smarks 	"invalid event",
3629ecd6cf80Smarks 	"pool create",
3630ecd6cf80Smarks 	"vdev add",
3631ecd6cf80Smarks 	"pool remove",
3632ecd6cf80Smarks 	"pool destroy",
3633ecd6cf80Smarks 	"pool export",
3634ecd6cf80Smarks 	"pool import",
3635ecd6cf80Smarks 	"vdev attach",
3636ecd6cf80Smarks 	"vdev replace",
3637ecd6cf80Smarks 	"vdev detach",
3638ecd6cf80Smarks 	"vdev online",
3639ecd6cf80Smarks 	"vdev offline",
3640ecd6cf80Smarks 	"vdev upgrade",
3641ecd6cf80Smarks 	"pool clear",
3642ecd6cf80Smarks 	"pool scrub",
3643ecd6cf80Smarks 	"pool property set",
3644ecd6cf80Smarks 	"create",
3645ecd6cf80Smarks 	"clone",
3646ecd6cf80Smarks 	"destroy",
3647ecd6cf80Smarks 	"destroy_begin_sync",
3648ecd6cf80Smarks 	"inherit",
3649ecd6cf80Smarks 	"property set",
3650ecd6cf80Smarks 	"quota set",
3651ecd6cf80Smarks 	"permission update",
3652ecd6cf80Smarks 	"permission remove",
3653ecd6cf80Smarks 	"permission who remove",
3654ecd6cf80Smarks 	"promote",
3655ecd6cf80Smarks 	"receive",
3656ecd6cf80Smarks 	"rename",
3657ecd6cf80Smarks 	"reservation set",
3658ecd6cf80Smarks 	"replay_inc_sync",
3659ecd6cf80Smarks 	"replay_full_sync",
3660ecd6cf80Smarks 	"rollback",
3661ecd6cf80Smarks 	"snapshot",
3662e7437265Sahrens 	"filesystem version upgrade",
3663a9799022Sck153898 	"refquota set",
3664a9799022Sck153898 	"refreservation set",
3665088f3894Sahrens 	"pool scrub done",
3666842727c2SChris Kirby 	"user hold",
3667842727c2SChris Kirby 	"user release",
3668ecd6cf80Smarks };
3669ecd6cf80Smarks 
367006eeb2adSek110237 /*
367106eeb2adSek110237  * Print out the command history for a specific pool.
367206eeb2adSek110237  */
367306eeb2adSek110237 static int
367406eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
367506eeb2adSek110237 {
367606eeb2adSek110237 	nvlist_t *nvhis;
367706eeb2adSek110237 	nvlist_t **records;
367806eeb2adSek110237 	uint_t numrecords;
367906eeb2adSek110237 	char *cmdstr;
3680ecd6cf80Smarks 	char *pathstr;
368106eeb2adSek110237 	uint64_t dst_time;
368206eeb2adSek110237 	time_t tsec;
368306eeb2adSek110237 	struct tm t;
368406eeb2adSek110237 	char tbuf[30];
368506eeb2adSek110237 	int ret, i;
3686ecd6cf80Smarks 	uint64_t who;
3687ecd6cf80Smarks 	struct passwd *pwd;
3688ecd6cf80Smarks 	char *hostname;
3689ecd6cf80Smarks 	char *zonename;
3690ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3691ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3692ecd6cf80Smarks 	uint64_t txg;
3693ecd6cf80Smarks 	uint64_t ievent;
369406eeb2adSek110237 
3695ecd6cf80Smarks 	cb->first = B_FALSE;
369606eeb2adSek110237 
369706eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
369806eeb2adSek110237 
369906eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
370006eeb2adSek110237 		return (ret);
370106eeb2adSek110237 
370206eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
370306eeb2adSek110237 	    &records, &numrecords) == 0);
370406eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
370506eeb2adSek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3706ecd6cf80Smarks 		    &dst_time) != 0)
3707ecd6cf80Smarks 			continue;
3708ecd6cf80Smarks 
3709ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3710ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3711ecd6cf80Smarks 		    &cmdstr) != 0) {
3712ecd6cf80Smarks 			if (cb->internal == 0)
3713ecd6cf80Smarks 				continue;
3714ecd6cf80Smarks 
3715ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3716ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3717ecd6cf80Smarks 				continue;
3718ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3719ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3720ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3721ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3722088f3894Sahrens 			if (ievent >= LOG_END)
3723ecd6cf80Smarks 				continue;
3724ecd6cf80Smarks 			(void) snprintf(internalstr,
3725ecd6cf80Smarks 			    sizeof (internalstr),
3726ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3727ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3728ecd6cf80Smarks 			    pathstr);
3729ecd6cf80Smarks 			cmdstr = internalstr;
3730ecd6cf80Smarks 		}
373106eeb2adSek110237 		tsec = dst_time;
373206eeb2adSek110237 		(void) localtime_r(&tsec, &t);
373306eeb2adSek110237 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3734ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3735ecd6cf80Smarks 
3736ecd6cf80Smarks 		if (!cb->longfmt) {
3737ecd6cf80Smarks 			(void) printf("\n");
3738ecd6cf80Smarks 			continue;
373906eeb2adSek110237 		}
3740ecd6cf80Smarks 		(void) printf(" [");
3741ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3742ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3743ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3744ecd6cf80Smarks 			if (pwd)
3745ecd6cf80Smarks 				(void) printf("user %s on",
3746ecd6cf80Smarks 				    pwd->pw_name);
3747ecd6cf80Smarks 			else
3748ecd6cf80Smarks 				(void) printf("user %d on",
3749ecd6cf80Smarks 				    (int)who);
3750ecd6cf80Smarks 		} else {
3751ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3752ecd6cf80Smarks 			continue;
3753ecd6cf80Smarks 		}
3754ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3755ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3756ecd6cf80Smarks 			(void) printf(" %s", hostname);
3757ecd6cf80Smarks 		}
3758ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3759ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3760ecd6cf80Smarks 			(void) printf(":%s", zonename);
3761ecd6cf80Smarks 		}
3762ecd6cf80Smarks 
3763ecd6cf80Smarks 		(void) printf("]");
3764ecd6cf80Smarks 		(void) printf("\n");
376506eeb2adSek110237 	}
376606eeb2adSek110237 	(void) printf("\n");
376706eeb2adSek110237 	nvlist_free(nvhis);
376806eeb2adSek110237 
376906eeb2adSek110237 	return (ret);
377006eeb2adSek110237 }
377106eeb2adSek110237 
377206eeb2adSek110237 /*
377306eeb2adSek110237  * zpool history <pool>
377406eeb2adSek110237  *
377506eeb2adSek110237  * Displays the history of commands that modified pools.
377606eeb2adSek110237  */
3777ecd6cf80Smarks 
3778ecd6cf80Smarks 
377906eeb2adSek110237 int
378006eeb2adSek110237 zpool_do_history(int argc, char **argv)
378106eeb2adSek110237 {
3782ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
378306eeb2adSek110237 	int ret;
3784ecd6cf80Smarks 	int c;
378506eeb2adSek110237 
3786ecd6cf80Smarks 	cbdata.first = B_TRUE;
3787ecd6cf80Smarks 	/* check options */
3788ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3789ecd6cf80Smarks 		switch (c) {
3790ecd6cf80Smarks 		case 'l':
3791ecd6cf80Smarks 			cbdata.longfmt = 1;
3792ecd6cf80Smarks 			break;
3793ecd6cf80Smarks 		case 'i':
3794ecd6cf80Smarks 			cbdata.internal = 1;
3795ecd6cf80Smarks 			break;
3796ecd6cf80Smarks 		case '?':
3797ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3798ecd6cf80Smarks 			    optopt);
3799ecd6cf80Smarks 			usage(B_FALSE);
3800ecd6cf80Smarks 		}
3801ecd6cf80Smarks 	}
380206eeb2adSek110237 	argc -= optind;
380306eeb2adSek110237 	argv += optind;
380406eeb2adSek110237 
3805b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3806ecd6cf80Smarks 	    &cbdata);
380706eeb2adSek110237 
3808ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
380906eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
381006eeb2adSek110237 		return (0);
3811eaca9bbdSeschrock 	}
3812eaca9bbdSeschrock 
3813eaca9bbdSeschrock 	return (ret);
3814eaca9bbdSeschrock }
3815eaca9bbdSeschrock 
3816b1b8ab34Slling static int
3817b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3818b1b8ab34Slling {
3819990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3820b1b8ab34Slling 	char value[MAXNAMELEN];
3821990b4856Slling 	zprop_source_t srctype;
3822990b4856Slling 	zprop_list_t *pl;
3823b1b8ab34Slling 
3824b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3825b1b8ab34Slling 
3826b1b8ab34Slling 		/*
3827990b4856Slling 		 * Skip the special fake placeholder. This will also skip
3828990b4856Slling 		 * over the name property when 'all' is specified.
3829b1b8ab34Slling 		 */
3830990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3831b1b8ab34Slling 		    pl == cbp->cb_proplist)
3832b1b8ab34Slling 			continue;
3833b1b8ab34Slling 
3834b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3835b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3836b1b8ab34Slling 			continue;
3837b1b8ab34Slling 
3838990b4856Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
3839b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3840b1b8ab34Slling 	}
3841b1b8ab34Slling 	return (0);
3842b1b8ab34Slling }
3843b1b8ab34Slling 
3844b1b8ab34Slling int
3845b1b8ab34Slling zpool_do_get(int argc, char **argv)
3846b1b8ab34Slling {
3847990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
3848990b4856Slling 	zprop_list_t fake_name = { 0 };
3849b1b8ab34Slling 	int ret;
3850b1b8ab34Slling 
3851b1b8ab34Slling 	if (argc < 3)
3852b1b8ab34Slling 		usage(B_FALSE);
3853b1b8ab34Slling 
3854b1b8ab34Slling 	cb.cb_first = B_TRUE;
3855990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
3856b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3857b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3858b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3859b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3860990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
3861b1b8ab34Slling 
3862990b4856Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3863990b4856Slling 	    ZFS_TYPE_POOL) != 0)
3864b1b8ab34Slling 		usage(B_FALSE);
3865b1b8ab34Slling 
3866b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3867990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
3868b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3869b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3870b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3871b1b8ab34Slling 	}
3872b1b8ab34Slling 
3873b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3874b1b8ab34Slling 	    get_callback, &cb);
3875b1b8ab34Slling 
3876b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3877990b4856Slling 		zprop_free_list(fake_name.pl_next);
3878b1b8ab34Slling 	else
3879990b4856Slling 		zprop_free_list(cb.cb_proplist);
3880b1b8ab34Slling 
3881b1b8ab34Slling 	return (ret);
3882b1b8ab34Slling }
3883b1b8ab34Slling 
3884b1b8ab34Slling typedef struct set_cbdata {
3885b1b8ab34Slling 	char *cb_propname;
3886b1b8ab34Slling 	char *cb_value;
3887b1b8ab34Slling 	boolean_t cb_any_successful;
3888b1b8ab34Slling } set_cbdata_t;
3889b1b8ab34Slling 
3890b1b8ab34Slling int
3891b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3892b1b8ab34Slling {
3893b1b8ab34Slling 	int error;
3894b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3895b1b8ab34Slling 
3896b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3897b1b8ab34Slling 
3898b1b8ab34Slling 	if (!error)
3899b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3900b1b8ab34Slling 
3901b1b8ab34Slling 	return (error);
3902b1b8ab34Slling }
3903b1b8ab34Slling 
3904b1b8ab34Slling int
3905b1b8ab34Slling zpool_do_set(int argc, char **argv)
3906b1b8ab34Slling {
3907b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3908b1b8ab34Slling 	int error;
3909b1b8ab34Slling 
3910b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3911b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3912b1b8ab34Slling 		    argv[1][1]);
3913b1b8ab34Slling 		usage(B_FALSE);
3914b1b8ab34Slling 	}
3915b1b8ab34Slling 
3916b1b8ab34Slling 	if (argc < 2) {
3917b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3918b1b8ab34Slling 		    "argument\n"));
3919b1b8ab34Slling 		usage(B_FALSE);
3920b1b8ab34Slling 	}
3921b1b8ab34Slling 
3922b1b8ab34Slling 	if (argc < 3) {
3923b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3924b1b8ab34Slling 		usage(B_FALSE);
3925b1b8ab34Slling 	}
3926b1b8ab34Slling 
3927b1b8ab34Slling 	if (argc > 3) {
3928b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3929b1b8ab34Slling 		usage(B_FALSE);
3930b1b8ab34Slling 	}
3931b1b8ab34Slling 
3932b1b8ab34Slling 	cb.cb_propname = argv[1];
3933b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3934b1b8ab34Slling 	if (cb.cb_value == NULL) {
3935b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3936b1b8ab34Slling 		    "property=value argument\n"));
3937b1b8ab34Slling 		usage(B_FALSE);
3938b1b8ab34Slling 	}
3939b1b8ab34Slling 
3940b1b8ab34Slling 	*(cb.cb_value) = '\0';
3941b1b8ab34Slling 	cb.cb_value++;
3942b1b8ab34Slling 
3943b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3944b1b8ab34Slling 	    set_callback, &cb);
3945b1b8ab34Slling 
3946b1b8ab34Slling 	return (error);
3947b1b8ab34Slling }
3948b1b8ab34Slling 
3949b1b8ab34Slling static int
3950b1b8ab34Slling find_command_idx(char *command, int *idx)
3951b1b8ab34Slling {
3952b1b8ab34Slling 	int i;
3953b1b8ab34Slling 
3954b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3955b1b8ab34Slling 		if (command_table[i].name == NULL)
3956b1b8ab34Slling 			continue;
3957b1b8ab34Slling 
3958b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3959b1b8ab34Slling 			*idx = i;
3960b1b8ab34Slling 			return (0);
3961b1b8ab34Slling 		}
3962b1b8ab34Slling 	}
3963b1b8ab34Slling 	return (1);
3964b1b8ab34Slling }
3965b1b8ab34Slling 
3966fa9e4066Sahrens int
3967fa9e4066Sahrens main(int argc, char **argv)
3968fa9e4066Sahrens {
3969fa9e4066Sahrens 	int ret;
3970fa9e4066Sahrens 	int i;
3971fa9e4066Sahrens 	char *cmdname;
3972fa9e4066Sahrens 
3973fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3974fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3975fa9e4066Sahrens 
397699653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
397799653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3978203a47d8Snd150628 		    "initialize ZFS library\n"));
397999653d4eSeschrock 		return (1);
398099653d4eSeschrock 	}
398199653d4eSeschrock 
398299653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
398399653d4eSeschrock 
3984fa9e4066Sahrens 	opterr = 0;
3985fa9e4066Sahrens 
3986fa9e4066Sahrens 	/*
3987fa9e4066Sahrens 	 * Make sure the user has specified some command.
3988fa9e4066Sahrens 	 */
3989fa9e4066Sahrens 	if (argc < 2) {
3990fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
399199653d4eSeschrock 		usage(B_FALSE);
3992fa9e4066Sahrens 	}
3993fa9e4066Sahrens 
3994fa9e4066Sahrens 	cmdname = argv[1];
3995fa9e4066Sahrens 
3996fa9e4066Sahrens 	/*
3997fa9e4066Sahrens 	 * Special case '-?'
3998fa9e4066Sahrens 	 */
3999fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
400099653d4eSeschrock 		usage(B_TRUE);
4001fa9e4066Sahrens 
40022a6b87f0Sek110237 	zpool_set_history_str("zpool", argc, argv, history_str);
40032a6b87f0Sek110237 	verify(zpool_stage_history(g_zfs, history_str) == 0);
40042a6b87f0Sek110237 
4005fa9e4066Sahrens 	/*
4006fa9e4066Sahrens 	 * Run the appropriate command.
4007fa9e4066Sahrens 	 */
4008b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
4009fa9e4066Sahrens 		current_command = &command_table[i];
4010fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
401191ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
401291ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
401391ebeef5Sahrens 		current_command = &command_table[i];
401491ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
401591ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
4016fa9e4066Sahrens 		/*
401791ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
401891ebeef5Sahrens 		 * it as such.
4019fa9e4066Sahrens 		 */
4020ea8dc4b6Seschrock 		char buf[16384];
4021ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
4022fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
4023fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
402491ebeef5Sahrens 	} else {
4025fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
4026fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
402799653d4eSeschrock 		usage(B_FALSE);
4028fa9e4066Sahrens 	}
4029fa9e4066Sahrens 
403099653d4eSeschrock 	libzfs_fini(g_zfs);
403199653d4eSeschrock 
4032fa9e4066Sahrens 	/*
4033fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
4034fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
4035fa9e4066Sahrens 	 */
4036fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
4037fa9e4066Sahrens 		(void) printf("dumping core by request\n");
4038fa9e4066Sahrens 		abort();
4039fa9e4066Sahrens 	}
4040fa9e4066Sahrens 
4041fa9e4066Sahrens 	return (ret);
4042fa9e4066Sahrens }
4043