xref: /illumos-gate/usr/src/cmd/zpool/zpool_main.c (revision 990b4856d0eaada6f8140335733a1b1771ed2746)
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 /*
2339c23413Seschrock  * Copyright 2007 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 
7906eeb2adSek static int zpool_do_history(int, char **);
8006eeb2adSek 
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,
10806eeb2adSek 	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		},
16206eeb2adSek 	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
16306eeb2adSek 	{ 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;
1722a6b87f0Sek 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:
185*990b4856Slling 		return (gettext("\tcreate [-fn] [-o property=value] ... \n"
186*990b4856Slling 		    "\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"));
19306eeb2adSek 	case HELP_HISTORY:
194ecd6cf80Smarks 		return (gettext("\thistory [-il] [<pool>] ...\n"));
19565cd9f28Seschrock 	case HELP_IMPORT:
1964c58d714Sdarrenm 		return (gettext("\timport [-d dir] [-D]\n"
197*990b4856Slling 		    "\timport [-o mntopts] [-o property=value] ... [-d dir]\n"
198*990b4856Slling 		    "\t    [-D] [-f] [-R root] -a\n"
199*990b4856Slling 		    "\timport [-o mntopts] [-o property=value] ... [-d dir]\n"
200*990b4856Slling 		    "\t    [-D] [-f] [-R root] <pool | id> [newpool]\n"));
20165cd9f28Seschrock 	case HELP_IOSTAT:
20265cd9f28Seschrock 		return (gettext("\tiostat [-v] [pool] ... [interval "
20365cd9f28Seschrock 		    "[count]]\n"));
20465cd9f28Seschrock 	case HELP_LIST:
205*990b4856Slling 		return (gettext("\tlist [-H] [-o property[,...]] "
206*990b4856Slling 		    "[pool] ...\n"));
20765cd9f28Seschrock 	case HELP_OFFLINE:
208441d80aaSlling 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
20965cd9f28Seschrock 	case HELP_ONLINE:
210441d80aaSlling 		return (gettext("\tonline <pool> <device> ...\n"));
21165cd9f28Seschrock 	case HELP_REPLACE:
21265cd9f28Seschrock 		return (gettext("\treplace [-f] <pool> <device> "
213e45ce728Sahrens 		    "[new-device]\n"));
21499653d4eSeschrock 	case HELP_REMOVE:
21599653d4eSeschrock 		return (gettext("\tremove <pool> <device>\n"));
21665cd9f28Seschrock 	case HELP_SCRUB:
21765cd9f28Seschrock 		return (gettext("\tscrub [-s] <pool> ...\n"));
21865cd9f28Seschrock 	case HELP_STATUS:
21965cd9f28Seschrock 		return (gettext("\tstatus [-vx] [pool] ...\n"));
220eaca9bbdSeschrock 	case HELP_UPGRADE:
221eaca9bbdSeschrock 		return (gettext("\tupgrade\n"
222eaca9bbdSeschrock 		    "\tupgrade -v\n"
223*990b4856Slling 		    "\tupgrade [-V version] <-a | pool ...>\n"));
224b1b8ab34Slling 	case HELP_GET:
225e45ce728Sahrens 		return (gettext("\tget <\"all\" | property[,...]> "
226b1b8ab34Slling 		    "<pool> ...\n"));
227b1b8ab34Slling 	case HELP_SET:
228b1b8ab34Slling 		return (gettext("\tset <property=value> <pool> \n"));
22965cd9f28Seschrock 	}
23065cd9f28Seschrock 
23165cd9f28Seschrock 	abort();
23265cd9f28Seschrock 	/* NOTREACHED */
23365cd9f28Seschrock }
23465cd9f28Seschrock 
235fa9e4066Sahrens 
236b1b8ab34Slling /*
237b1b8ab34Slling  * Callback routine that will print out a pool property value.
238b1b8ab34Slling  */
239*990b4856Slling static int
240*990b4856Slling print_prop_cb(int prop, void *cb)
241b1b8ab34Slling {
242b1b8ab34Slling 	FILE *fp = cb;
243b1b8ab34Slling 
244b1b8ab34Slling 	(void) fprintf(fp, "\t%-13s  ", zpool_prop_to_name(prop));
245b1b8ab34Slling 
246*990b4856Slling 	if (zpool_prop_readonly(prop))
247*990b4856Slling 		(void) fprintf(fp, "  NO   ");
248*990b4856Slling 	else
249*990b4856Slling 		(void) fprintf(fp, " YES    ");
250*990b4856Slling 
251b1b8ab34Slling 	if (zpool_prop_values(prop) == NULL)
252b1b8ab34Slling 		(void) fprintf(fp, "-\n");
253b1b8ab34Slling 	else
254b1b8ab34Slling 		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
255b1b8ab34Slling 
256*990b4856Slling 	return (ZPROP_CONT);
257b1b8ab34Slling }
258b1b8ab34Slling 
259fa9e4066Sahrens /*
260fa9e4066Sahrens  * Display usage message.  If we're inside a command, display only the usage for
261fa9e4066Sahrens  * that command.  Otherwise, iterate over the entire command table and display
262fa9e4066Sahrens  * a complete usage message.
263fa9e4066Sahrens  */
264fa9e4066Sahrens void
26599653d4eSeschrock usage(boolean_t requested)
266fa9e4066Sahrens {
267fa9e4066Sahrens 	FILE *fp = requested ? stdout : stderr;
268fa9e4066Sahrens 
269fa9e4066Sahrens 	if (current_command == NULL) {
270fa9e4066Sahrens 		int i;
271fa9e4066Sahrens 
272fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
273fa9e4066Sahrens 		(void) fprintf(fp,
274fa9e4066Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
275fa9e4066Sahrens 
276fa9e4066Sahrens 		for (i = 0; i < NCOMMAND; i++) {
277fa9e4066Sahrens 			if (command_table[i].name == NULL)
278fa9e4066Sahrens 				(void) fprintf(fp, "\n");
279fa9e4066Sahrens 			else
280fa9e4066Sahrens 				(void) fprintf(fp, "%s",
28165cd9f28Seschrock 				    get_usage(command_table[i].usage));
282fa9e4066Sahrens 		}
283fa9e4066Sahrens 	} else {
284fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
28565cd9f28Seschrock 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
286fa9e4066Sahrens 	}
287fa9e4066Sahrens 
288b1b8ab34Slling 	if (current_command != NULL &&
289b1b8ab34Slling 	    ((strcmp(current_command->name, "set") == 0) ||
290*990b4856Slling 	    (strcmp(current_command->name, "get") == 0) ||
291*990b4856Slling 	    (strcmp(current_command->name, "list") == 0))) {
292b1b8ab34Slling 
293b1b8ab34Slling 		(void) fprintf(fp,
294b1b8ab34Slling 		    gettext("\nthe following properties are supported:\n"));
295b1b8ab34Slling 
296*990b4856Slling 		(void) fprintf(fp, "\n\t%-13s  %s  %s\n\n",
297*990b4856Slling 		    "PROPERTY", "EDIT", "VALUES");
298b1b8ab34Slling 
299b1b8ab34Slling 		/* Iterate over all properties */
300*990b4856Slling 		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
301*990b4856Slling 		    ZFS_TYPE_POOL);
302b1b8ab34Slling 	}
303b1b8ab34Slling 
304e9dbad6fSeschrock 	/*
305e9dbad6fSeschrock 	 * See comments at end of main().
306e9dbad6fSeschrock 	 */
307e9dbad6fSeschrock 	if (getenv("ZFS_ABORT") != NULL) {
308e9dbad6fSeschrock 		(void) printf("dumping core by request\n");
309e9dbad6fSeschrock 		abort();
310e9dbad6fSeschrock 	}
311e9dbad6fSeschrock 
312fa9e4066Sahrens 	exit(requested ? 0 : 2);
313fa9e4066Sahrens }
314fa9e4066Sahrens 
315fa9e4066Sahrens void
3168654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
3178654d025Sperrin     boolean_t print_logs)
318fa9e4066Sahrens {
319fa9e4066Sahrens 	nvlist_t **child;
320fa9e4066Sahrens 	uint_t c, children;
321afefbcddSeschrock 	char *vname;
322fa9e4066Sahrens 
323fa9e4066Sahrens 	if (name != NULL)
324fa9e4066Sahrens 		(void) printf("\t%*s%s\n", indent, "", name);
325fa9e4066Sahrens 
326fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
327fa9e4066Sahrens 	    &child, &children) != 0)
328fa9e4066Sahrens 		return;
329fa9e4066Sahrens 
330afefbcddSeschrock 	for (c = 0; c < children; c++) {
3318654d025Sperrin 		uint64_t is_log = B_FALSE;
3328654d025Sperrin 
3338654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3348654d025Sperrin 		    &is_log);
3358654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
3368654d025Sperrin 			continue;
3378654d025Sperrin 
33899653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
3398654d025Sperrin 		print_vdev_tree(zhp, vname, child[c], indent + 2,
3408654d025Sperrin 		    B_FALSE);
341afefbcddSeschrock 		free(vname);
342afefbcddSeschrock 	}
343fa9e4066Sahrens }
344fa9e4066Sahrens 
345*990b4856Slling /*
346*990b4856Slling  * Add a property pair (name, string-value) into a property nvlist.
347*990b4856Slling  */
348*990b4856Slling static int
349*990b4856Slling add_prop_list(const char *propname, char *propval, nvlist_t **props)
350*990b4856Slling {
351*990b4856Slling 	char *strval;
352*990b4856Slling 	nvlist_t *proplist;
353*990b4856Slling 	zpool_prop_t prop;
354*990b4856Slling 
355*990b4856Slling 	if (*props == NULL &&
356*990b4856Slling 	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
357*990b4856Slling 		(void) fprintf(stderr,
358*990b4856Slling 		    gettext("internal error: out of memory\n"));
359*990b4856Slling 		return (1);
360*990b4856Slling 	}
361*990b4856Slling 
362*990b4856Slling 	proplist = *props;
363*990b4856Slling 
364*990b4856Slling 	if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
365*990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' is "
366*990b4856Slling 		    "not a valid pool property\n"), propname);
367*990b4856Slling 		return (2);
368*990b4856Slling 	}
369*990b4856Slling 
370*990b4856Slling 	/* Use normalized property name for nvlist operations */
371*990b4856Slling 	if (nvlist_lookup_string(proplist, zpool_prop_to_name(prop),
372*990b4856Slling 	    &strval) == 0) {
373*990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' "
374*990b4856Slling 		    "specified multiple times\n"), propname);
375*990b4856Slling 		return (2);
376*990b4856Slling 	}
377*990b4856Slling 
378*990b4856Slling 	if (nvlist_add_string(proplist, zpool_prop_to_name(prop),
379*990b4856Slling 	    propval) != 0) {
380*990b4856Slling 		(void) fprintf(stderr, gettext("internal "
381*990b4856Slling 		    "error: out of memory\n"));
382*990b4856Slling 		return (1);
383*990b4856Slling 	}
384*990b4856Slling 
385*990b4856Slling 	return (0);
386*990b4856Slling }
387*990b4856Slling 
388fa9e4066Sahrens /*
389fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
390fa9e4066Sahrens  *
391fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
392fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
393fa9e4066Sahrens  *		they were to be added.
394fa9e4066Sahrens  *
395fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
396fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
397fa9e4066Sahrens  * libzfs.
398fa9e4066Sahrens  */
399fa9e4066Sahrens int
400fa9e4066Sahrens zpool_do_add(int argc, char **argv)
401fa9e4066Sahrens {
40299653d4eSeschrock 	boolean_t force = B_FALSE;
40399653d4eSeschrock 	boolean_t dryrun = B_FALSE;
404fa9e4066Sahrens 	int c;
405fa9e4066Sahrens 	nvlist_t *nvroot;
406fa9e4066Sahrens 	char *poolname;
407fa9e4066Sahrens 	int ret;
408fa9e4066Sahrens 	zpool_handle_t *zhp;
409fa9e4066Sahrens 	nvlist_t *config;
410fa9e4066Sahrens 
411fa9e4066Sahrens 	/* check options */
412fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
413fa9e4066Sahrens 		switch (c) {
414fa9e4066Sahrens 		case 'f':
41599653d4eSeschrock 			force = B_TRUE;
416fa9e4066Sahrens 			break;
417fa9e4066Sahrens 		case 'n':
41899653d4eSeschrock 			dryrun = B_TRUE;
419fa9e4066Sahrens 			break;
420fa9e4066Sahrens 		case '?':
421fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
422fa9e4066Sahrens 			    optopt);
42399653d4eSeschrock 			usage(B_FALSE);
424fa9e4066Sahrens 		}
425fa9e4066Sahrens 	}
426fa9e4066Sahrens 
427fa9e4066Sahrens 	argc -= optind;
428fa9e4066Sahrens 	argv += optind;
429fa9e4066Sahrens 
430fa9e4066Sahrens 	/* get pool name and check number of arguments */
431fa9e4066Sahrens 	if (argc < 1) {
432fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
43399653d4eSeschrock 		usage(B_FALSE);
434fa9e4066Sahrens 	}
435fa9e4066Sahrens 	if (argc < 2) {
436fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
43799653d4eSeschrock 		usage(B_FALSE);
438fa9e4066Sahrens 	}
439fa9e4066Sahrens 
440fa9e4066Sahrens 	poolname = argv[0];
441fa9e4066Sahrens 
442fa9e4066Sahrens 	argc--;
443fa9e4066Sahrens 	argv++;
444fa9e4066Sahrens 
44599653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
446fa9e4066Sahrens 		return (1);
447fa9e4066Sahrens 
448088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
449fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
450fa9e4066Sahrens 		    poolname);
451fa9e4066Sahrens 		zpool_close(zhp);
452fa9e4066Sahrens 		return (1);
453fa9e4066Sahrens 	}
454fa9e4066Sahrens 
455fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
4568488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv);
457fa9e4066Sahrens 	if (nvroot == NULL) {
458fa9e4066Sahrens 		zpool_close(zhp);
459fa9e4066Sahrens 		return (1);
460fa9e4066Sahrens 	}
461fa9e4066Sahrens 
462fa9e4066Sahrens 	if (dryrun) {
463fa9e4066Sahrens 		nvlist_t *poolnvroot;
464fa9e4066Sahrens 
465fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
466fa9e4066Sahrens 		    &poolnvroot) == 0);
467fa9e4066Sahrens 
468fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
469fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
470fa9e4066Sahrens 
4718654d025Sperrin 		/* print original main pool and new tree */
4728654d025Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
4738654d025Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
4748654d025Sperrin 
4758654d025Sperrin 		/* Do the same for the logs */
4768654d025Sperrin 		if (num_logs(poolnvroot) > 0) {
4778654d025Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
4788654d025Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
4798654d025Sperrin 		} else if (num_logs(nvroot) > 0) {
4808654d025Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
4818654d025Sperrin 		}
482fa9e4066Sahrens 
483fa9e4066Sahrens 		ret = 0;
484fa9e4066Sahrens 	} else {
485fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
486fa9e4066Sahrens 	}
487fa9e4066Sahrens 
48899653d4eSeschrock 	nvlist_free(nvroot);
48999653d4eSeschrock 	zpool_close(zhp);
49099653d4eSeschrock 
49199653d4eSeschrock 	return (ret);
49299653d4eSeschrock }
49399653d4eSeschrock 
49499653d4eSeschrock /*
49599653d4eSeschrock  * zpool remove <pool> <vdev>
49699653d4eSeschrock  *
49799653d4eSeschrock  * Removes the given vdev from the pool.  Currently, this only supports removing
49899653d4eSeschrock  * spares from the pool.  Eventually, we'll want to support removing leaf vdevs
49999653d4eSeschrock  * (as an alias for 'detach') as well as toplevel vdevs.
50099653d4eSeschrock  */
50199653d4eSeschrock int
50299653d4eSeschrock zpool_do_remove(int argc, char **argv)
50399653d4eSeschrock {
50499653d4eSeschrock 	char *poolname;
50599653d4eSeschrock 	int ret;
50699653d4eSeschrock 	zpool_handle_t *zhp;
50799653d4eSeschrock 
50899653d4eSeschrock 	argc--;
50999653d4eSeschrock 	argv++;
51099653d4eSeschrock 
51199653d4eSeschrock 	/* get pool name and check number of arguments */
51299653d4eSeschrock 	if (argc < 1) {
51399653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
51499653d4eSeschrock 		usage(B_FALSE);
51599653d4eSeschrock 	}
51699653d4eSeschrock 	if (argc < 2) {
51799653d4eSeschrock 		(void) fprintf(stderr, gettext("missing device\n"));
51899653d4eSeschrock 		usage(B_FALSE);
51999653d4eSeschrock 	}
52099653d4eSeschrock 
52199653d4eSeschrock 	poolname = argv[0];
52299653d4eSeschrock 
52399653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
52499653d4eSeschrock 		return (1);
52599653d4eSeschrock 
52699653d4eSeschrock 	ret = (zpool_vdev_remove(zhp, argv[1]) != 0);
52799653d4eSeschrock 
528fa9e4066Sahrens 	return (ret);
529fa9e4066Sahrens }
530fa9e4066Sahrens 
531fa9e4066Sahrens /*
532*990b4856Slling  * zpool create [-fn] [-o property=value] ... [-R root] [-m mountpoint]
533*990b4856Slling  *		<pool> <dev> ...
534fa9e4066Sahrens  *
535fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
536fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
537fa9e4066Sahrens  *		were to be created.
538fa9e4066Sahrens  *      -R	Create a pool under an alternate root
539fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
540fa9e4066Sahrens  *      	'/<pool>'
541*990b4856Slling  *	-o	Set property=value.
542fa9e4066Sahrens  *
543b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
544fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
545fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
546fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
547fa9e4066Sahrens  */
548fa9e4066Sahrens int
549fa9e4066Sahrens zpool_do_create(int argc, char **argv)
550fa9e4066Sahrens {
55199653d4eSeschrock 	boolean_t force = B_FALSE;
55299653d4eSeschrock 	boolean_t dryrun = B_FALSE;
553fa9e4066Sahrens 	int c;
554*990b4856Slling 	nvlist_t *nvroot = NULL;
555fa9e4066Sahrens 	char *poolname;
556*990b4856Slling 	int ret = 1;
557fa9e4066Sahrens 	char *altroot = NULL;
558fa9e4066Sahrens 	char *mountpoint = NULL;
55999653d4eSeschrock 	nvlist_t **child;
56099653d4eSeschrock 	uint_t children;
561*990b4856Slling 	nvlist_t *props = NULL;
562*990b4856Slling 	char *propval = NULL;
563fa9e4066Sahrens 
564fa9e4066Sahrens 	/* check options */
565*990b4856Slling 	while ((c = getopt(argc, argv, ":fnR:m:o:")) != -1) {
566fa9e4066Sahrens 		switch (c) {
567fa9e4066Sahrens 		case 'f':
56899653d4eSeschrock 			force = B_TRUE;
569fa9e4066Sahrens 			break;
570fa9e4066Sahrens 		case 'n':
57199653d4eSeschrock 			dryrun = B_TRUE;
572fa9e4066Sahrens 			break;
573fa9e4066Sahrens 		case 'R':
574fa9e4066Sahrens 			altroot = optarg;
575*990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
576*990b4856Slling 			    ZPOOL_PROP_ALTROOT), optarg, &props))
577*990b4856Slling 				goto errout;
578*990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
579*990b4856Slling 			    ZPOOL_PROP_TEMPORARY), "on", &props))
580*990b4856Slling 				goto errout;
581fa9e4066Sahrens 			break;
582fa9e4066Sahrens 		case 'm':
583fa9e4066Sahrens 			mountpoint = optarg;
584fa9e4066Sahrens 			break;
585*990b4856Slling 		case 'o':
586*990b4856Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
587*990b4856Slling 				(void) fprintf(stderr, gettext("missing "
588*990b4856Slling 				    "'=' for -o option\n"));
589*990b4856Slling 				goto errout;
590*990b4856Slling 			}
591*990b4856Slling 			*propval = '\0';
592*990b4856Slling 			propval++;
593*990b4856Slling 
594*990b4856Slling 			if (add_prop_list(optarg, propval, &props))
595*990b4856Slling 				goto errout;
596*990b4856Slling 			break;
597fa9e4066Sahrens 		case ':':
598fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
599fa9e4066Sahrens 			    "'%c' option\n"), optopt);
600*990b4856Slling 			goto badusage;
601fa9e4066Sahrens 		case '?':
602fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
603fa9e4066Sahrens 			    optopt);
604*990b4856Slling 			goto badusage;
605fa9e4066Sahrens 		}
606fa9e4066Sahrens 	}
607fa9e4066Sahrens 
608fa9e4066Sahrens 	argc -= optind;
609fa9e4066Sahrens 	argv += optind;
610fa9e4066Sahrens 
611fa9e4066Sahrens 	/* get pool name and check number of arguments */
612fa9e4066Sahrens 	if (argc < 1) {
613fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
614*990b4856Slling 		goto badusage;
615fa9e4066Sahrens 	}
616fa9e4066Sahrens 	if (argc < 2) {
617fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
618*990b4856Slling 		goto badusage;
619fa9e4066Sahrens 	}
620fa9e4066Sahrens 
621fa9e4066Sahrens 	poolname = argv[0];
622fa9e4066Sahrens 
623fa9e4066Sahrens 	/*
624fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
625fa9e4066Sahrens 	 * user to use 'zfs create' instead.
626fa9e4066Sahrens 	 */
627fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
628fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
629fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
630fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
631fa9e4066Sahrens 		    "create a dataset\n"));
632*990b4856Slling 		goto errout;
633fa9e4066Sahrens 	}
634fa9e4066Sahrens 
635fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
63699653d4eSeschrock 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1,
63799653d4eSeschrock 	    argv + 1);
638fa9e4066Sahrens 	if (nvroot == NULL)
639fa9e4066Sahrens 		return (1);
640fa9e4066Sahrens 
64199653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
64299653d4eSeschrock 	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
64399653d4eSeschrock 	    &child, &children) == 0);
64499653d4eSeschrock 	if (children == 0) {
64599653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
64699653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
64799653d4eSeschrock 		    "specified\n"));
648*990b4856Slling 		goto errout;
64999653d4eSeschrock 	}
65099653d4eSeschrock 
65199653d4eSeschrock 
652fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
653fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
654e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
655*990b4856Slling 		goto errout;
656fa9e4066Sahrens 	}
657fa9e4066Sahrens 
658fa9e4066Sahrens 	/*
659fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
660fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
661fa9e4066Sahrens 	 */
662fa9e4066Sahrens 	if (mountpoint == NULL ||
663fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
664fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
665fa9e4066Sahrens 		char buf[MAXPATHLEN];
666fa9e4066Sahrens 		struct stat64 statbuf;
667fa9e4066Sahrens 
668fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
669fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
670fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
671fa9e4066Sahrens 			    "'none'\n"), mountpoint);
672*990b4856Slling 			goto errout;
673fa9e4066Sahrens 		}
674fa9e4066Sahrens 
675fa9e4066Sahrens 		if (mountpoint == NULL) {
676fa9e4066Sahrens 			if (altroot != NULL)
677fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
678fa9e4066Sahrens 				    altroot, poolname);
679fa9e4066Sahrens 			else
680fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
681fa9e4066Sahrens 				    poolname);
682fa9e4066Sahrens 		} else {
683fa9e4066Sahrens 			if (altroot != NULL)
684fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
685fa9e4066Sahrens 				    altroot, mountpoint);
686fa9e4066Sahrens 			else
687fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
688fa9e4066Sahrens 				    mountpoint);
689fa9e4066Sahrens 		}
690fa9e4066Sahrens 
691fa9e4066Sahrens 		if (stat64(buf, &statbuf) == 0 &&
692fa9e4066Sahrens 		    statbuf.st_nlink != 2) {
693fa9e4066Sahrens 			if (mountpoint == NULL)
694fa9e4066Sahrens 				(void) fprintf(stderr, gettext("default "
695fa9e4066Sahrens 				    "mountpoint '%s' exists and is not "
696fa9e4066Sahrens 				    "empty\n"), buf);
697fa9e4066Sahrens 			else
698fa9e4066Sahrens 				(void) fprintf(stderr, gettext("mountpoint "
699fa9e4066Sahrens 				    "'%s' exists and is not empty\n"), buf);
700fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
701fa9e4066Sahrens 			    "option to provide a different default\n"));
702*990b4856Slling 			goto errout;
703fa9e4066Sahrens 		}
704fa9e4066Sahrens 	}
705fa9e4066Sahrens 
706fa9e4066Sahrens 	if (dryrun) {
707fa9e4066Sahrens 		/*
708fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
709fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
710fa9e4066Sahrens 		 * appropriate hierarchy.
711fa9e4066Sahrens 		 */
712fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
713fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
714fa9e4066Sahrens 
7158654d025Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7168654d025Sperrin 		if (num_logs(nvroot) > 0)
7178654d025Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
718fa9e4066Sahrens 
719fa9e4066Sahrens 		ret = 0;
720fa9e4066Sahrens 	} else {
721fa9e4066Sahrens 		/*
722fa9e4066Sahrens 		 * Hand off to libzfs.
723fa9e4066Sahrens 		 */
724*990b4856Slling 		if (zpool_create(g_zfs, poolname, nvroot, props) == 0) {
72599653d4eSeschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
726fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
727fa9e4066Sahrens 			if (pool != NULL) {
728fa9e4066Sahrens 				if (mountpoint != NULL)
729fa9e4066Sahrens 					verify(zfs_prop_set(pool,
730e9dbad6fSeschrock 					    zfs_prop_to_name(
731e9dbad6fSeschrock 					    ZFS_PROP_MOUNTPOINT),
732fa9e4066Sahrens 					    mountpoint) == 0);
733fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
734f3861e1aSahl 					ret = zfs_share_nfs(pool);
735fa9e4066Sahrens 				zfs_close(pool);
736fa9e4066Sahrens 			}
73799653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
73899653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
73999653d4eSeschrock 			    "been omitted\n"));
740fa9e4066Sahrens 		}
741fa9e4066Sahrens 	}
742fa9e4066Sahrens 
743*990b4856Slling errout:
744*990b4856Slling 	if (nvroot)
745*990b4856Slling 		nvlist_free(nvroot);
746*990b4856Slling 	if (props)
747*990b4856Slling 		nvlist_free(props);
748fa9e4066Sahrens 	return (ret);
749*990b4856Slling badusage:
750*990b4856Slling 	nvlist_free(props);
751*990b4856Slling 	usage(B_FALSE);
752*990b4856Slling 	return (2);
753fa9e4066Sahrens }
754fa9e4066Sahrens 
755fa9e4066Sahrens /*
756fa9e4066Sahrens  * zpool destroy <pool>
757fa9e4066Sahrens  *
758fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
759fa9e4066Sahrens  *
760fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
761fa9e4066Sahrens  */
762fa9e4066Sahrens int
763fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
764fa9e4066Sahrens {
76599653d4eSeschrock 	boolean_t force = B_FALSE;
766fa9e4066Sahrens 	int c;
767fa9e4066Sahrens 	char *pool;
768fa9e4066Sahrens 	zpool_handle_t *zhp;
769fa9e4066Sahrens 	int ret;
770fa9e4066Sahrens 
771fa9e4066Sahrens 	/* check options */
772fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
773fa9e4066Sahrens 		switch (c) {
774fa9e4066Sahrens 		case 'f':
77599653d4eSeschrock 			force = B_TRUE;
776fa9e4066Sahrens 			break;
777fa9e4066Sahrens 		case '?':
778fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
779fa9e4066Sahrens 			    optopt);
78099653d4eSeschrock 			usage(B_FALSE);
781fa9e4066Sahrens 		}
782fa9e4066Sahrens 	}
783fa9e4066Sahrens 
784fa9e4066Sahrens 	argc -= optind;
785fa9e4066Sahrens 	argv += optind;
786fa9e4066Sahrens 
787fa9e4066Sahrens 	/* check arguments */
788fa9e4066Sahrens 	if (argc < 1) {
789fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
79099653d4eSeschrock 		usage(B_FALSE);
791fa9e4066Sahrens 	}
792fa9e4066Sahrens 	if (argc > 1) {
793fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
79499653d4eSeschrock 		usage(B_FALSE);
795fa9e4066Sahrens 	}
796fa9e4066Sahrens 
797fa9e4066Sahrens 	pool = argv[0];
798fa9e4066Sahrens 
79999653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
800fa9e4066Sahrens 		/*
801fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
802fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
803fa9e4066Sahrens 		 */
804fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
805fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
806fa9e4066Sahrens 			    "destroy a dataset\n"));
807fa9e4066Sahrens 		return (1);
808fa9e4066Sahrens 	}
809fa9e4066Sahrens 
810f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
811fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
812fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
813fa9e4066Sahrens 		return (1);
814fa9e4066Sahrens 	}
815fa9e4066Sahrens 
816fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
817fa9e4066Sahrens 
818fa9e4066Sahrens 	zpool_close(zhp);
819fa9e4066Sahrens 
820fa9e4066Sahrens 	return (ret);
821fa9e4066Sahrens }
822fa9e4066Sahrens 
823fa9e4066Sahrens /*
824fa9e4066Sahrens  * zpool export [-f] <pool> ...
825fa9e4066Sahrens  *
826fa9e4066Sahrens  *	-f	Forcefully unmount datasets
827fa9e4066Sahrens  *
828b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
829fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
830fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
831fa9e4066Sahrens  */
832fa9e4066Sahrens int
833fa9e4066Sahrens zpool_do_export(int argc, char **argv)
834fa9e4066Sahrens {
83599653d4eSeschrock 	boolean_t force = B_FALSE;
836fa9e4066Sahrens 	int c;
837fa9e4066Sahrens 	zpool_handle_t *zhp;
838fa9e4066Sahrens 	int ret;
839fa9e4066Sahrens 	int i;
840fa9e4066Sahrens 
841fa9e4066Sahrens 	/* check options */
842fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
843fa9e4066Sahrens 		switch (c) {
844fa9e4066Sahrens 		case 'f':
84599653d4eSeschrock 			force = B_TRUE;
846fa9e4066Sahrens 			break;
847fa9e4066Sahrens 		case '?':
848fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
849fa9e4066Sahrens 			    optopt);
85099653d4eSeschrock 			usage(B_FALSE);
851fa9e4066Sahrens 		}
852fa9e4066Sahrens 	}
853fa9e4066Sahrens 
854fa9e4066Sahrens 	argc -= optind;
855fa9e4066Sahrens 	argv += optind;
856fa9e4066Sahrens 
857fa9e4066Sahrens 	/* check arguments */
858fa9e4066Sahrens 	if (argc < 1) {
859fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
86099653d4eSeschrock 		usage(B_FALSE);
861fa9e4066Sahrens 	}
862fa9e4066Sahrens 
863fa9e4066Sahrens 	ret = 0;
864fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
86599653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
866fa9e4066Sahrens 			ret = 1;
867fa9e4066Sahrens 			continue;
868fa9e4066Sahrens 		}
869fa9e4066Sahrens 
870f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
871fa9e4066Sahrens 			ret = 1;
872fa9e4066Sahrens 			zpool_close(zhp);
873fa9e4066Sahrens 			continue;
874fa9e4066Sahrens 		}
875fa9e4066Sahrens 
876fa9e4066Sahrens 		if (zpool_export(zhp) != 0)
877fa9e4066Sahrens 			ret = 1;
878fa9e4066Sahrens 
879fa9e4066Sahrens 		zpool_close(zhp);
880fa9e4066Sahrens 	}
881fa9e4066Sahrens 
882fa9e4066Sahrens 	return (ret);
883fa9e4066Sahrens }
884fa9e4066Sahrens 
885fa9e4066Sahrens /*
886fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
887fa9e4066Sahrens  * name column.
888fa9e4066Sahrens  */
889fa9e4066Sahrens static int
890c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
891fa9e4066Sahrens {
89299653d4eSeschrock 	char *name = zpool_vdev_name(g_zfs, zhp, nv);
893fa9e4066Sahrens 	nvlist_t **child;
894fa9e4066Sahrens 	uint_t c, children;
895fa9e4066Sahrens 	int ret;
896fa9e4066Sahrens 
897fa9e4066Sahrens 	if (strlen(name) + depth > max)
898fa9e4066Sahrens 		max = strlen(name) + depth;
899fa9e4066Sahrens 
900afefbcddSeschrock 	free(name);
901afefbcddSeschrock 
90299653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
90399653d4eSeschrock 	    &child, &children) == 0) {
90499653d4eSeschrock 		for (c = 0; c < children; c++)
90599653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
90699653d4eSeschrock 			    max)) > max)
90799653d4eSeschrock 				max = ret;
90899653d4eSeschrock 	}
90999653d4eSeschrock 
910fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
91199653d4eSeschrock 	    &child, &children) == 0) {
91299653d4eSeschrock 		for (c = 0; c < children; c++)
91399653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
91499653d4eSeschrock 			    max)) > max)
91599653d4eSeschrock 				max = ret;
91699653d4eSeschrock 	}
917fa9e4066Sahrens 
918fa9e4066Sahrens 
919fa9e4066Sahrens 	return (max);
920fa9e4066Sahrens }
921fa9e4066Sahrens 
922fa9e4066Sahrens 
923fa9e4066Sahrens /*
924fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
925fa9e4066Sahrens  * pool, printing out the name and status for each one.
926fa9e4066Sahrens  */
927fa9e4066Sahrens void
9288654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
9298654d025Sperrin     boolean_t print_logs)
930fa9e4066Sahrens {
931fa9e4066Sahrens 	nvlist_t **child;
932fa9e4066Sahrens 	uint_t c, children;
933fa9e4066Sahrens 	vdev_stat_t *vs;
934afefbcddSeschrock 	char *type, *vname;
935fa9e4066Sahrens 
936fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
937fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
938fa9e4066Sahrens 		return;
939fa9e4066Sahrens 
940fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
941fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
942fa9e4066Sahrens 
943fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
944*990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
945fa9e4066Sahrens 
946fa9e4066Sahrens 	if (vs->vs_aux != 0) {
9473d7072f8Seschrock 		(void) printf("  ");
948fa9e4066Sahrens 
949fa9e4066Sahrens 		switch (vs->vs_aux) {
950fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
951fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
952fa9e4066Sahrens 			break;
953fa9e4066Sahrens 
954fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
955fa9e4066Sahrens 			(void) printf(gettext("missing device"));
956fa9e4066Sahrens 			break;
957fa9e4066Sahrens 
958fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
959fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
960fa9e4066Sahrens 			break;
961fa9e4066Sahrens 
962eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
963eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
964eaca9bbdSeschrock 			break;
965eaca9bbdSeschrock 
9663d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
9673d7072f8Seschrock 			(void) printf(gettext("too many errors"));
9683d7072f8Seschrock 			break;
9693d7072f8Seschrock 
970fa9e4066Sahrens 		default:
971fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
972fa9e4066Sahrens 			break;
973fa9e4066Sahrens 		}
974fa9e4066Sahrens 	}
975fa9e4066Sahrens 	(void) printf("\n");
976fa9e4066Sahrens 
977fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
978fa9e4066Sahrens 	    &child, &children) != 0)
979fa9e4066Sahrens 		return;
980fa9e4066Sahrens 
981afefbcddSeschrock 	for (c = 0; c < children; c++) {
9828654d025Sperrin 		uint64_t is_log = B_FALSE;
9838654d025Sperrin 
9848654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
9858654d025Sperrin 		    &is_log);
9868654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
9878654d025Sperrin 			continue;
9888654d025Sperrin 
98999653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
990afefbcddSeschrock 		print_import_config(vname, child[c],
9918654d025Sperrin 		    namewidth, depth + 2, B_FALSE);
992afefbcddSeschrock 		free(vname);
993afefbcddSeschrock 	}
99499653d4eSeschrock 
99599653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
99699653d4eSeschrock 	    &child, &children) != 0)
99799653d4eSeschrock 		return;
99899653d4eSeschrock 
99999653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
100099653d4eSeschrock 	for (c = 0; c < children; c++) {
100199653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
100299653d4eSeschrock 		(void) printf("\t  %s\n", vname);
100399653d4eSeschrock 		free(vname);
100499653d4eSeschrock 	}
1005fa9e4066Sahrens }
1006fa9e4066Sahrens 
1007fa9e4066Sahrens /*
1008fa9e4066Sahrens  * Display the status for the given pool.
1009fa9e4066Sahrens  */
1010fa9e4066Sahrens static void
1011fa9e4066Sahrens show_import(nvlist_t *config)
1012fa9e4066Sahrens {
1013fa9e4066Sahrens 	uint64_t pool_state;
1014fa9e4066Sahrens 	vdev_stat_t *vs;
1015fa9e4066Sahrens 	char *name;
1016fa9e4066Sahrens 	uint64_t guid;
1017fa9e4066Sahrens 	char *msgid;
1018fa9e4066Sahrens 	nvlist_t *nvroot;
1019fa9e4066Sahrens 	int reason;
102046657f8dSmmusante 	const char *health;
1021fa9e4066Sahrens 	uint_t vsc;
1022fa9e4066Sahrens 	int namewidth;
1023fa9e4066Sahrens 
1024fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1025fa9e4066Sahrens 	    &name) == 0);
1026fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1027fa9e4066Sahrens 	    &guid) == 0);
1028fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1029fa9e4066Sahrens 	    &pool_state) == 0);
1030fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1031fa9e4066Sahrens 	    &nvroot) == 0);
1032fa9e4066Sahrens 
1033fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1034fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1035*990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1036fa9e4066Sahrens 
1037fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1038fa9e4066Sahrens 
103946657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
104046657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
104146657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
10424c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
1043b1b8ab34Slling 		(void) printf(gettext(" (DESTROYED)"));
10444c58d714Sdarrenm 	(void) printf("\n");
1045fa9e4066Sahrens 
1046fa9e4066Sahrens 	switch (reason) {
1047fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1048fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1049fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1050fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1051fa9e4066Sahrens 		    "from the system.\n"));
1052fa9e4066Sahrens 		break;
1053fa9e4066Sahrens 
1054fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1055fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1056fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1057fa9e4066Sahrens 		    "corrupted data.\n"));
1058fa9e4066Sahrens 		break;
1059fa9e4066Sahrens 
1060fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1061fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1062fa9e4066Sahrens 		break;
1063fa9e4066Sahrens 
1064441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1065441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1066441d80aaSlling 		    "are offlined.\n"));
1067441d80aaSlling 		break;
1068441d80aaSlling 
1069ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1070ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1071ea8dc4b6Seschrock 		    "corrupted.\n"));
1072ea8dc4b6Seschrock 		break;
1073ea8dc4b6Seschrock 
1074eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1075eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1076eaca9bbdSeschrock 		    "older on-disk version.\n"));
1077eaca9bbdSeschrock 		break;
1078eaca9bbdSeschrock 
1079eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1080eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1081eaca9bbdSeschrock 		    "incompatible version.\n"));
1082eaca9bbdSeschrock 		break;
108395173954Sek 	case ZPOOL_STATUS_HOSTID_MISMATCH:
108495173954Sek 		(void) printf(gettext("status: The pool was last accessed by "
108595173954Sek 		    "another system.\n"));
108695173954Sek 		break;
10873d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
10883d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
10893d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
10903d7072f8Seschrock 		    "faulted.\n"));
10913d7072f8Seschrock 		break;
10923d7072f8Seschrock 
1093fa9e4066Sahrens 	default:
1094fa9e4066Sahrens 		/*
1095fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1096fa9e4066Sahrens 		 */
1097fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1098fa9e4066Sahrens 	}
1099fa9e4066Sahrens 
1100fa9e4066Sahrens 	/*
1101fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1102fa9e4066Sahrens 	 */
110346657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1104eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1105eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1106eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1107eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1108eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
110995173954Sek 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
111095173954Sek 			(void) printf(gettext("action: The pool can be "
111195173954Sek 			    "imported using its name or numeric "
111295173954Sek 			    "identifier and\n\tthe '-f' flag.\n"));
1113fa9e4066Sahrens 		else
1114eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1115eaca9bbdSeschrock 			    "imported using its name or numeric "
1116eaca9bbdSeschrock 			    "identifier.\n"));
111746657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1118fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1119fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1120eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1121fa9e4066Sahrens 	} else {
1122eaca9bbdSeschrock 		switch (reason) {
1123eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1124eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1125eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1126eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1127eaca9bbdSeschrock 			    "backup.\n"));
1128eaca9bbdSeschrock 			break;
1129eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1130eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1131eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1132fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1133fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1134fa9e4066Sahrens 			    "again.\n"));
1135eaca9bbdSeschrock 			break;
1136eaca9bbdSeschrock 		default:
1137fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1138fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1139eaca9bbdSeschrock 		}
1140eaca9bbdSeschrock 	}
1141eaca9bbdSeschrock 
114246657f8dSmmusante 	/*
114346657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
114446657f8dSmmusante 	 * is "corrupt data":
114546657f8dSmmusante 	 */
114646657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
114746657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
114846657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1149eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1150eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1151eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1152eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1153eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
1154eaca9bbdSeschrock 			    "on another system, but can be imported using\n\t"
1155eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1156fa9e4066Sahrens 	}
1157fa9e4066Sahrens 
1158fa9e4066Sahrens 	if (msgid != NULL)
1159fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1160fa9e4066Sahrens 		    msgid);
1161fa9e4066Sahrens 
1162fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1163fa9e4066Sahrens 
1164c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1165fa9e4066Sahrens 	if (namewidth < 10)
1166fa9e4066Sahrens 		namewidth = 10;
11678654d025Sperrin 
11688654d025Sperrin 	print_import_config(name, nvroot, namewidth, 0, B_FALSE);
11698654d025Sperrin 	if (num_logs(nvroot) > 0) {
11708654d025Sperrin 		(void) printf(gettext("\tlogs\n"));
11718654d025Sperrin 		print_import_config(name, nvroot, namewidth, 0, B_TRUE);
11728654d025Sperrin 	}
1173fa9e4066Sahrens 
1174fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
117546657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1176fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
117746657f8dSmmusante 		    "configuration cannot be determined.\n"));
1178fa9e4066Sahrens 	}
1179fa9e4066Sahrens }
1180fa9e4066Sahrens 
1181fa9e4066Sahrens /*
1182fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1183*990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1184*990b4856Slling  * within the pool.
1185fa9e4066Sahrens  */
1186fa9e4066Sahrens static int
1187fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
1188*990b4856Slling     int force, nvlist_t *props)
1189fa9e4066Sahrens {
1190fa9e4066Sahrens 	zpool_handle_t *zhp;
1191fa9e4066Sahrens 	char *name;
1192fa9e4066Sahrens 	uint64_t state;
1193eaca9bbdSeschrock 	uint64_t version;
1194ecd6cf80Smarks 	int error = 0;
1195fa9e4066Sahrens 
1196fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1197fa9e4066Sahrens 	    &name) == 0);
1198fa9e4066Sahrens 
1199fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1200fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1201eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1202eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1203e7437265Sahrens 	if (version > SPA_VERSION) {
1204eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1205eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1206eaca9bbdSeschrock 		return (1);
1207eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
120895173954Sek 		uint64_t hostid;
120995173954Sek 
121095173954Sek 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
121195173954Sek 		    &hostid) == 0) {
121295173954Sek 			if ((unsigned long)hostid != gethostid()) {
121395173954Sek 				char *hostname;
121495173954Sek 				uint64_t timestamp;
121595173954Sek 				time_t t;
121695173954Sek 
121795173954Sek 				verify(nvlist_lookup_string(config,
121895173954Sek 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
121995173954Sek 				verify(nvlist_lookup_uint64(config,
122095173954Sek 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
122195173954Sek 				t = timestamp;
122295173954Sek 				(void) fprintf(stderr, gettext("cannot import "
122395173954Sek 				    "'%s': pool may be in use from other "
122495173954Sek 				    "system, it was last accessed by %s "
122595173954Sek 				    "(hostid: 0x%lx) on %s"), name, hostname,
122695173954Sek 				    (unsigned long)hostid,
122795173954Sek 				    asctime(localtime(&t)));
122895173954Sek 				(void) fprintf(stderr, gettext("use '-f' to "
122995173954Sek 				    "import anyway\n"));
123095173954Sek 				return (1);
123195173954Sek 			}
123295173954Sek 		} else {
123395173954Sek 			(void) fprintf(stderr, gettext("cannot import '%s': "
123495173954Sek 			    "pool may be in use from other system\n"), name);
123595173954Sek 			(void) fprintf(stderr, gettext("use '-f' to import "
123695173954Sek 			    "anyway\n"));
123795173954Sek 			return (1);
123895173954Sek 		}
1239fa9e4066Sahrens 	}
1240fa9e4066Sahrens 
1241*990b4856Slling 	if (zpool_import_props(g_zfs, config, newname, props) != 0)
1242fa9e4066Sahrens 		return (1);
1243fa9e4066Sahrens 
1244fa9e4066Sahrens 	if (newname != NULL)
1245fa9e4066Sahrens 		name = (char *)newname;
1246fa9e4066Sahrens 
124799653d4eSeschrock 	verify((zhp = zpool_open(g_zfs, name)) != NULL);
1248fa9e4066Sahrens 
1249f3861e1aSahl 	if (zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1250fa9e4066Sahrens 		zpool_close(zhp);
1251fa9e4066Sahrens 		return (1);
1252fa9e4066Sahrens 	}
1253fa9e4066Sahrens 
1254fa9e4066Sahrens 	zpool_close(zhp);
1255ecd6cf80Smarks 	return (error);
1256fa9e4066Sahrens }
1257fa9e4066Sahrens 
1258fa9e4066Sahrens /*
12594c58d714Sdarrenm  * zpool import [-d dir] [-D]
1260*990b4856Slling  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-d dir] [-f] -a
1261*990b4856Slling  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-d dir] [-f]
1262*990b4856Slling  *		<pool | id> [newpool]
1263fa9e4066Sahrens  *
1264fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1265fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1266fa9e4066Sahrens  *
12674c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
12684c58d714Sdarrenm  *              specified destroyed pools.
12694c58d714Sdarrenm  *
1270fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1271fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1272fa9e4066Sahrens  *		is rebooted.
1273fa9e4066Sahrens  *
1274fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1275fa9e4066Sahrens  *
1276fa9e4066Sahrens  *       -a	Import all pools found.
1277fa9e4066Sahrens  *
1278*990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1279ecd6cf80Smarks  *
1280fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1281fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1282fa9e4066Sahrens  */
1283fa9e4066Sahrens int
1284fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1285fa9e4066Sahrens {
1286fa9e4066Sahrens 	char **searchdirs = NULL;
1287fa9e4066Sahrens 	int nsearch = 0;
1288fa9e4066Sahrens 	int c;
1289fa9e4066Sahrens 	int err;
1290fa9e4066Sahrens 	nvlist_t *pools;
129199653d4eSeschrock 	boolean_t do_all = B_FALSE;
129299653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1293fa9e4066Sahrens 	char *mntopts = NULL;
129499653d4eSeschrock 	boolean_t do_force = B_FALSE;
1295fa9e4066Sahrens 	nvpair_t *elem;
1296fa9e4066Sahrens 	nvlist_t *config;
1297fa9e4066Sahrens 	uint64_t searchguid;
1298fa9e4066Sahrens 	char *searchname;
1299*990b4856Slling 	char *propval;
1300fa9e4066Sahrens 	nvlist_t *found_config;
1301ecd6cf80Smarks 	nvlist_t *props = NULL;
130299653d4eSeschrock 	boolean_t first;
13034c58d714Sdarrenm 	uint64_t pool_state;
1304fa9e4066Sahrens 
1305fa9e4066Sahrens 	/* check options */
1306ecd6cf80Smarks 	while ((c = getopt(argc, argv, ":Dfd:R:ao:p:")) != -1) {
1307fa9e4066Sahrens 		switch (c) {
1308fa9e4066Sahrens 		case 'a':
130999653d4eSeschrock 			do_all = B_TRUE;
1310fa9e4066Sahrens 			break;
1311fa9e4066Sahrens 		case 'd':
1312fa9e4066Sahrens 			if (searchdirs == NULL) {
1313fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1314fa9e4066Sahrens 			} else {
1315fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1316fa9e4066Sahrens 				    sizeof (char *));
1317fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1318fa9e4066Sahrens 				    sizeof (char *));
1319fa9e4066Sahrens 				free(searchdirs);
1320fa9e4066Sahrens 				searchdirs = tmp;
1321fa9e4066Sahrens 			}
1322fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1323fa9e4066Sahrens 			break;
13244c58d714Sdarrenm 		case 'D':
132599653d4eSeschrock 			do_destroyed = B_TRUE;
13264c58d714Sdarrenm 			break;
1327fa9e4066Sahrens 		case 'f':
132899653d4eSeschrock 			do_force = B_TRUE;
1329fa9e4066Sahrens 			break;
1330fa9e4066Sahrens 		case 'o':
1331*990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1332*990b4856Slling 				*propval = '\0';
1333*990b4856Slling 				propval++;
1334*990b4856Slling 				if (add_prop_list(optarg, propval, &props))
1335*990b4856Slling 					goto error;
1336*990b4856Slling 			} else {
1337*990b4856Slling 				mntopts = optarg;
1338*990b4856Slling 			}
1339fa9e4066Sahrens 			break;
1340fa9e4066Sahrens 		case 'R':
1341*990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
1342*990b4856Slling 			    ZPOOL_PROP_ALTROOT), optarg, &props))
1343*990b4856Slling 				goto error;
1344*990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
1345*990b4856Slling 			    ZPOOL_PROP_TEMPORARY), "on", &props))
1346*990b4856Slling 				goto error;
1347fa9e4066Sahrens 			break;
1348fa9e4066Sahrens 		case ':':
1349fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1350fa9e4066Sahrens 			    "'%c' option\n"), optopt);
135199653d4eSeschrock 			usage(B_FALSE);
1352fa9e4066Sahrens 			break;
1353fa9e4066Sahrens 		case '?':
1354fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1355fa9e4066Sahrens 			    optopt);
135699653d4eSeschrock 			usage(B_FALSE);
1357fa9e4066Sahrens 		}
1358fa9e4066Sahrens 	}
1359fa9e4066Sahrens 
1360fa9e4066Sahrens 	argc -= optind;
1361fa9e4066Sahrens 	argv += optind;
1362fa9e4066Sahrens 
1363fa9e4066Sahrens 	if (searchdirs == NULL) {
1364fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1365fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1366fa9e4066Sahrens 		nsearch = 1;
1367fa9e4066Sahrens 	}
1368fa9e4066Sahrens 
1369fa9e4066Sahrens 	/* check argument count */
1370fa9e4066Sahrens 	if (do_all) {
1371fa9e4066Sahrens 		if (argc != 0) {
1372fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
137399653d4eSeschrock 			usage(B_FALSE);
1374fa9e4066Sahrens 		}
1375fa9e4066Sahrens 	} else {
1376fa9e4066Sahrens 		if (argc > 2) {
1377fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
137899653d4eSeschrock 			usage(B_FALSE);
1379fa9e4066Sahrens 		}
1380fa9e4066Sahrens 
1381fa9e4066Sahrens 		/*
1382fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1383fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1384fa9e4066Sahrens 		 * silently fail.
1385fa9e4066Sahrens 		 */
1386fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1387fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1388fa9e4066Sahrens 			    "discover pools: permission denied\n"));
138999653d4eSeschrock 			free(searchdirs);
1390fa9e4066Sahrens 			return (1);
1391fa9e4066Sahrens 		}
1392fa9e4066Sahrens 	}
1393fa9e4066Sahrens 
139499653d4eSeschrock 	if ((pools = zpool_find_import(g_zfs, nsearch, searchdirs)) == NULL) {
139599653d4eSeschrock 		free(searchdirs);
1396fa9e4066Sahrens 		return (1);
139799653d4eSeschrock 	}
1398fa9e4066Sahrens 
1399fa9e4066Sahrens 	/*
1400fa9e4066Sahrens 	 * We now have a list of all available pools in the given directories.
1401fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1402fa9e4066Sahrens 	 *
1403fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1404fa9e4066Sahrens 	 *		each one.
1405fa9e4066Sahrens 	 *
1406fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1407fa9e4066Sahrens 	 *
1408fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1409fa9e4066Sahrens 	 *		name and import that one.
14104c58d714Sdarrenm 	 *
14114c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1412fa9e4066Sahrens 	 */
1413fa9e4066Sahrens 	if (argc != 0) {
1414fa9e4066Sahrens 		char *endptr;
1415fa9e4066Sahrens 
1416fa9e4066Sahrens 		errno = 0;
1417fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1418fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1419fa9e4066Sahrens 			searchname = argv[0];
1420fa9e4066Sahrens 		else
1421fa9e4066Sahrens 			searchname = NULL;
1422fa9e4066Sahrens 		found_config = NULL;
1423fa9e4066Sahrens 	}
1424fa9e4066Sahrens 
1425fa9e4066Sahrens 	err = 0;
1426fa9e4066Sahrens 	elem = NULL;
142799653d4eSeschrock 	first = B_TRUE;
1428fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1429fa9e4066Sahrens 
1430fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1431fa9e4066Sahrens 
14324c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
14334c58d714Sdarrenm 		    &pool_state) == 0);
14344c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
14354c58d714Sdarrenm 			continue;
14364c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
14374c58d714Sdarrenm 			continue;
14384c58d714Sdarrenm 
1439fa9e4066Sahrens 		if (argc == 0) {
1440fa9e4066Sahrens 			if (first)
144199653d4eSeschrock 				first = B_FALSE;
14423bb79becSeschrock 			else if (!do_all)
1443fa9e4066Sahrens 				(void) printf("\n");
1444fa9e4066Sahrens 
1445fa9e4066Sahrens 			if (do_all)
1446fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1447*990b4856Slling 				    do_force, props);
1448fa9e4066Sahrens 			else
1449fa9e4066Sahrens 				show_import(config);
1450fa9e4066Sahrens 		} else if (searchname != NULL) {
1451fa9e4066Sahrens 			char *name;
1452fa9e4066Sahrens 
1453fa9e4066Sahrens 			/*
1454fa9e4066Sahrens 			 * We are searching for a pool based on name.
1455fa9e4066Sahrens 			 */
1456fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1457fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1458fa9e4066Sahrens 
1459fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1460fa9e4066Sahrens 				if (found_config != NULL) {
1461fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1462fa9e4066Sahrens 					    "cannot import '%s': more than "
1463fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1464fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1465fa9e4066Sahrens 					    "import by numeric ID instead\n"));
146699653d4eSeschrock 					err = B_TRUE;
1467fa9e4066Sahrens 				}
1468fa9e4066Sahrens 				found_config = config;
1469fa9e4066Sahrens 			}
1470fa9e4066Sahrens 		} else {
1471fa9e4066Sahrens 			uint64_t guid;
1472fa9e4066Sahrens 
1473fa9e4066Sahrens 			/*
1474fa9e4066Sahrens 			 * Search for a pool by guid.
1475fa9e4066Sahrens 			 */
1476fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1477fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1478fa9e4066Sahrens 
1479fa9e4066Sahrens 			if (guid == searchguid)
1480fa9e4066Sahrens 				found_config = config;
1481fa9e4066Sahrens 		}
1482fa9e4066Sahrens 	}
1483fa9e4066Sahrens 
1484fa9e4066Sahrens 	/*
1485fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1486fa9e4066Sahrens 	 * pool, and then do the import.
1487fa9e4066Sahrens 	 */
1488fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1489fa9e4066Sahrens 		if (found_config == NULL) {
1490fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1491fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
149299653d4eSeschrock 			err = B_TRUE;
1493fa9e4066Sahrens 		} else {
1494fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1495*990b4856Slling 			    argv[1], mntopts, do_force, props);
1496fa9e4066Sahrens 		}
1497fa9e4066Sahrens 	}
1498fa9e4066Sahrens 
1499fa9e4066Sahrens 	/*
1500fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1501fa9e4066Sahrens 	 * found.
1502fa9e4066Sahrens 	 */
1503fa9e4066Sahrens 	if (argc == 0 && first)
1504fa9e4066Sahrens 		(void) fprintf(stderr,
1505fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1506fa9e4066Sahrens 
1507ecd6cf80Smarks error:
1508ecd6cf80Smarks 	if (props)
1509ecd6cf80Smarks 		nvlist_free(props);
1510fa9e4066Sahrens 	nvlist_free(pools);
151199653d4eSeschrock 	free(searchdirs);
1512fa9e4066Sahrens 
1513fa9e4066Sahrens 	return (err ? 1 : 0);
1514fa9e4066Sahrens }
1515fa9e4066Sahrens 
1516fa9e4066Sahrens typedef struct iostat_cbdata {
1517fa9e4066Sahrens 	zpool_list_t *cb_list;
1518fa9e4066Sahrens 	int cb_verbose;
1519fa9e4066Sahrens 	int cb_iteration;
1520fa9e4066Sahrens 	int cb_namewidth;
1521fa9e4066Sahrens } iostat_cbdata_t;
1522fa9e4066Sahrens 
1523fa9e4066Sahrens static void
1524fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1525fa9e4066Sahrens {
1526fa9e4066Sahrens 	int i = 0;
1527fa9e4066Sahrens 
1528fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1529fa9e4066Sahrens 		(void) printf("-");
1530fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1531fa9e4066Sahrens }
1532fa9e4066Sahrens 
1533fa9e4066Sahrens static void
1534fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1535fa9e4066Sahrens {
1536fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1537fa9e4066Sahrens 	    cb->cb_namewidth, "");
1538fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1539fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1540fa9e4066Sahrens 	print_iostat_separator(cb);
1541fa9e4066Sahrens }
1542fa9e4066Sahrens 
1543fa9e4066Sahrens /*
1544fa9e4066Sahrens  * Display a single statistic.
1545fa9e4066Sahrens  */
1546*990b4856Slling static void
1547fa9e4066Sahrens print_one_stat(uint64_t value)
1548fa9e4066Sahrens {
1549fa9e4066Sahrens 	char buf[64];
1550fa9e4066Sahrens 
1551fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1552fa9e4066Sahrens 	(void) printf("  %5s", buf);
1553fa9e4066Sahrens }
1554fa9e4066Sahrens 
1555fa9e4066Sahrens /*
1556fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1557fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1558fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1559fa9e4066Sahrens  */
1560fa9e4066Sahrens void
1561c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1562c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1563fa9e4066Sahrens {
1564fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1565fa9e4066Sahrens 	uint_t c, children;
1566fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1567fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1568fa9e4066Sahrens 	uint64_t tdelta;
1569fa9e4066Sahrens 	double scale;
1570afefbcddSeschrock 	char *vname;
1571fa9e4066Sahrens 
1572fa9e4066Sahrens 	if (oldnv != NULL) {
1573fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1574fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1575fa9e4066Sahrens 	} else {
1576fa9e4066Sahrens 		oldvs = &zerovs;
1577fa9e4066Sahrens 	}
1578fa9e4066Sahrens 
1579fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1580fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1581fa9e4066Sahrens 
1582fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1583fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1584fa9e4066Sahrens 	else
1585fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1586fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1587fa9e4066Sahrens 
1588fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1589fa9e4066Sahrens 
1590fa9e4066Sahrens 	if (tdelta == 0)
1591fa9e4066Sahrens 		scale = 1.0;
1592fa9e4066Sahrens 	else
1593fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1594fa9e4066Sahrens 
1595fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1596fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1597fa9e4066Sahrens 		(void) printf("      -      -");
1598fa9e4066Sahrens 	} else {
1599fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1600fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1601fa9e4066Sahrens 	}
1602fa9e4066Sahrens 
1603fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1604fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1605fa9e4066Sahrens 
1606fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1607fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1608fa9e4066Sahrens 
1609fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1610fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1611fa9e4066Sahrens 
1612fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1613fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1614fa9e4066Sahrens 
1615fa9e4066Sahrens 	(void) printf("\n");
1616fa9e4066Sahrens 
1617fa9e4066Sahrens 	if (!cb->cb_verbose)
1618fa9e4066Sahrens 		return;
1619fa9e4066Sahrens 
1620fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1621fa9e4066Sahrens 	    &newchild, &children) != 0)
1622fa9e4066Sahrens 		return;
1623fa9e4066Sahrens 
1624fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1625fa9e4066Sahrens 	    &oldchild, &c) != 0)
1626fa9e4066Sahrens 		return;
1627fa9e4066Sahrens 
1628afefbcddSeschrock 	for (c = 0; c < children; c++) {
162999653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1630c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1631afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1632afefbcddSeschrock 		free(vname);
1633afefbcddSeschrock 	}
1634fa9e4066Sahrens }
1635fa9e4066Sahrens 
1636088e9d47Seschrock static int
1637088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
1638088e9d47Seschrock {
1639088e9d47Seschrock 	iostat_cbdata_t *cb = data;
164094de1d4cSeschrock 	boolean_t missing;
1641088e9d47Seschrock 
1642088e9d47Seschrock 	/*
1643088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
1644088e9d47Seschrock 	 */
164594de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
164694de1d4cSeschrock 		return (-1);
164794de1d4cSeschrock 
164894de1d4cSeschrock 	if (missing)
1649088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
1650088e9d47Seschrock 
1651088e9d47Seschrock 	return (0);
1652088e9d47Seschrock }
1653088e9d47Seschrock 
1654fa9e4066Sahrens /*
1655fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
1656fa9e4066Sahrens  */
1657fa9e4066Sahrens int
1658fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
1659fa9e4066Sahrens {
1660fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1661fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
1662fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
1663fa9e4066Sahrens 
1664088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
1665fa9e4066Sahrens 
1666088e9d47Seschrock 	if (cb->cb_iteration == 1)
1667fa9e4066Sahrens 		oldconfig = NULL;
1668fa9e4066Sahrens 
1669fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1670fa9e4066Sahrens 	    &newnvroot) == 0);
1671fa9e4066Sahrens 
1672088e9d47Seschrock 	if (oldconfig == NULL)
1673fa9e4066Sahrens 		oldnvroot = NULL;
1674088e9d47Seschrock 	else
1675088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
1676088e9d47Seschrock 		    &oldnvroot) == 0);
1677fa9e4066Sahrens 
1678fa9e4066Sahrens 	/*
1679fa9e4066Sahrens 	 * Print out the statistics for the pool.
1680fa9e4066Sahrens 	 */
1681c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1682fa9e4066Sahrens 
1683fa9e4066Sahrens 	if (cb->cb_verbose)
1684fa9e4066Sahrens 		print_iostat_separator(cb);
1685fa9e4066Sahrens 
1686fa9e4066Sahrens 	return (0);
1687fa9e4066Sahrens }
1688fa9e4066Sahrens 
1689fa9e4066Sahrens int
1690fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
1691fa9e4066Sahrens {
1692fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1693fa9e4066Sahrens 	nvlist_t *config, *nvroot;
1694fa9e4066Sahrens 
1695088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
1696fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1697fa9e4066Sahrens 		    &nvroot) == 0);
1698fa9e4066Sahrens 		if (!cb->cb_verbose)
1699fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1700fa9e4066Sahrens 		else
1701c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
1702fa9e4066Sahrens 	}
1703fa9e4066Sahrens 
1704fa9e4066Sahrens 	/*
1705fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
1706fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
1707fa9e4066Sahrens 	 */
1708fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
1709fa9e4066Sahrens 		cb->cb_namewidth = 10;
1710fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
1711fa9e4066Sahrens 		cb->cb_namewidth = 38;
1712fa9e4066Sahrens 
1713fa9e4066Sahrens 	return (0);
1714fa9e4066Sahrens }
1715fa9e4066Sahrens 
1716fa9e4066Sahrens /*
1717fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
1718fa9e4066Sahrens  *
1719fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
1720fa9e4066Sahrens  *
1721fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
1722fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
1723fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1724fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
1725fa9e4066Sahrens  * changes are all handled within libzfs.
1726fa9e4066Sahrens  */
1727fa9e4066Sahrens int
1728fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
1729fa9e4066Sahrens {
1730fa9e4066Sahrens 	int c;
1731fa9e4066Sahrens 	int ret;
1732fa9e4066Sahrens 	int npools;
1733fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
1734fa9e4066Sahrens 	zpool_list_t *list;
173599653d4eSeschrock 	boolean_t verbose = B_FALSE;
1736fa9e4066Sahrens 	iostat_cbdata_t cb;
1737fa9e4066Sahrens 
1738fa9e4066Sahrens 	/* check options */
1739fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
1740fa9e4066Sahrens 		switch (c) {
1741fa9e4066Sahrens 		case 'v':
174299653d4eSeschrock 			verbose = B_TRUE;
1743fa9e4066Sahrens 			break;
1744fa9e4066Sahrens 		case '?':
1745fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1746fa9e4066Sahrens 			    optopt);
174799653d4eSeschrock 			usage(B_FALSE);
1748fa9e4066Sahrens 		}
1749fa9e4066Sahrens 	}
1750fa9e4066Sahrens 
1751fa9e4066Sahrens 	argc -= optind;
1752fa9e4066Sahrens 	argv += optind;
1753fa9e4066Sahrens 
1754fa9e4066Sahrens 	/*
1755fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
1756fa9e4066Sahrens 	 */
1757fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1758fa9e4066Sahrens 		char *end;
1759fa9e4066Sahrens 
1760fa9e4066Sahrens 		errno = 0;
1761fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1762fa9e4066Sahrens 
1763fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1764fa9e4066Sahrens 			if (interval == 0) {
1765fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1766fa9e4066Sahrens 				    "cannot be zero\n"));
176799653d4eSeschrock 				usage(B_FALSE);
1768fa9e4066Sahrens 			}
1769fa9e4066Sahrens 
1770fa9e4066Sahrens 			/*
1771fa9e4066Sahrens 			 * Ignore the last parameter
1772fa9e4066Sahrens 			 */
1773fa9e4066Sahrens 			argc--;
1774fa9e4066Sahrens 		} else {
1775fa9e4066Sahrens 			/*
1776fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
1777fa9e4066Sahrens 			 * user will get a more informative error message later
1778fa9e4066Sahrens 			 * on.
1779fa9e4066Sahrens 			 */
1780fa9e4066Sahrens 			interval = 0;
1781fa9e4066Sahrens 		}
1782fa9e4066Sahrens 	}
1783fa9e4066Sahrens 
1784fa9e4066Sahrens 	/*
1785fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
1786fa9e4066Sahrens 	 * and an integer.
1787fa9e4066Sahrens 	 */
1788fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1789fa9e4066Sahrens 		char *end;
1790fa9e4066Sahrens 
1791fa9e4066Sahrens 		errno = 0;
1792fa9e4066Sahrens 		count = interval;
1793fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1794fa9e4066Sahrens 
1795fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1796fa9e4066Sahrens 			if (interval == 0) {
1797fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1798fa9e4066Sahrens 				    "cannot be zero\n"));
179999653d4eSeschrock 				usage(B_FALSE);
1800fa9e4066Sahrens 			}
1801fa9e4066Sahrens 
1802fa9e4066Sahrens 			/*
1803fa9e4066Sahrens 			 * Ignore the last parameter
1804fa9e4066Sahrens 			 */
1805fa9e4066Sahrens 			argc--;
1806fa9e4066Sahrens 		} else {
1807fa9e4066Sahrens 			interval = 0;
1808fa9e4066Sahrens 		}
1809fa9e4066Sahrens 	}
1810fa9e4066Sahrens 
1811fa9e4066Sahrens 	/*
1812fa9e4066Sahrens 	 * Construct the list of all interesting pools.
1813fa9e4066Sahrens 	 */
1814fa9e4066Sahrens 	ret = 0;
1815b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
1816fa9e4066Sahrens 		return (1);
1817fa9e4066Sahrens 
181899653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
181999653d4eSeschrock 		pool_list_free(list);
1820fa9e4066Sahrens 		return (1);
182199653d4eSeschrock 	}
1822fa9e4066Sahrens 
1823fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
182499653d4eSeschrock 		pool_list_free(list);
1825fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
1826fa9e4066Sahrens 		return (1);
1827fa9e4066Sahrens 	}
1828fa9e4066Sahrens 
1829fa9e4066Sahrens 	/*
1830fa9e4066Sahrens 	 * Enter the main iostat loop.
1831fa9e4066Sahrens 	 */
1832fa9e4066Sahrens 	cb.cb_list = list;
1833fa9e4066Sahrens 	cb.cb_verbose = verbose;
1834fa9e4066Sahrens 	cb.cb_iteration = 0;
1835fa9e4066Sahrens 	cb.cb_namewidth = 0;
1836fa9e4066Sahrens 
1837fa9e4066Sahrens 	for (;;) {
1838fa9e4066Sahrens 		pool_list_update(list);
1839fa9e4066Sahrens 
1840fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
1841fa9e4066Sahrens 			break;
1842fa9e4066Sahrens 
1843088e9d47Seschrock 		/*
1844088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
1845088e9d47Seschrock 		 * before calculating the maximum name width, so that any
1846088e9d47Seschrock 		 * configuration changes are properly accounted for.
1847088e9d47Seschrock 		 */
184899653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
1849088e9d47Seschrock 
1850fa9e4066Sahrens 		/*
1851fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
1852fa9e4066Sahrens 		 * for the pool / device name column across all pools.
1853fa9e4066Sahrens 		 */
1854fa9e4066Sahrens 		cb.cb_namewidth = 0;
185599653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
1856fa9e4066Sahrens 
1857fa9e4066Sahrens 		/*
1858fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
1859fa9e4066Sahrens 		 */
1860fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
1861fa9e4066Sahrens 			print_iostat_header(&cb);
1862fa9e4066Sahrens 
186399653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
1864fa9e4066Sahrens 
1865fa9e4066Sahrens 		/*
1866fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
1867fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
1868fa9e4066Sahrens 		 */
1869fa9e4066Sahrens 		if (npools > 1 && !verbose)
1870fa9e4066Sahrens 			print_iostat_separator(&cb);
1871fa9e4066Sahrens 
1872fa9e4066Sahrens 		if (verbose)
1873fa9e4066Sahrens 			(void) printf("\n");
1874fa9e4066Sahrens 
187539c23413Seschrock 		/*
187639c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
187739c23413Seschrock 		 * indefinitely.
187839c23413Seschrock 		 */
187939c23413Seschrock 		(void) fflush(stdout);
188039c23413Seschrock 
1881fa9e4066Sahrens 		if (interval == 0)
1882fa9e4066Sahrens 			break;
1883fa9e4066Sahrens 
1884fa9e4066Sahrens 		if (count != 0 && --count == 0)
1885fa9e4066Sahrens 			break;
1886fa9e4066Sahrens 
1887fa9e4066Sahrens 		(void) sleep(interval);
1888fa9e4066Sahrens 	}
1889fa9e4066Sahrens 
1890fa9e4066Sahrens 	pool_list_free(list);
1891fa9e4066Sahrens 
1892fa9e4066Sahrens 	return (ret);
1893fa9e4066Sahrens }
1894fa9e4066Sahrens 
1895fa9e4066Sahrens typedef struct list_cbdata {
189699653d4eSeschrock 	boolean_t	cb_scripted;
189799653d4eSeschrock 	boolean_t	cb_first;
1898*990b4856Slling 	zprop_list_t	*cb_proplist;
1899fa9e4066Sahrens } list_cbdata_t;
1900fa9e4066Sahrens 
1901fa9e4066Sahrens /*
1902fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
1903fa9e4066Sahrens  */
1904*990b4856Slling static void
1905*990b4856Slling print_header(zprop_list_t *pl)
1906fa9e4066Sahrens {
1907*990b4856Slling 	const char *header;
1908*990b4856Slling 	boolean_t first = B_TRUE;
1909*990b4856Slling 	boolean_t right_justify;
1910*990b4856Slling 
1911*990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
1912*990b4856Slling 		if (pl->pl_prop == ZPROP_INVAL)
1913*990b4856Slling 			continue;
1914fa9e4066Sahrens 
1915*990b4856Slling 		if (!first)
1916fa9e4066Sahrens 			(void) printf("  ");
1917fa9e4066Sahrens 		else
1918*990b4856Slling 			first = B_FALSE;
1919*990b4856Slling 
1920*990b4856Slling 		header = zpool_prop_column_name(pl->pl_prop);
1921*990b4856Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
1922fa9e4066Sahrens 
1923*990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
1924*990b4856Slling 			(void) printf("%s", header);
1925*990b4856Slling 		else if (right_justify)
1926*990b4856Slling 			(void) printf("%*s", pl->pl_width, header);
1927*990b4856Slling 		else
1928*990b4856Slling 			(void) printf("%-*s", pl->pl_width, header);
1929fa9e4066Sahrens 	}
1930fa9e4066Sahrens 
1931fa9e4066Sahrens 	(void) printf("\n");
1932fa9e4066Sahrens }
1933fa9e4066Sahrens 
1934*990b4856Slling /*
1935*990b4856Slling  * Given a pool and a list of properties, print out all the properties according
1936*990b4856Slling  * to the described layout.
1937*990b4856Slling  */
1938*990b4856Slling static void
1939*990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
1940fa9e4066Sahrens {
1941*990b4856Slling 	boolean_t first = B_TRUE;
1942*990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
1943*990b4856Slling 	char *propstr;
1944*990b4856Slling 	boolean_t right_justify;
1945*990b4856Slling 	int width;
1946*990b4856Slling 
1947*990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
1948*990b4856Slling 		if (!first) {
1949*990b4856Slling 			if (scripted)
1950fa9e4066Sahrens 				(void) printf("\t");
1951fa9e4066Sahrens 			else
1952fa9e4066Sahrens 				(void) printf("  ");
1953*990b4856Slling 		} else {
1954*990b4856Slling 			first = B_FALSE;
1955fa9e4066Sahrens 		}
1956fa9e4066Sahrens 
1957*990b4856Slling 		right_justify = B_FALSE;
1958*990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
1959*990b4856Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
1960*990b4856Slling 			    sizeof (property), NULL) != 0)
1961*990b4856Slling 				propstr = "-";
1962fa9e4066Sahrens 			else
1963*990b4856Slling 				propstr = property;
1964fa9e4066Sahrens 
1965*990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
1966*990b4856Slling 		} else {
1967*990b4856Slling 			propstr = "-";
1968*990b4856Slling 		}
1969fa9e4066Sahrens 
1970*990b4856Slling 		width = pl->pl_width;
1971fa9e4066Sahrens 
1972*990b4856Slling 		/*
1973*990b4856Slling 		 * If this is being called in scripted mode, or if this is the
1974*990b4856Slling 		 * last column and it is left-justified, don't include a width
1975*990b4856Slling 		 * format specifier.
1976*990b4856Slling 		 */
1977*990b4856Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
1978*990b4856Slling 			(void) printf("%s", propstr);
1979*990b4856Slling 		else if (right_justify)
1980*990b4856Slling 			(void) printf("%*s", width, propstr);
1981*990b4856Slling 		else
1982*990b4856Slling 			(void) printf("%-*s", width, propstr);
1983*990b4856Slling 	}
1984fa9e4066Sahrens 
1985*990b4856Slling 	(void) printf("\n");
1986*990b4856Slling }
1987fa9e4066Sahrens 
1988*990b4856Slling /*
1989*990b4856Slling  * Generic callback function to list a pool.
1990*990b4856Slling  */
1991*990b4856Slling int
1992*990b4856Slling list_callback(zpool_handle_t *zhp, void *data)
1993*990b4856Slling {
1994*990b4856Slling 	list_cbdata_t *cbp = data;
1995fa9e4066Sahrens 
1996*990b4856Slling 	if (cbp->cb_first) {
1997*990b4856Slling 		if (!cbp->cb_scripted)
1998*990b4856Slling 			print_header(cbp->cb_proplist);
1999*990b4856Slling 		cbp->cb_first = B_FALSE;
2000fa9e4066Sahrens 	}
2001fa9e4066Sahrens 
2002*990b4856Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2003fa9e4066Sahrens 
2004fa9e4066Sahrens 	return (0);
2005fa9e4066Sahrens }
2006fa9e4066Sahrens 
2007fa9e4066Sahrens /*
2008*990b4856Slling  * zpool list [-H] [-o prop[,prop]*] [pool] ...
2009fa9e4066Sahrens  *
2010*990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2011*990b4856Slling  *		by a single tab.
2012*990b4856Slling  *	-o	List of properties to display.  Defaults to
2013*990b4856Slling  *		"name,size,used,available,capacity,health,altroot"
2014fa9e4066Sahrens  *
2015fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2016fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2017fa9e4066Sahrens  */
2018fa9e4066Sahrens int
2019fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2020fa9e4066Sahrens {
2021fa9e4066Sahrens 	int c;
2022fa9e4066Sahrens 	int ret;
2023fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2024*990b4856Slling 	static char default_props[] =
2025*990b4856Slling 	    "name,size,used,available,capacity,health,altroot";
2026*990b4856Slling 	char *props = default_props;
2027fa9e4066Sahrens 
2028fa9e4066Sahrens 	/* check options */
2029fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2030fa9e4066Sahrens 		switch (c) {
2031fa9e4066Sahrens 		case 'H':
203299653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2033fa9e4066Sahrens 			break;
2034fa9e4066Sahrens 		case 'o':
2035*990b4856Slling 			props = optarg;
2036fa9e4066Sahrens 			break;
2037fa9e4066Sahrens 		case ':':
2038fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2039fa9e4066Sahrens 			    "'%c' option\n"), optopt);
204099653d4eSeschrock 			usage(B_FALSE);
2041fa9e4066Sahrens 			break;
2042fa9e4066Sahrens 		case '?':
2043fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2044fa9e4066Sahrens 			    optopt);
204599653d4eSeschrock 			usage(B_FALSE);
2046fa9e4066Sahrens 		}
2047fa9e4066Sahrens 	}
2048fa9e4066Sahrens 
2049fa9e4066Sahrens 	argc -= optind;
2050fa9e4066Sahrens 	argv += optind;
2051fa9e4066Sahrens 
2052*990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
2053*990b4856Slling 		usage(B_FALSE);
2054fa9e4066Sahrens 
205599653d4eSeschrock 	cb.cb_first = B_TRUE;
2056fa9e4066Sahrens 
2057*990b4856Slling 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2058*990b4856Slling 	    list_callback, &cb);
2059*990b4856Slling 
2060*990b4856Slling 	zprop_free_list(cb.cb_proplist);
2061fa9e4066Sahrens 
2062fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2063fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2064fa9e4066Sahrens 		return (0);
2065fa9e4066Sahrens 	}
2066fa9e4066Sahrens 
2067fa9e4066Sahrens 	return (ret);
2068fa9e4066Sahrens }
2069fa9e4066Sahrens 
2070fa9e4066Sahrens static nvlist_t *
2071fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2072fa9e4066Sahrens {
2073fa9e4066Sahrens 	nvlist_t **child;
2074fa9e4066Sahrens 	uint_t c, children;
2075fa9e4066Sahrens 	nvlist_t *match;
2076fa9e4066Sahrens 	char *path;
2077fa9e4066Sahrens 
2078fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2079fa9e4066Sahrens 	    &child, &children) != 0) {
2080fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2081fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2082fa9e4066Sahrens 			name += 9;
2083fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2084fa9e4066Sahrens 			path += 9;
2085fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2086fa9e4066Sahrens 			return (nv);
2087fa9e4066Sahrens 		return (NULL);
2088fa9e4066Sahrens 	}
2089fa9e4066Sahrens 
2090fa9e4066Sahrens 	for (c = 0; c < children; c++)
2091fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2092fa9e4066Sahrens 			return (match);
2093fa9e4066Sahrens 
2094fa9e4066Sahrens 	return (NULL);
2095fa9e4066Sahrens }
2096fa9e4066Sahrens 
2097fa9e4066Sahrens static int
2098fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2099fa9e4066Sahrens {
210099653d4eSeschrock 	boolean_t force = B_FALSE;
2101fa9e4066Sahrens 	int c;
2102fa9e4066Sahrens 	nvlist_t *nvroot;
2103fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2104fa9e4066Sahrens 	zpool_handle_t *zhp;
210599653d4eSeschrock 	int ret;
2106fa9e4066Sahrens 
2107fa9e4066Sahrens 	/* check options */
2108fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2109fa9e4066Sahrens 		switch (c) {
2110fa9e4066Sahrens 		case 'f':
211199653d4eSeschrock 			force = B_TRUE;
2112fa9e4066Sahrens 			break;
2113fa9e4066Sahrens 		case '?':
2114fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2115fa9e4066Sahrens 			    optopt);
211699653d4eSeschrock 			usage(B_FALSE);
2117fa9e4066Sahrens 		}
2118fa9e4066Sahrens 	}
2119fa9e4066Sahrens 
2120fa9e4066Sahrens 	argc -= optind;
2121fa9e4066Sahrens 	argv += optind;
2122fa9e4066Sahrens 
2123fa9e4066Sahrens 	/* get pool name and check number of arguments */
2124fa9e4066Sahrens 	if (argc < 1) {
2125fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
212699653d4eSeschrock 		usage(B_FALSE);
2127fa9e4066Sahrens 	}
2128fa9e4066Sahrens 
2129fa9e4066Sahrens 	poolname = argv[0];
2130fa9e4066Sahrens 
2131fa9e4066Sahrens 	if (argc < 2) {
2132fa9e4066Sahrens 		(void) fprintf(stderr,
2133fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
213499653d4eSeschrock 		usage(B_FALSE);
2135fa9e4066Sahrens 	}
2136fa9e4066Sahrens 
2137fa9e4066Sahrens 	old_disk = argv[1];
2138fa9e4066Sahrens 
2139fa9e4066Sahrens 	if (argc < 3) {
2140fa9e4066Sahrens 		if (!replacing) {
2141fa9e4066Sahrens 			(void) fprintf(stderr,
2142fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
214399653d4eSeschrock 			usage(B_FALSE);
2144fa9e4066Sahrens 		}
2145fa9e4066Sahrens 		new_disk = old_disk;
2146fa9e4066Sahrens 		argc -= 1;
2147fa9e4066Sahrens 		argv += 1;
2148fa9e4066Sahrens 	} else {
2149fa9e4066Sahrens 		new_disk = argv[2];
2150fa9e4066Sahrens 		argc -= 2;
2151fa9e4066Sahrens 		argv += 2;
2152fa9e4066Sahrens 	}
2153fa9e4066Sahrens 
2154fa9e4066Sahrens 	if (argc > 1) {
2155fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
215699653d4eSeschrock 		usage(B_FALSE);
2157fa9e4066Sahrens 	}
2158fa9e4066Sahrens 
215999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2160fa9e4066Sahrens 		return (1);
2161fa9e4066Sahrens 
21628488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2163fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2164fa9e4066Sahrens 		    poolname);
2165fa9e4066Sahrens 		zpool_close(zhp);
2166fa9e4066Sahrens 		return (1);
2167fa9e4066Sahrens 	}
2168fa9e4066Sahrens 
21698488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv);
2170fa9e4066Sahrens 	if (nvroot == NULL) {
2171fa9e4066Sahrens 		zpool_close(zhp);
2172fa9e4066Sahrens 		return (1);
2173fa9e4066Sahrens 	}
2174fa9e4066Sahrens 
217599653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
217699653d4eSeschrock 
217799653d4eSeschrock 	nvlist_free(nvroot);
217899653d4eSeschrock 	zpool_close(zhp);
217999653d4eSeschrock 
218099653d4eSeschrock 	return (ret);
2181fa9e4066Sahrens }
2182fa9e4066Sahrens 
2183fa9e4066Sahrens /*
2184fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2185fa9e4066Sahrens  *
2186fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2187fa9e4066Sahrens  *
2188fa9e4066Sahrens  * Replace <device> with <new_device>.
2189fa9e4066Sahrens  */
2190fa9e4066Sahrens /* ARGSUSED */
2191fa9e4066Sahrens int
2192fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2193fa9e4066Sahrens {
2194fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2195fa9e4066Sahrens }
2196fa9e4066Sahrens 
2197fa9e4066Sahrens /*
2198fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2199fa9e4066Sahrens  *
2200fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2201fa9e4066Sahrens  *
2202fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2203fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2204fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2205fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2206fa9e4066Sahrens  */
2207fa9e4066Sahrens int
2208fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2209fa9e4066Sahrens {
2210fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2211fa9e4066Sahrens }
2212fa9e4066Sahrens 
2213fa9e4066Sahrens /*
2214fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2215fa9e4066Sahrens  *
2216fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2217fa9e4066Sahrens  *		(not supported yet)
2218fa9e4066Sahrens  *
2219fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2220fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2221fa9e4066Sahrens  * has the only valid copy of some data.
2222fa9e4066Sahrens  */
2223fa9e4066Sahrens /* ARGSUSED */
2224fa9e4066Sahrens int
2225fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2226fa9e4066Sahrens {
2227fa9e4066Sahrens 	int c;
2228fa9e4066Sahrens 	char *poolname, *path;
2229fa9e4066Sahrens 	zpool_handle_t *zhp;
223099653d4eSeschrock 	int ret;
2231fa9e4066Sahrens 
2232fa9e4066Sahrens 	/* check options */
2233fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2234fa9e4066Sahrens 		switch (c) {
2235fa9e4066Sahrens 		case 'f':
2236fa9e4066Sahrens 		case '?':
2237fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2238fa9e4066Sahrens 			    optopt);
223999653d4eSeschrock 			usage(B_FALSE);
2240fa9e4066Sahrens 		}
2241fa9e4066Sahrens 	}
2242fa9e4066Sahrens 
2243fa9e4066Sahrens 	argc -= optind;
2244fa9e4066Sahrens 	argv += optind;
2245fa9e4066Sahrens 
2246fa9e4066Sahrens 	/* get pool name and check number of arguments */
2247fa9e4066Sahrens 	if (argc < 1) {
2248fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
224999653d4eSeschrock 		usage(B_FALSE);
2250fa9e4066Sahrens 	}
2251fa9e4066Sahrens 
2252fa9e4066Sahrens 	if (argc < 2) {
2253fa9e4066Sahrens 		(void) fprintf(stderr,
2254fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
225599653d4eSeschrock 		usage(B_FALSE);
2256fa9e4066Sahrens 	}
2257fa9e4066Sahrens 
2258fa9e4066Sahrens 	poolname = argv[0];
2259fa9e4066Sahrens 	path = argv[1];
2260fa9e4066Sahrens 
226199653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2262fa9e4066Sahrens 		return (1);
2263fa9e4066Sahrens 
226499653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
226599653d4eSeschrock 
226699653d4eSeschrock 	zpool_close(zhp);
226799653d4eSeschrock 
226899653d4eSeschrock 	return (ret);
2269fa9e4066Sahrens }
2270fa9e4066Sahrens 
2271fa9e4066Sahrens /*
2272441d80aaSlling  * zpool online <pool> <device> ...
2273fa9e4066Sahrens  */
2274fa9e4066Sahrens int
2275fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2276fa9e4066Sahrens {
2277fa9e4066Sahrens 	int c, i;
2278fa9e4066Sahrens 	char *poolname;
2279fa9e4066Sahrens 	zpool_handle_t *zhp;
2280fa9e4066Sahrens 	int ret = 0;
22813d7072f8Seschrock 	vdev_state_t newstate;
2282fa9e4066Sahrens 
2283fa9e4066Sahrens 	/* check options */
2284fa9e4066Sahrens 	while ((c = getopt(argc, argv, "t")) != -1) {
2285fa9e4066Sahrens 		switch (c) {
2286fa9e4066Sahrens 		case 't':
2287fa9e4066Sahrens 		case '?':
2288fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2289fa9e4066Sahrens 			    optopt);
229099653d4eSeschrock 			usage(B_FALSE);
2291fa9e4066Sahrens 		}
2292fa9e4066Sahrens 	}
2293fa9e4066Sahrens 
2294fa9e4066Sahrens 	argc -= optind;
2295fa9e4066Sahrens 	argv += optind;
2296fa9e4066Sahrens 
2297fa9e4066Sahrens 	/* get pool name and check number of arguments */
2298fa9e4066Sahrens 	if (argc < 1) {
2299fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
230099653d4eSeschrock 		usage(B_FALSE);
2301fa9e4066Sahrens 	}
2302fa9e4066Sahrens 	if (argc < 2) {
2303fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
230499653d4eSeschrock 		usage(B_FALSE);
2305fa9e4066Sahrens 	}
2306fa9e4066Sahrens 
2307fa9e4066Sahrens 	poolname = argv[0];
2308fa9e4066Sahrens 
230999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2310fa9e4066Sahrens 		return (1);
2311fa9e4066Sahrens 
23123d7072f8Seschrock 	for (i = 1; i < argc; i++) {
23133d7072f8Seschrock 		if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
23143d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
23153d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
23163d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
23173d7072f8Seschrock 				    argv[i]);
23183d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
23193d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
23203d7072f8Seschrock 					    "clear' to restore a faulted "
23213d7072f8Seschrock 					    "device\n"));
23223d7072f8Seschrock 				else
23233d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
23243d7072f8Seschrock 					    "replace' to replace devices "
23253d7072f8Seschrock 					    "that are no longer present\n"));
23263d7072f8Seschrock 			}
23273d7072f8Seschrock 		} else {
2328fa9e4066Sahrens 			ret = 1;
23293d7072f8Seschrock 		}
23303d7072f8Seschrock 	}
2331fa9e4066Sahrens 
233299653d4eSeschrock 	zpool_close(zhp);
233399653d4eSeschrock 
2334fa9e4066Sahrens 	return (ret);
2335fa9e4066Sahrens }
2336fa9e4066Sahrens 
2337fa9e4066Sahrens /*
2338441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2339fa9e4066Sahrens  *
2340fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2341fa9e4066Sahrens  *		so would appear to compromise pool availability.
2342fa9e4066Sahrens  *		(not supported yet)
2343fa9e4066Sahrens  *
2344fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2345fa9e4066Sahrens  *		state will not be persistent across reboots.
2346fa9e4066Sahrens  */
2347fa9e4066Sahrens /* ARGSUSED */
2348fa9e4066Sahrens int
2349fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2350fa9e4066Sahrens {
2351fa9e4066Sahrens 	int c, i;
2352fa9e4066Sahrens 	char *poolname;
2353fa9e4066Sahrens 	zpool_handle_t *zhp;
235499653d4eSeschrock 	int ret = 0;
235599653d4eSeschrock 	boolean_t istmp = B_FALSE;
2356fa9e4066Sahrens 
2357fa9e4066Sahrens 	/* check options */
2358fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2359fa9e4066Sahrens 		switch (c) {
2360fa9e4066Sahrens 		case 't':
236199653d4eSeschrock 			istmp = B_TRUE;
2362441d80aaSlling 			break;
2363441d80aaSlling 		case 'f':
2364fa9e4066Sahrens 		case '?':
2365fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2366fa9e4066Sahrens 			    optopt);
236799653d4eSeschrock 			usage(B_FALSE);
2368fa9e4066Sahrens 		}
2369fa9e4066Sahrens 	}
2370fa9e4066Sahrens 
2371fa9e4066Sahrens 	argc -= optind;
2372fa9e4066Sahrens 	argv += optind;
2373fa9e4066Sahrens 
2374fa9e4066Sahrens 	/* get pool name and check number of arguments */
2375fa9e4066Sahrens 	if (argc < 1) {
2376fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
237799653d4eSeschrock 		usage(B_FALSE);
2378fa9e4066Sahrens 	}
2379fa9e4066Sahrens 	if (argc < 2) {
2380fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
238199653d4eSeschrock 		usage(B_FALSE);
2382fa9e4066Sahrens 	}
2383fa9e4066Sahrens 
2384fa9e4066Sahrens 	poolname = argv[0];
2385fa9e4066Sahrens 
238699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2387fa9e4066Sahrens 		return (1);
2388fa9e4066Sahrens 
23893d7072f8Seschrock 	for (i = 1; i < argc; i++) {
23903d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2391fa9e4066Sahrens 			ret = 1;
23923d7072f8Seschrock 	}
2393fa9e4066Sahrens 
239499653d4eSeschrock 	zpool_close(zhp);
239599653d4eSeschrock 
2396fa9e4066Sahrens 	return (ret);
2397fa9e4066Sahrens }
2398fa9e4066Sahrens 
2399ea8dc4b6Seschrock /*
2400ea8dc4b6Seschrock  * zpool clear <pool> [device]
2401ea8dc4b6Seschrock  *
2402ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2403ea8dc4b6Seschrock  */
2404ea8dc4b6Seschrock int
2405ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2406ea8dc4b6Seschrock {
2407ea8dc4b6Seschrock 	int ret = 0;
2408ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2409ea8dc4b6Seschrock 	char *pool, *device;
2410ea8dc4b6Seschrock 
2411ea8dc4b6Seschrock 	if (argc < 2) {
2412ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
241399653d4eSeschrock 		usage(B_FALSE);
2414ea8dc4b6Seschrock 	}
2415ea8dc4b6Seschrock 
2416ea8dc4b6Seschrock 	if (argc > 3) {
2417ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
241899653d4eSeschrock 		usage(B_FALSE);
2419ea8dc4b6Seschrock 	}
2420ea8dc4b6Seschrock 
2421ea8dc4b6Seschrock 	pool = argv[1];
2422ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2423ea8dc4b6Seschrock 
242499653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, pool)) == NULL)
2425ea8dc4b6Seschrock 		return (1);
2426ea8dc4b6Seschrock 
2427ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2428ea8dc4b6Seschrock 		ret = 1;
2429ea8dc4b6Seschrock 
2430ea8dc4b6Seschrock 	zpool_close(zhp);
2431ea8dc4b6Seschrock 
2432ea8dc4b6Seschrock 	return (ret);
2433ea8dc4b6Seschrock }
2434ea8dc4b6Seschrock 
2435fa9e4066Sahrens typedef struct scrub_cbdata {
2436fa9e4066Sahrens 	int	cb_type;
243706eeb2adSek 	int	cb_argc;
243806eeb2adSek 	char	**cb_argv;
2439fa9e4066Sahrens } scrub_cbdata_t;
2440fa9e4066Sahrens 
2441fa9e4066Sahrens int
2442fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2443fa9e4066Sahrens {
2444fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
244506eeb2adSek 	int err;
2446fa9e4066Sahrens 
2447ea8dc4b6Seschrock 	/*
2448ea8dc4b6Seschrock 	 * Ignore faulted pools.
2449ea8dc4b6Seschrock 	 */
2450ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2451ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2452ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2453ea8dc4b6Seschrock 		return (1);
2454ea8dc4b6Seschrock 	}
2455ea8dc4b6Seschrock 
245606eeb2adSek 	err = zpool_scrub(zhp, cb->cb_type);
245706eeb2adSek 
245806eeb2adSek 	return (err != 0);
2459fa9e4066Sahrens }
2460fa9e4066Sahrens 
2461fa9e4066Sahrens /*
2462fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2463fa9e4066Sahrens  *
2464fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2465fa9e4066Sahrens  */
2466fa9e4066Sahrens int
2467fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2468fa9e4066Sahrens {
2469fa9e4066Sahrens 	int c;
2470fa9e4066Sahrens 	scrub_cbdata_t cb;
2471fa9e4066Sahrens 
2472fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2473fa9e4066Sahrens 
2474fa9e4066Sahrens 	/* check options */
2475fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2476fa9e4066Sahrens 		switch (c) {
2477fa9e4066Sahrens 		case 's':
2478fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2479fa9e4066Sahrens 			break;
2480fa9e4066Sahrens 		case '?':
2481fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2482fa9e4066Sahrens 			    optopt);
248399653d4eSeschrock 			usage(B_FALSE);
2484fa9e4066Sahrens 		}
2485fa9e4066Sahrens 	}
2486fa9e4066Sahrens 
248706eeb2adSek 	cb.cb_argc = argc;
248806eeb2adSek 	cb.cb_argv = argv;
2489fa9e4066Sahrens 	argc -= optind;
2490fa9e4066Sahrens 	argv += optind;
2491fa9e4066Sahrens 
2492fa9e4066Sahrens 	if (argc < 1) {
2493fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
249499653d4eSeschrock 		usage(B_FALSE);
2495fa9e4066Sahrens 	}
2496fa9e4066Sahrens 
2497b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2498fa9e4066Sahrens }
2499fa9e4066Sahrens 
2500fa9e4066Sahrens typedef struct status_cbdata {
250199653d4eSeschrock 	int		cb_count;
2502e9dbad6fSeschrock 	boolean_t	cb_allpools;
250399653d4eSeschrock 	boolean_t	cb_verbose;
250499653d4eSeschrock 	boolean_t	cb_explain;
250599653d4eSeschrock 	boolean_t	cb_first;
2506fa9e4066Sahrens } status_cbdata_t;
2507fa9e4066Sahrens 
2508fa9e4066Sahrens /*
2509fa9e4066Sahrens  * Print out detailed scrub status.
2510fa9e4066Sahrens  */
2511fa9e4066Sahrens void
2512fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2513fa9e4066Sahrens {
2514fa9e4066Sahrens 	vdev_stat_t *vs;
2515fa9e4066Sahrens 	uint_t vsc;
2516fa9e4066Sahrens 	time_t start, end, now;
2517fa9e4066Sahrens 	double fraction_done;
2518fa9e4066Sahrens 	uint64_t examined, total, minutes_left;
2519fa9e4066Sahrens 	char *scrub_type;
2520fa9e4066Sahrens 
2521fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2522fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2523fa9e4066Sahrens 
2524fa9e4066Sahrens 	/*
2525fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2526fa9e4066Sahrens 	 */
2527fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2528fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2529fa9e4066Sahrens 		return;
2530fa9e4066Sahrens 	}
2531fa9e4066Sahrens 
2532fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2533fa9e4066Sahrens 	    "resilver" : "scrub";
2534fa9e4066Sahrens 
2535fa9e4066Sahrens 	start = vs->vs_scrub_start;
2536fa9e4066Sahrens 	end = vs->vs_scrub_end;
2537fa9e4066Sahrens 	now = time(NULL);
2538fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2539fa9e4066Sahrens 	total = vs->vs_alloc;
2540fa9e4066Sahrens 
2541fa9e4066Sahrens 	if (end != 0) {
2542fa9e4066Sahrens 		(void) printf(gettext("%s %s with %llu errors on %s"),
2543fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
2544fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2545fa9e4066Sahrens 		return;
2546fa9e4066Sahrens 	}
2547fa9e4066Sahrens 
2548fa9e4066Sahrens 	if (examined == 0)
2549fa9e4066Sahrens 		examined = 1;
2550fa9e4066Sahrens 	if (examined > total)
2551fa9e4066Sahrens 		total = examined;
2552fa9e4066Sahrens 
2553fa9e4066Sahrens 	fraction_done = (double)examined / total;
2554fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2555fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
2556fa9e4066Sahrens 
2557fa9e4066Sahrens 	(void) printf(gettext("%s in progress, %.2f%% done, %lluh%um to go\n"),
2558fa9e4066Sahrens 	    scrub_type, 100 * fraction_done,
2559fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2560fa9e4066Sahrens }
2561fa9e4066Sahrens 
256299653d4eSeschrock typedef struct spare_cbdata {
256399653d4eSeschrock 	uint64_t	cb_guid;
256499653d4eSeschrock 	zpool_handle_t	*cb_zhp;
256599653d4eSeschrock } spare_cbdata_t;
256699653d4eSeschrock 
256799653d4eSeschrock static boolean_t
256899653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search)
256999653d4eSeschrock {
257099653d4eSeschrock 	uint64_t guid;
257199653d4eSeschrock 	nvlist_t **child;
257299653d4eSeschrock 	uint_t c, children;
257399653d4eSeschrock 
257499653d4eSeschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
257599653d4eSeschrock 	    search == guid)
257699653d4eSeschrock 		return (B_TRUE);
257799653d4eSeschrock 
257899653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
257999653d4eSeschrock 	    &child, &children) == 0) {
258099653d4eSeschrock 		for (c = 0; c < children; c++)
258199653d4eSeschrock 			if (find_vdev(child[c], search))
258299653d4eSeschrock 				return (B_TRUE);
258399653d4eSeschrock 	}
258499653d4eSeschrock 
258599653d4eSeschrock 	return (B_FALSE);
258699653d4eSeschrock }
258799653d4eSeschrock 
258899653d4eSeschrock static int
258999653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data)
259099653d4eSeschrock {
259199653d4eSeschrock 	spare_cbdata_t *cbp = data;
259299653d4eSeschrock 	nvlist_t *config, *nvroot;
259399653d4eSeschrock 
259499653d4eSeschrock 	config = zpool_get_config(zhp, NULL);
259599653d4eSeschrock 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
259699653d4eSeschrock 	    &nvroot) == 0);
259799653d4eSeschrock 
259899653d4eSeschrock 	if (find_vdev(nvroot, cbp->cb_guid)) {
259999653d4eSeschrock 		cbp->cb_zhp = zhp;
260099653d4eSeschrock 		return (1);
260199653d4eSeschrock 	}
260299653d4eSeschrock 
260399653d4eSeschrock 	zpool_close(zhp);
260499653d4eSeschrock 	return (0);
260599653d4eSeschrock }
260699653d4eSeschrock 
2607fa9e4066Sahrens /*
2608fa9e4066Sahrens  * Print out configuration state as requested by status_callback.
2609fa9e4066Sahrens  */
2610fa9e4066Sahrens void
2611c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
26128654d025Sperrin     int namewidth, int depth, boolean_t isspare, boolean_t print_logs)
2613fa9e4066Sahrens {
2614fa9e4066Sahrens 	nvlist_t **child;
2615fa9e4066Sahrens 	uint_t c, children;
2616fa9e4066Sahrens 	vdev_stat_t *vs;
2617ea8dc4b6Seschrock 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
2618afefbcddSeschrock 	char *vname;
2619ea8dc4b6Seschrock 	uint64_t notpresent;
262099653d4eSeschrock 	spare_cbdata_t cb;
2621*990b4856Slling 	char *state;
2622fa9e4066Sahrens 
2623fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2624fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2625fa9e4066Sahrens 
2626fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2627fa9e4066Sahrens 	    &child, &children) != 0)
2628fa9e4066Sahrens 		children = 0;
2629fa9e4066Sahrens 
2630*990b4856Slling 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
263199653d4eSeschrock 	if (isspare) {
263299653d4eSeschrock 		/*
263399653d4eSeschrock 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
263499653d4eSeschrock 		 * online drives.
263599653d4eSeschrock 		 */
263699653d4eSeschrock 		if (vs->vs_aux == VDEV_AUX_SPARED)
263799653d4eSeschrock 			state = "INUSE";
263899653d4eSeschrock 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
263999653d4eSeschrock 			state = "AVAIL";
264099653d4eSeschrock 	}
264199653d4eSeschrock 
2642fa9e4066Sahrens 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
264399653d4eSeschrock 	    name, state);
2644fa9e4066Sahrens 
264599653d4eSeschrock 	if (!isspare) {
264699653d4eSeschrock 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
264799653d4eSeschrock 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
264899653d4eSeschrock 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
264999653d4eSeschrock 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
265099653d4eSeschrock 	}
2651fa9e4066Sahrens 
2652ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2653ea8dc4b6Seschrock 	    &notpresent) == 0) {
2654ea8dc4b6Seschrock 		char *path;
2655ea8dc4b6Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
26560917b783Seschrock 		(void) printf("  was %s", path);
2657ea8dc4b6Seschrock 	} else if (vs->vs_aux != 0) {
2658fa9e4066Sahrens 		(void) printf("  ");
2659fa9e4066Sahrens 
2660fa9e4066Sahrens 		switch (vs->vs_aux) {
2661fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2662fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2663fa9e4066Sahrens 			break;
2664fa9e4066Sahrens 
2665fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2666fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2667fa9e4066Sahrens 			break;
2668fa9e4066Sahrens 
2669fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2670fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2671fa9e4066Sahrens 			break;
2672fa9e4066Sahrens 
2673eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
2674eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
2675eaca9bbdSeschrock 			break;
2676eaca9bbdSeschrock 
267799653d4eSeschrock 		case VDEV_AUX_SPARED:
267899653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
267999653d4eSeschrock 			    &cb.cb_guid) == 0);
268099653d4eSeschrock 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
268199653d4eSeschrock 				if (strcmp(zpool_get_name(cb.cb_zhp),
268299653d4eSeschrock 				    zpool_get_name(zhp)) == 0)
268399653d4eSeschrock 					(void) printf(gettext("currently in "
268499653d4eSeschrock 					    "use"));
268599653d4eSeschrock 				else
268699653d4eSeschrock 					(void) printf(gettext("in use by "
268799653d4eSeschrock 					    "pool '%s'"),
268899653d4eSeschrock 					    zpool_get_name(cb.cb_zhp));
268999653d4eSeschrock 				zpool_close(cb.cb_zhp);
269099653d4eSeschrock 			} else {
269199653d4eSeschrock 				(void) printf(gettext("currently in use"));
269299653d4eSeschrock 			}
269399653d4eSeschrock 			break;
269499653d4eSeschrock 
26953d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
26963d7072f8Seschrock 			(void) printf(gettext("too many errors"));
26973d7072f8Seschrock 			break;
26983d7072f8Seschrock 
2699fa9e4066Sahrens 		default:
2700fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2701fa9e4066Sahrens 			break;
2702fa9e4066Sahrens 		}
2703fa9e4066Sahrens 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2704fa9e4066Sahrens 		/*
2705fa9e4066Sahrens 		 * Report bytes resilvered/repaired on leaf devices.
2706fa9e4066Sahrens 		 */
2707fa9e4066Sahrens 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2708fa9e4066Sahrens 		(void) printf(gettext("  %s %s"), repaired,
2709fa9e4066Sahrens 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2710fa9e4066Sahrens 		    "resilvered" : "repaired");
2711fa9e4066Sahrens 	}
2712fa9e4066Sahrens 
2713fa9e4066Sahrens 	(void) printf("\n");
2714fa9e4066Sahrens 
2715afefbcddSeschrock 	for (c = 0; c < children; c++) {
27168654d025Sperrin 		uint64_t is_log = B_FALSE;
27178654d025Sperrin 
27188654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
27198654d025Sperrin 		    &is_log);
27208654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
27218654d025Sperrin 			continue;
272299653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
2723c67d9675Seschrock 		print_status_config(zhp, vname, child[c],
27248654d025Sperrin 		    namewidth, depth + 2, isspare, B_FALSE);
2725afefbcddSeschrock 		free(vname);
2726afefbcddSeschrock 	}
2727fa9e4066Sahrens }
2728fa9e4066Sahrens 
2729ea8dc4b6Seschrock static void
2730ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
2731ea8dc4b6Seschrock {
273275519f38Sek 	nvlist_t *nverrlist = NULL;
273355434c77Sek 	nvpair_t *elem;
273455434c77Sek 	char *pathname;
273555434c77Sek 	size_t len = MAXPATHLEN * 2;
2736ea8dc4b6Seschrock 
273755434c77Sek 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2738ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
2739ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
2740ea8dc4b6Seschrock 		return;
2741ea8dc4b6Seschrock 	}
2742ea8dc4b6Seschrock 
274355434c77Sek 	(void) printf("errors: Permanent errors have been "
274455434c77Sek 	    "detected in the following files:\n\n");
2745ea8dc4b6Seschrock 
274655434c77Sek 	pathname = safe_malloc(len);
274755434c77Sek 	elem = NULL;
274855434c77Sek 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
274955434c77Sek 		nvlist_t *nv;
275055434c77Sek 		uint64_t dsobj, obj;
275155434c77Sek 
275255434c77Sek 		verify(nvpair_value_nvlist(elem, &nv) == 0);
275355434c77Sek 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
275455434c77Sek 		    &dsobj) == 0);
275555434c77Sek 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
275655434c77Sek 		    &obj) == 0);
275755434c77Sek 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
275855434c77Sek 		(void) printf("%7s %s\n", "", pathname);
275955434c77Sek 	}
276055434c77Sek 	free(pathname);
276155434c77Sek 	nvlist_free(nverrlist);
2762ea8dc4b6Seschrock }
2763ea8dc4b6Seschrock 
276499653d4eSeschrock static void
276599653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
276699653d4eSeschrock     int namewidth)
276799653d4eSeschrock {
276899653d4eSeschrock 	uint_t i;
276999653d4eSeschrock 	char *name;
277099653d4eSeschrock 
277199653d4eSeschrock 	if (nspares == 0)
277299653d4eSeschrock 		return;
277399653d4eSeschrock 
277499653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
277599653d4eSeschrock 
277699653d4eSeschrock 	for (i = 0; i < nspares; i++) {
277799653d4eSeschrock 		name = zpool_vdev_name(g_zfs, zhp, spares[i]);
277899653d4eSeschrock 		print_status_config(zhp, name, spares[i],
27798654d025Sperrin 		    namewidth, 2, B_TRUE, B_FALSE);
278099653d4eSeschrock 		free(name);
278199653d4eSeschrock 	}
278299653d4eSeschrock }
278399653d4eSeschrock 
2784fa9e4066Sahrens /*
2785fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
2786fa9e4066Sahrens  *
2787fa9e4066Sahrens  *        pool: tank
2788fa9e4066Sahrens  *	status: DEGRADED
2789fa9e4066Sahrens  *	reason: One or more devices ...
2790fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
2791fa9e4066Sahrens  *	config:
2792fa9e4066Sahrens  *		mirror		DEGRADED
2793fa9e4066Sahrens  *                c1t0d0	OK
2794ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
2795fa9e4066Sahrens  *
2796fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
2797fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
2798fa9e4066Sahrens  */
2799fa9e4066Sahrens int
2800fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
2801fa9e4066Sahrens {
2802fa9e4066Sahrens 	status_cbdata_t *cbp = data;
2803fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2804fa9e4066Sahrens 	char *msgid;
2805fa9e4066Sahrens 	int reason;
280646657f8dSmmusante 	const char *health;
280746657f8dSmmusante 	uint_t c;
280846657f8dSmmusante 	vdev_stat_t *vs;
2809fa9e4066Sahrens 
2810088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
2811fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
2812fa9e4066Sahrens 
2813fa9e4066Sahrens 	cbp->cb_count++;
2814fa9e4066Sahrens 
2815fa9e4066Sahrens 	/*
2816fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
2817fa9e4066Sahrens 	 * problems.
2818fa9e4066Sahrens 	 */
2819e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
2820e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
2821e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
2822e9dbad6fSeschrock 			    zpool_get_name(zhp));
2823e9dbad6fSeschrock 			if (cbp->cb_first)
2824e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
2825e9dbad6fSeschrock 		}
2826fa9e4066Sahrens 		return (0);
2827e9dbad6fSeschrock 	}
2828fa9e4066Sahrens 
2829fa9e4066Sahrens 	if (cbp->cb_first)
283099653d4eSeschrock 		cbp->cb_first = B_FALSE;
2831fa9e4066Sahrens 	else
2832fa9e4066Sahrens 		(void) printf("\n");
2833fa9e4066Sahrens 
283446657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
283546657f8dSmmusante 	    &nvroot) == 0);
283646657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
283746657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
2838*990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
2839fa9e4066Sahrens 
2840fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
2841fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
2842fa9e4066Sahrens 
2843fa9e4066Sahrens 	switch (reason) {
2844fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
2845fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2846fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
2847fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
2848fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2849fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2850fa9e4066Sahrens 		break;
2851fa9e4066Sahrens 
2852fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
2853fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2854fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
2855fa9e4066Sahrens 		    "pool to continue functioning.\n"));
2856fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2857fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2858fa9e4066Sahrens 		break;
2859fa9e4066Sahrens 
2860fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
2861fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2862fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
2863fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
2864fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
2865fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
2866fa9e4066Sahrens 		    "'zpool replace'.\n"));
2867fa9e4066Sahrens 		break;
2868fa9e4066Sahrens 
2869fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
2870fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2871b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
2872fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
2873fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
2874fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
2875fa9e4066Sahrens 		    "from a backup source.\n"));
2876fa9e4066Sahrens 		break;
2877fa9e4066Sahrens 
2878fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
2879fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
2880fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
2881fa9e4066Sahrens 		    "made to correct the error.  Applications are "
2882fa9e4066Sahrens 		    "unaffected.\n"));
2883fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
2884fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
2885ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
2886fa9e4066Sahrens 		    "replace'.\n"));
2887fa9e4066Sahrens 		break;
2888fa9e4066Sahrens 
2889fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
2890fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
2891d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
2892fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
2893fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
2894fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
2895fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
2896fa9e4066Sahrens 		    "replace'.\n"));
2897fa9e4066Sahrens 		break;
2898fa9e4066Sahrens 
2899fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
2900fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
2901fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
2902fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
2903fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
2904fa9e4066Sahrens 		    "complete.\n"));
2905fa9e4066Sahrens 		break;
2906fa9e4066Sahrens 
2907ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
2908ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
2909ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
2910ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
2911ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
2912ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
2913ea8dc4b6Seschrock 		    "backup.\n"));
2914ea8dc4b6Seschrock 		break;
2915ea8dc4b6Seschrock 
2916ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
2917ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
2918ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
2919ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
2920ea8dc4b6Seschrock 		    "from a backup source.\n"));
2921ea8dc4b6Seschrock 		break;
2922ea8dc4b6Seschrock 
2923eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
2924eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
2925eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
2926eaca9bbdSeschrock 		    "some features are unavailable.\n"));
2927eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
2928eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
2929eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
2930eaca9bbdSeschrock 		break;
2931eaca9bbdSeschrock 
2932eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
2933eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
2934eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
2935eaca9bbdSeschrock 		    "be accessed on this system.\n"));
2936eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
2937eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
2938eaca9bbdSeschrock 		    "backup.\n"));
2939eaca9bbdSeschrock 		break;
2940eaca9bbdSeschrock 
29413d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
29423d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
29433d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
29443d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
29453d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
29463d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
29473d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
29483d7072f8Seschrock 		break;
29493d7072f8Seschrock 
29503d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
29513d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
29523d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
29533d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
29543d7072f8Seschrock 		    "functioning.\n"));
29553d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
29563d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
29573d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
29583d7072f8Seschrock 		    "to be recovered.\n"));
29593d7072f8Seschrock 		break;
29603d7072f8Seschrock 
2961fa9e4066Sahrens 	default:
2962fa9e4066Sahrens 		/*
2963fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
2964fa9e4066Sahrens 		 */
2965fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
2966fa9e4066Sahrens 	}
2967fa9e4066Sahrens 
2968fa9e4066Sahrens 	if (msgid != NULL)
2969fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
2970fa9e4066Sahrens 		    msgid);
2971fa9e4066Sahrens 
2972fa9e4066Sahrens 	if (config != NULL) {
2973fa9e4066Sahrens 		int namewidth;
2974ea8dc4b6Seschrock 		uint64_t nerr;
297599653d4eSeschrock 		nvlist_t **spares;
297699653d4eSeschrock 		uint_t nspares;
2977fa9e4066Sahrens 
2978fa9e4066Sahrens 
2979fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
2980fa9e4066Sahrens 		print_scrub_status(nvroot);
2981fa9e4066Sahrens 
2982c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
2983fa9e4066Sahrens 		if (namewidth < 10)
2984fa9e4066Sahrens 			namewidth = 10;
2985fa9e4066Sahrens 
2986fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
2987fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
2988fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
2989c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
29908654d025Sperrin 		    namewidth, 0, B_FALSE, B_FALSE);
29918654d025Sperrin 		if (num_logs(nvroot) > 0)
29928654d025Sperrin 			print_status_config(zhp, "logs", nvroot, namewidth, 0,
29938654d025Sperrin 			    B_FALSE, B_TRUE);
299499653d4eSeschrock 
299599653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
299699653d4eSeschrock 		    &spares, &nspares) == 0)
299799653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
2998ea8dc4b6Seschrock 
2999ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3000ea8dc4b6Seschrock 		    &nerr) == 0) {
300155434c77Sek 			nvlist_t *nverrlist = NULL;
300255434c77Sek 
3003ea8dc4b6Seschrock 			/*
3004ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3005ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3006ea8dc4b6Seschrock 			 * uniquifying the results.
3007ea8dc4b6Seschrock 			 */
300875519f38Sek 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
300955434c77Sek 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
301055434c77Sek 				nvpair_t *elem;
301155434c77Sek 
301255434c77Sek 				elem = NULL;
301355434c77Sek 				nerr = 0;
301455434c77Sek 				while ((elem = nvlist_next_nvpair(nverrlist,
301555434c77Sek 				    elem)) != NULL) {
301655434c77Sek 					nerr++;
301755434c77Sek 				}
301855434c77Sek 			}
301955434c77Sek 			nvlist_free(nverrlist);
3020ea8dc4b6Seschrock 
3021ea8dc4b6Seschrock 			(void) printf("\n");
302299653d4eSeschrock 
3023ea8dc4b6Seschrock 			if (nerr == 0)
3024ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3025ea8dc4b6Seschrock 				    "errors\n"));
3026ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3027e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
30285ad82045Snd 				    "errors, use '-v' for a list\n"),
30295ad82045Snd 				    (u_longlong_t)nerr);
3030ea8dc4b6Seschrock 			else
3031ea8dc4b6Seschrock 				print_error_log(zhp);
3032ea8dc4b6Seschrock 		}
3033fa9e4066Sahrens 	} else {
3034fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3035fa9e4066Sahrens 		    "determined.\n"));
3036fa9e4066Sahrens 	}
3037fa9e4066Sahrens 
3038fa9e4066Sahrens 	return (0);
3039fa9e4066Sahrens }
3040fa9e4066Sahrens 
3041fa9e4066Sahrens /*
3042fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3043fa9e4066Sahrens  *
3044fa9e4066Sahrens  *	-v	Display complete error logs
3045fa9e4066Sahrens  *	-x	Display only pools with potential problems
3046fa9e4066Sahrens  *
3047fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3048fa9e4066Sahrens  */
3049fa9e4066Sahrens int
3050fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3051fa9e4066Sahrens {
3052fa9e4066Sahrens 	int c;
3053fa9e4066Sahrens 	int ret;
3054fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3055fa9e4066Sahrens 
3056fa9e4066Sahrens 	/* check options */
3057fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3058fa9e4066Sahrens 		switch (c) {
3059fa9e4066Sahrens 		case 'v':
306099653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3061fa9e4066Sahrens 			break;
3062fa9e4066Sahrens 		case 'x':
306399653d4eSeschrock 			cb.cb_explain = B_TRUE;
3064fa9e4066Sahrens 			break;
3065fa9e4066Sahrens 		case '?':
3066fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3067fa9e4066Sahrens 			    optopt);
306899653d4eSeschrock 			usage(B_FALSE);
3069fa9e4066Sahrens 		}
3070fa9e4066Sahrens 	}
3071fa9e4066Sahrens 
3072fa9e4066Sahrens 	argc -= optind;
3073fa9e4066Sahrens 	argv += optind;
3074fa9e4066Sahrens 
307599653d4eSeschrock 	cb.cb_first = B_TRUE;
3076fa9e4066Sahrens 
3077e9dbad6fSeschrock 	if (argc == 0)
3078e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3079e9dbad6fSeschrock 
3080b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3081fa9e4066Sahrens 
3082fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3083fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3084e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3085e9dbad6fSeschrock 		(void) printf(gettext("all pools are healthy\n"));
3086fa9e4066Sahrens 
3087fa9e4066Sahrens 	return (ret);
3088fa9e4066Sahrens }
3089fa9e4066Sahrens 
3090eaca9bbdSeschrock typedef struct upgrade_cbdata {
3091eaca9bbdSeschrock 	int	cb_all;
3092eaca9bbdSeschrock 	int	cb_first;
3093eaca9bbdSeschrock 	int	cb_newer;
309406eeb2adSek 	int	cb_argc;
3095*990b4856Slling 	uint64_t cb_version;
309606eeb2adSek 	char	**cb_argv;
3097eaca9bbdSeschrock } upgrade_cbdata_t;
3098eaca9bbdSeschrock 
3099eaca9bbdSeschrock static int
3100eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3101eaca9bbdSeschrock {
3102eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3103eaca9bbdSeschrock 	nvlist_t *config;
3104eaca9bbdSeschrock 	uint64_t version;
3105eaca9bbdSeschrock 	int ret = 0;
3106eaca9bbdSeschrock 
3107eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3108eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3109eaca9bbdSeschrock 	    &version) == 0);
3110eaca9bbdSeschrock 
3111e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3112eaca9bbdSeschrock 		if (!cbp->cb_all) {
3113eaca9bbdSeschrock 			if (cbp->cb_first) {
3114eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3115eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3116eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3117eaca9bbdSeschrock 				    "longer be accessible by older software "
3118eaca9bbdSeschrock 				    "versions.\n\n"));
3119eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3120eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
312199653d4eSeschrock 				cbp->cb_first = B_FALSE;
3122eaca9bbdSeschrock 			}
3123eaca9bbdSeschrock 
31245ad82045Snd 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3125eaca9bbdSeschrock 			    zpool_get_name(zhp));
3126eaca9bbdSeschrock 		} else {
312799653d4eSeschrock 			cbp->cb_first = B_FALSE;
3128*990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
312906eeb2adSek 			if (!ret) {
3130eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3131*990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
313206eeb2adSek 			}
3133eaca9bbdSeschrock 		}
3134e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3135eaca9bbdSeschrock 		assert(!cbp->cb_all);
3136eaca9bbdSeschrock 
3137eaca9bbdSeschrock 		if (cbp->cb_first) {
3138eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3139eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3140eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3141eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3142eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
314399653d4eSeschrock 			cbp->cb_first = B_FALSE;
3144eaca9bbdSeschrock 		}
3145eaca9bbdSeschrock 
31465ad82045Snd 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3147eaca9bbdSeschrock 		    zpool_get_name(zhp));
3148eaca9bbdSeschrock 	}
3149eaca9bbdSeschrock 
3150eaca9bbdSeschrock 	zpool_close(zhp);
3151eaca9bbdSeschrock 	return (ret);
3152eaca9bbdSeschrock }
3153eaca9bbdSeschrock 
3154eaca9bbdSeschrock /* ARGSUSED */
3155eaca9bbdSeschrock static int
315606eeb2adSek upgrade_one(zpool_handle_t *zhp, void *data)
3157eaca9bbdSeschrock {
3158*990b4856Slling 	upgrade_cbdata_t *cbp = data;
3159*990b4856Slling 	uint64_t cur_version;
3160eaca9bbdSeschrock 	int ret;
3161eaca9bbdSeschrock 
31628654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
31638654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
31648654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
31658654d025Sperrin 		    " to upgrade.\n"));
31668654d025Sperrin 		return (1);
31678654d025Sperrin 	}
3168*990b4856Slling 
3169*990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3170*990b4856Slling 	if (cur_version >= cbp->cb_version) {
3171eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3172*990b4856Slling 		    "using more current version '%d'.\n"), zpool_get_name(zhp),
3173*990b4856Slling 		    cur_version);
3174eaca9bbdSeschrock 		return (0);
3175eaca9bbdSeschrock 	}
3176eaca9bbdSeschrock 
3177*990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
317806eeb2adSek 
317906eeb2adSek 	if (!ret) {
318044cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
3181*990b4856Slling 		    "from version %llu to version %llu\n\n"),
3182*990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3183*990b4856Slling 		    (u_longlong_t)cbp->cb_version);
318406eeb2adSek 	}
3185eaca9bbdSeschrock 
3186eaca9bbdSeschrock 	return (ret != 0);
3187eaca9bbdSeschrock }
3188eaca9bbdSeschrock 
3189eaca9bbdSeschrock /*
3190eaca9bbdSeschrock  * zpool upgrade
3191eaca9bbdSeschrock  * zpool upgrade -v
3192*990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
3193eaca9bbdSeschrock  *
3194eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3195eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3196eaca9bbdSeschrock  * upgrade all pools.
3197eaca9bbdSeschrock  */
3198eaca9bbdSeschrock int
3199eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3200eaca9bbdSeschrock {
3201eaca9bbdSeschrock 	int c;
3202eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3203eaca9bbdSeschrock 	int ret = 0;
3204eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3205*990b4856Slling 	char *end;
3206*990b4856Slling 
3207*990b4856Slling 	cb.cb_version = SPA_VERSION;
3208eaca9bbdSeschrock 
3209eaca9bbdSeschrock 	/* check options */
3210*990b4856Slling 	while ((c = getopt(argc, argv, "avV:")) != -1) {
3211eaca9bbdSeschrock 		switch (c) {
3212eaca9bbdSeschrock 		case 'a':
321399653d4eSeschrock 			cb.cb_all = B_TRUE;
3214eaca9bbdSeschrock 			break;
3215eaca9bbdSeschrock 		case 'v':
3216eaca9bbdSeschrock 			showversions = B_TRUE;
3217eaca9bbdSeschrock 			break;
3218*990b4856Slling 		case 'V':
3219*990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
3220*990b4856Slling 			if (*end != '\0') {
3221*990b4856Slling 				(void) fprintf(stderr,
3222*990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
3223*990b4856Slling 				usage(B_FALSE);
3224*990b4856Slling 			}
3225*990b4856Slling 			break;
3226eaca9bbdSeschrock 		case '?':
3227eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3228eaca9bbdSeschrock 			    optopt);
322999653d4eSeschrock 			usage(B_FALSE);
3230eaca9bbdSeschrock 		}
3231eaca9bbdSeschrock 	}
3232eaca9bbdSeschrock 
323306eeb2adSek 	cb.cb_argc = argc;
323406eeb2adSek 	cb.cb_argv = argv;
3235eaca9bbdSeschrock 	argc -= optind;
3236eaca9bbdSeschrock 	argv += optind;
3237eaca9bbdSeschrock 
3238eaca9bbdSeschrock 	if (showversions) {
3239eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3240eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3241eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
324299653d4eSeschrock 			usage(B_FALSE);
3243eaca9bbdSeschrock 		}
3244eaca9bbdSeschrock 	} else if (cb.cb_all) {
3245eaca9bbdSeschrock 		if (argc != 0) {
3246eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-a option is "
3247eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
324899653d4eSeschrock 			usage(B_FALSE);
3249eaca9bbdSeschrock 		}
3250eaca9bbdSeschrock 	}
3251eaca9bbdSeschrock 
3252e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3253e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
325499653d4eSeschrock 	cb.cb_first = B_TRUE;
3255eaca9bbdSeschrock 	if (showversions) {
3256eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3257d7d4af51Smmusante 		    "supported:\n\n"));
3258eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3259eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3260eaca9bbdSeschrock 		    "---------------\n");
326199653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
326244cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
326344cd46caSbillm 		    "(replicated metadata)\n"));
326499653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
326599653d4eSeschrock 		    "RAID-Z\n"));
3266d7306b64Sek 		(void) printf(gettext(" 4   zpool history\n"));
3267c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3268c9431fa1Sahl 		    "algorithm\n"));
3269*990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
32708654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3271ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
32728654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3273eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3274eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3275eaca9bbdSeschrock 		    "version/N\n\n");
3276eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3277eaca9bbdSeschrock 	} else if (argc == 0) {
3278eaca9bbdSeschrock 		int notfound;
3279eaca9bbdSeschrock 
328099653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3281eaca9bbdSeschrock 		notfound = cb.cb_first;
3282eaca9bbdSeschrock 
3283eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3284eaca9bbdSeschrock 			if (!cb.cb_first)
3285eaca9bbdSeschrock 				(void) printf("\n");
3286eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3287eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
328899653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3289eaca9bbdSeschrock 			if (!cb.cb_first) {
3290eaca9bbdSeschrock 				notfound = B_FALSE;
3291eaca9bbdSeschrock 				(void) printf("\n");
3292eaca9bbdSeschrock 			}
3293eaca9bbdSeschrock 		}
3294eaca9bbdSeschrock 
3295eaca9bbdSeschrock 		if (ret == 0) {
3296eaca9bbdSeschrock 			if (notfound)
3297eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3298eaca9bbdSeschrock 				    "using this version.\n"));
3299eaca9bbdSeschrock 			else if (!cb.cb_all)
3300eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3301eaca9bbdSeschrock 				    "for a list of available versions and "
3302eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3303eaca9bbdSeschrock 		}
3304eaca9bbdSeschrock 	} else {
3305b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3306b1b8ab34Slling 		    upgrade_one, &cb);
330706eeb2adSek 	}
330806eeb2adSek 
330906eeb2adSek 	return (ret);
331006eeb2adSek }
331106eeb2adSek 
3312ecd6cf80Smarks typedef struct hist_cbdata {
3313ecd6cf80Smarks 	boolean_t first;
3314ecd6cf80Smarks 	int longfmt;
3315ecd6cf80Smarks 	int internal;
3316ecd6cf80Smarks } hist_cbdata_t;
3317ecd6cf80Smarks 
3318ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3319ecd6cf80Smarks 	"invalid event",
3320ecd6cf80Smarks 	"pool create",
3321ecd6cf80Smarks 	"vdev add",
3322ecd6cf80Smarks 	"pool remove",
3323ecd6cf80Smarks 	"pool destroy",
3324ecd6cf80Smarks 	"pool export",
3325ecd6cf80Smarks 	"pool import",
3326ecd6cf80Smarks 	"vdev attach",
3327ecd6cf80Smarks 	"vdev replace",
3328ecd6cf80Smarks 	"vdev detach",
3329ecd6cf80Smarks 	"vdev online",
3330ecd6cf80Smarks 	"vdev offline",
3331ecd6cf80Smarks 	"vdev upgrade",
3332ecd6cf80Smarks 	"pool clear",
3333ecd6cf80Smarks 	"pool scrub",
3334ecd6cf80Smarks 	"pool property set",
3335ecd6cf80Smarks 	"create",
3336ecd6cf80Smarks 	"clone",
3337ecd6cf80Smarks 	"destroy",
3338ecd6cf80Smarks 	"destroy_begin_sync",
3339ecd6cf80Smarks 	"inherit",
3340ecd6cf80Smarks 	"property set",
3341ecd6cf80Smarks 	"quota set",
3342ecd6cf80Smarks 	"permission update",
3343ecd6cf80Smarks 	"permission remove",
3344ecd6cf80Smarks 	"permission who remove",
3345ecd6cf80Smarks 	"promote",
3346ecd6cf80Smarks 	"receive",
3347ecd6cf80Smarks 	"rename",
3348ecd6cf80Smarks 	"reservation set",
3349ecd6cf80Smarks 	"replay_inc_sync",
3350ecd6cf80Smarks 	"replay_full_sync",
3351ecd6cf80Smarks 	"rollback",
3352ecd6cf80Smarks 	"snapshot",
3353e7437265Sahrens 	"filesystem version upgrade",
3354ecd6cf80Smarks };
3355ecd6cf80Smarks 
335606eeb2adSek /*
335706eeb2adSek  * Print out the command history for a specific pool.
335806eeb2adSek  */
335906eeb2adSek static int
336006eeb2adSek get_history_one(zpool_handle_t *zhp, void *data)
336106eeb2adSek {
336206eeb2adSek 	nvlist_t *nvhis;
336306eeb2adSek 	nvlist_t **records;
336406eeb2adSek 	uint_t numrecords;
336506eeb2adSek 	char *cmdstr;
3366ecd6cf80Smarks 	char *pathstr;
336706eeb2adSek 	uint64_t dst_time;
336806eeb2adSek 	time_t tsec;
336906eeb2adSek 	struct tm t;
337006eeb2adSek 	char tbuf[30];
337106eeb2adSek 	int ret, i;
3372ecd6cf80Smarks 	uint64_t who;
3373ecd6cf80Smarks 	struct passwd *pwd;
3374ecd6cf80Smarks 	char *hostname;
3375ecd6cf80Smarks 	char *zonename;
3376ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3377ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3378ecd6cf80Smarks 	uint64_t txg;
3379ecd6cf80Smarks 	uint64_t ievent;
338006eeb2adSek 
3381ecd6cf80Smarks 	cb->first = B_FALSE;
338206eeb2adSek 
338306eeb2adSek 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
338406eeb2adSek 
338506eeb2adSek 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
338606eeb2adSek 		return (ret);
338706eeb2adSek 
338806eeb2adSek 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
338906eeb2adSek 	    &records, &numrecords) == 0);
339006eeb2adSek 	for (i = 0; i < numrecords; i++) {
339106eeb2adSek 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3392ecd6cf80Smarks 		    &dst_time) != 0)
3393ecd6cf80Smarks 			continue;
3394ecd6cf80Smarks 
3395ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3396ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3397ecd6cf80Smarks 		    &cmdstr) != 0) {
3398ecd6cf80Smarks 			if (cb->internal == 0)
3399ecd6cf80Smarks 				continue;
3400ecd6cf80Smarks 
3401ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3402ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3403ecd6cf80Smarks 				continue;
3404ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3405ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3406ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3407ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3408ecd6cf80Smarks 			if (ievent > LOG_END)
3409ecd6cf80Smarks 				continue;
3410ecd6cf80Smarks 			(void) snprintf(internalstr,
3411ecd6cf80Smarks 			    sizeof (internalstr),
3412ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3413ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3414ecd6cf80Smarks 			    pathstr);
3415ecd6cf80Smarks 			cmdstr = internalstr;
341606eeb2adSek 		}
3417ecd6cf80Smarks 		tsec = dst_time;
3418ecd6cf80Smarks 		(void) localtime_r(&tsec, &t);
3419ecd6cf80Smarks 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3420ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3421ecd6cf80Smarks 
3422ecd6cf80Smarks 		if (!cb->longfmt) {
3423ecd6cf80Smarks 			(void) printf("\n");
3424ecd6cf80Smarks 			continue;
3425ecd6cf80Smarks 		}
3426ecd6cf80Smarks 		(void) printf(" [");
3427ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3428ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3429ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3430ecd6cf80Smarks 			if (pwd)
3431ecd6cf80Smarks 				(void) printf("user %s on",
3432ecd6cf80Smarks 				    pwd->pw_name);
3433ecd6cf80Smarks 			else
3434ecd6cf80Smarks 				(void) printf("user %d on",
3435ecd6cf80Smarks 				    (int)who);
3436ecd6cf80Smarks 		} else {
3437ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3438ecd6cf80Smarks 			continue;
3439ecd6cf80Smarks 		}
3440ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3441ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3442ecd6cf80Smarks 			(void) printf(" %s", hostname);
3443ecd6cf80Smarks 		}
3444ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3445ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3446ecd6cf80Smarks 			(void) printf(":%s", zonename);
3447ecd6cf80Smarks 		}
3448ecd6cf80Smarks 
3449ecd6cf80Smarks 		(void) printf("]");
3450ecd6cf80Smarks 		(void) printf("\n");
345106eeb2adSek 	}
345206eeb2adSek 	(void) printf("\n");
345306eeb2adSek 	nvlist_free(nvhis);
345406eeb2adSek 
345506eeb2adSek 	return (ret);
345606eeb2adSek }
345706eeb2adSek 
345806eeb2adSek /*
345906eeb2adSek  * zpool history <pool>
346006eeb2adSek  *
346106eeb2adSek  * Displays the history of commands that modified pools.
346206eeb2adSek  */
3463ecd6cf80Smarks 
3464ecd6cf80Smarks 
346506eeb2adSek int
346606eeb2adSek zpool_do_history(int argc, char **argv)
346706eeb2adSek {
3468ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
346906eeb2adSek 	int ret;
3470ecd6cf80Smarks 	int c;
347106eeb2adSek 
3472ecd6cf80Smarks 	cbdata.first = B_TRUE;
3473ecd6cf80Smarks 	/* check options */
3474ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3475ecd6cf80Smarks 		switch (c) {
3476ecd6cf80Smarks 		case 'l':
3477ecd6cf80Smarks 			cbdata.longfmt = 1;
3478ecd6cf80Smarks 			break;
3479ecd6cf80Smarks 		case 'i':
3480ecd6cf80Smarks 			cbdata.internal = 1;
3481ecd6cf80Smarks 			break;
3482ecd6cf80Smarks 		case '?':
3483ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3484ecd6cf80Smarks 			    optopt);
3485ecd6cf80Smarks 			usage(B_FALSE);
3486ecd6cf80Smarks 		}
3487ecd6cf80Smarks 	}
348806eeb2adSek 	argc -= optind;
348906eeb2adSek 	argv += optind;
349006eeb2adSek 
3491b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3492ecd6cf80Smarks 	    &cbdata);
349306eeb2adSek 
3494ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
349506eeb2adSek 		(void) printf(gettext("no pools available\n"));
349606eeb2adSek 		return (0);
3497eaca9bbdSeschrock 	}
3498eaca9bbdSeschrock 
3499eaca9bbdSeschrock 	return (ret);
3500eaca9bbdSeschrock }
3501eaca9bbdSeschrock 
3502b1b8ab34Slling static int
3503b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3504b1b8ab34Slling {
3505*990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3506b1b8ab34Slling 	char value[MAXNAMELEN];
3507*990b4856Slling 	zprop_source_t srctype;
3508*990b4856Slling 	zprop_list_t *pl;
3509b1b8ab34Slling 
3510b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3511b1b8ab34Slling 
3512b1b8ab34Slling 		/*
3513*990b4856Slling 		 * Skip the special fake placeholder. This will also skip
3514*990b4856Slling 		 * over the name property when 'all' is specified.
3515b1b8ab34Slling 		 */
3516*990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3517b1b8ab34Slling 		    pl == cbp->cb_proplist)
3518b1b8ab34Slling 			continue;
3519b1b8ab34Slling 
3520b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3521b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3522b1b8ab34Slling 			continue;
3523b1b8ab34Slling 
3524*990b4856Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
3525b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3526b1b8ab34Slling 	}
3527b1b8ab34Slling 	return (0);
3528b1b8ab34Slling }
3529b1b8ab34Slling 
3530b1b8ab34Slling int
3531b1b8ab34Slling zpool_do_get(int argc, char **argv)
3532b1b8ab34Slling {
3533*990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
3534*990b4856Slling 	zprop_list_t fake_name = { 0 };
3535b1b8ab34Slling 	int ret;
3536b1b8ab34Slling 
3537b1b8ab34Slling 	if (argc < 3)
3538b1b8ab34Slling 		usage(B_FALSE);
3539b1b8ab34Slling 
3540b1b8ab34Slling 	cb.cb_first = B_TRUE;
3541*990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
3542b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3543b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3544b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3545b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3546*990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
3547b1b8ab34Slling 
3548*990b4856Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3549*990b4856Slling 	    ZFS_TYPE_POOL) != 0)
3550b1b8ab34Slling 		usage(B_FALSE);
3551b1b8ab34Slling 
3552b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3553*990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
3554b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3555b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3556b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3557b1b8ab34Slling 	}
3558b1b8ab34Slling 
3559b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3560b1b8ab34Slling 	    get_callback, &cb);
3561b1b8ab34Slling 
3562b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3563*990b4856Slling 		zprop_free_list(fake_name.pl_next);
3564b1b8ab34Slling 	else
3565*990b4856Slling 		zprop_free_list(cb.cb_proplist);
3566b1b8ab34Slling 
3567b1b8ab34Slling 	return (ret);
3568b1b8ab34Slling }
3569b1b8ab34Slling 
3570b1b8ab34Slling typedef struct set_cbdata {
3571b1b8ab34Slling 	char *cb_propname;
3572b1b8ab34Slling 	char *cb_value;
3573b1b8ab34Slling 	boolean_t cb_any_successful;
3574b1b8ab34Slling } set_cbdata_t;
3575b1b8ab34Slling 
3576b1b8ab34Slling int
3577b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3578b1b8ab34Slling {
3579b1b8ab34Slling 	int error;
3580b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3581b1b8ab34Slling 
3582b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3583b1b8ab34Slling 
3584b1b8ab34Slling 	if (!error)
3585b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3586b1b8ab34Slling 
3587b1b8ab34Slling 	return (error);
3588b1b8ab34Slling }
3589b1b8ab34Slling 
3590b1b8ab34Slling int
3591b1b8ab34Slling zpool_do_set(int argc, char **argv)
3592b1b8ab34Slling {
3593b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3594b1b8ab34Slling 	int error;
3595b1b8ab34Slling 
3596b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3597b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3598b1b8ab34Slling 		    argv[1][1]);
3599b1b8ab34Slling 		usage(B_FALSE);
3600b1b8ab34Slling 	}
3601b1b8ab34Slling 
3602b1b8ab34Slling 	if (argc < 2) {
3603b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3604b1b8ab34Slling 		    "argument\n"));
3605b1b8ab34Slling 		usage(B_FALSE);
3606b1b8ab34Slling 	}
3607b1b8ab34Slling 
3608b1b8ab34Slling 	if (argc < 3) {
3609b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3610b1b8ab34Slling 		usage(B_FALSE);
3611b1b8ab34Slling 	}
3612b1b8ab34Slling 
3613b1b8ab34Slling 	if (argc > 3) {
3614b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3615b1b8ab34Slling 		usage(B_FALSE);
3616b1b8ab34Slling 	}
3617b1b8ab34Slling 
3618b1b8ab34Slling 	cb.cb_propname = argv[1];
3619b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3620b1b8ab34Slling 	if (cb.cb_value == NULL) {
3621b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3622b1b8ab34Slling 		    "property=value argument\n"));
3623b1b8ab34Slling 		usage(B_FALSE);
3624b1b8ab34Slling 	}
3625b1b8ab34Slling 
3626b1b8ab34Slling 	*(cb.cb_value) = '\0';
3627b1b8ab34Slling 	cb.cb_value++;
3628b1b8ab34Slling 
3629b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3630b1b8ab34Slling 	    set_callback, &cb);
3631b1b8ab34Slling 
3632b1b8ab34Slling 	return (error);
3633b1b8ab34Slling }
3634b1b8ab34Slling 
3635b1b8ab34Slling static int
3636b1b8ab34Slling find_command_idx(char *command, int *idx)
3637b1b8ab34Slling {
3638b1b8ab34Slling 	int i;
3639b1b8ab34Slling 
3640b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3641b1b8ab34Slling 		if (command_table[i].name == NULL)
3642b1b8ab34Slling 			continue;
3643b1b8ab34Slling 
3644b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3645b1b8ab34Slling 			*idx = i;
3646b1b8ab34Slling 			return (0);
3647b1b8ab34Slling 		}
3648b1b8ab34Slling 	}
3649b1b8ab34Slling 	return (1);
3650b1b8ab34Slling }
3651b1b8ab34Slling 
3652fa9e4066Sahrens int
3653fa9e4066Sahrens main(int argc, char **argv)
3654fa9e4066Sahrens {
3655fa9e4066Sahrens 	int ret;
3656fa9e4066Sahrens 	int i;
3657fa9e4066Sahrens 	char *cmdname;
3658fa9e4066Sahrens 
3659fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3660fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3661fa9e4066Sahrens 
366299653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
366399653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3664203a47d8Snd 		    "initialize ZFS library\n"));
366599653d4eSeschrock 		return (1);
366699653d4eSeschrock 	}
366799653d4eSeschrock 
366899653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
366999653d4eSeschrock 
3670fa9e4066Sahrens 	opterr = 0;
3671fa9e4066Sahrens 
3672fa9e4066Sahrens 	/*
3673fa9e4066Sahrens 	 * Make sure the user has specified some command.
3674fa9e4066Sahrens 	 */
3675fa9e4066Sahrens 	if (argc < 2) {
3676fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
367799653d4eSeschrock 		usage(B_FALSE);
3678fa9e4066Sahrens 	}
3679fa9e4066Sahrens 
3680fa9e4066Sahrens 	cmdname = argv[1];
3681fa9e4066Sahrens 
3682fa9e4066Sahrens 	/*
3683fa9e4066Sahrens 	 * Special case '-?'
3684fa9e4066Sahrens 	 */
3685fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
368699653d4eSeschrock 		usage(B_TRUE);
3687fa9e4066Sahrens 
36882a6b87f0Sek 	zpool_set_history_str("zpool", argc, argv, history_str);
36892a6b87f0Sek 	verify(zpool_stage_history(g_zfs, history_str) == 0);
36902a6b87f0Sek 
3691fa9e4066Sahrens 	/*
3692fa9e4066Sahrens 	 * Run the appropriate command.
3693fa9e4066Sahrens 	 */
3694b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
3695b1b8ab34Slling 		current_command = &command_table[i];
3696b1b8ab34Slling 		ret = command_table[i].func(argc - 1, argv + 1);
369791ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
369891ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
369991ebeef5Sahrens 		current_command = &command_table[i];
370091ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
370191ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
370291ebeef5Sahrens 		/*
370391ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
370491ebeef5Sahrens 		 * it as such.
370591ebeef5Sahrens 		 */
3706ea8dc4b6Seschrock 		char buf[16384];
3707ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
3708fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
3709fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
371091ebeef5Sahrens 	} else {
3711fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
3712fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
371399653d4eSeschrock 		usage(B_FALSE);
3714fa9e4066Sahrens 	}
3715fa9e4066Sahrens 
371699653d4eSeschrock 	libzfs_fini(g_zfs);
371799653d4eSeschrock 
3718fa9e4066Sahrens 	/*
3719fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3720fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
3721fa9e4066Sahrens 	 */
3722fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
3723fa9e4066Sahrens 		(void) printf("dumping core by request\n");
3724fa9e4066Sahrens 		abort();
3725fa9e4066Sahrens 	}
3726fa9e4066Sahrens 
3727fa9e4066Sahrens 	return (ret);
3728fa9e4066Sahrens }
3729