xref: /titanic_53/usr/src/cmd/zpool/zpool_main.c (revision 85dc7ea5e05c7627ea92c11ccb34fd22efd21452)
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 /*
2318ce54dfSek110237  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28fa9e4066Sahrens 
29fa9e4066Sahrens #include <assert.h>
30fa9e4066Sahrens #include <ctype.h>
31fa9e4066Sahrens #include <dirent.h>
32fa9e4066Sahrens #include <errno.h>
33fa9e4066Sahrens #include <fcntl.h>
34fa9e4066Sahrens #include <libgen.h>
35fa9e4066Sahrens #include <libintl.h>
36fa9e4066Sahrens #include <libuutil.h>
37fa9e4066Sahrens #include <locale.h>
38fa9e4066Sahrens #include <stdio.h>
39fa9e4066Sahrens #include <stdlib.h>
40fa9e4066Sahrens #include <string.h>
41fa9e4066Sahrens #include <strings.h>
42fa9e4066Sahrens #include <unistd.h>
43fa9e4066Sahrens #include <priv.h>
44ecd6cf80Smarks #include <pwd.h>
45ecd6cf80Smarks #include <zone.h>
46b1b8ab34Slling #include <sys/fs/zfs.h>
47fa9e4066Sahrens 
48fa9e4066Sahrens #include <sys/stat.h>
49fa9e4066Sahrens 
50fa9e4066Sahrens #include <libzfs.h>
51fa9e4066Sahrens 
52fa9e4066Sahrens #include "zpool_util.h"
53fa9e4066Sahrens 
54fa9e4066Sahrens static int zpool_do_create(int, char **);
55fa9e4066Sahrens static int zpool_do_destroy(int, char **);
56fa9e4066Sahrens 
57fa9e4066Sahrens static int zpool_do_add(int, char **);
5899653d4eSeschrock static int zpool_do_remove(int, char **);
59fa9e4066Sahrens 
60fa9e4066Sahrens static int zpool_do_list(int, char **);
61fa9e4066Sahrens static int zpool_do_iostat(int, char **);
62fa9e4066Sahrens static int zpool_do_status(int, char **);
63fa9e4066Sahrens 
64fa9e4066Sahrens static int zpool_do_online(int, char **);
65fa9e4066Sahrens static int zpool_do_offline(int, char **);
66ea8dc4b6Seschrock static int zpool_do_clear(int, char **);
67fa9e4066Sahrens 
68fa9e4066Sahrens static int zpool_do_attach(int, char **);
69fa9e4066Sahrens static int zpool_do_detach(int, char **);
70fa9e4066Sahrens static int zpool_do_replace(int, char **);
71fa9e4066Sahrens 
72fa9e4066Sahrens static int zpool_do_scrub(int, char **);
73fa9e4066Sahrens 
74fa9e4066Sahrens static int zpool_do_import(int, char **);
75fa9e4066Sahrens static int zpool_do_export(int, char **);
76fa9e4066Sahrens 
77eaca9bbdSeschrock static int zpool_do_upgrade(int, char **);
78eaca9bbdSeschrock 
7906eeb2adSek110237 static int zpool_do_history(int, char **);
8006eeb2adSek110237 
81b1b8ab34Slling static int zpool_do_get(int, char **);
82b1b8ab34Slling static int zpool_do_set(int, char **);
83b1b8ab34Slling 
84fa9e4066Sahrens /*
85fa9e4066Sahrens  * These libumem hooks provide a reasonable set of defaults for the allocator's
86fa9e4066Sahrens  * debugging facilities.
87fa9e4066Sahrens  */
88fa9e4066Sahrens const char *
8999653d4eSeschrock _umem_debug_init(void)
90fa9e4066Sahrens {
91fa9e4066Sahrens 	return ("default,verbose"); /* $UMEM_DEBUG setting */
92fa9e4066Sahrens }
93fa9e4066Sahrens 
94fa9e4066Sahrens const char *
95fa9e4066Sahrens _umem_logging_init(void)
96fa9e4066Sahrens {
97fa9e4066Sahrens 	return ("fail,contents"); /* $UMEM_LOGGING setting */
98fa9e4066Sahrens }
99fa9e4066Sahrens 
10065cd9f28Seschrock typedef enum {
10165cd9f28Seschrock 	HELP_ADD,
10265cd9f28Seschrock 	HELP_ATTACH,
103ea8dc4b6Seschrock 	HELP_CLEAR,
10465cd9f28Seschrock 	HELP_CREATE,
10565cd9f28Seschrock 	HELP_DESTROY,
10665cd9f28Seschrock 	HELP_DETACH,
10765cd9f28Seschrock 	HELP_EXPORT,
10806eeb2adSek110237 	HELP_HISTORY,
10965cd9f28Seschrock 	HELP_IMPORT,
11065cd9f28Seschrock 	HELP_IOSTAT,
11165cd9f28Seschrock 	HELP_LIST,
11265cd9f28Seschrock 	HELP_OFFLINE,
11365cd9f28Seschrock 	HELP_ONLINE,
11465cd9f28Seschrock 	HELP_REPLACE,
11599653d4eSeschrock 	HELP_REMOVE,
11665cd9f28Seschrock 	HELP_SCRUB,
117eaca9bbdSeschrock 	HELP_STATUS,
118b1b8ab34Slling 	HELP_UPGRADE,
119b1b8ab34Slling 	HELP_GET,
120b1b8ab34Slling 	HELP_SET
12165cd9f28Seschrock } zpool_help_t;
12265cd9f28Seschrock 
12365cd9f28Seschrock 
124fa9e4066Sahrens typedef struct zpool_command {
125fa9e4066Sahrens 	const char	*name;
126fa9e4066Sahrens 	int		(*func)(int, char **);
12765cd9f28Seschrock 	zpool_help_t	usage;
128fa9e4066Sahrens } zpool_command_t;
129fa9e4066Sahrens 
130fa9e4066Sahrens /*
131fa9e4066Sahrens  * Master command table.  Each ZFS command has a name, associated function, and
132ea8dc4b6Seschrock  * usage message.  The usage messages need to be internationalized, so we have
133ea8dc4b6Seschrock  * to have a function to return the usage message based on a command index.
13465cd9f28Seschrock  *
13565cd9f28Seschrock  * These commands are organized according to how they are displayed in the usage
13665cd9f28Seschrock  * message.  An empty command (one with a NULL name) indicates an empty line in
13765cd9f28Seschrock  * the generic usage message.
138fa9e4066Sahrens  */
139fa9e4066Sahrens static zpool_command_t command_table[] = {
14065cd9f28Seschrock 	{ "create",	zpool_do_create,	HELP_CREATE		},
14165cd9f28Seschrock 	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
142fa9e4066Sahrens 	{ NULL },
14365cd9f28Seschrock 	{ "add",	zpool_do_add,		HELP_ADD		},
14499653d4eSeschrock 	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
145fa9e4066Sahrens 	{ NULL },
14665cd9f28Seschrock 	{ "list",	zpool_do_list,		HELP_LIST		},
14765cd9f28Seschrock 	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
14865cd9f28Seschrock 	{ "status",	zpool_do_status,	HELP_STATUS		},
149fa9e4066Sahrens 	{ NULL },
15065cd9f28Seschrock 	{ "online",	zpool_do_online,	HELP_ONLINE		},
15165cd9f28Seschrock 	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
152ea8dc4b6Seschrock 	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
153fa9e4066Sahrens 	{ NULL },
15465cd9f28Seschrock 	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
15565cd9f28Seschrock 	{ "detach",	zpool_do_detach,	HELP_DETACH		},
15665cd9f28Seschrock 	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
157fa9e4066Sahrens 	{ NULL },
15865cd9f28Seschrock 	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
159fa9e4066Sahrens 	{ NULL },
16065cd9f28Seschrock 	{ "import",	zpool_do_import,	HELP_IMPORT		},
16165cd9f28Seschrock 	{ "export",	zpool_do_export,	HELP_EXPORT		},
16206eeb2adSek110237 	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
16306eeb2adSek110237 	{ NULL },
164b1b8ab34Slling 	{ "history",	zpool_do_history,	HELP_HISTORY		},
165b1b8ab34Slling 	{ "get",	zpool_do_get,		HELP_GET		},
166b1b8ab34Slling 	{ "set",	zpool_do_set,		HELP_SET		},
167fa9e4066Sahrens };
168fa9e4066Sahrens 
169fa9e4066Sahrens #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
170fa9e4066Sahrens 
171fa9e4066Sahrens zpool_command_t *current_command;
1722a6b87f0Sek110237 static char history_str[HIS_MAX_RECORD_LEN];
173fa9e4066Sahrens 
17465cd9f28Seschrock static const char *
17565cd9f28Seschrock get_usage(zpool_help_t idx) {
17665cd9f28Seschrock 	switch (idx) {
17765cd9f28Seschrock 	case HELP_ADD:
17865cd9f28Seschrock 		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
17965cd9f28Seschrock 	case HELP_ATTACH:
18065cd9f28Seschrock 		return (gettext("\tattach [-f] <pool> <device> "
181e45ce728Sahrens 		    "<new-device>\n"));
182ea8dc4b6Seschrock 	case HELP_CLEAR:
183ea8dc4b6Seschrock 		return (gettext("\tclear <pool> [device]\n"));
18465cd9f28Seschrock 	case HELP_CREATE:
185990b4856Slling 		return (gettext("\tcreate [-fn] [-o property=value] ... \n"
186990b4856Slling 		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
18765cd9f28Seschrock 	case HELP_DESTROY:
18865cd9f28Seschrock 		return (gettext("\tdestroy [-f] <pool>\n"));
18965cd9f28Seschrock 	case HELP_DETACH:
19065cd9f28Seschrock 		return (gettext("\tdetach <pool> <device>\n"));
19165cd9f28Seschrock 	case HELP_EXPORT:
19265cd9f28Seschrock 		return (gettext("\texport [-f] <pool> ...\n"));
19306eeb2adSek110237 	case HELP_HISTORY:
194ecd6cf80Smarks 		return (gettext("\thistory [-il] [<pool>] ...\n"));
19565cd9f28Seschrock 	case HELP_IMPORT:
1964c58d714Sdarrenm 		return (gettext("\timport [-d dir] [-D]\n"
1972f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
1982f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n"
1992f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
2002f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] "
2012f8aaab3Seschrock 		    "<pool | id> [newpool]\n"));
20265cd9f28Seschrock 	case HELP_IOSTAT:
20365cd9f28Seschrock 		return (gettext("\tiostat [-v] [pool] ... [interval "
20465cd9f28Seschrock 		    "[count]]\n"));
20565cd9f28Seschrock 	case HELP_LIST:
206990b4856Slling 		return (gettext("\tlist [-H] [-o property[,...]] "
207990b4856Slling 		    "[pool] ...\n"));
20865cd9f28Seschrock 	case HELP_OFFLINE:
209441d80aaSlling 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
21065cd9f28Seschrock 	case HELP_ONLINE:
211441d80aaSlling 		return (gettext("\tonline <pool> <device> ...\n"));
21265cd9f28Seschrock 	case HELP_REPLACE:
21365cd9f28Seschrock 		return (gettext("\treplace [-f] <pool> <device> "
214e45ce728Sahrens 		    "[new-device]\n"));
21599653d4eSeschrock 	case HELP_REMOVE:
216fa94a07fSbrendan 		return (gettext("\tremove <pool> <device> ...\n"));
21765cd9f28Seschrock 	case HELP_SCRUB:
21865cd9f28Seschrock 		return (gettext("\tscrub [-s] <pool> ...\n"));
21965cd9f28Seschrock 	case HELP_STATUS:
22065cd9f28Seschrock 		return (gettext("\tstatus [-vx] [pool] ...\n"));
221eaca9bbdSeschrock 	case HELP_UPGRADE:
222eaca9bbdSeschrock 		return (gettext("\tupgrade\n"
223eaca9bbdSeschrock 		    "\tupgrade -v\n"
224990b4856Slling 		    "\tupgrade [-V version] <-a | pool ...>\n"));
225b1b8ab34Slling 	case HELP_GET:
226e45ce728Sahrens 		return (gettext("\tget <\"all\" | property[,...]> "
227b1b8ab34Slling 		    "<pool> ...\n"));
228b1b8ab34Slling 	case HELP_SET:
229b1b8ab34Slling 		return (gettext("\tset <property=value> <pool> \n"));
23065cd9f28Seschrock 	}
23165cd9f28Seschrock 
23265cd9f28Seschrock 	abort();
23365cd9f28Seschrock 	/* NOTREACHED */
23465cd9f28Seschrock }
23565cd9f28Seschrock 
236fa9e4066Sahrens 
237fa9e4066Sahrens /*
238b1b8ab34Slling  * Callback routine that will print out a pool property value.
239b1b8ab34Slling  */
240990b4856Slling static int
241990b4856Slling print_prop_cb(int prop, void *cb)
242b1b8ab34Slling {
243b1b8ab34Slling 	FILE *fp = cb;
244b1b8ab34Slling 
245b1b8ab34Slling 	(void) fprintf(fp, "\t%-13s  ", zpool_prop_to_name(prop));
246b1b8ab34Slling 
247990b4856Slling 	if (zpool_prop_readonly(prop))
248990b4856Slling 		(void) fprintf(fp, "  NO   ");
249990b4856Slling 	else
250990b4856Slling 		(void) fprintf(fp, " YES    ");
251990b4856Slling 
252b1b8ab34Slling 	if (zpool_prop_values(prop) == NULL)
253b1b8ab34Slling 		(void) fprintf(fp, "-\n");
254b1b8ab34Slling 	else
255b1b8ab34Slling 		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
256b1b8ab34Slling 
257990b4856Slling 	return (ZPROP_CONT);
258b1b8ab34Slling }
259b1b8ab34Slling 
260b1b8ab34Slling /*
261fa9e4066Sahrens  * Display usage message.  If we're inside a command, display only the usage for
262fa9e4066Sahrens  * that command.  Otherwise, iterate over the entire command table and display
263fa9e4066Sahrens  * a complete usage message.
264fa9e4066Sahrens  */
265fa9e4066Sahrens void
26699653d4eSeschrock usage(boolean_t requested)
267fa9e4066Sahrens {
268fa9e4066Sahrens 	FILE *fp = requested ? stdout : stderr;
269fa9e4066Sahrens 
270fa9e4066Sahrens 	if (current_command == NULL) {
271fa9e4066Sahrens 		int i;
272fa9e4066Sahrens 
273fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
274fa9e4066Sahrens 		(void) fprintf(fp,
275fa9e4066Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
276fa9e4066Sahrens 
277fa9e4066Sahrens 		for (i = 0; i < NCOMMAND; i++) {
278fa9e4066Sahrens 			if (command_table[i].name == NULL)
279fa9e4066Sahrens 				(void) fprintf(fp, "\n");
280fa9e4066Sahrens 			else
281fa9e4066Sahrens 				(void) fprintf(fp, "%s",
28265cd9f28Seschrock 				    get_usage(command_table[i].usage));
283fa9e4066Sahrens 		}
284fa9e4066Sahrens 	} else {
285fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
28665cd9f28Seschrock 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
287fa9e4066Sahrens 	}
288fa9e4066Sahrens 
289b1b8ab34Slling 	if (current_command != NULL &&
290b1b8ab34Slling 	    ((strcmp(current_command->name, "set") == 0) ||
291990b4856Slling 	    (strcmp(current_command->name, "get") == 0) ||
292990b4856Slling 	    (strcmp(current_command->name, "list") == 0))) {
293b1b8ab34Slling 
294b1b8ab34Slling 		(void) fprintf(fp,
295b1b8ab34Slling 		    gettext("\nthe following properties are supported:\n"));
296b1b8ab34Slling 
297990b4856Slling 		(void) fprintf(fp, "\n\t%-13s  %s  %s\n\n",
298990b4856Slling 		    "PROPERTY", "EDIT", "VALUES");
299b1b8ab34Slling 
300b1b8ab34Slling 		/* Iterate over all properties */
301990b4856Slling 		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
302990b4856Slling 		    ZFS_TYPE_POOL);
303b1b8ab34Slling 	}
304b1b8ab34Slling 
305e9dbad6fSeschrock 	/*
306e9dbad6fSeschrock 	 * See comments at end of main().
307e9dbad6fSeschrock 	 */
308e9dbad6fSeschrock 	if (getenv("ZFS_ABORT") != NULL) {
309e9dbad6fSeschrock 		(void) printf("dumping core by request\n");
310e9dbad6fSeschrock 		abort();
311e9dbad6fSeschrock 	}
312e9dbad6fSeschrock 
313fa9e4066Sahrens 	exit(requested ? 0 : 2);
314fa9e4066Sahrens }
315fa9e4066Sahrens 
316fa9e4066Sahrens void
3178654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
3188654d025Sperrin     boolean_t print_logs)
319fa9e4066Sahrens {
320fa9e4066Sahrens 	nvlist_t **child;
321fa9e4066Sahrens 	uint_t c, children;
322afefbcddSeschrock 	char *vname;
323fa9e4066Sahrens 
324fa9e4066Sahrens 	if (name != NULL)
325fa9e4066Sahrens 		(void) printf("\t%*s%s\n", indent, "", name);
326fa9e4066Sahrens 
327fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
328fa9e4066Sahrens 	    &child, &children) != 0)
329fa9e4066Sahrens 		return;
330fa9e4066Sahrens 
331afefbcddSeschrock 	for (c = 0; c < children; c++) {
3328654d025Sperrin 		uint64_t is_log = B_FALSE;
3338654d025Sperrin 
3348654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3358654d025Sperrin 		    &is_log);
3368654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
3378654d025Sperrin 			continue;
3388654d025Sperrin 
33999653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
3408654d025Sperrin 		print_vdev_tree(zhp, vname, child[c], indent + 2,
3418654d025Sperrin 		    B_FALSE);
342afefbcddSeschrock 		free(vname);
343afefbcddSeschrock 	}
344fa9e4066Sahrens }
345fa9e4066Sahrens 
346fa9e4066Sahrens /*
347990b4856Slling  * Add a property pair (name, string-value) into a property nvlist.
348990b4856Slling  */
349990b4856Slling static int
350990b4856Slling add_prop_list(const char *propname, char *propval, nvlist_t **props)
351990b4856Slling {
352990b4856Slling 	char *strval;
353990b4856Slling 	nvlist_t *proplist;
354990b4856Slling 	zpool_prop_t prop;
355990b4856Slling 
356990b4856Slling 	if (*props == NULL &&
357990b4856Slling 	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
358990b4856Slling 		(void) fprintf(stderr,
359990b4856Slling 		    gettext("internal error: out of memory\n"));
360990b4856Slling 		return (1);
361990b4856Slling 	}
362990b4856Slling 
363990b4856Slling 	proplist = *props;
364990b4856Slling 
365990b4856Slling 	if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
366990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' is "
367990b4856Slling 		    "not a valid pool property\n"), propname);
368990b4856Slling 		return (2);
369990b4856Slling 	}
370990b4856Slling 
371990b4856Slling 	/* Use normalized property name for nvlist operations */
372990b4856Slling 	if (nvlist_lookup_string(proplist, zpool_prop_to_name(prop),
3732f8aaab3Seschrock 	    &strval) == 0 && prop != ZPOOL_PROP_CACHEFILE) {
374990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' "
375990b4856Slling 		    "specified multiple times\n"), propname);
376990b4856Slling 		return (2);
377990b4856Slling 	}
378990b4856Slling 
379990b4856Slling 	if (nvlist_add_string(proplist, zpool_prop_to_name(prop),
380990b4856Slling 	    propval) != 0) {
381990b4856Slling 		(void) fprintf(stderr, gettext("internal "
382990b4856Slling 		    "error: out of memory\n"));
383990b4856Slling 		return (1);
384990b4856Slling 	}
385990b4856Slling 
386990b4856Slling 	return (0);
387990b4856Slling }
388990b4856Slling 
389990b4856Slling /*
390fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
391fa9e4066Sahrens  *
392fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
393fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
394fa9e4066Sahrens  *		they were to be added.
395fa9e4066Sahrens  *
396fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
397fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
398fa9e4066Sahrens  * libzfs.
399fa9e4066Sahrens  */
400fa9e4066Sahrens int
401fa9e4066Sahrens zpool_do_add(int argc, char **argv)
402fa9e4066Sahrens {
40399653d4eSeschrock 	boolean_t force = B_FALSE;
40499653d4eSeschrock 	boolean_t dryrun = B_FALSE;
405fa9e4066Sahrens 	int c;
406fa9e4066Sahrens 	nvlist_t *nvroot;
407fa9e4066Sahrens 	char *poolname;
408fa9e4066Sahrens 	int ret;
409fa9e4066Sahrens 	zpool_handle_t *zhp;
410fa9e4066Sahrens 	nvlist_t *config;
411fa9e4066Sahrens 
412fa9e4066Sahrens 	/* check options */
413fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
414fa9e4066Sahrens 		switch (c) {
415fa9e4066Sahrens 		case 'f':
41699653d4eSeschrock 			force = B_TRUE;
417fa9e4066Sahrens 			break;
418fa9e4066Sahrens 		case 'n':
41999653d4eSeschrock 			dryrun = B_TRUE;
420fa9e4066Sahrens 			break;
421fa9e4066Sahrens 		case '?':
422fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
423fa9e4066Sahrens 			    optopt);
42499653d4eSeschrock 			usage(B_FALSE);
425fa9e4066Sahrens 		}
426fa9e4066Sahrens 	}
427fa9e4066Sahrens 
428fa9e4066Sahrens 	argc -= optind;
429fa9e4066Sahrens 	argv += optind;
430fa9e4066Sahrens 
431fa9e4066Sahrens 	/* get pool name and check number of arguments */
432fa9e4066Sahrens 	if (argc < 1) {
433fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
43499653d4eSeschrock 		usage(B_FALSE);
435fa9e4066Sahrens 	}
436fa9e4066Sahrens 	if (argc < 2) {
437fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
43899653d4eSeschrock 		usage(B_FALSE);
439fa9e4066Sahrens 	}
440fa9e4066Sahrens 
441fa9e4066Sahrens 	poolname = argv[0];
442fa9e4066Sahrens 
443fa9e4066Sahrens 	argc--;
444fa9e4066Sahrens 	argv++;
445fa9e4066Sahrens 
44699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
447fa9e4066Sahrens 		return (1);
448fa9e4066Sahrens 
449088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
450fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
451fa9e4066Sahrens 		    poolname);
452fa9e4066Sahrens 		zpool_close(zhp);
453fa9e4066Sahrens 		return (1);
454fa9e4066Sahrens 	}
455fa9e4066Sahrens 
456fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
4578488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv);
458fa9e4066Sahrens 	if (nvroot == NULL) {
459fa9e4066Sahrens 		zpool_close(zhp);
460fa9e4066Sahrens 		return (1);
461fa9e4066Sahrens 	}
462fa9e4066Sahrens 
463fa9e4066Sahrens 	if (dryrun) {
464fa9e4066Sahrens 		nvlist_t *poolnvroot;
465fa9e4066Sahrens 
466fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
467fa9e4066Sahrens 		    &poolnvroot) == 0);
468fa9e4066Sahrens 
469fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
470fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
471fa9e4066Sahrens 
4728654d025Sperrin 		/* print original main pool and new tree */
4738654d025Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
4748654d025Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
4758654d025Sperrin 
4768654d025Sperrin 		/* Do the same for the logs */
4778654d025Sperrin 		if (num_logs(poolnvroot) > 0) {
4788654d025Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
4798654d025Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
4808654d025Sperrin 		} else if (num_logs(nvroot) > 0) {
4818654d025Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
4828654d025Sperrin 		}
483fa9e4066Sahrens 
484fa9e4066Sahrens 		ret = 0;
485fa9e4066Sahrens 	} else {
486fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
487fa9e4066Sahrens 	}
488fa9e4066Sahrens 
48999653d4eSeschrock 	nvlist_free(nvroot);
49099653d4eSeschrock 	zpool_close(zhp);
49199653d4eSeschrock 
49299653d4eSeschrock 	return (ret);
49399653d4eSeschrock }
49499653d4eSeschrock 
49599653d4eSeschrock /*
496fa94a07fSbrendan  * zpool remove <pool> <vdev> ...
49799653d4eSeschrock  *
49899653d4eSeschrock  * Removes the given vdev from the pool.  Currently, this only supports removing
499fa94a07fSbrendan  * spares and cache devices from the pool.  Eventually, we'll want to support
500fa94a07fSbrendan  * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs.
50199653d4eSeschrock  */
50299653d4eSeschrock int
50399653d4eSeschrock zpool_do_remove(int argc, char **argv)
50499653d4eSeschrock {
50599653d4eSeschrock 	char *poolname;
506fa94a07fSbrendan 	int i, ret = 0;
50799653d4eSeschrock 	zpool_handle_t *zhp;
50899653d4eSeschrock 
50999653d4eSeschrock 	argc--;
51099653d4eSeschrock 	argv++;
51199653d4eSeschrock 
51299653d4eSeschrock 	/* get pool name and check number of arguments */
51399653d4eSeschrock 	if (argc < 1) {
51499653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
51599653d4eSeschrock 		usage(B_FALSE);
51699653d4eSeschrock 	}
51799653d4eSeschrock 	if (argc < 2) {
51899653d4eSeschrock 		(void) fprintf(stderr, gettext("missing device\n"));
51999653d4eSeschrock 		usage(B_FALSE);
52099653d4eSeschrock 	}
52199653d4eSeschrock 
52299653d4eSeschrock 	poolname = argv[0];
52399653d4eSeschrock 
52499653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
52599653d4eSeschrock 		return (1);
52699653d4eSeschrock 
527fa94a07fSbrendan 	for (i = 1; i < argc; i++) {
528fa94a07fSbrendan 		if (zpool_vdev_remove(zhp, argv[i]) != 0)
529fa94a07fSbrendan 			ret = 1;
530fa94a07fSbrendan 	}
53199653d4eSeschrock 
532fa9e4066Sahrens 	return (ret);
533fa9e4066Sahrens }
534fa9e4066Sahrens 
535fa9e4066Sahrens /*
536990b4856Slling  * zpool create [-fn] [-o property=value] ... [-R root] [-m mountpoint]
537990b4856Slling  *		<pool> <dev> ...
538fa9e4066Sahrens  *
539fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
540fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
541fa9e4066Sahrens  *		were to be created.
542fa9e4066Sahrens  *      -R	Create a pool under an alternate root
543fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
544fa9e4066Sahrens  *      	'/<pool>'
545990b4856Slling  *	-o	Set property=value.
546fa9e4066Sahrens  *
547b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
548fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
549fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
550fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
551fa9e4066Sahrens  */
552fa9e4066Sahrens int
553fa9e4066Sahrens zpool_do_create(int argc, char **argv)
554fa9e4066Sahrens {
55599653d4eSeschrock 	boolean_t force = B_FALSE;
55699653d4eSeschrock 	boolean_t dryrun = B_FALSE;
557fa9e4066Sahrens 	int c;
558990b4856Slling 	nvlist_t *nvroot = NULL;
559fa9e4066Sahrens 	char *poolname;
560990b4856Slling 	int ret = 1;
561fa9e4066Sahrens 	char *altroot = NULL;
562fa9e4066Sahrens 	char *mountpoint = NULL;
563*85dc7ea5Sdm120769 	nvlist_t **child;
564*85dc7ea5Sdm120769 	uint_t children;
565990b4856Slling 	nvlist_t *props = NULL;
5662f8aaab3Seschrock 	char *propval;
567fa9e4066Sahrens 
568fa9e4066Sahrens 	/* check options */
569990b4856Slling 	while ((c = getopt(argc, argv, ":fnR:m:o:")) != -1) {
570fa9e4066Sahrens 		switch (c) {
571fa9e4066Sahrens 		case 'f':
57299653d4eSeschrock 			force = B_TRUE;
573fa9e4066Sahrens 			break;
574fa9e4066Sahrens 		case 'n':
57599653d4eSeschrock 			dryrun = B_TRUE;
576fa9e4066Sahrens 			break;
577fa9e4066Sahrens 		case 'R':
578fa9e4066Sahrens 			altroot = optarg;
579990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
580990b4856Slling 			    ZPOOL_PROP_ALTROOT), optarg, &props))
581990b4856Slling 				goto errout;
5822f8aaab3Seschrock 			if (nvlist_lookup_string(props,
5832f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
5842f8aaab3Seschrock 			    &propval) == 0)
5852f8aaab3Seschrock 				break;
586990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
5872f8aaab3Seschrock 			    ZPOOL_PROP_CACHEFILE), "none", &props))
588990b4856Slling 				goto errout;
589fa9e4066Sahrens 			break;
590fa9e4066Sahrens 		case 'm':
591fa9e4066Sahrens 			mountpoint = optarg;
592fa9e4066Sahrens 			break;
593990b4856Slling 		case 'o':
594990b4856Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
595990b4856Slling 				(void) fprintf(stderr, gettext("missing "
596990b4856Slling 				    "'=' for -o option\n"));
597990b4856Slling 				goto errout;
598990b4856Slling 			}
599990b4856Slling 			*propval = '\0';
600990b4856Slling 			propval++;
601990b4856Slling 
602990b4856Slling 			if (add_prop_list(optarg, propval, &props))
603990b4856Slling 				goto errout;
604990b4856Slling 			break;
605fa9e4066Sahrens 		case ':':
606fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
607fa9e4066Sahrens 			    "'%c' option\n"), optopt);
608990b4856Slling 			goto badusage;
609fa9e4066Sahrens 		case '?':
610fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
611fa9e4066Sahrens 			    optopt);
612990b4856Slling 			goto badusage;
613fa9e4066Sahrens 		}
614fa9e4066Sahrens 	}
615fa9e4066Sahrens 
616fa9e4066Sahrens 	argc -= optind;
617fa9e4066Sahrens 	argv += optind;
618fa9e4066Sahrens 
619fa9e4066Sahrens 	/* get pool name and check number of arguments */
620fa9e4066Sahrens 	if (argc < 1) {
621fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
622990b4856Slling 		goto badusage;
623fa9e4066Sahrens 	}
624fa9e4066Sahrens 	if (argc < 2) {
625fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
626990b4856Slling 		goto badusage;
627fa9e4066Sahrens 	}
628fa9e4066Sahrens 
629fa9e4066Sahrens 	poolname = argv[0];
630fa9e4066Sahrens 
631fa9e4066Sahrens 	/*
632fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
633fa9e4066Sahrens 	 * user to use 'zfs create' instead.
634fa9e4066Sahrens 	 */
635fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
636fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
637fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
638fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
639fa9e4066Sahrens 		    "create a dataset\n"));
640990b4856Slling 		goto errout;
641fa9e4066Sahrens 	}
642fa9e4066Sahrens 
643fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
64499653d4eSeschrock 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1,
64599653d4eSeschrock 	    argv + 1);
646fa9e4066Sahrens 	if (nvroot == NULL)
647fa9e4066Sahrens 		return (1);
648fa9e4066Sahrens 
64999653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
650*85dc7ea5Sdm120769 	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
651*85dc7ea5Sdm120769 	    &child, &children) == 0);
652*85dc7ea5Sdm120769 	if (children == 0) {
65399653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
65499653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
65599653d4eSeschrock 		    "specified\n"));
656990b4856Slling 		goto errout;
65799653d4eSeschrock 	}
65899653d4eSeschrock 
65999653d4eSeschrock 
660fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
661fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
662e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
663990b4856Slling 		goto errout;
664fa9e4066Sahrens 	}
665fa9e4066Sahrens 
666fa9e4066Sahrens 	/*
667fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
668fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
669fa9e4066Sahrens 	 */
670fa9e4066Sahrens 	if (mountpoint == NULL ||
671fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
672fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
673fa9e4066Sahrens 		char buf[MAXPATHLEN];
674fa9e4066Sahrens 		struct stat64 statbuf;
675fa9e4066Sahrens 
676fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
677fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
678fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
679fa9e4066Sahrens 			    "'none'\n"), mountpoint);
680990b4856Slling 			goto errout;
681fa9e4066Sahrens 		}
682fa9e4066Sahrens 
683fa9e4066Sahrens 		if (mountpoint == NULL) {
684fa9e4066Sahrens 			if (altroot != NULL)
685fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
686fa9e4066Sahrens 				    altroot, poolname);
687fa9e4066Sahrens 			else
688fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
689fa9e4066Sahrens 				    poolname);
690fa9e4066Sahrens 		} else {
691fa9e4066Sahrens 			if (altroot != NULL)
692fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
693fa9e4066Sahrens 				    altroot, mountpoint);
694fa9e4066Sahrens 			else
695fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
696fa9e4066Sahrens 				    mountpoint);
697fa9e4066Sahrens 		}
698fa9e4066Sahrens 
699fa9e4066Sahrens 		if (stat64(buf, &statbuf) == 0 &&
700fa9e4066Sahrens 		    statbuf.st_nlink != 2) {
701fa9e4066Sahrens 			if (mountpoint == NULL)
702fa9e4066Sahrens 				(void) fprintf(stderr, gettext("default "
703fa9e4066Sahrens 				    "mountpoint '%s' exists and is not "
704fa9e4066Sahrens 				    "empty\n"), buf);
705fa9e4066Sahrens 			else
706fa9e4066Sahrens 				(void) fprintf(stderr, gettext("mountpoint "
707fa9e4066Sahrens 				    "'%s' exists and is not empty\n"), buf);
708fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
709fa9e4066Sahrens 			    "option to provide a different default\n"));
710990b4856Slling 			goto errout;
711fa9e4066Sahrens 		}
712fa9e4066Sahrens 	}
713fa9e4066Sahrens 
714fa9e4066Sahrens 	if (dryrun) {
715fa9e4066Sahrens 		/*
716fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
717fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
718fa9e4066Sahrens 		 * appropriate hierarchy.
719fa9e4066Sahrens 		 */
720fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
721fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
722fa9e4066Sahrens 
7238654d025Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7248654d025Sperrin 		if (num_logs(nvroot) > 0)
7258654d025Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
726fa9e4066Sahrens 
727fa9e4066Sahrens 		ret = 0;
728fa9e4066Sahrens 	} else {
729fa9e4066Sahrens 		/*
730fa9e4066Sahrens 		 * Hand off to libzfs.
731fa9e4066Sahrens 		 */
732990b4856Slling 		if (zpool_create(g_zfs, poolname, nvroot, props) == 0) {
73399653d4eSeschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
734fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
735fa9e4066Sahrens 			if (pool != NULL) {
736fa9e4066Sahrens 				if (mountpoint != NULL)
737fa9e4066Sahrens 					verify(zfs_prop_set(pool,
738e9dbad6fSeschrock 					    zfs_prop_to_name(
739e9dbad6fSeschrock 					    ZFS_PROP_MOUNTPOINT),
740fa9e4066Sahrens 					    mountpoint) == 0);
741fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
742da6c28aaSamw 					ret = zfs_shareall(pool);
743fa9e4066Sahrens 				zfs_close(pool);
744fa9e4066Sahrens 			}
74599653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
74699653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
74799653d4eSeschrock 			    "been omitted\n"));
748fa9e4066Sahrens 		}
749fa9e4066Sahrens 	}
750fa9e4066Sahrens 
751990b4856Slling errout:
752fa9e4066Sahrens 	nvlist_free(nvroot);
753990b4856Slling 	nvlist_free(props);
754fa9e4066Sahrens 	return (ret);
755990b4856Slling badusage:
756990b4856Slling 	nvlist_free(props);
757990b4856Slling 	usage(B_FALSE);
758990b4856Slling 	return (2);
759fa9e4066Sahrens }
760fa9e4066Sahrens 
761fa9e4066Sahrens /*
762fa9e4066Sahrens  * zpool destroy <pool>
763fa9e4066Sahrens  *
764fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
765fa9e4066Sahrens  *
766fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
767fa9e4066Sahrens  */
768fa9e4066Sahrens int
769fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
770fa9e4066Sahrens {
77199653d4eSeschrock 	boolean_t force = B_FALSE;
772fa9e4066Sahrens 	int c;
773fa9e4066Sahrens 	char *pool;
774fa9e4066Sahrens 	zpool_handle_t *zhp;
775fa9e4066Sahrens 	int ret;
776fa9e4066Sahrens 
777fa9e4066Sahrens 	/* check options */
778fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
779fa9e4066Sahrens 		switch (c) {
780fa9e4066Sahrens 		case 'f':
78199653d4eSeschrock 			force = B_TRUE;
782fa9e4066Sahrens 			break;
783fa9e4066Sahrens 		case '?':
784fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
785fa9e4066Sahrens 			    optopt);
78699653d4eSeschrock 			usage(B_FALSE);
787fa9e4066Sahrens 		}
788fa9e4066Sahrens 	}
789fa9e4066Sahrens 
790fa9e4066Sahrens 	argc -= optind;
791fa9e4066Sahrens 	argv += optind;
792fa9e4066Sahrens 
793fa9e4066Sahrens 	/* check arguments */
794fa9e4066Sahrens 	if (argc < 1) {
795fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
79699653d4eSeschrock 		usage(B_FALSE);
797fa9e4066Sahrens 	}
798fa9e4066Sahrens 	if (argc > 1) {
799fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
80099653d4eSeschrock 		usage(B_FALSE);
801fa9e4066Sahrens 	}
802fa9e4066Sahrens 
803fa9e4066Sahrens 	pool = argv[0];
804fa9e4066Sahrens 
80599653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
806fa9e4066Sahrens 		/*
807fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
808fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
809fa9e4066Sahrens 		 */
810fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
811fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
812fa9e4066Sahrens 			    "destroy a dataset\n"));
813fa9e4066Sahrens 		return (1);
814fa9e4066Sahrens 	}
815fa9e4066Sahrens 
816f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
817fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
818fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
819fa9e4066Sahrens 		return (1);
820fa9e4066Sahrens 	}
821fa9e4066Sahrens 
822fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
823fa9e4066Sahrens 
824fa9e4066Sahrens 	zpool_close(zhp);
825fa9e4066Sahrens 
826fa9e4066Sahrens 	return (ret);
827fa9e4066Sahrens }
828fa9e4066Sahrens 
829fa9e4066Sahrens /*
830fa9e4066Sahrens  * zpool export [-f] <pool> ...
831fa9e4066Sahrens  *
832fa9e4066Sahrens  *	-f	Forcefully unmount datasets
833fa9e4066Sahrens  *
834b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
835fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
836fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
837fa9e4066Sahrens  */
838fa9e4066Sahrens int
839fa9e4066Sahrens zpool_do_export(int argc, char **argv)
840fa9e4066Sahrens {
84199653d4eSeschrock 	boolean_t force = B_FALSE;
842fa9e4066Sahrens 	int c;
843fa9e4066Sahrens 	zpool_handle_t *zhp;
844fa9e4066Sahrens 	int ret;
845fa9e4066Sahrens 	int i;
846fa9e4066Sahrens 
847fa9e4066Sahrens 	/* check options */
848fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
849fa9e4066Sahrens 		switch (c) {
850fa9e4066Sahrens 		case 'f':
85199653d4eSeschrock 			force = B_TRUE;
852fa9e4066Sahrens 			break;
853fa9e4066Sahrens 		case '?':
854fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
855fa9e4066Sahrens 			    optopt);
85699653d4eSeschrock 			usage(B_FALSE);
857fa9e4066Sahrens 		}
858fa9e4066Sahrens 	}
859fa9e4066Sahrens 
860fa9e4066Sahrens 	argc -= optind;
861fa9e4066Sahrens 	argv += optind;
862fa9e4066Sahrens 
863fa9e4066Sahrens 	/* check arguments */
864fa9e4066Sahrens 	if (argc < 1) {
865fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
86699653d4eSeschrock 		usage(B_FALSE);
867fa9e4066Sahrens 	}
868fa9e4066Sahrens 
869fa9e4066Sahrens 	ret = 0;
870fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
87199653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
872fa9e4066Sahrens 			ret = 1;
873fa9e4066Sahrens 			continue;
874fa9e4066Sahrens 		}
875fa9e4066Sahrens 
876f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
877fa9e4066Sahrens 			ret = 1;
878fa9e4066Sahrens 			zpool_close(zhp);
879fa9e4066Sahrens 			continue;
880fa9e4066Sahrens 		}
881fa9e4066Sahrens 
882fa9e4066Sahrens 		if (zpool_export(zhp) != 0)
883fa9e4066Sahrens 			ret = 1;
884fa9e4066Sahrens 
885fa9e4066Sahrens 		zpool_close(zhp);
886fa9e4066Sahrens 	}
887fa9e4066Sahrens 
888fa9e4066Sahrens 	return (ret);
889fa9e4066Sahrens }
890fa9e4066Sahrens 
891fa9e4066Sahrens /*
892fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
893fa9e4066Sahrens  * name column.
894fa9e4066Sahrens  */
895fa9e4066Sahrens static int
896c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
897fa9e4066Sahrens {
89899653d4eSeschrock 	char *name = zpool_vdev_name(g_zfs, zhp, nv);
899fa9e4066Sahrens 	nvlist_t **child;
900fa9e4066Sahrens 	uint_t c, children;
901fa9e4066Sahrens 	int ret;
902fa9e4066Sahrens 
903fa9e4066Sahrens 	if (strlen(name) + depth > max)
904fa9e4066Sahrens 		max = strlen(name) + depth;
905fa9e4066Sahrens 
906afefbcddSeschrock 	free(name);
907afefbcddSeschrock 
90899653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
90999653d4eSeschrock 	    &child, &children) == 0) {
910fa9e4066Sahrens 		for (c = 0; c < children; c++)
91199653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
91299653d4eSeschrock 			    max)) > max)
913fa9e4066Sahrens 				max = ret;
91499653d4eSeschrock 	}
91599653d4eSeschrock 
916fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
917fa94a07fSbrendan 	    &child, &children) == 0) {
918fa94a07fSbrendan 		for (c = 0; c < children; c++)
919fa94a07fSbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
920fa94a07fSbrendan 			    max)) > max)
921fa94a07fSbrendan 				max = ret;
922fa94a07fSbrendan 	}
923fa94a07fSbrendan 
92499653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
92599653d4eSeschrock 	    &child, &children) == 0) {
92699653d4eSeschrock 		for (c = 0; c < children; c++)
92799653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
92899653d4eSeschrock 			    max)) > max)
92999653d4eSeschrock 				max = ret;
93099653d4eSeschrock 	}
93199653d4eSeschrock 
932fa9e4066Sahrens 
933fa9e4066Sahrens 	return (max);
934fa9e4066Sahrens }
935fa9e4066Sahrens 
936fa9e4066Sahrens 
937fa9e4066Sahrens /*
938fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
939fa9e4066Sahrens  * pool, printing out the name and status for each one.
940fa9e4066Sahrens  */
941fa9e4066Sahrens void
9428654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
9438654d025Sperrin     boolean_t print_logs)
944fa9e4066Sahrens {
945fa9e4066Sahrens 	nvlist_t **child;
946fa9e4066Sahrens 	uint_t c, children;
947fa9e4066Sahrens 	vdev_stat_t *vs;
948afefbcddSeschrock 	char *type, *vname;
949fa9e4066Sahrens 
950fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
951fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
952fa9e4066Sahrens 		return;
953fa9e4066Sahrens 
954fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
955fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
956fa9e4066Sahrens 
957fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
958990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
959fa9e4066Sahrens 
960fa9e4066Sahrens 	if (vs->vs_aux != 0) {
9613d7072f8Seschrock 		(void) printf("  ");
962fa9e4066Sahrens 
963fa9e4066Sahrens 		switch (vs->vs_aux) {
964fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
965fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
966fa9e4066Sahrens 			break;
967fa9e4066Sahrens 
968fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
969fa9e4066Sahrens 			(void) printf(gettext("missing device"));
970fa9e4066Sahrens 			break;
971fa9e4066Sahrens 
972fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
973fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
974fa9e4066Sahrens 			break;
975fa9e4066Sahrens 
976eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
977eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
978eaca9bbdSeschrock 			break;
979eaca9bbdSeschrock 
9803d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
9813d7072f8Seschrock 			(void) printf(gettext("too many errors"));
9823d7072f8Seschrock 			break;
9833d7072f8Seschrock 
984fa9e4066Sahrens 		default:
985fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
986fa9e4066Sahrens 			break;
987fa9e4066Sahrens 		}
988fa9e4066Sahrens 	}
989fa9e4066Sahrens 	(void) printf("\n");
990fa9e4066Sahrens 
991fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
992fa9e4066Sahrens 	    &child, &children) != 0)
993fa9e4066Sahrens 		return;
994fa9e4066Sahrens 
995afefbcddSeschrock 	for (c = 0; c < children; c++) {
9968654d025Sperrin 		uint64_t is_log = B_FALSE;
9978654d025Sperrin 
9988654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
9998654d025Sperrin 		    &is_log);
10008654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
10018654d025Sperrin 			continue;
10028654d025Sperrin 
100399653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1004afefbcddSeschrock 		print_import_config(vname, child[c],
10058654d025Sperrin 		    namewidth, depth + 2, B_FALSE);
1006afefbcddSeschrock 		free(vname);
1007afefbcddSeschrock 	}
100899653d4eSeschrock 
1009fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1010fa94a07fSbrendan 	    &child, &children) == 0) {
1011fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
1012fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1013fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1014fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1015fa94a07fSbrendan 			free(vname);
1016fa94a07fSbrendan 		}
1017fa94a07fSbrendan 	}
101899653d4eSeschrock 
1019fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1020fa94a07fSbrendan 	    &child, &children) == 0) {
102199653d4eSeschrock 		(void) printf(gettext("\tspares\n"));
102299653d4eSeschrock 		for (c = 0; c < children; c++) {
102399653d4eSeschrock 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
102499653d4eSeschrock 			(void) printf("\t  %s\n", vname);
102599653d4eSeschrock 			free(vname);
102699653d4eSeschrock 		}
1027fa9e4066Sahrens 	}
1028fa94a07fSbrendan }
1029fa9e4066Sahrens 
1030fa9e4066Sahrens /*
1031fa9e4066Sahrens  * Display the status for the given pool.
1032fa9e4066Sahrens  */
1033fa9e4066Sahrens static void
1034fa9e4066Sahrens show_import(nvlist_t *config)
1035fa9e4066Sahrens {
1036fa9e4066Sahrens 	uint64_t pool_state;
1037fa9e4066Sahrens 	vdev_stat_t *vs;
1038fa9e4066Sahrens 	char *name;
1039fa9e4066Sahrens 	uint64_t guid;
1040fa9e4066Sahrens 	char *msgid;
1041fa9e4066Sahrens 	nvlist_t *nvroot;
1042fa9e4066Sahrens 	int reason;
104346657f8dSmmusante 	const char *health;
1044fa9e4066Sahrens 	uint_t vsc;
1045fa9e4066Sahrens 	int namewidth;
1046fa9e4066Sahrens 
1047fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1048fa9e4066Sahrens 	    &name) == 0);
1049fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1050fa9e4066Sahrens 	    &guid) == 0);
1051fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1052fa9e4066Sahrens 	    &pool_state) == 0);
1053fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1054fa9e4066Sahrens 	    &nvroot) == 0);
1055fa9e4066Sahrens 
1056fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1057fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1058990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1059fa9e4066Sahrens 
1060fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1061fa9e4066Sahrens 
106246657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
106346657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
106446657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
10654c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
106646657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
10674c58d714Sdarrenm 	(void) printf("\n");
1068fa9e4066Sahrens 
1069fa9e4066Sahrens 	switch (reason) {
1070fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1071fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1072fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1073fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1074fa9e4066Sahrens 		    "from the system.\n"));
1075fa9e4066Sahrens 		break;
1076fa9e4066Sahrens 
1077fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1078fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1079fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1080fa9e4066Sahrens 		    "corrupted data.\n"));
1081fa9e4066Sahrens 		break;
1082fa9e4066Sahrens 
1083fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1084fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1085fa9e4066Sahrens 		break;
1086fa9e4066Sahrens 
1087441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1088441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1089441d80aaSlling 		    "are offlined.\n"));
1090441d80aaSlling 		break;
1091441d80aaSlling 
1092ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1093ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1094ea8dc4b6Seschrock 		    "corrupted.\n"));
1095ea8dc4b6Seschrock 		break;
1096ea8dc4b6Seschrock 
1097eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1098eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1099eaca9bbdSeschrock 		    "older on-disk version.\n"));
1100eaca9bbdSeschrock 		break;
1101eaca9bbdSeschrock 
1102eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1103eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1104eaca9bbdSeschrock 		    "incompatible version.\n"));
1105eaca9bbdSeschrock 		break;
110695173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
110795173954Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
110895173954Sek110237 		    "another system.\n"));
110995173954Sek110237 		break;
11103d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
11113d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
11123d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
11133d7072f8Seschrock 		    "faulted.\n"));
11143d7072f8Seschrock 		break;
11153d7072f8Seschrock 
1116fa9e4066Sahrens 	default:
1117fa9e4066Sahrens 		/*
1118fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1119fa9e4066Sahrens 		 */
1120fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1121fa9e4066Sahrens 	}
1122fa9e4066Sahrens 
1123fa9e4066Sahrens 	/*
1124fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1125fa9e4066Sahrens 	 */
112646657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1127eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1128eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1129eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1130eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1131eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
113295173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
113395173954Sek110237 			(void) printf(gettext("action: The pool can be "
113495173954Sek110237 			    "imported using its name or numeric "
113595173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1136fa9e4066Sahrens 		else
1137eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1138eaca9bbdSeschrock 			    "imported using its name or numeric "
1139eaca9bbdSeschrock 			    "identifier.\n"));
114046657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1141fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1142fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1143eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1144fa9e4066Sahrens 	} else {
1145eaca9bbdSeschrock 		switch (reason) {
1146eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1147eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1148eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1149eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1150eaca9bbdSeschrock 			    "backup.\n"));
1151eaca9bbdSeschrock 			break;
1152eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1153eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1154eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1155fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1156fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1157fa9e4066Sahrens 			    "again.\n"));
1158eaca9bbdSeschrock 			break;
1159eaca9bbdSeschrock 		default:
1160fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1161fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1162fa9e4066Sahrens 		}
1163eaca9bbdSeschrock 	}
1164eaca9bbdSeschrock 
116546657f8dSmmusante 	/*
116646657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
116746657f8dSmmusante 	 * is "corrupt data":
116846657f8dSmmusante 	 */
116946657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
117046657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
117146657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1172eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1173eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1174eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1175eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1176eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
117718ce54dfSek110237 			    "another system, but can be imported using\n\t"
1178eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1179eaca9bbdSeschrock 	}
1180fa9e4066Sahrens 
1181fa9e4066Sahrens 	if (msgid != NULL)
1182fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1183fa9e4066Sahrens 		    msgid);
1184fa9e4066Sahrens 
1185fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1186fa9e4066Sahrens 
1187c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1188fa9e4066Sahrens 	if (namewidth < 10)
1189fa9e4066Sahrens 		namewidth = 10;
11908654d025Sperrin 
11918654d025Sperrin 	print_import_config(name, nvroot, namewidth, 0, B_FALSE);
11928654d025Sperrin 	if (num_logs(nvroot) > 0) {
11938654d025Sperrin 		(void) printf(gettext("\tlogs\n"));
11948654d025Sperrin 		print_import_config(name, nvroot, namewidth, 0, B_TRUE);
11958654d025Sperrin 	}
1196fa9e4066Sahrens 
1197fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
119846657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1199fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
120046657f8dSmmusante 		    "configuration cannot be determined.\n"));
1201fa9e4066Sahrens 	}
1202fa9e4066Sahrens }
1203fa9e4066Sahrens 
1204fa9e4066Sahrens /*
1205fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1206990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1207990b4856Slling  * within the pool.
1208fa9e4066Sahrens  */
1209fa9e4066Sahrens static int
1210fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
1211990b4856Slling     int force, nvlist_t *props)
1212fa9e4066Sahrens {
1213fa9e4066Sahrens 	zpool_handle_t *zhp;
1214fa9e4066Sahrens 	char *name;
1215fa9e4066Sahrens 	uint64_t state;
1216eaca9bbdSeschrock 	uint64_t version;
1217ecd6cf80Smarks 	int error = 0;
1218fa9e4066Sahrens 
1219fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1220fa9e4066Sahrens 	    &name) == 0);
1221fa9e4066Sahrens 
1222fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1223fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1224eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1225eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1226e7437265Sahrens 	if (version > SPA_VERSION) {
1227eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1228eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1229eaca9bbdSeschrock 		return (1);
1230eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
123195173954Sek110237 		uint64_t hostid;
123295173954Sek110237 
123395173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
123495173954Sek110237 		    &hostid) == 0) {
123595173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
123695173954Sek110237 				char *hostname;
123795173954Sek110237 				uint64_t timestamp;
123895173954Sek110237 				time_t t;
123995173954Sek110237 
124095173954Sek110237 				verify(nvlist_lookup_string(config,
124195173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
124295173954Sek110237 				verify(nvlist_lookup_uint64(config,
124395173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
124495173954Sek110237 				t = timestamp;
124595173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
124695173954Sek110237 				    "'%s': pool may be in use from other "
124795173954Sek110237 				    "system, it was last accessed by %s "
124895173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
124995173954Sek110237 				    (unsigned long)hostid,
125095173954Sek110237 				    asctime(localtime(&t)));
125195173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
125295173954Sek110237 				    "import anyway\n"));
1253fa9e4066Sahrens 				return (1);
1254fa9e4066Sahrens 			}
125595173954Sek110237 		} else {
125695173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
125795173954Sek110237 			    "pool may be in use from other system\n"), name);
125895173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
125995173954Sek110237 			    "anyway\n"));
126095173954Sek110237 			return (1);
126195173954Sek110237 		}
126295173954Sek110237 	}
1263fa9e4066Sahrens 
1264990b4856Slling 	if (zpool_import_props(g_zfs, config, newname, props) != 0)
1265fa9e4066Sahrens 		return (1);
1266fa9e4066Sahrens 
1267fa9e4066Sahrens 	if (newname != NULL)
1268fa9e4066Sahrens 		name = (char *)newname;
1269fa9e4066Sahrens 
127099653d4eSeschrock 	verify((zhp = zpool_open(g_zfs, name)) != NULL);
1271fa9e4066Sahrens 
1272f3861e1aSahl 	if (zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1273fa9e4066Sahrens 		zpool_close(zhp);
1274fa9e4066Sahrens 		return (1);
1275fa9e4066Sahrens 	}
1276fa9e4066Sahrens 
1277fa9e4066Sahrens 	zpool_close(zhp);
1278ecd6cf80Smarks 	return (error);
1279fa9e4066Sahrens }
1280fa9e4066Sahrens 
1281fa9e4066Sahrens /*
12824c58d714Sdarrenm  * zpool import [-d dir] [-D]
12832f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
12842f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
12852f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
12862f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] <pool | id> [newpool]
12872f8aaab3Seschrock  *
12882f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
12892f8aaab3Seschrock  *		devices.
1290fa9e4066Sahrens  *
1291fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1292fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1293fa9e4066Sahrens  *
12944c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
12954c58d714Sdarrenm  *              specified destroyed pools.
12964c58d714Sdarrenm  *
1297fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1298fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1299fa9e4066Sahrens  *		is rebooted.
1300fa9e4066Sahrens  *
1301fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1302fa9e4066Sahrens  *
1303fa9e4066Sahrens  *       -a	Import all pools found.
1304fa9e4066Sahrens  *
1305990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1306ecd6cf80Smarks  *
1307fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1308fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1309fa9e4066Sahrens  */
1310fa9e4066Sahrens int
1311fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1312fa9e4066Sahrens {
1313fa9e4066Sahrens 	char **searchdirs = NULL;
1314fa9e4066Sahrens 	int nsearch = 0;
1315fa9e4066Sahrens 	int c;
1316fa9e4066Sahrens 	int err;
13172f8aaab3Seschrock 	nvlist_t *pools = NULL;
131899653d4eSeschrock 	boolean_t do_all = B_FALSE;
131999653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1320fa9e4066Sahrens 	char *mntopts = NULL;
132199653d4eSeschrock 	boolean_t do_force = B_FALSE;
1322fa9e4066Sahrens 	nvpair_t *elem;
1323fa9e4066Sahrens 	nvlist_t *config;
1324fa9e4066Sahrens 	uint64_t searchguid;
1325fa9e4066Sahrens 	char *searchname;
1326990b4856Slling 	char *propval;
1327fa9e4066Sahrens 	nvlist_t *found_config;
1328ecd6cf80Smarks 	nvlist_t *props = NULL;
132999653d4eSeschrock 	boolean_t first;
13304c58d714Sdarrenm 	uint64_t pool_state;
13312f8aaab3Seschrock 	char *cachefile = NULL;
1332fa9e4066Sahrens 
1333fa9e4066Sahrens 	/* check options */
13342f8aaab3Seschrock 	while ((c = getopt(argc, argv, ":afc:d:Do:p:R:")) != -1) {
1335fa9e4066Sahrens 		switch (c) {
1336fa9e4066Sahrens 		case 'a':
133799653d4eSeschrock 			do_all = B_TRUE;
1338fa9e4066Sahrens 			break;
13392f8aaab3Seschrock 		case 'c':
13402f8aaab3Seschrock 			cachefile = optarg;
13412f8aaab3Seschrock 			break;
1342fa9e4066Sahrens 		case 'd':
1343fa9e4066Sahrens 			if (searchdirs == NULL) {
1344fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1345fa9e4066Sahrens 			} else {
1346fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1347fa9e4066Sahrens 				    sizeof (char *));
1348fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1349fa9e4066Sahrens 				    sizeof (char *));
1350fa9e4066Sahrens 				free(searchdirs);
1351fa9e4066Sahrens 				searchdirs = tmp;
1352fa9e4066Sahrens 			}
1353fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1354fa9e4066Sahrens 			break;
13554c58d714Sdarrenm 		case 'D':
135699653d4eSeschrock 			do_destroyed = B_TRUE;
13574c58d714Sdarrenm 			break;
1358fa9e4066Sahrens 		case 'f':
135999653d4eSeschrock 			do_force = B_TRUE;
1360fa9e4066Sahrens 			break;
1361fa9e4066Sahrens 		case 'o':
1362990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1363990b4856Slling 				*propval = '\0';
1364990b4856Slling 				propval++;
1365990b4856Slling 				if (add_prop_list(optarg, propval, &props))
1366990b4856Slling 					goto error;
1367990b4856Slling 			} else {
1368fa9e4066Sahrens 				mntopts = optarg;
1369990b4856Slling 			}
1370fa9e4066Sahrens 			break;
1371fa9e4066Sahrens 		case 'R':
1372990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
1373990b4856Slling 			    ZPOOL_PROP_ALTROOT), optarg, &props))
1374990b4856Slling 				goto error;
13752f8aaab3Seschrock 			if (nvlist_lookup_string(props,
13762f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
13772f8aaab3Seschrock 			    &propval) == 0)
13782f8aaab3Seschrock 				break;
1379990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
13802f8aaab3Seschrock 			    ZPOOL_PROP_CACHEFILE), "none", &props))
1381990b4856Slling 				goto error;
1382fa9e4066Sahrens 			break;
1383fa9e4066Sahrens 		case ':':
1384fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1385fa9e4066Sahrens 			    "'%c' option\n"), optopt);
138699653d4eSeschrock 			usage(B_FALSE);
1387fa9e4066Sahrens 			break;
1388fa9e4066Sahrens 		case '?':
1389fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1390fa9e4066Sahrens 			    optopt);
139199653d4eSeschrock 			usage(B_FALSE);
1392fa9e4066Sahrens 		}
1393fa9e4066Sahrens 	}
1394fa9e4066Sahrens 
1395fa9e4066Sahrens 	argc -= optind;
1396fa9e4066Sahrens 	argv += optind;
1397fa9e4066Sahrens 
13982f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
13992f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
14002f8aaab3Seschrock 		usage(B_FALSE);
14012f8aaab3Seschrock 	}
14022f8aaab3Seschrock 
1403fa9e4066Sahrens 	if (searchdirs == NULL) {
1404fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1405fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1406fa9e4066Sahrens 		nsearch = 1;
1407fa9e4066Sahrens 	}
1408fa9e4066Sahrens 
1409fa9e4066Sahrens 	/* check argument count */
1410fa9e4066Sahrens 	if (do_all) {
1411fa9e4066Sahrens 		if (argc != 0) {
1412fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
141399653d4eSeschrock 			usage(B_FALSE);
1414fa9e4066Sahrens 		}
1415fa9e4066Sahrens 	} else {
1416fa9e4066Sahrens 		if (argc > 2) {
1417fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
141899653d4eSeschrock 			usage(B_FALSE);
1419fa9e4066Sahrens 		}
1420fa9e4066Sahrens 
1421fa9e4066Sahrens 		/*
1422fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1423fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1424fa9e4066Sahrens 		 * silently fail.
1425fa9e4066Sahrens 		 */
1426fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1427fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1428fa9e4066Sahrens 			    "discover pools: permission denied\n"));
142999653d4eSeschrock 			free(searchdirs);
1430fa9e4066Sahrens 			return (1);
1431fa9e4066Sahrens 		}
1432fa9e4066Sahrens 	}
1433fa9e4066Sahrens 
14342f8aaab3Seschrock 	if (cachefile)
14352f8aaab3Seschrock 		pools = zpool_find_import_cached(g_zfs, cachefile);
14362f8aaab3Seschrock 	else
14372f8aaab3Seschrock 		pools = zpool_find_import(g_zfs, nsearch, searchdirs);
14382f8aaab3Seschrock 
14392f8aaab3Seschrock 	if (pools == NULL) {
144099653d4eSeschrock 		free(searchdirs);
1441fa9e4066Sahrens 		return (1);
144299653d4eSeschrock 	}
1443fa9e4066Sahrens 
1444fa9e4066Sahrens 	/*
1445fa9e4066Sahrens 	 * We now have a list of all available pools in the given directories.
1446fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1447fa9e4066Sahrens 	 *
1448fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1449fa9e4066Sahrens 	 *		each one.
1450fa9e4066Sahrens 	 *
1451fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1452fa9e4066Sahrens 	 *
1453fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1454fa9e4066Sahrens 	 *		name and import that one.
14554c58d714Sdarrenm 	 *
14564c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1457fa9e4066Sahrens 	 */
1458fa9e4066Sahrens 	if (argc != 0) {
1459fa9e4066Sahrens 		char *endptr;
1460fa9e4066Sahrens 
1461fa9e4066Sahrens 		errno = 0;
1462fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1463fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1464fa9e4066Sahrens 			searchname = argv[0];
1465fa9e4066Sahrens 		else
1466fa9e4066Sahrens 			searchname = NULL;
1467fa9e4066Sahrens 		found_config = NULL;
1468fa9e4066Sahrens 	}
1469fa9e4066Sahrens 
1470fa9e4066Sahrens 	err = 0;
1471fa9e4066Sahrens 	elem = NULL;
147299653d4eSeschrock 	first = B_TRUE;
1473fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1474fa9e4066Sahrens 
1475fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1476fa9e4066Sahrens 
14774c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
14784c58d714Sdarrenm 		    &pool_state) == 0);
14794c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
14804c58d714Sdarrenm 			continue;
14814c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
14824c58d714Sdarrenm 			continue;
14834c58d714Sdarrenm 
1484fa9e4066Sahrens 		if (argc == 0) {
1485fa9e4066Sahrens 			if (first)
148699653d4eSeschrock 				first = B_FALSE;
14873bb79becSeschrock 			else if (!do_all)
1488fa9e4066Sahrens 				(void) printf("\n");
1489fa9e4066Sahrens 
1490fa9e4066Sahrens 			if (do_all)
1491fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1492990b4856Slling 				    do_force, props);
1493fa9e4066Sahrens 			else
1494fa9e4066Sahrens 				show_import(config);
1495fa9e4066Sahrens 		} else if (searchname != NULL) {
1496fa9e4066Sahrens 			char *name;
1497fa9e4066Sahrens 
1498fa9e4066Sahrens 			/*
1499fa9e4066Sahrens 			 * We are searching for a pool based on name.
1500fa9e4066Sahrens 			 */
1501fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1502fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1503fa9e4066Sahrens 
1504fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1505fa9e4066Sahrens 				if (found_config != NULL) {
1506fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1507fa9e4066Sahrens 					    "cannot import '%s': more than "
1508fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1509fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1510fa9e4066Sahrens 					    "import by numeric ID instead\n"));
151199653d4eSeschrock 					err = B_TRUE;
1512fa9e4066Sahrens 				}
1513fa9e4066Sahrens 				found_config = config;
1514fa9e4066Sahrens 			}
1515fa9e4066Sahrens 		} else {
1516fa9e4066Sahrens 			uint64_t guid;
1517fa9e4066Sahrens 
1518fa9e4066Sahrens 			/*
1519fa9e4066Sahrens 			 * Search for a pool by guid.
1520fa9e4066Sahrens 			 */
1521fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1522fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1523fa9e4066Sahrens 
1524fa9e4066Sahrens 			if (guid == searchguid)
1525fa9e4066Sahrens 				found_config = config;
1526fa9e4066Sahrens 		}
1527fa9e4066Sahrens 	}
1528fa9e4066Sahrens 
1529fa9e4066Sahrens 	/*
1530fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1531fa9e4066Sahrens 	 * pool, and then do the import.
1532fa9e4066Sahrens 	 */
1533fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1534fa9e4066Sahrens 		if (found_config == NULL) {
1535fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1536fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
153799653d4eSeschrock 			err = B_TRUE;
1538fa9e4066Sahrens 		} else {
1539fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1540990b4856Slling 			    argv[1], mntopts, do_force, props);
1541fa9e4066Sahrens 		}
1542fa9e4066Sahrens 	}
1543fa9e4066Sahrens 
1544fa9e4066Sahrens 	/*
1545fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1546fa9e4066Sahrens 	 * found.
1547fa9e4066Sahrens 	 */
1548fa9e4066Sahrens 	if (argc == 0 && first)
1549fa9e4066Sahrens 		(void) fprintf(stderr,
1550fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1551fa9e4066Sahrens 
1552ecd6cf80Smarks error:
1553ecd6cf80Smarks 	nvlist_free(props);
1554fa9e4066Sahrens 	nvlist_free(pools);
155599653d4eSeschrock 	free(searchdirs);
1556fa9e4066Sahrens 
1557fa9e4066Sahrens 	return (err ? 1 : 0);
1558fa9e4066Sahrens }
1559fa9e4066Sahrens 
1560fa9e4066Sahrens typedef struct iostat_cbdata {
1561fa9e4066Sahrens 	zpool_list_t *cb_list;
1562fa9e4066Sahrens 	int cb_verbose;
1563fa9e4066Sahrens 	int cb_iteration;
1564fa9e4066Sahrens 	int cb_namewidth;
1565fa9e4066Sahrens } iostat_cbdata_t;
1566fa9e4066Sahrens 
1567fa9e4066Sahrens static void
1568fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1569fa9e4066Sahrens {
1570fa9e4066Sahrens 	int i = 0;
1571fa9e4066Sahrens 
1572fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1573fa9e4066Sahrens 		(void) printf("-");
1574fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1575fa9e4066Sahrens }
1576fa9e4066Sahrens 
1577fa9e4066Sahrens static void
1578fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1579fa9e4066Sahrens {
1580fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1581fa9e4066Sahrens 	    cb->cb_namewidth, "");
1582fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1583fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1584fa9e4066Sahrens 	print_iostat_separator(cb);
1585fa9e4066Sahrens }
1586fa9e4066Sahrens 
1587fa9e4066Sahrens /*
1588fa9e4066Sahrens  * Display a single statistic.
1589fa9e4066Sahrens  */
1590990b4856Slling static void
1591fa9e4066Sahrens print_one_stat(uint64_t value)
1592fa9e4066Sahrens {
1593fa9e4066Sahrens 	char buf[64];
1594fa9e4066Sahrens 
1595fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1596fa9e4066Sahrens 	(void) printf("  %5s", buf);
1597fa9e4066Sahrens }
1598fa9e4066Sahrens 
1599fa9e4066Sahrens /*
1600fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1601fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1602fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1603fa9e4066Sahrens  */
1604fa9e4066Sahrens void
1605c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1606c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1607fa9e4066Sahrens {
1608fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1609fa9e4066Sahrens 	uint_t c, children;
1610fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1611fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1612fa9e4066Sahrens 	uint64_t tdelta;
1613fa9e4066Sahrens 	double scale;
1614afefbcddSeschrock 	char *vname;
1615fa9e4066Sahrens 
1616fa9e4066Sahrens 	if (oldnv != NULL) {
1617fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1618fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1619fa9e4066Sahrens 	} else {
1620fa9e4066Sahrens 		oldvs = &zerovs;
1621fa9e4066Sahrens 	}
1622fa9e4066Sahrens 
1623fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1624fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1625fa9e4066Sahrens 
1626fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1627fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1628fa9e4066Sahrens 	else
1629fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1630fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1631fa9e4066Sahrens 
1632fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1633fa9e4066Sahrens 
1634fa9e4066Sahrens 	if (tdelta == 0)
1635fa9e4066Sahrens 		scale = 1.0;
1636fa9e4066Sahrens 	else
1637fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1638fa9e4066Sahrens 
1639fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1640fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1641fa9e4066Sahrens 		(void) printf("      -      -");
1642fa9e4066Sahrens 	} else {
1643fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1644fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1645fa9e4066Sahrens 	}
1646fa9e4066Sahrens 
1647fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1648fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1649fa9e4066Sahrens 
1650fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1651fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1652fa9e4066Sahrens 
1653fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1654fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1655fa9e4066Sahrens 
1656fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1657fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1658fa9e4066Sahrens 
1659fa9e4066Sahrens 	(void) printf("\n");
1660fa9e4066Sahrens 
1661fa9e4066Sahrens 	if (!cb->cb_verbose)
1662fa9e4066Sahrens 		return;
1663fa9e4066Sahrens 
1664fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1665fa9e4066Sahrens 	    &newchild, &children) != 0)
1666fa9e4066Sahrens 		return;
1667fa9e4066Sahrens 
1668fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1669fa9e4066Sahrens 	    &oldchild, &c) != 0)
1670fa9e4066Sahrens 		return;
1671fa9e4066Sahrens 
1672afefbcddSeschrock 	for (c = 0; c < children; c++) {
167399653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1674c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1675afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1676afefbcddSeschrock 		free(vname);
1677afefbcddSeschrock 	}
1678fa94a07fSbrendan 
1679fa94a07fSbrendan 	/*
1680fa94a07fSbrendan 	 * Include level 2 ARC devices in iostat output
1681fa94a07fSbrendan 	 */
1682fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
1683fa94a07fSbrendan 	    &newchild, &children) != 0)
1684fa94a07fSbrendan 		return;
1685fa94a07fSbrendan 
1686fa94a07fSbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
1687fa94a07fSbrendan 	    &oldchild, &c) != 0)
1688fa94a07fSbrendan 		return;
1689fa94a07fSbrendan 
1690fa94a07fSbrendan 	if (children > 0) {
1691fa94a07fSbrendan 		(void) printf("%-*s      -      -      -      -      -      "
1692fa94a07fSbrendan 		    "-\n", cb->cb_namewidth, "cache");
1693fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1694fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1695fa94a07fSbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1696fa94a07fSbrendan 			    newchild[c], cb, depth + 2);
1697fa94a07fSbrendan 			free(vname);
1698fa94a07fSbrendan 		}
1699fa94a07fSbrendan 	}
1700fa9e4066Sahrens }
1701fa9e4066Sahrens 
1702088e9d47Seschrock static int
1703088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
1704088e9d47Seschrock {
1705088e9d47Seschrock 	iostat_cbdata_t *cb = data;
170694de1d4cSeschrock 	boolean_t missing;
1707088e9d47Seschrock 
1708088e9d47Seschrock 	/*
1709088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
1710088e9d47Seschrock 	 */
171194de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
171294de1d4cSeschrock 		return (-1);
171394de1d4cSeschrock 
171494de1d4cSeschrock 	if (missing)
1715088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
1716088e9d47Seschrock 
1717088e9d47Seschrock 	return (0);
1718088e9d47Seschrock }
1719088e9d47Seschrock 
1720fa9e4066Sahrens /*
1721fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
1722fa9e4066Sahrens  */
1723fa9e4066Sahrens int
1724fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
1725fa9e4066Sahrens {
1726fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1727fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
1728fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
1729fa9e4066Sahrens 
1730088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
1731fa9e4066Sahrens 
1732088e9d47Seschrock 	if (cb->cb_iteration == 1)
1733fa9e4066Sahrens 		oldconfig = NULL;
1734fa9e4066Sahrens 
1735fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1736fa9e4066Sahrens 	    &newnvroot) == 0);
1737fa9e4066Sahrens 
1738088e9d47Seschrock 	if (oldconfig == NULL)
1739fa9e4066Sahrens 		oldnvroot = NULL;
1740088e9d47Seschrock 	else
1741088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
1742088e9d47Seschrock 		    &oldnvroot) == 0);
1743fa9e4066Sahrens 
1744fa9e4066Sahrens 	/*
1745fa9e4066Sahrens 	 * Print out the statistics for the pool.
1746fa9e4066Sahrens 	 */
1747c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1748fa9e4066Sahrens 
1749fa9e4066Sahrens 	if (cb->cb_verbose)
1750fa9e4066Sahrens 		print_iostat_separator(cb);
1751fa9e4066Sahrens 
1752fa9e4066Sahrens 	return (0);
1753fa9e4066Sahrens }
1754fa9e4066Sahrens 
1755fa9e4066Sahrens int
1756fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
1757fa9e4066Sahrens {
1758fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1759fa9e4066Sahrens 	nvlist_t *config, *nvroot;
1760fa9e4066Sahrens 
1761088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
1762fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1763fa9e4066Sahrens 		    &nvroot) == 0);
1764fa9e4066Sahrens 		if (!cb->cb_verbose)
1765fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1766fa9e4066Sahrens 		else
1767c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
1768fa9e4066Sahrens 	}
1769fa9e4066Sahrens 
1770fa9e4066Sahrens 	/*
1771fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
1772fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
1773fa9e4066Sahrens 	 */
1774fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
1775fa9e4066Sahrens 		cb->cb_namewidth = 10;
1776fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
1777fa9e4066Sahrens 		cb->cb_namewidth = 38;
1778fa9e4066Sahrens 
1779fa9e4066Sahrens 	return (0);
1780fa9e4066Sahrens }
1781fa9e4066Sahrens 
1782fa9e4066Sahrens /*
1783fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
1784fa9e4066Sahrens  *
1785fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
1786fa9e4066Sahrens  *
1787fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
1788fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
1789fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1790fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
1791fa9e4066Sahrens  * changes are all handled within libzfs.
1792fa9e4066Sahrens  */
1793fa9e4066Sahrens int
1794fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
1795fa9e4066Sahrens {
1796fa9e4066Sahrens 	int c;
1797fa9e4066Sahrens 	int ret;
1798fa9e4066Sahrens 	int npools;
1799fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
1800fa9e4066Sahrens 	zpool_list_t *list;
180199653d4eSeschrock 	boolean_t verbose = B_FALSE;
1802fa9e4066Sahrens 	iostat_cbdata_t cb;
1803fa9e4066Sahrens 
1804fa9e4066Sahrens 	/* check options */
1805fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
1806fa9e4066Sahrens 		switch (c) {
1807fa9e4066Sahrens 		case 'v':
180899653d4eSeschrock 			verbose = B_TRUE;
1809fa9e4066Sahrens 			break;
1810fa9e4066Sahrens 		case '?':
1811fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1812fa9e4066Sahrens 			    optopt);
181399653d4eSeschrock 			usage(B_FALSE);
1814fa9e4066Sahrens 		}
1815fa9e4066Sahrens 	}
1816fa9e4066Sahrens 
1817fa9e4066Sahrens 	argc -= optind;
1818fa9e4066Sahrens 	argv += optind;
1819fa9e4066Sahrens 
1820fa9e4066Sahrens 	/*
1821fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
1822fa9e4066Sahrens 	 */
1823fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1824fa9e4066Sahrens 		char *end;
1825fa9e4066Sahrens 
1826fa9e4066Sahrens 		errno = 0;
1827fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1828fa9e4066Sahrens 
1829fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1830fa9e4066Sahrens 			if (interval == 0) {
1831fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1832fa9e4066Sahrens 				    "cannot be zero\n"));
183399653d4eSeschrock 				usage(B_FALSE);
1834fa9e4066Sahrens 			}
1835fa9e4066Sahrens 
1836fa9e4066Sahrens 			/*
1837fa9e4066Sahrens 			 * Ignore the last parameter
1838fa9e4066Sahrens 			 */
1839fa9e4066Sahrens 			argc--;
1840fa9e4066Sahrens 		} else {
1841fa9e4066Sahrens 			/*
1842fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
1843fa9e4066Sahrens 			 * user will get a more informative error message later
1844fa9e4066Sahrens 			 * on.
1845fa9e4066Sahrens 			 */
1846fa9e4066Sahrens 			interval = 0;
1847fa9e4066Sahrens 		}
1848fa9e4066Sahrens 	}
1849fa9e4066Sahrens 
1850fa9e4066Sahrens 	/*
1851fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
1852fa9e4066Sahrens 	 * and an integer.
1853fa9e4066Sahrens 	 */
1854fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1855fa9e4066Sahrens 		char *end;
1856fa9e4066Sahrens 
1857fa9e4066Sahrens 		errno = 0;
1858fa9e4066Sahrens 		count = interval;
1859fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1860fa9e4066Sahrens 
1861fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1862fa9e4066Sahrens 			if (interval == 0) {
1863fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1864fa9e4066Sahrens 				    "cannot be zero\n"));
186599653d4eSeschrock 				usage(B_FALSE);
1866fa9e4066Sahrens 			}
1867fa9e4066Sahrens 
1868fa9e4066Sahrens 			/*
1869fa9e4066Sahrens 			 * Ignore the last parameter
1870fa9e4066Sahrens 			 */
1871fa9e4066Sahrens 			argc--;
1872fa9e4066Sahrens 		} else {
1873fa9e4066Sahrens 			interval = 0;
1874fa9e4066Sahrens 		}
1875fa9e4066Sahrens 	}
1876fa9e4066Sahrens 
1877fa9e4066Sahrens 	/*
1878fa9e4066Sahrens 	 * Construct the list of all interesting pools.
1879fa9e4066Sahrens 	 */
1880fa9e4066Sahrens 	ret = 0;
1881b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
1882fa9e4066Sahrens 		return (1);
1883fa9e4066Sahrens 
188499653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
188599653d4eSeschrock 		pool_list_free(list);
1886fa9e4066Sahrens 		return (1);
188799653d4eSeschrock 	}
1888fa9e4066Sahrens 
1889fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
189099653d4eSeschrock 		pool_list_free(list);
1891fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
1892fa9e4066Sahrens 		return (1);
1893fa9e4066Sahrens 	}
1894fa9e4066Sahrens 
1895fa9e4066Sahrens 	/*
1896fa9e4066Sahrens 	 * Enter the main iostat loop.
1897fa9e4066Sahrens 	 */
1898fa9e4066Sahrens 	cb.cb_list = list;
1899fa9e4066Sahrens 	cb.cb_verbose = verbose;
1900fa9e4066Sahrens 	cb.cb_iteration = 0;
1901fa9e4066Sahrens 	cb.cb_namewidth = 0;
1902fa9e4066Sahrens 
1903fa9e4066Sahrens 	for (;;) {
1904fa9e4066Sahrens 		pool_list_update(list);
1905fa9e4066Sahrens 
1906fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
1907fa9e4066Sahrens 			break;
1908fa9e4066Sahrens 
1909fa9e4066Sahrens 		/*
1910088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
1911088e9d47Seschrock 		 * before calculating the maximum name width, so that any
1912088e9d47Seschrock 		 * configuration changes are properly accounted for.
1913088e9d47Seschrock 		 */
191499653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
1915088e9d47Seschrock 
1916088e9d47Seschrock 		/*
1917fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
1918fa9e4066Sahrens 		 * for the pool / device name column across all pools.
1919fa9e4066Sahrens 		 */
1920fa9e4066Sahrens 		cb.cb_namewidth = 0;
192199653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
1922fa9e4066Sahrens 
1923fa9e4066Sahrens 		/*
1924fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
1925fa9e4066Sahrens 		 */
1926fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
1927fa9e4066Sahrens 			print_iostat_header(&cb);
1928fa9e4066Sahrens 
192999653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
1930fa9e4066Sahrens 
1931fa9e4066Sahrens 		/*
1932fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
1933fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
1934fa9e4066Sahrens 		 */
1935fa9e4066Sahrens 		if (npools > 1 && !verbose)
1936fa9e4066Sahrens 			print_iostat_separator(&cb);
1937fa9e4066Sahrens 
1938fa9e4066Sahrens 		if (verbose)
1939fa9e4066Sahrens 			(void) printf("\n");
1940fa9e4066Sahrens 
194139c23413Seschrock 		/*
194239c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
194339c23413Seschrock 		 * indefinitely.
194439c23413Seschrock 		 */
194539c23413Seschrock 		(void) fflush(stdout);
194639c23413Seschrock 
1947fa9e4066Sahrens 		if (interval == 0)
1948fa9e4066Sahrens 			break;
1949fa9e4066Sahrens 
1950fa9e4066Sahrens 		if (count != 0 && --count == 0)
1951fa9e4066Sahrens 			break;
1952fa9e4066Sahrens 
1953fa9e4066Sahrens 		(void) sleep(interval);
1954fa9e4066Sahrens 	}
1955fa9e4066Sahrens 
1956fa9e4066Sahrens 	pool_list_free(list);
1957fa9e4066Sahrens 
1958fa9e4066Sahrens 	return (ret);
1959fa9e4066Sahrens }
1960fa9e4066Sahrens 
1961fa9e4066Sahrens typedef struct list_cbdata {
196299653d4eSeschrock 	boolean_t	cb_scripted;
196399653d4eSeschrock 	boolean_t	cb_first;
1964990b4856Slling 	zprop_list_t	*cb_proplist;
1965fa9e4066Sahrens } list_cbdata_t;
1966fa9e4066Sahrens 
1967fa9e4066Sahrens /*
1968fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
1969fa9e4066Sahrens  */
1970990b4856Slling static void
1971990b4856Slling print_header(zprop_list_t *pl)
1972fa9e4066Sahrens {
1973990b4856Slling 	const char *header;
1974990b4856Slling 	boolean_t first = B_TRUE;
1975990b4856Slling 	boolean_t right_justify;
1976fa9e4066Sahrens 
1977990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
1978990b4856Slling 		if (pl->pl_prop == ZPROP_INVAL)
1979990b4856Slling 			continue;
1980990b4856Slling 
1981990b4856Slling 		if (!first)
1982fa9e4066Sahrens 			(void) printf("  ");
1983fa9e4066Sahrens 		else
1984990b4856Slling 			first = B_FALSE;
1985fa9e4066Sahrens 
1986990b4856Slling 		header = zpool_prop_column_name(pl->pl_prop);
1987990b4856Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
1988990b4856Slling 
1989990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
1990990b4856Slling 			(void) printf("%s", header);
1991990b4856Slling 		else if (right_justify)
1992990b4856Slling 			(void) printf("%*s", pl->pl_width, header);
1993990b4856Slling 		else
1994990b4856Slling 			(void) printf("%-*s", pl->pl_width, header);
1995fa9e4066Sahrens 	}
1996fa9e4066Sahrens 
1997fa9e4066Sahrens 	(void) printf("\n");
1998fa9e4066Sahrens }
1999fa9e4066Sahrens 
2000990b4856Slling /*
2001990b4856Slling  * Given a pool and a list of properties, print out all the properties according
2002990b4856Slling  * to the described layout.
2003990b4856Slling  */
2004990b4856Slling static void
2005990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
2006990b4856Slling {
2007990b4856Slling 	boolean_t first = B_TRUE;
2008990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
2009990b4856Slling 	char *propstr;
2010990b4856Slling 	boolean_t right_justify;
2011990b4856Slling 	int width;
2012990b4856Slling 
2013990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2014990b4856Slling 		if (!first) {
2015990b4856Slling 			if (scripted)
2016990b4856Slling 				(void) printf("\t");
2017990b4856Slling 			else
2018990b4856Slling 				(void) printf("  ");
2019990b4856Slling 		} else {
2020990b4856Slling 			first = B_FALSE;
2021990b4856Slling 		}
2022990b4856Slling 
2023990b4856Slling 		right_justify = B_FALSE;
2024990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
2025990b4856Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
2026990b4856Slling 			    sizeof (property), NULL) != 0)
2027990b4856Slling 				propstr = "-";
2028990b4856Slling 			else
2029990b4856Slling 				propstr = property;
2030990b4856Slling 
2031990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2032990b4856Slling 		} else {
2033990b4856Slling 			propstr = "-";
2034990b4856Slling 		}
2035990b4856Slling 
2036990b4856Slling 		width = pl->pl_width;
2037990b4856Slling 
2038990b4856Slling 		/*
2039990b4856Slling 		 * If this is being called in scripted mode, or if this is the
2040990b4856Slling 		 * last column and it is left-justified, don't include a width
2041990b4856Slling 		 * format specifier.
2042990b4856Slling 		 */
2043990b4856Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
2044990b4856Slling 			(void) printf("%s", propstr);
2045990b4856Slling 		else if (right_justify)
2046990b4856Slling 			(void) printf("%*s", width, propstr);
2047990b4856Slling 		else
2048990b4856Slling 			(void) printf("%-*s", width, propstr);
2049990b4856Slling 	}
2050990b4856Slling 
2051990b4856Slling 	(void) printf("\n");
2052990b4856Slling }
2053990b4856Slling 
2054990b4856Slling /*
2055990b4856Slling  * Generic callback function to list a pool.
2056990b4856Slling  */
2057fa9e4066Sahrens int
2058fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2059fa9e4066Sahrens {
2060fa9e4066Sahrens 	list_cbdata_t *cbp = data;
2061fa9e4066Sahrens 
2062fa9e4066Sahrens 	if (cbp->cb_first) {
2063fa9e4066Sahrens 		if (!cbp->cb_scripted)
2064990b4856Slling 			print_header(cbp->cb_proplist);
206599653d4eSeschrock 		cbp->cb_first = B_FALSE;
2066fa9e4066Sahrens 	}
2067fa9e4066Sahrens 
2068990b4856Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2069fa9e4066Sahrens 
2070fa9e4066Sahrens 	return (0);
2071fa9e4066Sahrens }
2072fa9e4066Sahrens 
2073fa9e4066Sahrens /*
2074990b4856Slling  * zpool list [-H] [-o prop[,prop]*] [pool] ...
2075fa9e4066Sahrens  *
2076990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2077990b4856Slling  *		by a single tab.
2078990b4856Slling  *	-o	List of properties to display.  Defaults to
2079990b4856Slling  *		"name,size,used,available,capacity,health,altroot"
2080fa9e4066Sahrens  *
2081fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2082fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2083fa9e4066Sahrens  */
2084fa9e4066Sahrens int
2085fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2086fa9e4066Sahrens {
2087fa9e4066Sahrens 	int c;
2088fa9e4066Sahrens 	int ret;
2089fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2090990b4856Slling 	static char default_props[] =
2091990b4856Slling 	    "name,size,used,available,capacity,health,altroot";
2092990b4856Slling 	char *props = default_props;
2093fa9e4066Sahrens 
2094fa9e4066Sahrens 	/* check options */
2095fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2096fa9e4066Sahrens 		switch (c) {
2097fa9e4066Sahrens 		case 'H':
209899653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2099fa9e4066Sahrens 			break;
2100fa9e4066Sahrens 		case 'o':
2101990b4856Slling 			props = optarg;
2102fa9e4066Sahrens 			break;
2103fa9e4066Sahrens 		case ':':
2104fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2105fa9e4066Sahrens 			    "'%c' option\n"), optopt);
210699653d4eSeschrock 			usage(B_FALSE);
2107fa9e4066Sahrens 			break;
2108fa9e4066Sahrens 		case '?':
2109fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2110fa9e4066Sahrens 			    optopt);
211199653d4eSeschrock 			usage(B_FALSE);
2112fa9e4066Sahrens 		}
2113fa9e4066Sahrens 	}
2114fa9e4066Sahrens 
2115fa9e4066Sahrens 	argc -= optind;
2116fa9e4066Sahrens 	argv += optind;
2117fa9e4066Sahrens 
2118990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
211999653d4eSeschrock 		usage(B_FALSE);
2120fa9e4066Sahrens 
212199653d4eSeschrock 	cb.cb_first = B_TRUE;
2122fa9e4066Sahrens 
2123990b4856Slling 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2124990b4856Slling 	    list_callback, &cb);
2125990b4856Slling 
2126990b4856Slling 	zprop_free_list(cb.cb_proplist);
2127fa9e4066Sahrens 
2128fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2129fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2130fa9e4066Sahrens 		return (0);
2131fa9e4066Sahrens 	}
2132fa9e4066Sahrens 
2133fa9e4066Sahrens 	return (ret);
2134fa9e4066Sahrens }
2135fa9e4066Sahrens 
2136fa9e4066Sahrens static nvlist_t *
2137fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2138fa9e4066Sahrens {
2139fa9e4066Sahrens 	nvlist_t **child;
2140fa9e4066Sahrens 	uint_t c, children;
2141fa9e4066Sahrens 	nvlist_t *match;
2142fa9e4066Sahrens 	char *path;
2143fa9e4066Sahrens 
2144fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2145fa9e4066Sahrens 	    &child, &children) != 0) {
2146fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2147fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2148fa9e4066Sahrens 			name += 9;
2149fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2150fa9e4066Sahrens 			path += 9;
2151fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2152fa9e4066Sahrens 			return (nv);
2153fa9e4066Sahrens 		return (NULL);
2154fa9e4066Sahrens 	}
2155fa9e4066Sahrens 
2156fa9e4066Sahrens 	for (c = 0; c < children; c++)
2157fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2158fa9e4066Sahrens 			return (match);
2159fa9e4066Sahrens 
2160fa9e4066Sahrens 	return (NULL);
2161fa9e4066Sahrens }
2162fa9e4066Sahrens 
2163fa9e4066Sahrens static int
2164fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2165fa9e4066Sahrens {
216699653d4eSeschrock 	boolean_t force = B_FALSE;
2167fa9e4066Sahrens 	int c;
2168fa9e4066Sahrens 	nvlist_t *nvroot;
2169fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2170fa9e4066Sahrens 	zpool_handle_t *zhp;
217199653d4eSeschrock 	int ret;
2172fa9e4066Sahrens 
2173fa9e4066Sahrens 	/* check options */
2174fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2175fa9e4066Sahrens 		switch (c) {
2176fa9e4066Sahrens 		case 'f':
217799653d4eSeschrock 			force = B_TRUE;
2178fa9e4066Sahrens 			break;
2179fa9e4066Sahrens 		case '?':
2180fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2181fa9e4066Sahrens 			    optopt);
218299653d4eSeschrock 			usage(B_FALSE);
2183fa9e4066Sahrens 		}
2184fa9e4066Sahrens 	}
2185fa9e4066Sahrens 
2186fa9e4066Sahrens 	argc -= optind;
2187fa9e4066Sahrens 	argv += optind;
2188fa9e4066Sahrens 
2189fa9e4066Sahrens 	/* get pool name and check number of arguments */
2190fa9e4066Sahrens 	if (argc < 1) {
2191fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
219299653d4eSeschrock 		usage(B_FALSE);
2193fa9e4066Sahrens 	}
2194fa9e4066Sahrens 
2195fa9e4066Sahrens 	poolname = argv[0];
2196fa9e4066Sahrens 
2197fa9e4066Sahrens 	if (argc < 2) {
2198fa9e4066Sahrens 		(void) fprintf(stderr,
2199fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
220099653d4eSeschrock 		usage(B_FALSE);
2201fa9e4066Sahrens 	}
2202fa9e4066Sahrens 
2203fa9e4066Sahrens 	old_disk = argv[1];
2204fa9e4066Sahrens 
2205fa9e4066Sahrens 	if (argc < 3) {
2206fa9e4066Sahrens 		if (!replacing) {
2207fa9e4066Sahrens 			(void) fprintf(stderr,
2208fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
220999653d4eSeschrock 			usage(B_FALSE);
2210fa9e4066Sahrens 		}
2211fa9e4066Sahrens 		new_disk = old_disk;
2212fa9e4066Sahrens 		argc -= 1;
2213fa9e4066Sahrens 		argv += 1;
2214fa9e4066Sahrens 	} else {
2215fa9e4066Sahrens 		new_disk = argv[2];
2216fa9e4066Sahrens 		argc -= 2;
2217fa9e4066Sahrens 		argv += 2;
2218fa9e4066Sahrens 	}
2219fa9e4066Sahrens 
2220fa9e4066Sahrens 	if (argc > 1) {
2221fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
222299653d4eSeschrock 		usage(B_FALSE);
2223fa9e4066Sahrens 	}
2224fa9e4066Sahrens 
222599653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2226fa9e4066Sahrens 		return (1);
2227fa9e4066Sahrens 
22288488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2229fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2230fa9e4066Sahrens 		    poolname);
2231fa9e4066Sahrens 		zpool_close(zhp);
2232fa9e4066Sahrens 		return (1);
2233fa9e4066Sahrens 	}
2234fa9e4066Sahrens 
22358488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv);
2236fa9e4066Sahrens 	if (nvroot == NULL) {
2237fa9e4066Sahrens 		zpool_close(zhp);
2238fa9e4066Sahrens 		return (1);
2239fa9e4066Sahrens 	}
2240fa9e4066Sahrens 
224199653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
224299653d4eSeschrock 
224399653d4eSeschrock 	nvlist_free(nvroot);
224499653d4eSeschrock 	zpool_close(zhp);
224599653d4eSeschrock 
224699653d4eSeschrock 	return (ret);
2247fa9e4066Sahrens }
2248fa9e4066Sahrens 
2249fa9e4066Sahrens /*
2250fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2251fa9e4066Sahrens  *
2252fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2253fa9e4066Sahrens  *
2254fa9e4066Sahrens  * Replace <device> with <new_device>.
2255fa9e4066Sahrens  */
2256fa9e4066Sahrens /* ARGSUSED */
2257fa9e4066Sahrens int
2258fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2259fa9e4066Sahrens {
2260fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2261fa9e4066Sahrens }
2262fa9e4066Sahrens 
2263fa9e4066Sahrens /*
2264fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2265fa9e4066Sahrens  *
2266fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2267fa9e4066Sahrens  *
2268fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2269fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2270fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2271fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2272fa9e4066Sahrens  */
2273fa9e4066Sahrens int
2274fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2275fa9e4066Sahrens {
2276fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2277fa9e4066Sahrens }
2278fa9e4066Sahrens 
2279fa9e4066Sahrens /*
2280fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2281fa9e4066Sahrens  *
2282fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2283fa9e4066Sahrens  *		(not supported yet)
2284fa9e4066Sahrens  *
2285fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2286fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2287fa9e4066Sahrens  * has the only valid copy of some data.
2288fa9e4066Sahrens  */
2289fa9e4066Sahrens /* ARGSUSED */
2290fa9e4066Sahrens int
2291fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2292fa9e4066Sahrens {
2293fa9e4066Sahrens 	int c;
2294fa9e4066Sahrens 	char *poolname, *path;
2295fa9e4066Sahrens 	zpool_handle_t *zhp;
229699653d4eSeschrock 	int ret;
2297fa9e4066Sahrens 
2298fa9e4066Sahrens 	/* check options */
2299fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2300fa9e4066Sahrens 		switch (c) {
2301fa9e4066Sahrens 		case 'f':
2302fa9e4066Sahrens 		case '?':
2303fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2304fa9e4066Sahrens 			    optopt);
230599653d4eSeschrock 			usage(B_FALSE);
2306fa9e4066Sahrens 		}
2307fa9e4066Sahrens 	}
2308fa9e4066Sahrens 
2309fa9e4066Sahrens 	argc -= optind;
2310fa9e4066Sahrens 	argv += optind;
2311fa9e4066Sahrens 
2312fa9e4066Sahrens 	/* get pool name and check number of arguments */
2313fa9e4066Sahrens 	if (argc < 1) {
2314fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
231599653d4eSeschrock 		usage(B_FALSE);
2316fa9e4066Sahrens 	}
2317fa9e4066Sahrens 
2318fa9e4066Sahrens 	if (argc < 2) {
2319fa9e4066Sahrens 		(void) fprintf(stderr,
2320fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
232199653d4eSeschrock 		usage(B_FALSE);
2322fa9e4066Sahrens 	}
2323fa9e4066Sahrens 
2324fa9e4066Sahrens 	poolname = argv[0];
2325fa9e4066Sahrens 	path = argv[1];
2326fa9e4066Sahrens 
232799653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2328fa9e4066Sahrens 		return (1);
2329fa9e4066Sahrens 
233099653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
233199653d4eSeschrock 
233299653d4eSeschrock 	zpool_close(zhp);
233399653d4eSeschrock 
233499653d4eSeschrock 	return (ret);
2335fa9e4066Sahrens }
2336fa9e4066Sahrens 
2337fa9e4066Sahrens /*
2338441d80aaSlling  * zpool online <pool> <device> ...
2339fa9e4066Sahrens  */
2340fa9e4066Sahrens int
2341fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2342fa9e4066Sahrens {
2343fa9e4066Sahrens 	int c, i;
2344fa9e4066Sahrens 	char *poolname;
2345fa9e4066Sahrens 	zpool_handle_t *zhp;
2346fa9e4066Sahrens 	int ret = 0;
23473d7072f8Seschrock 	vdev_state_t newstate;
2348fa9e4066Sahrens 
2349fa9e4066Sahrens 	/* check options */
2350fa9e4066Sahrens 	while ((c = getopt(argc, argv, "t")) != -1) {
2351fa9e4066Sahrens 		switch (c) {
2352fa9e4066Sahrens 		case 't':
2353fa9e4066Sahrens 		case '?':
2354fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2355fa9e4066Sahrens 			    optopt);
235699653d4eSeschrock 			usage(B_FALSE);
2357fa9e4066Sahrens 		}
2358fa9e4066Sahrens 	}
2359fa9e4066Sahrens 
2360fa9e4066Sahrens 	argc -= optind;
2361fa9e4066Sahrens 	argv += optind;
2362fa9e4066Sahrens 
2363fa9e4066Sahrens 	/* get pool name and check number of arguments */
2364fa9e4066Sahrens 	if (argc < 1) {
2365fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
236699653d4eSeschrock 		usage(B_FALSE);
2367fa9e4066Sahrens 	}
2368fa9e4066Sahrens 	if (argc < 2) {
2369fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
237099653d4eSeschrock 		usage(B_FALSE);
2371fa9e4066Sahrens 	}
2372fa9e4066Sahrens 
2373fa9e4066Sahrens 	poolname = argv[0];
2374fa9e4066Sahrens 
237599653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2376fa9e4066Sahrens 		return (1);
2377fa9e4066Sahrens 
23783d7072f8Seschrock 	for (i = 1; i < argc; i++) {
23793d7072f8Seschrock 		if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
23803d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
23813d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
23823d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
2383fa9e4066Sahrens 				    argv[i]);
23843d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
23853d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
23863d7072f8Seschrock 					    "clear' to restore a faulted "
23873d7072f8Seschrock 					    "device\n"));
2388fa9e4066Sahrens 				else
23893d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
23903d7072f8Seschrock 					    "replace' to replace devices "
23913d7072f8Seschrock 					    "that are no longer present\n"));
23923d7072f8Seschrock 			}
23933d7072f8Seschrock 		} else {
2394fa9e4066Sahrens 			ret = 1;
23953d7072f8Seschrock 		}
23963d7072f8Seschrock 	}
2397fa9e4066Sahrens 
239899653d4eSeschrock 	zpool_close(zhp);
239999653d4eSeschrock 
2400fa9e4066Sahrens 	return (ret);
2401fa9e4066Sahrens }
2402fa9e4066Sahrens 
2403fa9e4066Sahrens /*
2404441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2405fa9e4066Sahrens  *
2406fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2407fa9e4066Sahrens  *		so would appear to compromise pool availability.
2408fa9e4066Sahrens  *		(not supported yet)
2409fa9e4066Sahrens  *
2410fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2411fa9e4066Sahrens  *		state will not be persistent across reboots.
2412fa9e4066Sahrens  */
2413fa9e4066Sahrens /* ARGSUSED */
2414fa9e4066Sahrens int
2415fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2416fa9e4066Sahrens {
2417fa9e4066Sahrens 	int c, i;
2418fa9e4066Sahrens 	char *poolname;
2419fa9e4066Sahrens 	zpool_handle_t *zhp;
242099653d4eSeschrock 	int ret = 0;
242199653d4eSeschrock 	boolean_t istmp = B_FALSE;
2422fa9e4066Sahrens 
2423fa9e4066Sahrens 	/* check options */
2424fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2425fa9e4066Sahrens 		switch (c) {
2426fa9e4066Sahrens 		case 't':
242799653d4eSeschrock 			istmp = B_TRUE;
2428441d80aaSlling 			break;
2429441d80aaSlling 		case 'f':
2430fa9e4066Sahrens 		case '?':
2431fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2432fa9e4066Sahrens 			    optopt);
243399653d4eSeschrock 			usage(B_FALSE);
2434fa9e4066Sahrens 		}
2435fa9e4066Sahrens 	}
2436fa9e4066Sahrens 
2437fa9e4066Sahrens 	argc -= optind;
2438fa9e4066Sahrens 	argv += optind;
2439fa9e4066Sahrens 
2440fa9e4066Sahrens 	/* get pool name and check number of arguments */
2441fa9e4066Sahrens 	if (argc < 1) {
2442fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
244399653d4eSeschrock 		usage(B_FALSE);
2444fa9e4066Sahrens 	}
2445fa9e4066Sahrens 	if (argc < 2) {
2446fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
244799653d4eSeschrock 		usage(B_FALSE);
2448fa9e4066Sahrens 	}
2449fa9e4066Sahrens 
2450fa9e4066Sahrens 	poolname = argv[0];
2451fa9e4066Sahrens 
245299653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2453fa9e4066Sahrens 		return (1);
2454fa9e4066Sahrens 
24553d7072f8Seschrock 	for (i = 1; i < argc; i++) {
24563d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2457fa9e4066Sahrens 			ret = 1;
24583d7072f8Seschrock 	}
2459fa9e4066Sahrens 
246099653d4eSeschrock 	zpool_close(zhp);
246199653d4eSeschrock 
2462fa9e4066Sahrens 	return (ret);
2463fa9e4066Sahrens }
2464fa9e4066Sahrens 
2465ea8dc4b6Seschrock /*
2466ea8dc4b6Seschrock  * zpool clear <pool> [device]
2467ea8dc4b6Seschrock  *
2468ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2469ea8dc4b6Seschrock  */
2470ea8dc4b6Seschrock int
2471ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2472ea8dc4b6Seschrock {
2473ea8dc4b6Seschrock 	int ret = 0;
2474ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2475ea8dc4b6Seschrock 	char *pool, *device;
2476ea8dc4b6Seschrock 
2477ea8dc4b6Seschrock 	if (argc < 2) {
2478ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
247999653d4eSeschrock 		usage(B_FALSE);
2480ea8dc4b6Seschrock 	}
2481ea8dc4b6Seschrock 
2482ea8dc4b6Seschrock 	if (argc > 3) {
2483ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
248499653d4eSeschrock 		usage(B_FALSE);
2485ea8dc4b6Seschrock 	}
2486ea8dc4b6Seschrock 
2487ea8dc4b6Seschrock 	pool = argv[1];
2488ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2489ea8dc4b6Seschrock 
249099653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, pool)) == NULL)
2491ea8dc4b6Seschrock 		return (1);
2492ea8dc4b6Seschrock 
2493ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2494ea8dc4b6Seschrock 		ret = 1;
2495ea8dc4b6Seschrock 
2496ea8dc4b6Seschrock 	zpool_close(zhp);
2497ea8dc4b6Seschrock 
2498ea8dc4b6Seschrock 	return (ret);
2499ea8dc4b6Seschrock }
2500ea8dc4b6Seschrock 
2501fa9e4066Sahrens typedef struct scrub_cbdata {
2502fa9e4066Sahrens 	int	cb_type;
250306eeb2adSek110237 	int	cb_argc;
250406eeb2adSek110237 	char	**cb_argv;
2505fa9e4066Sahrens } scrub_cbdata_t;
2506fa9e4066Sahrens 
2507fa9e4066Sahrens int
2508fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2509fa9e4066Sahrens {
2510fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
251106eeb2adSek110237 	int err;
2512fa9e4066Sahrens 
2513ea8dc4b6Seschrock 	/*
2514ea8dc4b6Seschrock 	 * Ignore faulted pools.
2515ea8dc4b6Seschrock 	 */
2516ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2517ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2518ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2519ea8dc4b6Seschrock 		return (1);
2520ea8dc4b6Seschrock 	}
2521ea8dc4b6Seschrock 
252206eeb2adSek110237 	err = zpool_scrub(zhp, cb->cb_type);
252306eeb2adSek110237 
252406eeb2adSek110237 	return (err != 0);
2525fa9e4066Sahrens }
2526fa9e4066Sahrens 
2527fa9e4066Sahrens /*
2528fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2529fa9e4066Sahrens  *
2530fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2531fa9e4066Sahrens  */
2532fa9e4066Sahrens int
2533fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2534fa9e4066Sahrens {
2535fa9e4066Sahrens 	int c;
2536fa9e4066Sahrens 	scrub_cbdata_t cb;
2537fa9e4066Sahrens 
2538fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2539fa9e4066Sahrens 
2540fa9e4066Sahrens 	/* check options */
2541fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2542fa9e4066Sahrens 		switch (c) {
2543fa9e4066Sahrens 		case 's':
2544fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2545fa9e4066Sahrens 			break;
2546fa9e4066Sahrens 		case '?':
2547fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2548fa9e4066Sahrens 			    optopt);
254999653d4eSeschrock 			usage(B_FALSE);
2550fa9e4066Sahrens 		}
2551fa9e4066Sahrens 	}
2552fa9e4066Sahrens 
255306eeb2adSek110237 	cb.cb_argc = argc;
255406eeb2adSek110237 	cb.cb_argv = argv;
2555fa9e4066Sahrens 	argc -= optind;
2556fa9e4066Sahrens 	argv += optind;
2557fa9e4066Sahrens 
2558fa9e4066Sahrens 	if (argc < 1) {
2559fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
256099653d4eSeschrock 		usage(B_FALSE);
2561fa9e4066Sahrens 	}
2562fa9e4066Sahrens 
2563b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2564fa9e4066Sahrens }
2565fa9e4066Sahrens 
2566fa9e4066Sahrens typedef struct status_cbdata {
2567fa9e4066Sahrens 	int		cb_count;
2568e9dbad6fSeschrock 	boolean_t	cb_allpools;
256999653d4eSeschrock 	boolean_t	cb_verbose;
257099653d4eSeschrock 	boolean_t	cb_explain;
257199653d4eSeschrock 	boolean_t	cb_first;
2572fa9e4066Sahrens } status_cbdata_t;
2573fa9e4066Sahrens 
2574fa9e4066Sahrens /*
2575fa9e4066Sahrens  * Print out detailed scrub status.
2576fa9e4066Sahrens  */
2577fa9e4066Sahrens void
2578fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2579fa9e4066Sahrens {
2580fa9e4066Sahrens 	vdev_stat_t *vs;
2581fa9e4066Sahrens 	uint_t vsc;
2582fa9e4066Sahrens 	time_t start, end, now;
2583fa9e4066Sahrens 	double fraction_done;
258418ce54dfSek110237 	uint64_t examined, total, minutes_left, minutes_taken;
2585fa9e4066Sahrens 	char *scrub_type;
2586fa9e4066Sahrens 
2587fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2588fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2589fa9e4066Sahrens 
2590fa9e4066Sahrens 	/*
2591fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2592fa9e4066Sahrens 	 */
2593fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2594fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2595fa9e4066Sahrens 		return;
2596fa9e4066Sahrens 	}
2597fa9e4066Sahrens 
2598fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2599fa9e4066Sahrens 	    "resilver" : "scrub";
2600fa9e4066Sahrens 
2601fa9e4066Sahrens 	start = vs->vs_scrub_start;
2602fa9e4066Sahrens 	end = vs->vs_scrub_end;
2603fa9e4066Sahrens 	now = time(NULL);
2604fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2605fa9e4066Sahrens 	total = vs->vs_alloc;
2606fa9e4066Sahrens 
2607fa9e4066Sahrens 	if (end != 0) {
260818ce54dfSek110237 		minutes_taken = (uint64_t)((end - start) / 60);
260918ce54dfSek110237 
261018ce54dfSek110237 		(void) printf(gettext("%s %s after %lluh%um with %llu errors "
261118ce54dfSek110237 		    "on %s"),
2612fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
261318ce54dfSek110237 		    (u_longlong_t)(minutes_taken / 60),
261418ce54dfSek110237 		    (uint_t)(minutes_taken % 60),
2615fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2616fa9e4066Sahrens 		return;
2617fa9e4066Sahrens 	}
2618fa9e4066Sahrens 
2619fa9e4066Sahrens 	if (examined == 0)
2620fa9e4066Sahrens 		examined = 1;
2621fa9e4066Sahrens 	if (examined > total)
2622fa9e4066Sahrens 		total = examined;
2623fa9e4066Sahrens 
2624fa9e4066Sahrens 	fraction_done = (double)examined / total;
2625fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2626fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
262718ce54dfSek110237 	minutes_taken = (uint64_t)((now - start) / 60);
2628fa9e4066Sahrens 
262918ce54dfSek110237 	(void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, "
263018ce54dfSek110237 	    "%lluh%um to go\n"),
263118ce54dfSek110237 	    scrub_type, (u_longlong_t)(minutes_taken / 60),
263218ce54dfSek110237 	    (uint_t)(minutes_taken % 60), 100 * fraction_done,
2633fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2634fa9e4066Sahrens }
2635fa9e4066Sahrens 
263699653d4eSeschrock typedef struct spare_cbdata {
263799653d4eSeschrock 	uint64_t	cb_guid;
263899653d4eSeschrock 	zpool_handle_t	*cb_zhp;
263999653d4eSeschrock } spare_cbdata_t;
264099653d4eSeschrock 
264199653d4eSeschrock static boolean_t
264299653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search)
264399653d4eSeschrock {
264499653d4eSeschrock 	uint64_t guid;
264599653d4eSeschrock 	nvlist_t **child;
264699653d4eSeschrock 	uint_t c, children;
264799653d4eSeschrock 
264899653d4eSeschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
264999653d4eSeschrock 	    search == guid)
265099653d4eSeschrock 		return (B_TRUE);
265199653d4eSeschrock 
265299653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
265399653d4eSeschrock 	    &child, &children) == 0) {
265499653d4eSeschrock 		for (c = 0; c < children; c++)
265599653d4eSeschrock 			if (find_vdev(child[c], search))
265699653d4eSeschrock 				return (B_TRUE);
265799653d4eSeschrock 	}
265899653d4eSeschrock 
265999653d4eSeschrock 	return (B_FALSE);
266099653d4eSeschrock }
266199653d4eSeschrock 
266299653d4eSeschrock static int
266399653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data)
266499653d4eSeschrock {
266599653d4eSeschrock 	spare_cbdata_t *cbp = data;
266699653d4eSeschrock 	nvlist_t *config, *nvroot;
266799653d4eSeschrock 
266899653d4eSeschrock 	config = zpool_get_config(zhp, NULL);
266999653d4eSeschrock 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
267099653d4eSeschrock 	    &nvroot) == 0);
267199653d4eSeschrock 
267299653d4eSeschrock 	if (find_vdev(nvroot, cbp->cb_guid)) {
267399653d4eSeschrock 		cbp->cb_zhp = zhp;
267499653d4eSeschrock 		return (1);
267599653d4eSeschrock 	}
267699653d4eSeschrock 
267799653d4eSeschrock 	zpool_close(zhp);
267899653d4eSeschrock 	return (0);
267999653d4eSeschrock }
268099653d4eSeschrock 
2681fa9e4066Sahrens /*
2682fa9e4066Sahrens  * Print out configuration state as requested by status_callback.
2683fa9e4066Sahrens  */
2684fa9e4066Sahrens void
2685c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
26868654d025Sperrin     int namewidth, int depth, boolean_t isspare, boolean_t print_logs)
2687fa9e4066Sahrens {
2688fa9e4066Sahrens 	nvlist_t **child;
2689fa9e4066Sahrens 	uint_t c, children;
2690fa9e4066Sahrens 	vdev_stat_t *vs;
2691ea8dc4b6Seschrock 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
2692afefbcddSeschrock 	char *vname;
2693ea8dc4b6Seschrock 	uint64_t notpresent;
269499653d4eSeschrock 	spare_cbdata_t cb;
2695990b4856Slling 	char *state;
2696fa9e4066Sahrens 
2697fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2698fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2699fa9e4066Sahrens 
2700fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2701fa9e4066Sahrens 	    &child, &children) != 0)
2702fa9e4066Sahrens 		children = 0;
2703fa9e4066Sahrens 
2704990b4856Slling 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
270599653d4eSeschrock 	if (isspare) {
270699653d4eSeschrock 		/*
270799653d4eSeschrock 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
270899653d4eSeschrock 		 * online drives.
270999653d4eSeschrock 		 */
271099653d4eSeschrock 		if (vs->vs_aux == VDEV_AUX_SPARED)
271199653d4eSeschrock 			state = "INUSE";
271299653d4eSeschrock 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
271399653d4eSeschrock 			state = "AVAIL";
271499653d4eSeschrock 	}
2715fa9e4066Sahrens 
271699653d4eSeschrock 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
271799653d4eSeschrock 	    name, state);
271899653d4eSeschrock 
271999653d4eSeschrock 	if (!isspare) {
2720fa9e4066Sahrens 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
2721fa9e4066Sahrens 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
2722fa9e4066Sahrens 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
2723fa9e4066Sahrens 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
272499653d4eSeschrock 	}
2725fa9e4066Sahrens 
2726ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2727ea8dc4b6Seschrock 	    &notpresent) == 0) {
2728ea8dc4b6Seschrock 		char *path;
2729ea8dc4b6Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
27300917b783Seschrock 		(void) printf("  was %s", path);
2731ea8dc4b6Seschrock 	} else if (vs->vs_aux != 0) {
2732fa9e4066Sahrens 		(void) printf("  ");
2733fa9e4066Sahrens 
2734fa9e4066Sahrens 		switch (vs->vs_aux) {
2735fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2736fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2737fa9e4066Sahrens 			break;
2738fa9e4066Sahrens 
2739fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2740fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2741fa9e4066Sahrens 			break;
2742fa9e4066Sahrens 
2743fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2744fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2745fa9e4066Sahrens 			break;
2746fa9e4066Sahrens 
2747eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
2748eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
2749eaca9bbdSeschrock 			break;
2750eaca9bbdSeschrock 
275199653d4eSeschrock 		case VDEV_AUX_SPARED:
275299653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
275399653d4eSeschrock 			    &cb.cb_guid) == 0);
275499653d4eSeschrock 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
275599653d4eSeschrock 				if (strcmp(zpool_get_name(cb.cb_zhp),
275699653d4eSeschrock 				    zpool_get_name(zhp)) == 0)
275799653d4eSeschrock 					(void) printf(gettext("currently in "
275899653d4eSeschrock 					    "use"));
275999653d4eSeschrock 				else
276099653d4eSeschrock 					(void) printf(gettext("in use by "
276199653d4eSeschrock 					    "pool '%s'"),
276299653d4eSeschrock 					    zpool_get_name(cb.cb_zhp));
276399653d4eSeschrock 				zpool_close(cb.cb_zhp);
276499653d4eSeschrock 			} else {
276599653d4eSeschrock 				(void) printf(gettext("currently in use"));
276699653d4eSeschrock 			}
276799653d4eSeschrock 			break;
276899653d4eSeschrock 
27693d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
27703d7072f8Seschrock 			(void) printf(gettext("too many errors"));
27713d7072f8Seschrock 			break;
27723d7072f8Seschrock 
2773fa9e4066Sahrens 		default:
2774fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2775fa9e4066Sahrens 			break;
2776fa9e4066Sahrens 		}
2777fa9e4066Sahrens 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2778fa9e4066Sahrens 		/*
2779fa9e4066Sahrens 		 * Report bytes resilvered/repaired on leaf devices.
2780fa9e4066Sahrens 		 */
2781fa9e4066Sahrens 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2782fa9e4066Sahrens 		(void) printf(gettext("  %s %s"), repaired,
2783fa9e4066Sahrens 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2784fa9e4066Sahrens 		    "resilvered" : "repaired");
2785fa9e4066Sahrens 	}
2786fa9e4066Sahrens 
2787fa9e4066Sahrens 	(void) printf("\n");
2788fa9e4066Sahrens 
2789afefbcddSeschrock 	for (c = 0; c < children; c++) {
27908654d025Sperrin 		uint64_t is_log = B_FALSE;
27918654d025Sperrin 
27928654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
27938654d025Sperrin 		    &is_log);
27948654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
27958654d025Sperrin 			continue;
279699653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
2797c67d9675Seschrock 		print_status_config(zhp, vname, child[c],
27988654d025Sperrin 		    namewidth, depth + 2, isspare, B_FALSE);
2799afefbcddSeschrock 		free(vname);
2800afefbcddSeschrock 	}
2801fa9e4066Sahrens }
2802fa9e4066Sahrens 
2803ea8dc4b6Seschrock static void
2804ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
2805ea8dc4b6Seschrock {
280675519f38Sek110237 	nvlist_t *nverrlist = NULL;
280755434c77Sek110237 	nvpair_t *elem;
280855434c77Sek110237 	char *pathname;
280955434c77Sek110237 	size_t len = MAXPATHLEN * 2;
2810ea8dc4b6Seschrock 
281155434c77Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2812ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
2813ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
2814ea8dc4b6Seschrock 		return;
2815ea8dc4b6Seschrock 	}
2816ea8dc4b6Seschrock 
281755434c77Sek110237 	(void) printf("errors: Permanent errors have been "
281855434c77Sek110237 	    "detected in the following files:\n\n");
2819ea8dc4b6Seschrock 
282055434c77Sek110237 	pathname = safe_malloc(len);
282155434c77Sek110237 	elem = NULL;
282255434c77Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
282355434c77Sek110237 		nvlist_t *nv;
282455434c77Sek110237 		uint64_t dsobj, obj;
2825ea8dc4b6Seschrock 
282655434c77Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
282755434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
282855434c77Sek110237 		    &dsobj) == 0);
282955434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
283055434c77Sek110237 		    &obj) == 0);
283155434c77Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
283255434c77Sek110237 		(void) printf("%7s %s\n", "", pathname);
2833ea8dc4b6Seschrock 	}
283455434c77Sek110237 	free(pathname);
283555434c77Sek110237 	nvlist_free(nverrlist);
2836ea8dc4b6Seschrock }
2837ea8dc4b6Seschrock 
283899653d4eSeschrock static void
283999653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
284099653d4eSeschrock     int namewidth)
284199653d4eSeschrock {
284299653d4eSeschrock 	uint_t i;
284399653d4eSeschrock 	char *name;
284499653d4eSeschrock 
284599653d4eSeschrock 	if (nspares == 0)
284699653d4eSeschrock 		return;
284799653d4eSeschrock 
284899653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
284999653d4eSeschrock 
285099653d4eSeschrock 	for (i = 0; i < nspares; i++) {
285199653d4eSeschrock 		name = zpool_vdev_name(g_zfs, zhp, spares[i]);
285299653d4eSeschrock 		print_status_config(zhp, name, spares[i],
28538654d025Sperrin 		    namewidth, 2, B_TRUE, B_FALSE);
285499653d4eSeschrock 		free(name);
285599653d4eSeschrock 	}
285699653d4eSeschrock }
285799653d4eSeschrock 
2858fa94a07fSbrendan static void
2859fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
2860fa94a07fSbrendan     int namewidth)
2861fa94a07fSbrendan {
2862fa94a07fSbrendan 	uint_t i;
2863fa94a07fSbrendan 	char *name;
2864fa94a07fSbrendan 
2865fa94a07fSbrendan 	if (nl2cache == 0)
2866fa94a07fSbrendan 		return;
2867fa94a07fSbrendan 
2868fa94a07fSbrendan 	(void) printf(gettext("\tcache\n"));
2869fa94a07fSbrendan 
2870fa94a07fSbrendan 	for (i = 0; i < nl2cache; i++) {
2871fa94a07fSbrendan 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i]);
2872fa94a07fSbrendan 		print_status_config(zhp, name, l2cache[i],
2873fa94a07fSbrendan 		    namewidth, 2, B_FALSE, B_FALSE);
2874fa94a07fSbrendan 		free(name);
2875fa94a07fSbrendan 	}
2876fa94a07fSbrendan }
2877fa94a07fSbrendan 
2878fa9e4066Sahrens /*
2879fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
2880fa9e4066Sahrens  *
2881fa9e4066Sahrens  *        pool: tank
2882fa9e4066Sahrens  *	status: DEGRADED
2883fa9e4066Sahrens  *	reason: One or more devices ...
2884fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
2885fa9e4066Sahrens  *	config:
2886fa9e4066Sahrens  *		mirror		DEGRADED
2887fa9e4066Sahrens  *                c1t0d0	OK
2888ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
2889fa9e4066Sahrens  *
2890fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
2891fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
2892fa9e4066Sahrens  */
2893fa9e4066Sahrens int
2894fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
2895fa9e4066Sahrens {
2896fa9e4066Sahrens 	status_cbdata_t *cbp = data;
2897fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2898fa9e4066Sahrens 	char *msgid;
2899fa9e4066Sahrens 	int reason;
290046657f8dSmmusante 	const char *health;
290146657f8dSmmusante 	uint_t c;
290246657f8dSmmusante 	vdev_stat_t *vs;
2903fa9e4066Sahrens 
2904088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
2905fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
2906fa9e4066Sahrens 
2907fa9e4066Sahrens 	cbp->cb_count++;
2908fa9e4066Sahrens 
2909fa9e4066Sahrens 	/*
2910fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
2911fa9e4066Sahrens 	 * problems.
2912fa9e4066Sahrens 	 */
2913e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
2914e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
2915e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
2916e9dbad6fSeschrock 			    zpool_get_name(zhp));
2917e9dbad6fSeschrock 			if (cbp->cb_first)
2918e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
2919e9dbad6fSeschrock 		}
2920fa9e4066Sahrens 		return (0);
2921e9dbad6fSeschrock 	}
2922fa9e4066Sahrens 
2923fa9e4066Sahrens 	if (cbp->cb_first)
292499653d4eSeschrock 		cbp->cb_first = B_FALSE;
2925fa9e4066Sahrens 	else
2926fa9e4066Sahrens 		(void) printf("\n");
2927fa9e4066Sahrens 
292846657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
292946657f8dSmmusante 	    &nvroot) == 0);
293046657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
293146657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
2932990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
2933fa9e4066Sahrens 
2934fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
2935fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
2936fa9e4066Sahrens 
2937fa9e4066Sahrens 	switch (reason) {
2938fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
2939fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2940fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
2941fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
2942fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2943fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2944fa9e4066Sahrens 		break;
2945fa9e4066Sahrens 
2946fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
2947fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2948fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
2949fa9e4066Sahrens 		    "pool to continue functioning.\n"));
2950fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2951fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2952fa9e4066Sahrens 		break;
2953fa9e4066Sahrens 
2954fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
2955fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2956fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
2957fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
2958fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
2959fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
2960fa9e4066Sahrens 		    "'zpool replace'.\n"));
2961fa9e4066Sahrens 		break;
2962fa9e4066Sahrens 
2963fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
2964fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2965b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
2966fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
2967fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
2968fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
2969fa9e4066Sahrens 		    "from a backup source.\n"));
2970fa9e4066Sahrens 		break;
2971fa9e4066Sahrens 
2972fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
2973fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
2974fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
2975fa9e4066Sahrens 		    "made to correct the error.  Applications are "
2976fa9e4066Sahrens 		    "unaffected.\n"));
2977fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
2978fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
2979ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
2980fa9e4066Sahrens 		    "replace'.\n"));
2981fa9e4066Sahrens 		break;
2982fa9e4066Sahrens 
2983fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
2984fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
2985d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
2986fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
2987fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
2988fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
2989fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
2990fa9e4066Sahrens 		    "replace'.\n"));
2991fa9e4066Sahrens 		break;
2992fa9e4066Sahrens 
2993fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
2994fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
2995fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
2996fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
2997fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
2998fa9e4066Sahrens 		    "complete.\n"));
2999fa9e4066Sahrens 		break;
3000fa9e4066Sahrens 
3001ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3002ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3003ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3004ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3005ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3006ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3007ea8dc4b6Seschrock 		    "backup.\n"));
3008ea8dc4b6Seschrock 		break;
3009ea8dc4b6Seschrock 
3010ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3011ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3012ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3013ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
3014ea8dc4b6Seschrock 		    "from a backup source.\n"));
3015ea8dc4b6Seschrock 		break;
3016ea8dc4b6Seschrock 
3017eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3018eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3019eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3020eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3021eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3022eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3023eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3024eaca9bbdSeschrock 		break;
3025eaca9bbdSeschrock 
3026eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3027eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3028eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3029eaca9bbdSeschrock 		    "be accessed on this system.\n"));
3030eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
3031eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
3032eaca9bbdSeschrock 		    "backup.\n"));
3033eaca9bbdSeschrock 		break;
3034eaca9bbdSeschrock 
30353d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
30363d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
30373d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
30383d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
30393d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
30403d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
30413d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
30423d7072f8Seschrock 		break;
30433d7072f8Seschrock 
30443d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
30453d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
30463d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
30473d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
30483d7072f8Seschrock 		    "functioning.\n"));
30493d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
30503d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
30513d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
30523d7072f8Seschrock 		    "to be recovered.\n"));
30533d7072f8Seschrock 		break;
30543d7072f8Seschrock 
3055fa9e4066Sahrens 	default:
3056fa9e4066Sahrens 		/*
3057fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
3058fa9e4066Sahrens 		 */
3059fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
3060fa9e4066Sahrens 	}
3061fa9e4066Sahrens 
3062fa9e4066Sahrens 	if (msgid != NULL)
3063fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3064fa9e4066Sahrens 		    msgid);
3065fa9e4066Sahrens 
3066fa9e4066Sahrens 	if (config != NULL) {
3067fa9e4066Sahrens 		int namewidth;
3068ea8dc4b6Seschrock 		uint64_t nerr;
3069fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
3070fa94a07fSbrendan 		uint_t nspares, nl2cache;
3071fa9e4066Sahrens 
3072fa9e4066Sahrens 
3073fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
3074fa9e4066Sahrens 		print_scrub_status(nvroot);
3075fa9e4066Sahrens 
3076c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3077fa9e4066Sahrens 		if (namewidth < 10)
3078fa9e4066Sahrens 			namewidth = 10;
3079fa9e4066Sahrens 
3080fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
3081fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3082fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3083c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
30848654d025Sperrin 		    namewidth, 0, B_FALSE, B_FALSE);
30858654d025Sperrin 		if (num_logs(nvroot) > 0)
30868654d025Sperrin 			print_status_config(zhp, "logs", nvroot, namewidth, 0,
30878654d025Sperrin 			    B_FALSE, B_TRUE);
308899653d4eSeschrock 
3089fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
3090fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
3091fa94a07fSbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
3092fa94a07fSbrendan 
309399653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
309499653d4eSeschrock 		    &spares, &nspares) == 0)
309599653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
3096ea8dc4b6Seschrock 
3097ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3098ea8dc4b6Seschrock 		    &nerr) == 0) {
309955434c77Sek110237 			nvlist_t *nverrlist = NULL;
310055434c77Sek110237 
3101ea8dc4b6Seschrock 			/*
3102ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3103ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3104ea8dc4b6Seschrock 			 * uniquifying the results.
3105ea8dc4b6Seschrock 			 */
310675519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
310755434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
310855434c77Sek110237 				nvpair_t *elem;
310955434c77Sek110237 
311055434c77Sek110237 				elem = NULL;
311155434c77Sek110237 				nerr = 0;
311255434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
311355434c77Sek110237 				    elem)) != NULL) {
311455434c77Sek110237 					nerr++;
311555434c77Sek110237 				}
311655434c77Sek110237 			}
311755434c77Sek110237 			nvlist_free(nverrlist);
3118ea8dc4b6Seschrock 
3119ea8dc4b6Seschrock 			(void) printf("\n");
312099653d4eSeschrock 
3121ea8dc4b6Seschrock 			if (nerr == 0)
3122ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3123ea8dc4b6Seschrock 				    "errors\n"));
3124ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3125e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
31265ad82045Snd150628 				    "errors, use '-v' for a list\n"),
31275ad82045Snd150628 				    (u_longlong_t)nerr);
3128ea8dc4b6Seschrock 			else
3129ea8dc4b6Seschrock 				print_error_log(zhp);
3130ea8dc4b6Seschrock 		}
3131fa9e4066Sahrens 	} else {
3132fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3133fa9e4066Sahrens 		    "determined.\n"));
3134fa9e4066Sahrens 	}
3135fa9e4066Sahrens 
3136fa9e4066Sahrens 	return (0);
3137fa9e4066Sahrens }
3138fa9e4066Sahrens 
3139fa9e4066Sahrens /*
3140fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3141fa9e4066Sahrens  *
3142fa9e4066Sahrens  *	-v	Display complete error logs
3143fa9e4066Sahrens  *	-x	Display only pools with potential problems
3144fa9e4066Sahrens  *
3145fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3146fa9e4066Sahrens  */
3147fa9e4066Sahrens int
3148fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3149fa9e4066Sahrens {
3150fa9e4066Sahrens 	int c;
3151fa9e4066Sahrens 	int ret;
3152fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3153fa9e4066Sahrens 
3154fa9e4066Sahrens 	/* check options */
3155fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3156fa9e4066Sahrens 		switch (c) {
3157fa9e4066Sahrens 		case 'v':
315899653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3159fa9e4066Sahrens 			break;
3160fa9e4066Sahrens 		case 'x':
316199653d4eSeschrock 			cb.cb_explain = B_TRUE;
3162fa9e4066Sahrens 			break;
3163fa9e4066Sahrens 		case '?':
3164fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3165fa9e4066Sahrens 			    optopt);
316699653d4eSeschrock 			usage(B_FALSE);
3167fa9e4066Sahrens 		}
3168fa9e4066Sahrens 	}
3169fa9e4066Sahrens 
3170fa9e4066Sahrens 	argc -= optind;
3171fa9e4066Sahrens 	argv += optind;
3172fa9e4066Sahrens 
317399653d4eSeschrock 	cb.cb_first = B_TRUE;
3174fa9e4066Sahrens 
3175e9dbad6fSeschrock 	if (argc == 0)
3176e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3177e9dbad6fSeschrock 
3178b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3179fa9e4066Sahrens 
3180fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3181fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3182e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3183fa9e4066Sahrens 		(void) printf(gettext("all pools are healthy\n"));
3184fa9e4066Sahrens 
3185fa9e4066Sahrens 	return (ret);
3186fa9e4066Sahrens }
3187fa9e4066Sahrens 
3188eaca9bbdSeschrock typedef struct upgrade_cbdata {
3189eaca9bbdSeschrock 	int	cb_all;
3190eaca9bbdSeschrock 	int	cb_first;
3191eaca9bbdSeschrock 	int	cb_newer;
319206eeb2adSek110237 	int	cb_argc;
3193990b4856Slling 	uint64_t cb_version;
319406eeb2adSek110237 	char	**cb_argv;
3195eaca9bbdSeschrock } upgrade_cbdata_t;
3196eaca9bbdSeschrock 
3197eaca9bbdSeschrock static int
3198eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3199eaca9bbdSeschrock {
3200eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3201eaca9bbdSeschrock 	nvlist_t *config;
3202eaca9bbdSeschrock 	uint64_t version;
3203eaca9bbdSeschrock 	int ret = 0;
3204eaca9bbdSeschrock 
3205eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3206eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3207eaca9bbdSeschrock 	    &version) == 0);
3208eaca9bbdSeschrock 
3209e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3210eaca9bbdSeschrock 		if (!cbp->cb_all) {
3211eaca9bbdSeschrock 			if (cbp->cb_first) {
3212eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3213eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3214eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3215eaca9bbdSeschrock 				    "longer be accessible by older software "
3216eaca9bbdSeschrock 				    "versions.\n\n"));
3217eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3218eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
321999653d4eSeschrock 				cbp->cb_first = B_FALSE;
3220eaca9bbdSeschrock 			}
3221eaca9bbdSeschrock 
32225ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3223eaca9bbdSeschrock 			    zpool_get_name(zhp));
3224eaca9bbdSeschrock 		} else {
322599653d4eSeschrock 			cbp->cb_first = B_FALSE;
3226990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
322706eeb2adSek110237 			if (!ret) {
3228eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3229990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
3230eaca9bbdSeschrock 			}
323106eeb2adSek110237 		}
3232e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3233eaca9bbdSeschrock 		assert(!cbp->cb_all);
3234eaca9bbdSeschrock 
3235eaca9bbdSeschrock 		if (cbp->cb_first) {
3236eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3237eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3238eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3239eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3240eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
324199653d4eSeschrock 			cbp->cb_first = B_FALSE;
3242eaca9bbdSeschrock 		}
3243eaca9bbdSeschrock 
32445ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3245eaca9bbdSeschrock 		    zpool_get_name(zhp));
3246eaca9bbdSeschrock 	}
3247eaca9bbdSeschrock 
3248eaca9bbdSeschrock 	zpool_close(zhp);
3249eaca9bbdSeschrock 	return (ret);
3250eaca9bbdSeschrock }
3251eaca9bbdSeschrock 
3252eaca9bbdSeschrock /* ARGSUSED */
3253eaca9bbdSeschrock static int
325406eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
3255eaca9bbdSeschrock {
3256990b4856Slling 	upgrade_cbdata_t *cbp = data;
3257990b4856Slling 	uint64_t cur_version;
3258eaca9bbdSeschrock 	int ret;
3259eaca9bbdSeschrock 
32608654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
32618654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
32628654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
32638654d025Sperrin 		    " to upgrade.\n"));
32648654d025Sperrin 		return (1);
32658654d025Sperrin 	}
3266990b4856Slling 
3267990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3268990b4856Slling 	if (cur_version >= cbp->cb_version) {
3269eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3270990b4856Slling 		    "using more current version '%d'.\n"), zpool_get_name(zhp),
3271990b4856Slling 		    cur_version);
3272eaca9bbdSeschrock 		return (0);
3273eaca9bbdSeschrock 	}
3274eaca9bbdSeschrock 
3275990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
327606eeb2adSek110237 
327706eeb2adSek110237 	if (!ret) {
327844cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
3279990b4856Slling 		    "from version %llu to version %llu\n\n"),
3280990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3281990b4856Slling 		    (u_longlong_t)cbp->cb_version);
328206eeb2adSek110237 	}
3283eaca9bbdSeschrock 
3284eaca9bbdSeschrock 	return (ret != 0);
3285eaca9bbdSeschrock }
3286eaca9bbdSeschrock 
3287eaca9bbdSeschrock /*
3288eaca9bbdSeschrock  * zpool upgrade
3289eaca9bbdSeschrock  * zpool upgrade -v
3290990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
3291eaca9bbdSeschrock  *
3292eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3293eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3294eaca9bbdSeschrock  * upgrade all pools.
3295eaca9bbdSeschrock  */
3296eaca9bbdSeschrock int
3297eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3298eaca9bbdSeschrock {
3299eaca9bbdSeschrock 	int c;
3300eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3301eaca9bbdSeschrock 	int ret = 0;
3302eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3303990b4856Slling 	char *end;
3304990b4856Slling 
3305eaca9bbdSeschrock 
3306eaca9bbdSeschrock 	/* check options */
3307990b4856Slling 	while ((c = getopt(argc, argv, "avV:")) != -1) {
3308eaca9bbdSeschrock 		switch (c) {
3309eaca9bbdSeschrock 		case 'a':
331099653d4eSeschrock 			cb.cb_all = B_TRUE;
3311eaca9bbdSeschrock 			break;
3312eaca9bbdSeschrock 		case 'v':
3313eaca9bbdSeschrock 			showversions = B_TRUE;
3314eaca9bbdSeschrock 			break;
3315990b4856Slling 		case 'V':
3316990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
3317351420b3Slling 			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
3318351420b3Slling 			    cb.cb_version < SPA_VERSION_1) {
3319990b4856Slling 				(void) fprintf(stderr,
3320990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
3321990b4856Slling 				usage(B_FALSE);
3322990b4856Slling 			}
3323990b4856Slling 			break;
3324eaca9bbdSeschrock 		case '?':
3325eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3326eaca9bbdSeschrock 			    optopt);
332799653d4eSeschrock 			usage(B_FALSE);
3328eaca9bbdSeschrock 		}
3329eaca9bbdSeschrock 	}
3330eaca9bbdSeschrock 
333106eeb2adSek110237 	cb.cb_argc = argc;
333206eeb2adSek110237 	cb.cb_argv = argv;
3333eaca9bbdSeschrock 	argc -= optind;
3334eaca9bbdSeschrock 	argv += optind;
3335eaca9bbdSeschrock 
3336351420b3Slling 	if (cb.cb_version == 0) {
3337351420b3Slling 		cb.cb_version = SPA_VERSION;
3338351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
3339351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
3340351420b3Slling 		    "incompatible with other arguments\n"));
3341351420b3Slling 		usage(B_FALSE);
3342351420b3Slling 	}
3343351420b3Slling 
3344eaca9bbdSeschrock 	if (showversions) {
3345eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3346eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3347eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
334899653d4eSeschrock 			usage(B_FALSE);
3349eaca9bbdSeschrock 		}
3350eaca9bbdSeschrock 	} else if (cb.cb_all) {
3351eaca9bbdSeschrock 		if (argc != 0) {
3352351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
3353351420b3Slling 			    "be used along with a pool name\n"));
335499653d4eSeschrock 			usage(B_FALSE);
3355eaca9bbdSeschrock 		}
3356eaca9bbdSeschrock 	}
3357eaca9bbdSeschrock 
3358e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3359e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
336099653d4eSeschrock 	cb.cb_first = B_TRUE;
3361eaca9bbdSeschrock 	if (showversions) {
3362eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3363d7d4af51Smmusante 		    "supported:\n\n"));
3364eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3365eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3366eaca9bbdSeschrock 		    "---------------\n");
336799653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
336844cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
336944cd46caSbillm 		    "(replicated metadata)\n"));
337099653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
337199653d4eSeschrock 		    "RAID-Z\n"));
3372d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
3373c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3374c9431fa1Sahl 		    "algorithm\n"));
3375990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
33768654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3377ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
3378a9799022Sck153898 		(void) printf(gettext(" 9   refquota and refreservation "
3379a9799022Sck153898 		    "properties\n"));
3380fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
33818654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3382eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3383eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3384eaca9bbdSeschrock 		    "version/N\n\n");
3385eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3386eaca9bbdSeschrock 	} else if (argc == 0) {
3387eaca9bbdSeschrock 		int notfound;
3388eaca9bbdSeschrock 
338999653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3390eaca9bbdSeschrock 		notfound = cb.cb_first;
3391eaca9bbdSeschrock 
3392eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3393eaca9bbdSeschrock 			if (!cb.cb_first)
3394eaca9bbdSeschrock 				(void) printf("\n");
3395eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3396eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
339799653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3398eaca9bbdSeschrock 			if (!cb.cb_first) {
3399eaca9bbdSeschrock 				notfound = B_FALSE;
3400eaca9bbdSeschrock 				(void) printf("\n");
3401eaca9bbdSeschrock 			}
3402eaca9bbdSeschrock 		}
3403eaca9bbdSeschrock 
3404eaca9bbdSeschrock 		if (ret == 0) {
3405eaca9bbdSeschrock 			if (notfound)
3406eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3407eaca9bbdSeschrock 				    "using this version.\n"));
3408eaca9bbdSeschrock 			else if (!cb.cb_all)
3409eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3410eaca9bbdSeschrock 				    "for a list of available versions and "
3411eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3412eaca9bbdSeschrock 		}
3413eaca9bbdSeschrock 	} else {
3414b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3415b1b8ab34Slling 		    upgrade_one, &cb);
341606eeb2adSek110237 	}
341706eeb2adSek110237 
341806eeb2adSek110237 	return (ret);
341906eeb2adSek110237 }
342006eeb2adSek110237 
3421ecd6cf80Smarks typedef struct hist_cbdata {
3422ecd6cf80Smarks 	boolean_t first;
3423ecd6cf80Smarks 	int longfmt;
3424ecd6cf80Smarks 	int internal;
3425ecd6cf80Smarks } hist_cbdata_t;
3426ecd6cf80Smarks 
3427ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3428ecd6cf80Smarks 	"invalid event",
3429ecd6cf80Smarks 	"pool create",
3430ecd6cf80Smarks 	"vdev add",
3431ecd6cf80Smarks 	"pool remove",
3432ecd6cf80Smarks 	"pool destroy",
3433ecd6cf80Smarks 	"pool export",
3434ecd6cf80Smarks 	"pool import",
3435ecd6cf80Smarks 	"vdev attach",
3436ecd6cf80Smarks 	"vdev replace",
3437ecd6cf80Smarks 	"vdev detach",
3438ecd6cf80Smarks 	"vdev online",
3439ecd6cf80Smarks 	"vdev offline",
3440ecd6cf80Smarks 	"vdev upgrade",
3441ecd6cf80Smarks 	"pool clear",
3442ecd6cf80Smarks 	"pool scrub",
3443ecd6cf80Smarks 	"pool property set",
3444ecd6cf80Smarks 	"create",
3445ecd6cf80Smarks 	"clone",
3446ecd6cf80Smarks 	"destroy",
3447ecd6cf80Smarks 	"destroy_begin_sync",
3448ecd6cf80Smarks 	"inherit",
3449ecd6cf80Smarks 	"property set",
3450ecd6cf80Smarks 	"quota set",
3451ecd6cf80Smarks 	"permission update",
3452ecd6cf80Smarks 	"permission remove",
3453ecd6cf80Smarks 	"permission who remove",
3454ecd6cf80Smarks 	"promote",
3455ecd6cf80Smarks 	"receive",
3456ecd6cf80Smarks 	"rename",
3457ecd6cf80Smarks 	"reservation set",
3458ecd6cf80Smarks 	"replay_inc_sync",
3459ecd6cf80Smarks 	"replay_full_sync",
3460ecd6cf80Smarks 	"rollback",
3461ecd6cf80Smarks 	"snapshot",
3462e7437265Sahrens 	"filesystem version upgrade",
3463a9799022Sck153898 	"refquota set",
3464a9799022Sck153898 	"refreservation set",
3465ecd6cf80Smarks };
3466ecd6cf80Smarks 
346706eeb2adSek110237 /*
346806eeb2adSek110237  * Print out the command history for a specific pool.
346906eeb2adSek110237  */
347006eeb2adSek110237 static int
347106eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
347206eeb2adSek110237 {
347306eeb2adSek110237 	nvlist_t *nvhis;
347406eeb2adSek110237 	nvlist_t **records;
347506eeb2adSek110237 	uint_t numrecords;
347606eeb2adSek110237 	char *cmdstr;
3477ecd6cf80Smarks 	char *pathstr;
347806eeb2adSek110237 	uint64_t dst_time;
347906eeb2adSek110237 	time_t tsec;
348006eeb2adSek110237 	struct tm t;
348106eeb2adSek110237 	char tbuf[30];
348206eeb2adSek110237 	int ret, i;
3483ecd6cf80Smarks 	uint64_t who;
3484ecd6cf80Smarks 	struct passwd *pwd;
3485ecd6cf80Smarks 	char *hostname;
3486ecd6cf80Smarks 	char *zonename;
3487ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3488ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3489ecd6cf80Smarks 	uint64_t txg;
3490ecd6cf80Smarks 	uint64_t ievent;
349106eeb2adSek110237 
3492ecd6cf80Smarks 	cb->first = B_FALSE;
349306eeb2adSek110237 
349406eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
349506eeb2adSek110237 
349606eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
349706eeb2adSek110237 		return (ret);
349806eeb2adSek110237 
349906eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
350006eeb2adSek110237 	    &records, &numrecords) == 0);
350106eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
350206eeb2adSek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3503ecd6cf80Smarks 		    &dst_time) != 0)
3504ecd6cf80Smarks 			continue;
3505ecd6cf80Smarks 
3506ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3507ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3508ecd6cf80Smarks 		    &cmdstr) != 0) {
3509ecd6cf80Smarks 			if (cb->internal == 0)
3510ecd6cf80Smarks 				continue;
3511ecd6cf80Smarks 
3512ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3513ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3514ecd6cf80Smarks 				continue;
3515ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3516ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3517ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3518ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3519ecd6cf80Smarks 			if (ievent > LOG_END)
3520ecd6cf80Smarks 				continue;
3521ecd6cf80Smarks 			(void) snprintf(internalstr,
3522ecd6cf80Smarks 			    sizeof (internalstr),
3523ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3524ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3525ecd6cf80Smarks 			    pathstr);
3526ecd6cf80Smarks 			cmdstr = internalstr;
3527ecd6cf80Smarks 		}
352806eeb2adSek110237 		tsec = dst_time;
352906eeb2adSek110237 		(void) localtime_r(&tsec, &t);
353006eeb2adSek110237 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3531ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3532ecd6cf80Smarks 
3533ecd6cf80Smarks 		if (!cb->longfmt) {
3534ecd6cf80Smarks 			(void) printf("\n");
3535ecd6cf80Smarks 			continue;
353606eeb2adSek110237 		}
3537ecd6cf80Smarks 		(void) printf(" [");
3538ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3539ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3540ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3541ecd6cf80Smarks 			if (pwd)
3542ecd6cf80Smarks 				(void) printf("user %s on",
3543ecd6cf80Smarks 				    pwd->pw_name);
3544ecd6cf80Smarks 			else
3545ecd6cf80Smarks 				(void) printf("user %d on",
3546ecd6cf80Smarks 				    (int)who);
3547ecd6cf80Smarks 		} else {
3548ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3549ecd6cf80Smarks 			continue;
3550ecd6cf80Smarks 		}
3551ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3552ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3553ecd6cf80Smarks 			(void) printf(" %s", hostname);
3554ecd6cf80Smarks 		}
3555ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3556ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3557ecd6cf80Smarks 			(void) printf(":%s", zonename);
3558ecd6cf80Smarks 		}
3559ecd6cf80Smarks 
3560ecd6cf80Smarks 		(void) printf("]");
3561ecd6cf80Smarks 		(void) printf("\n");
356206eeb2adSek110237 	}
356306eeb2adSek110237 	(void) printf("\n");
356406eeb2adSek110237 	nvlist_free(nvhis);
356506eeb2adSek110237 
356606eeb2adSek110237 	return (ret);
356706eeb2adSek110237 }
356806eeb2adSek110237 
356906eeb2adSek110237 /*
357006eeb2adSek110237  * zpool history <pool>
357106eeb2adSek110237  *
357206eeb2adSek110237  * Displays the history of commands that modified pools.
357306eeb2adSek110237  */
3574ecd6cf80Smarks 
3575ecd6cf80Smarks 
357606eeb2adSek110237 int
357706eeb2adSek110237 zpool_do_history(int argc, char **argv)
357806eeb2adSek110237 {
3579ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
358006eeb2adSek110237 	int ret;
3581ecd6cf80Smarks 	int c;
358206eeb2adSek110237 
3583ecd6cf80Smarks 	cbdata.first = B_TRUE;
3584ecd6cf80Smarks 	/* check options */
3585ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3586ecd6cf80Smarks 		switch (c) {
3587ecd6cf80Smarks 		case 'l':
3588ecd6cf80Smarks 			cbdata.longfmt = 1;
3589ecd6cf80Smarks 			break;
3590ecd6cf80Smarks 		case 'i':
3591ecd6cf80Smarks 			cbdata.internal = 1;
3592ecd6cf80Smarks 			break;
3593ecd6cf80Smarks 		case '?':
3594ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3595ecd6cf80Smarks 			    optopt);
3596ecd6cf80Smarks 			usage(B_FALSE);
3597ecd6cf80Smarks 		}
3598ecd6cf80Smarks 	}
359906eeb2adSek110237 	argc -= optind;
360006eeb2adSek110237 	argv += optind;
360106eeb2adSek110237 
3602b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3603ecd6cf80Smarks 	    &cbdata);
360406eeb2adSek110237 
3605ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
360606eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
360706eeb2adSek110237 		return (0);
3608eaca9bbdSeschrock 	}
3609eaca9bbdSeschrock 
3610eaca9bbdSeschrock 	return (ret);
3611eaca9bbdSeschrock }
3612eaca9bbdSeschrock 
3613b1b8ab34Slling static int
3614b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3615b1b8ab34Slling {
3616990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3617b1b8ab34Slling 	char value[MAXNAMELEN];
3618990b4856Slling 	zprop_source_t srctype;
3619990b4856Slling 	zprop_list_t *pl;
3620b1b8ab34Slling 
3621b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3622b1b8ab34Slling 
3623b1b8ab34Slling 		/*
3624990b4856Slling 		 * Skip the special fake placeholder. This will also skip
3625990b4856Slling 		 * over the name property when 'all' is specified.
3626b1b8ab34Slling 		 */
3627990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3628b1b8ab34Slling 		    pl == cbp->cb_proplist)
3629b1b8ab34Slling 			continue;
3630b1b8ab34Slling 
3631b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3632b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3633b1b8ab34Slling 			continue;
3634b1b8ab34Slling 
3635990b4856Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
3636b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3637b1b8ab34Slling 	}
3638b1b8ab34Slling 	return (0);
3639b1b8ab34Slling }
3640b1b8ab34Slling 
3641b1b8ab34Slling int
3642b1b8ab34Slling zpool_do_get(int argc, char **argv)
3643b1b8ab34Slling {
3644990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
3645990b4856Slling 	zprop_list_t fake_name = { 0 };
3646b1b8ab34Slling 	int ret;
3647b1b8ab34Slling 
3648b1b8ab34Slling 	if (argc < 3)
3649b1b8ab34Slling 		usage(B_FALSE);
3650b1b8ab34Slling 
3651b1b8ab34Slling 	cb.cb_first = B_TRUE;
3652990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
3653b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3654b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3655b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3656b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3657990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
3658b1b8ab34Slling 
3659990b4856Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3660990b4856Slling 	    ZFS_TYPE_POOL) != 0)
3661b1b8ab34Slling 		usage(B_FALSE);
3662b1b8ab34Slling 
3663b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3664990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
3665b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3666b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3667b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3668b1b8ab34Slling 	}
3669b1b8ab34Slling 
3670b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3671b1b8ab34Slling 	    get_callback, &cb);
3672b1b8ab34Slling 
3673b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3674990b4856Slling 		zprop_free_list(fake_name.pl_next);
3675b1b8ab34Slling 	else
3676990b4856Slling 		zprop_free_list(cb.cb_proplist);
3677b1b8ab34Slling 
3678b1b8ab34Slling 	return (ret);
3679b1b8ab34Slling }
3680b1b8ab34Slling 
3681b1b8ab34Slling typedef struct set_cbdata {
3682b1b8ab34Slling 	char *cb_propname;
3683b1b8ab34Slling 	char *cb_value;
3684b1b8ab34Slling 	boolean_t cb_any_successful;
3685b1b8ab34Slling } set_cbdata_t;
3686b1b8ab34Slling 
3687b1b8ab34Slling int
3688b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3689b1b8ab34Slling {
3690b1b8ab34Slling 	int error;
3691b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3692b1b8ab34Slling 
3693b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3694b1b8ab34Slling 
3695b1b8ab34Slling 	if (!error)
3696b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3697b1b8ab34Slling 
3698b1b8ab34Slling 	return (error);
3699b1b8ab34Slling }
3700b1b8ab34Slling 
3701b1b8ab34Slling int
3702b1b8ab34Slling zpool_do_set(int argc, char **argv)
3703b1b8ab34Slling {
3704b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3705b1b8ab34Slling 	int error;
3706b1b8ab34Slling 
3707b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3708b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3709b1b8ab34Slling 		    argv[1][1]);
3710b1b8ab34Slling 		usage(B_FALSE);
3711b1b8ab34Slling 	}
3712b1b8ab34Slling 
3713b1b8ab34Slling 	if (argc < 2) {
3714b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3715b1b8ab34Slling 		    "argument\n"));
3716b1b8ab34Slling 		usage(B_FALSE);
3717b1b8ab34Slling 	}
3718b1b8ab34Slling 
3719b1b8ab34Slling 	if (argc < 3) {
3720b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3721b1b8ab34Slling 		usage(B_FALSE);
3722b1b8ab34Slling 	}
3723b1b8ab34Slling 
3724b1b8ab34Slling 	if (argc > 3) {
3725b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3726b1b8ab34Slling 		usage(B_FALSE);
3727b1b8ab34Slling 	}
3728b1b8ab34Slling 
3729b1b8ab34Slling 	cb.cb_propname = argv[1];
3730b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3731b1b8ab34Slling 	if (cb.cb_value == NULL) {
3732b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3733b1b8ab34Slling 		    "property=value argument\n"));
3734b1b8ab34Slling 		usage(B_FALSE);
3735b1b8ab34Slling 	}
3736b1b8ab34Slling 
3737b1b8ab34Slling 	*(cb.cb_value) = '\0';
3738b1b8ab34Slling 	cb.cb_value++;
3739b1b8ab34Slling 
3740b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3741b1b8ab34Slling 	    set_callback, &cb);
3742b1b8ab34Slling 
3743b1b8ab34Slling 	return (error);
3744b1b8ab34Slling }
3745b1b8ab34Slling 
3746b1b8ab34Slling static int
3747b1b8ab34Slling find_command_idx(char *command, int *idx)
3748b1b8ab34Slling {
3749b1b8ab34Slling 	int i;
3750b1b8ab34Slling 
3751b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3752b1b8ab34Slling 		if (command_table[i].name == NULL)
3753b1b8ab34Slling 			continue;
3754b1b8ab34Slling 
3755b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3756b1b8ab34Slling 			*idx = i;
3757b1b8ab34Slling 			return (0);
3758b1b8ab34Slling 		}
3759b1b8ab34Slling 	}
3760b1b8ab34Slling 	return (1);
3761b1b8ab34Slling }
3762b1b8ab34Slling 
3763fa9e4066Sahrens int
3764fa9e4066Sahrens main(int argc, char **argv)
3765fa9e4066Sahrens {
3766fa9e4066Sahrens 	int ret;
3767fa9e4066Sahrens 	int i;
3768fa9e4066Sahrens 	char *cmdname;
3769fa9e4066Sahrens 
3770fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3771fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3772fa9e4066Sahrens 
377399653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
377499653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3775203a47d8Snd150628 		    "initialize ZFS library\n"));
377699653d4eSeschrock 		return (1);
377799653d4eSeschrock 	}
377899653d4eSeschrock 
377999653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
378099653d4eSeschrock 
3781fa9e4066Sahrens 	opterr = 0;
3782fa9e4066Sahrens 
3783fa9e4066Sahrens 	/*
3784fa9e4066Sahrens 	 * Make sure the user has specified some command.
3785fa9e4066Sahrens 	 */
3786fa9e4066Sahrens 	if (argc < 2) {
3787fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
378899653d4eSeschrock 		usage(B_FALSE);
3789fa9e4066Sahrens 	}
3790fa9e4066Sahrens 
3791fa9e4066Sahrens 	cmdname = argv[1];
3792fa9e4066Sahrens 
3793fa9e4066Sahrens 	/*
3794fa9e4066Sahrens 	 * Special case '-?'
3795fa9e4066Sahrens 	 */
3796fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
379799653d4eSeschrock 		usage(B_TRUE);
3798fa9e4066Sahrens 
37992a6b87f0Sek110237 	zpool_set_history_str("zpool", argc, argv, history_str);
38002a6b87f0Sek110237 	verify(zpool_stage_history(g_zfs, history_str) == 0);
38012a6b87f0Sek110237 
3802fa9e4066Sahrens 	/*
3803fa9e4066Sahrens 	 * Run the appropriate command.
3804fa9e4066Sahrens 	 */
3805b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
3806fa9e4066Sahrens 		current_command = &command_table[i];
3807fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
380891ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
380991ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
381091ebeef5Sahrens 		current_command = &command_table[i];
381191ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
381291ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
3813fa9e4066Sahrens 		/*
381491ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
381591ebeef5Sahrens 		 * it as such.
3816fa9e4066Sahrens 		 */
3817ea8dc4b6Seschrock 		char buf[16384];
3818ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
3819fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
3820fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
382191ebeef5Sahrens 	} else {
3822fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
3823fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
382499653d4eSeschrock 		usage(B_FALSE);
3825fa9e4066Sahrens 	}
3826fa9e4066Sahrens 
382799653d4eSeschrock 	libzfs_fini(g_zfs);
382899653d4eSeschrock 
3829fa9e4066Sahrens 	/*
3830fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3831fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
3832fa9e4066Sahrens 	 */
3833fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
3834fa9e4066Sahrens 		(void) printf("dumping core by request\n");
3835fa9e4066Sahrens 		abort();
3836fa9e4066Sahrens 	}
3837fa9e4066Sahrens 
3838fa9e4066Sahrens 	return (ret);
3839fa9e4066Sahrens }
3840