xref: /titanic_53/usr/src/cmd/zpool/zpool_main.c (revision 74e7dc986c89efca1f2e4451c7a572e05e4a6e4f)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5441d80aaSlling  * Common Development and Distribution License (the "License").
6441d80aaSlling  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
2199653d4eSeschrock 
22fa9e4066Sahrens /*
2318ce54dfSek110237  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #include <assert.h>
28fa9e4066Sahrens #include <ctype.h>
29fa9e4066Sahrens #include <dirent.h>
30fa9e4066Sahrens #include <errno.h>
31fa9e4066Sahrens #include <fcntl.h>
32fa9e4066Sahrens #include <libgen.h>
33fa9e4066Sahrens #include <libintl.h>
34fa9e4066Sahrens #include <libuutil.h>
35fa9e4066Sahrens #include <locale.h>
36fa9e4066Sahrens #include <stdio.h>
37fa9e4066Sahrens #include <stdlib.h>
38fa9e4066Sahrens #include <string.h>
39fa9e4066Sahrens #include <strings.h>
40fa9e4066Sahrens #include <unistd.h>
41fa9e4066Sahrens #include <priv.h>
42ecd6cf80Smarks #include <pwd.h>
43ecd6cf80Smarks #include <zone.h>
44b1b8ab34Slling #include <sys/fs/zfs.h>
45fa9e4066Sahrens 
46fa9e4066Sahrens #include <sys/stat.h>
47fa9e4066Sahrens 
48fa9e4066Sahrens #include <libzfs.h>
49fa9e4066Sahrens 
50fa9e4066Sahrens #include "zpool_util.h"
51b7b97454Sperrin #include "zfs_comutil.h"
52fa9e4066Sahrens 
53fa9e4066Sahrens static int zpool_do_create(int, char **);
54fa9e4066Sahrens static int zpool_do_destroy(int, char **);
55fa9e4066Sahrens 
56fa9e4066Sahrens static int zpool_do_add(int, char **);
5799653d4eSeschrock static int zpool_do_remove(int, char **);
58fa9e4066Sahrens 
59fa9e4066Sahrens static int zpool_do_list(int, char **);
60fa9e4066Sahrens static int zpool_do_iostat(int, char **);
61fa9e4066Sahrens static int zpool_do_status(int, char **);
62fa9e4066Sahrens 
63fa9e4066Sahrens static int zpool_do_online(int, char **);
64fa9e4066Sahrens static int zpool_do_offline(int, char **);
65ea8dc4b6Seschrock static int zpool_do_clear(int, char **);
66fa9e4066Sahrens 
67fa9e4066Sahrens static int zpool_do_attach(int, char **);
68fa9e4066Sahrens static int zpool_do_detach(int, char **);
69fa9e4066Sahrens static int zpool_do_replace(int, char **);
70fa9e4066Sahrens 
71fa9e4066Sahrens static int zpool_do_scrub(int, char **);
72fa9e4066Sahrens 
73fa9e4066Sahrens static int zpool_do_import(int, char **);
74fa9e4066Sahrens static int zpool_do_export(int, char **);
75fa9e4066Sahrens 
76eaca9bbdSeschrock static int zpool_do_upgrade(int, char **);
77eaca9bbdSeschrock 
7806eeb2adSek110237 static int zpool_do_history(int, char **);
7906eeb2adSek110237 
80b1b8ab34Slling static int zpool_do_get(int, char **);
81b1b8ab34Slling static int zpool_do_set(int, char **);
82b1b8ab34Slling 
83fa9e4066Sahrens /*
84fa9e4066Sahrens  * These libumem hooks provide a reasonable set of defaults for the allocator's
85fa9e4066Sahrens  * debugging facilities.
86fa9e4066Sahrens  */
8729ab75c9Srm160521 
8829ab75c9Srm160521 #ifdef DEBUG
89fa9e4066Sahrens const char *
9099653d4eSeschrock _umem_debug_init(void)
91fa9e4066Sahrens {
92fa9e4066Sahrens 	return ("default,verbose"); /* $UMEM_DEBUG setting */
93fa9e4066Sahrens }
94fa9e4066Sahrens 
95fa9e4066Sahrens const char *
96fa9e4066Sahrens _umem_logging_init(void)
97fa9e4066Sahrens {
98fa9e4066Sahrens 	return ("fail,contents"); /* $UMEM_LOGGING setting */
99fa9e4066Sahrens }
10029ab75c9Srm160521 #endif
101fa9e4066Sahrens 
10265cd9f28Seschrock typedef enum {
10365cd9f28Seschrock 	HELP_ADD,
10465cd9f28Seschrock 	HELP_ATTACH,
105ea8dc4b6Seschrock 	HELP_CLEAR,
10665cd9f28Seschrock 	HELP_CREATE,
10765cd9f28Seschrock 	HELP_DESTROY,
10865cd9f28Seschrock 	HELP_DETACH,
10965cd9f28Seschrock 	HELP_EXPORT,
11006eeb2adSek110237 	HELP_HISTORY,
11165cd9f28Seschrock 	HELP_IMPORT,
11265cd9f28Seschrock 	HELP_IOSTAT,
11365cd9f28Seschrock 	HELP_LIST,
11465cd9f28Seschrock 	HELP_OFFLINE,
11565cd9f28Seschrock 	HELP_ONLINE,
11665cd9f28Seschrock 	HELP_REPLACE,
11799653d4eSeschrock 	HELP_REMOVE,
11865cd9f28Seschrock 	HELP_SCRUB,
119eaca9bbdSeschrock 	HELP_STATUS,
120b1b8ab34Slling 	HELP_UPGRADE,
121b1b8ab34Slling 	HELP_GET,
122b1b8ab34Slling 	HELP_SET
12365cd9f28Seschrock } zpool_help_t;
12465cd9f28Seschrock 
12565cd9f28Seschrock 
126fa9e4066Sahrens typedef struct zpool_command {
127fa9e4066Sahrens 	const char	*name;
128fa9e4066Sahrens 	int		(*func)(int, char **);
12965cd9f28Seschrock 	zpool_help_t	usage;
130fa9e4066Sahrens } zpool_command_t;
131fa9e4066Sahrens 
132fa9e4066Sahrens /*
133fa9e4066Sahrens  * Master command table.  Each ZFS command has a name, associated function, and
134ea8dc4b6Seschrock  * usage message.  The usage messages need to be internationalized, so we have
135ea8dc4b6Seschrock  * to have a function to return the usage message based on a command index.
13665cd9f28Seschrock  *
13765cd9f28Seschrock  * These commands are organized according to how they are displayed in the usage
13865cd9f28Seschrock  * message.  An empty command (one with a NULL name) indicates an empty line in
13965cd9f28Seschrock  * the generic usage message.
140fa9e4066Sahrens  */
141fa9e4066Sahrens static zpool_command_t command_table[] = {
14265cd9f28Seschrock 	{ "create",	zpool_do_create,	HELP_CREATE		},
14365cd9f28Seschrock 	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
144fa9e4066Sahrens 	{ NULL },
14565cd9f28Seschrock 	{ "add",	zpool_do_add,		HELP_ADD		},
14699653d4eSeschrock 	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
147fa9e4066Sahrens 	{ NULL },
14865cd9f28Seschrock 	{ "list",	zpool_do_list,		HELP_LIST		},
14965cd9f28Seschrock 	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
15065cd9f28Seschrock 	{ "status",	zpool_do_status,	HELP_STATUS		},
151fa9e4066Sahrens 	{ NULL },
15265cd9f28Seschrock 	{ "online",	zpool_do_online,	HELP_ONLINE		},
15365cd9f28Seschrock 	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
154ea8dc4b6Seschrock 	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
155fa9e4066Sahrens 	{ NULL },
15665cd9f28Seschrock 	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
15765cd9f28Seschrock 	{ "detach",	zpool_do_detach,	HELP_DETACH		},
15865cd9f28Seschrock 	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
159fa9e4066Sahrens 	{ NULL },
16065cd9f28Seschrock 	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
161fa9e4066Sahrens 	{ NULL },
16265cd9f28Seschrock 	{ "import",	zpool_do_import,	HELP_IMPORT		},
16365cd9f28Seschrock 	{ "export",	zpool_do_export,	HELP_EXPORT		},
16406eeb2adSek110237 	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
16506eeb2adSek110237 	{ NULL },
166b1b8ab34Slling 	{ "history",	zpool_do_history,	HELP_HISTORY		},
167b1b8ab34Slling 	{ "get",	zpool_do_get,		HELP_GET		},
168b1b8ab34Slling 	{ "set",	zpool_do_set,		HELP_SET		},
169fa9e4066Sahrens };
170fa9e4066Sahrens 
171fa9e4066Sahrens #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
172fa9e4066Sahrens 
173fa9e4066Sahrens zpool_command_t *current_command;
1742a6b87f0Sek110237 static char history_str[HIS_MAX_RECORD_LEN];
175fa9e4066Sahrens 
17665cd9f28Seschrock static const char *
17765cd9f28Seschrock get_usage(zpool_help_t idx) {
17865cd9f28Seschrock 	switch (idx) {
17965cd9f28Seschrock 	case HELP_ADD:
18065cd9f28Seschrock 		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
18165cd9f28Seschrock 	case HELP_ATTACH:
18265cd9f28Seschrock 		return (gettext("\tattach [-f] <pool> <device> "
183e45ce728Sahrens 		    "<new-device>\n"));
184ea8dc4b6Seschrock 	case HELP_CLEAR:
185ea8dc4b6Seschrock 		return (gettext("\tclear <pool> [device]\n"));
18665cd9f28Seschrock 	case HELP_CREATE:
187990b4856Slling 		return (gettext("\tcreate [-fn] [-o property=value] ... \n"
1880a48a24eStimh 		    "\t    [-O file-system-property=value] ... \n"
189990b4856Slling 		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
19065cd9f28Seschrock 	case HELP_DESTROY:
19165cd9f28Seschrock 		return (gettext("\tdestroy [-f] <pool>\n"));
19265cd9f28Seschrock 	case HELP_DETACH:
19365cd9f28Seschrock 		return (gettext("\tdetach <pool> <device>\n"));
19465cd9f28Seschrock 	case HELP_EXPORT:
19565cd9f28Seschrock 		return (gettext("\texport [-f] <pool> ...\n"));
19606eeb2adSek110237 	case HELP_HISTORY:
197ecd6cf80Smarks 		return (gettext("\thistory [-il] [<pool>] ...\n"));
19865cd9f28Seschrock 	case HELP_IMPORT:
1994c58d714Sdarrenm 		return (gettext("\timport [-d dir] [-D]\n"
2002f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
2012f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n"
2022f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
2032f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] "
2042f8aaab3Seschrock 		    "<pool | id> [newpool]\n"));
20565cd9f28Seschrock 	case HELP_IOSTAT:
20665cd9f28Seschrock 		return (gettext("\tiostat [-v] [pool] ... [interval "
20765cd9f28Seschrock 		    "[count]]\n"));
20865cd9f28Seschrock 	case HELP_LIST:
209990b4856Slling 		return (gettext("\tlist [-H] [-o property[,...]] "
210990b4856Slling 		    "[pool] ...\n"));
21165cd9f28Seschrock 	case HELP_OFFLINE:
212441d80aaSlling 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
21365cd9f28Seschrock 	case HELP_ONLINE:
214441d80aaSlling 		return (gettext("\tonline <pool> <device> ...\n"));
21565cd9f28Seschrock 	case HELP_REPLACE:
21665cd9f28Seschrock 		return (gettext("\treplace [-f] <pool> <device> "
217e45ce728Sahrens 		    "[new-device]\n"));
21899653d4eSeschrock 	case HELP_REMOVE:
219fa94a07fSbrendan 		return (gettext("\tremove <pool> <device> ...\n"));
22065cd9f28Seschrock 	case HELP_SCRUB:
22165cd9f28Seschrock 		return (gettext("\tscrub [-s] <pool> ...\n"));
22265cd9f28Seschrock 	case HELP_STATUS:
22365cd9f28Seschrock 		return (gettext("\tstatus [-vx] [pool] ...\n"));
224eaca9bbdSeschrock 	case HELP_UPGRADE:
225eaca9bbdSeschrock 		return (gettext("\tupgrade\n"
226eaca9bbdSeschrock 		    "\tupgrade -v\n"
227990b4856Slling 		    "\tupgrade [-V version] <-a | pool ...>\n"));
228b1b8ab34Slling 	case HELP_GET:
229e45ce728Sahrens 		return (gettext("\tget <\"all\" | property[,...]> "
230b1b8ab34Slling 		    "<pool> ...\n"));
231b1b8ab34Slling 	case HELP_SET:
232b1b8ab34Slling 		return (gettext("\tset <property=value> <pool> \n"));
23365cd9f28Seschrock 	}
23465cd9f28Seschrock 
23565cd9f28Seschrock 	abort();
23665cd9f28Seschrock 	/* NOTREACHED */
23765cd9f28Seschrock }
23865cd9f28Seschrock 
239fa9e4066Sahrens 
240fa9e4066Sahrens /*
241b1b8ab34Slling  * Callback routine that will print out a pool property value.
242b1b8ab34Slling  */
243990b4856Slling static int
244990b4856Slling print_prop_cb(int prop, void *cb)
245b1b8ab34Slling {
246b1b8ab34Slling 	FILE *fp = cb;
247b1b8ab34Slling 
248b1b8ab34Slling 	(void) fprintf(fp, "\t%-13s  ", zpool_prop_to_name(prop));
249b1b8ab34Slling 
250990b4856Slling 	if (zpool_prop_readonly(prop))
251990b4856Slling 		(void) fprintf(fp, "  NO   ");
252990b4856Slling 	else
253990b4856Slling 		(void) fprintf(fp, " YES    ");
254990b4856Slling 
255b1b8ab34Slling 	if (zpool_prop_values(prop) == NULL)
256b1b8ab34Slling 		(void) fprintf(fp, "-\n");
257b1b8ab34Slling 	else
258b1b8ab34Slling 		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
259b1b8ab34Slling 
260990b4856Slling 	return (ZPROP_CONT);
261b1b8ab34Slling }
262b1b8ab34Slling 
263b1b8ab34Slling /*
264fa9e4066Sahrens  * Display usage message.  If we're inside a command, display only the usage for
265fa9e4066Sahrens  * that command.  Otherwise, iterate over the entire command table and display
266fa9e4066Sahrens  * a complete usage message.
267fa9e4066Sahrens  */
268fa9e4066Sahrens void
26999653d4eSeschrock usage(boolean_t requested)
270fa9e4066Sahrens {
271fa9e4066Sahrens 	FILE *fp = requested ? stdout : stderr;
272fa9e4066Sahrens 
273fa9e4066Sahrens 	if (current_command == NULL) {
274fa9e4066Sahrens 		int i;
275fa9e4066Sahrens 
276fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
277fa9e4066Sahrens 		(void) fprintf(fp,
278fa9e4066Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
279fa9e4066Sahrens 
280fa9e4066Sahrens 		for (i = 0; i < NCOMMAND; i++) {
281fa9e4066Sahrens 			if (command_table[i].name == NULL)
282fa9e4066Sahrens 				(void) fprintf(fp, "\n");
283fa9e4066Sahrens 			else
284fa9e4066Sahrens 				(void) fprintf(fp, "%s",
28565cd9f28Seschrock 				    get_usage(command_table[i].usage));
286fa9e4066Sahrens 		}
287fa9e4066Sahrens 	} else {
288fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
28965cd9f28Seschrock 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
290fa9e4066Sahrens 	}
291fa9e4066Sahrens 
292b1b8ab34Slling 	if (current_command != NULL &&
293b1b8ab34Slling 	    ((strcmp(current_command->name, "set") == 0) ||
294990b4856Slling 	    (strcmp(current_command->name, "get") == 0) ||
295990b4856Slling 	    (strcmp(current_command->name, "list") == 0))) {
296b1b8ab34Slling 
297b1b8ab34Slling 		(void) fprintf(fp,
298b1b8ab34Slling 		    gettext("\nthe following properties are supported:\n"));
299b1b8ab34Slling 
300990b4856Slling 		(void) fprintf(fp, "\n\t%-13s  %s  %s\n\n",
301990b4856Slling 		    "PROPERTY", "EDIT", "VALUES");
302b1b8ab34Slling 
303b1b8ab34Slling 		/* Iterate over all properties */
304990b4856Slling 		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
305990b4856Slling 		    ZFS_TYPE_POOL);
306b1b8ab34Slling 	}
307b1b8ab34Slling 
308e9dbad6fSeschrock 	/*
309e9dbad6fSeschrock 	 * See comments at end of main().
310e9dbad6fSeschrock 	 */
311e9dbad6fSeschrock 	if (getenv("ZFS_ABORT") != NULL) {
312e9dbad6fSeschrock 		(void) printf("dumping core by request\n");
313e9dbad6fSeschrock 		abort();
314e9dbad6fSeschrock 	}
315e9dbad6fSeschrock 
316fa9e4066Sahrens 	exit(requested ? 0 : 2);
317fa9e4066Sahrens }
318fa9e4066Sahrens 
319fa9e4066Sahrens void
3208654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
3218654d025Sperrin     boolean_t print_logs)
322fa9e4066Sahrens {
323fa9e4066Sahrens 	nvlist_t **child;
324fa9e4066Sahrens 	uint_t c, children;
325afefbcddSeschrock 	char *vname;
326fa9e4066Sahrens 
327fa9e4066Sahrens 	if (name != NULL)
328fa9e4066Sahrens 		(void) printf("\t%*s%s\n", indent, "", name);
329fa9e4066Sahrens 
330fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
331fa9e4066Sahrens 	    &child, &children) != 0)
332fa9e4066Sahrens 		return;
333fa9e4066Sahrens 
334afefbcddSeschrock 	for (c = 0; c < children; c++) {
3358654d025Sperrin 		uint64_t is_log = B_FALSE;
3368654d025Sperrin 
3378654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3388654d025Sperrin 		    &is_log);
3398654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
3408654d025Sperrin 			continue;
3418654d025Sperrin 
34299653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
3438654d025Sperrin 		print_vdev_tree(zhp, vname, child[c], indent + 2,
3448654d025Sperrin 		    B_FALSE);
345afefbcddSeschrock 		free(vname);
346afefbcddSeschrock 	}
347fa9e4066Sahrens }
348fa9e4066Sahrens 
349fa9e4066Sahrens /*
350990b4856Slling  * Add a property pair (name, string-value) into a property nvlist.
351990b4856Slling  */
352990b4856Slling static int
3530a48a24eStimh add_prop_list(const char *propname, char *propval, nvlist_t **props,
3540a48a24eStimh     boolean_t poolprop)
355990b4856Slling {
3560a48a24eStimh 	zpool_prop_t prop = ZPROP_INVAL;
3570a48a24eStimh 	zfs_prop_t fprop;
358990b4856Slling 	nvlist_t *proplist;
3590a48a24eStimh 	const char *normnm;
3600a48a24eStimh 	char *strval;
361990b4856Slling 
362990b4856Slling 	if (*props == NULL &&
363990b4856Slling 	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
364990b4856Slling 		(void) fprintf(stderr,
365990b4856Slling 		    gettext("internal error: out of memory\n"));
366990b4856Slling 		return (1);
367990b4856Slling 	}
368990b4856Slling 
369990b4856Slling 	proplist = *props;
370990b4856Slling 
3710a48a24eStimh 	if (poolprop) {
372990b4856Slling 		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
373990b4856Slling 			(void) fprintf(stderr, gettext("property '%s' is "
374990b4856Slling 			    "not a valid pool property\n"), propname);
375990b4856Slling 			return (2);
376990b4856Slling 		}
3770a48a24eStimh 		normnm = zpool_prop_to_name(prop);
3780a48a24eStimh 	} else {
3790a48a24eStimh 		if ((fprop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
3800a48a24eStimh 			(void) fprintf(stderr, gettext("property '%s' is "
3810a48a24eStimh 			    "not a valid file system property\n"), propname);
3820a48a24eStimh 			return (2);
3830a48a24eStimh 		}
3840a48a24eStimh 		normnm = zfs_prop_to_name(fprop);
3850a48a24eStimh 	}
386990b4856Slling 
3870a48a24eStimh 	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
3880a48a24eStimh 	    prop != ZPOOL_PROP_CACHEFILE) {
389990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' "
390990b4856Slling 		    "specified multiple times\n"), propname);
391990b4856Slling 		return (2);
392990b4856Slling 	}
393990b4856Slling 
3940a48a24eStimh 	if (nvlist_add_string(proplist, normnm, propval) != 0) {
395990b4856Slling 		(void) fprintf(stderr, gettext("internal "
396990b4856Slling 		    "error: out of memory\n"));
397990b4856Slling 		return (1);
398990b4856Slling 	}
399990b4856Slling 
400990b4856Slling 	return (0);
401990b4856Slling }
402990b4856Slling 
403990b4856Slling /*
404fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
405fa9e4066Sahrens  *
406fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
407fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
408fa9e4066Sahrens  *		they were to be added.
409fa9e4066Sahrens  *
410fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
411fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
412fa9e4066Sahrens  * libzfs.
413fa9e4066Sahrens  */
414fa9e4066Sahrens int
415fa9e4066Sahrens zpool_do_add(int argc, char **argv)
416fa9e4066Sahrens {
41799653d4eSeschrock 	boolean_t force = B_FALSE;
41899653d4eSeschrock 	boolean_t dryrun = B_FALSE;
419fa9e4066Sahrens 	int c;
420fa9e4066Sahrens 	nvlist_t *nvroot;
421fa9e4066Sahrens 	char *poolname;
422fa9e4066Sahrens 	int ret;
423fa9e4066Sahrens 	zpool_handle_t *zhp;
424fa9e4066Sahrens 	nvlist_t *config;
425fa9e4066Sahrens 
426fa9e4066Sahrens 	/* check options */
427fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
428fa9e4066Sahrens 		switch (c) {
429fa9e4066Sahrens 		case 'f':
43099653d4eSeschrock 			force = B_TRUE;
431fa9e4066Sahrens 			break;
432fa9e4066Sahrens 		case 'n':
43399653d4eSeschrock 			dryrun = B_TRUE;
434fa9e4066Sahrens 			break;
435fa9e4066Sahrens 		case '?':
436fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
437fa9e4066Sahrens 			    optopt);
43899653d4eSeschrock 			usage(B_FALSE);
439fa9e4066Sahrens 		}
440fa9e4066Sahrens 	}
441fa9e4066Sahrens 
442fa9e4066Sahrens 	argc -= optind;
443fa9e4066Sahrens 	argv += optind;
444fa9e4066Sahrens 
445fa9e4066Sahrens 	/* get pool name and check number of arguments */
446fa9e4066Sahrens 	if (argc < 1) {
447fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
44899653d4eSeschrock 		usage(B_FALSE);
449fa9e4066Sahrens 	}
450fa9e4066Sahrens 	if (argc < 2) {
451fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
45299653d4eSeschrock 		usage(B_FALSE);
453fa9e4066Sahrens 	}
454fa9e4066Sahrens 
455fa9e4066Sahrens 	poolname = argv[0];
456fa9e4066Sahrens 
457fa9e4066Sahrens 	argc--;
458fa9e4066Sahrens 	argv++;
459fa9e4066Sahrens 
46099653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
461fa9e4066Sahrens 		return (1);
462fa9e4066Sahrens 
463088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
464fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
465fa9e4066Sahrens 		    poolname);
466fa9e4066Sahrens 		zpool_close(zhp);
467fa9e4066Sahrens 		return (1);
468fa9e4066Sahrens 	}
469fa9e4066Sahrens 
470fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
471705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
472705040edSEric Taylor 	    argc, argv);
473fa9e4066Sahrens 	if (nvroot == NULL) {
474fa9e4066Sahrens 		zpool_close(zhp);
475fa9e4066Sahrens 		return (1);
476fa9e4066Sahrens 	}
477fa9e4066Sahrens 
478fa9e4066Sahrens 	if (dryrun) {
479fa9e4066Sahrens 		nvlist_t *poolnvroot;
480fa9e4066Sahrens 
481fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
482fa9e4066Sahrens 		    &poolnvroot) == 0);
483fa9e4066Sahrens 
484fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
485fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
486fa9e4066Sahrens 
4878654d025Sperrin 		/* print original main pool and new tree */
4888654d025Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
4898654d025Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
4908654d025Sperrin 
4918654d025Sperrin 		/* Do the same for the logs */
4928654d025Sperrin 		if (num_logs(poolnvroot) > 0) {
4938654d025Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
4948654d025Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
4958654d025Sperrin 		} else if (num_logs(nvroot) > 0) {
4968654d025Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
4978654d025Sperrin 		}
498fa9e4066Sahrens 
499fa9e4066Sahrens 		ret = 0;
500fa9e4066Sahrens 	} else {
501fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
502fa9e4066Sahrens 	}
503fa9e4066Sahrens 
50499653d4eSeschrock 	nvlist_free(nvroot);
50599653d4eSeschrock 	zpool_close(zhp);
50699653d4eSeschrock 
50799653d4eSeschrock 	return (ret);
50899653d4eSeschrock }
50999653d4eSeschrock 
51099653d4eSeschrock /*
511fa94a07fSbrendan  * zpool remove <pool> <vdev> ...
51299653d4eSeschrock  *
51399653d4eSeschrock  * Removes the given vdev from the pool.  Currently, this only supports removing
514fa94a07fSbrendan  * spares and cache devices from the pool.  Eventually, we'll want to support
515fa94a07fSbrendan  * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs.
51699653d4eSeschrock  */
51799653d4eSeschrock int
51899653d4eSeschrock zpool_do_remove(int argc, char **argv)
51999653d4eSeschrock {
52099653d4eSeschrock 	char *poolname;
521fa94a07fSbrendan 	int i, ret = 0;
52299653d4eSeschrock 	zpool_handle_t *zhp;
52399653d4eSeschrock 
52499653d4eSeschrock 	argc--;
52599653d4eSeschrock 	argv++;
52699653d4eSeschrock 
52799653d4eSeschrock 	/* get pool name and check number of arguments */
52899653d4eSeschrock 	if (argc < 1) {
52999653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
53099653d4eSeschrock 		usage(B_FALSE);
53199653d4eSeschrock 	}
53299653d4eSeschrock 	if (argc < 2) {
53399653d4eSeschrock 		(void) fprintf(stderr, gettext("missing device\n"));
53499653d4eSeschrock 		usage(B_FALSE);
53599653d4eSeschrock 	}
53699653d4eSeschrock 
53799653d4eSeschrock 	poolname = argv[0];
53899653d4eSeschrock 
53999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
54099653d4eSeschrock 		return (1);
54199653d4eSeschrock 
542fa94a07fSbrendan 	for (i = 1; i < argc; i++) {
543fa94a07fSbrendan 		if (zpool_vdev_remove(zhp, argv[i]) != 0)
544fa94a07fSbrendan 			ret = 1;
545fa94a07fSbrendan 	}
54699653d4eSeschrock 
547fa9e4066Sahrens 	return (ret);
548fa9e4066Sahrens }
549fa9e4066Sahrens 
550fa9e4066Sahrens /*
5510a48a24eStimh  * zpool create [-fn] [-o property=value] ...
5520a48a24eStimh  *		[-O file-system-property=value] ...
5530a48a24eStimh  *		[-R root] [-m mountpoint] <pool> <dev> ...
554fa9e4066Sahrens  *
555fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
556fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
557fa9e4066Sahrens  *		were to be created.
558fa9e4066Sahrens  *      -R	Create a pool under an alternate root
559fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
560fa9e4066Sahrens  *      	'/<pool>'
561990b4856Slling  *	-o	Set property=value.
5620a48a24eStimh  *	-O	Set fsproperty=value in the pool's root file system
563fa9e4066Sahrens  *
564b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
565fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
566fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
567fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
568fa9e4066Sahrens  */
569fa9e4066Sahrens int
570fa9e4066Sahrens zpool_do_create(int argc, char **argv)
571fa9e4066Sahrens {
57299653d4eSeschrock 	boolean_t force = B_FALSE;
57399653d4eSeschrock 	boolean_t dryrun = B_FALSE;
574fa9e4066Sahrens 	int c;
575990b4856Slling 	nvlist_t *nvroot = NULL;
576fa9e4066Sahrens 	char *poolname;
577990b4856Slling 	int ret = 1;
578fa9e4066Sahrens 	char *altroot = NULL;
579fa9e4066Sahrens 	char *mountpoint = NULL;
5800a48a24eStimh 	nvlist_t *fsprops = NULL;
581990b4856Slling 	nvlist_t *props = NULL;
5822f8aaab3Seschrock 	char *propval;
583fa9e4066Sahrens 
584fa9e4066Sahrens 	/* check options */
5850a48a24eStimh 	while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) {
586fa9e4066Sahrens 		switch (c) {
587fa9e4066Sahrens 		case 'f':
58899653d4eSeschrock 			force = B_TRUE;
589fa9e4066Sahrens 			break;
590fa9e4066Sahrens 		case 'n':
59199653d4eSeschrock 			dryrun = B_TRUE;
592fa9e4066Sahrens 			break;
593fa9e4066Sahrens 		case 'R':
594fa9e4066Sahrens 			altroot = optarg;
595990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
5960a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
597990b4856Slling 				goto errout;
5982f8aaab3Seschrock 			if (nvlist_lookup_string(props,
5992f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
6002f8aaab3Seschrock 			    &propval) == 0)
6012f8aaab3Seschrock 				break;
602990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
6030a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
604990b4856Slling 				goto errout;
605fa9e4066Sahrens 			break;
606fa9e4066Sahrens 		case 'm':
607fa9e4066Sahrens 			mountpoint = optarg;
608fa9e4066Sahrens 			break;
609990b4856Slling 		case 'o':
610990b4856Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
611990b4856Slling 				(void) fprintf(stderr, gettext("missing "
612990b4856Slling 				    "'=' for -o option\n"));
613990b4856Slling 				goto errout;
614990b4856Slling 			}
615990b4856Slling 			*propval = '\0';
616990b4856Slling 			propval++;
617990b4856Slling 
6180a48a24eStimh 			if (add_prop_list(optarg, propval, &props, B_TRUE))
6190a48a24eStimh 				goto errout;
6200a48a24eStimh 			break;
6210a48a24eStimh 		case 'O':
6220a48a24eStimh 			if ((propval = strchr(optarg, '=')) == NULL) {
6230a48a24eStimh 				(void) fprintf(stderr, gettext("missing "
6240a48a24eStimh 				    "'=' for -O option\n"));
6250a48a24eStimh 				goto errout;
6260a48a24eStimh 			}
6270a48a24eStimh 			*propval = '\0';
6280a48a24eStimh 			propval++;
6290a48a24eStimh 
6300a48a24eStimh 			if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
631990b4856Slling 				goto errout;
632990b4856Slling 			break;
633fa9e4066Sahrens 		case ':':
634fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
635fa9e4066Sahrens 			    "'%c' option\n"), optopt);
636990b4856Slling 			goto badusage;
637fa9e4066Sahrens 		case '?':
638fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
639fa9e4066Sahrens 			    optopt);
640990b4856Slling 			goto badusage;
641fa9e4066Sahrens 		}
642fa9e4066Sahrens 	}
643fa9e4066Sahrens 
644fa9e4066Sahrens 	argc -= optind;
645fa9e4066Sahrens 	argv += optind;
646fa9e4066Sahrens 
647fa9e4066Sahrens 	/* get pool name and check number of arguments */
648fa9e4066Sahrens 	if (argc < 1) {
649fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
650990b4856Slling 		goto badusage;
651fa9e4066Sahrens 	}
652fa9e4066Sahrens 	if (argc < 2) {
653fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
654990b4856Slling 		goto badusage;
655fa9e4066Sahrens 	}
656fa9e4066Sahrens 
657fa9e4066Sahrens 	poolname = argv[0];
658fa9e4066Sahrens 
659fa9e4066Sahrens 	/*
660fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
661fa9e4066Sahrens 	 * user to use 'zfs create' instead.
662fa9e4066Sahrens 	 */
663fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
664fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
665fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
666fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
667fa9e4066Sahrens 		    "create a dataset\n"));
668990b4856Slling 		goto errout;
669fa9e4066Sahrens 	}
670fa9e4066Sahrens 
671fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
672705040edSEric Taylor 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
673705040edSEric Taylor 	    argc - 1, argv + 1);
674fa9e4066Sahrens 	if (nvroot == NULL)
6750a48a24eStimh 		goto errout;
676fa9e4066Sahrens 
67799653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
678b7b97454Sperrin 	if (!zfs_allocatable_devs(nvroot)) {
67999653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
68099653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
68199653d4eSeschrock 		    "specified\n"));
682990b4856Slling 		goto errout;
68399653d4eSeschrock 	}
68499653d4eSeschrock 
68599653d4eSeschrock 
686fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
687fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
688e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
689990b4856Slling 		goto errout;
690fa9e4066Sahrens 	}
691fa9e4066Sahrens 
692fa9e4066Sahrens 	/*
693fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
694fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
695fa9e4066Sahrens 	 */
696fa9e4066Sahrens 	if (mountpoint == NULL ||
697fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
698fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
699fa9e4066Sahrens 		char buf[MAXPATHLEN];
70011022c7cStimh 		DIR *dirp;
701fa9e4066Sahrens 
702fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
703fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
704fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
705fa9e4066Sahrens 			    "'none'\n"), mountpoint);
706990b4856Slling 			goto errout;
707fa9e4066Sahrens 		}
708fa9e4066Sahrens 
709fa9e4066Sahrens 		if (mountpoint == NULL) {
710fa9e4066Sahrens 			if (altroot != NULL)
711fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
712fa9e4066Sahrens 				    altroot, poolname);
713fa9e4066Sahrens 			else
714fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
715fa9e4066Sahrens 				    poolname);
716fa9e4066Sahrens 		} else {
717fa9e4066Sahrens 			if (altroot != NULL)
718fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
719fa9e4066Sahrens 				    altroot, mountpoint);
720fa9e4066Sahrens 			else
721fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
722fa9e4066Sahrens 				    mountpoint);
723fa9e4066Sahrens 		}
724fa9e4066Sahrens 
72511022c7cStimh 		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
72611022c7cStimh 			(void) fprintf(stderr, gettext("mountpoint '%s' : "
72711022c7cStimh 			    "%s\n"), buf, strerror(errno));
728fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
729fa9e4066Sahrens 			    "option to provide a different default\n"));
730990b4856Slling 			goto errout;
73111022c7cStimh 		} else if (dirp) {
73211022c7cStimh 			int count = 0;
73311022c7cStimh 
73411022c7cStimh 			while (count < 3 && readdir(dirp) != NULL)
73511022c7cStimh 				count++;
73611022c7cStimh 			(void) closedir(dirp);
73711022c7cStimh 
73811022c7cStimh 			if (count > 2) {
73911022c7cStimh 				(void) fprintf(stderr, gettext("mountpoint "
74011022c7cStimh 				    "'%s' exists and is not empty\n"), buf);
74111022c7cStimh 				(void) fprintf(stderr, gettext("use '-m' "
74211022c7cStimh 				    "option to provide a "
74311022c7cStimh 				    "different default\n"));
74411022c7cStimh 				goto errout;
74511022c7cStimh 			}
746fa9e4066Sahrens 		}
747fa9e4066Sahrens 	}
748fa9e4066Sahrens 
749fa9e4066Sahrens 	if (dryrun) {
750fa9e4066Sahrens 		/*
751fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
752fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
753fa9e4066Sahrens 		 * appropriate hierarchy.
754fa9e4066Sahrens 		 */
755fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
756fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
757fa9e4066Sahrens 
7588654d025Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7598654d025Sperrin 		if (num_logs(nvroot) > 0)
7608654d025Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
761fa9e4066Sahrens 
762fa9e4066Sahrens 		ret = 0;
763fa9e4066Sahrens 	} else {
764fa9e4066Sahrens 		/*
765fa9e4066Sahrens 		 * Hand off to libzfs.
766fa9e4066Sahrens 		 */
7670a48a24eStimh 		if (zpool_create(g_zfs, poolname,
7680a48a24eStimh 		    nvroot, props, fsprops) == 0) {
76999653d4eSeschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
770fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
771fa9e4066Sahrens 			if (pool != NULL) {
772fa9e4066Sahrens 				if (mountpoint != NULL)
773fa9e4066Sahrens 					verify(zfs_prop_set(pool,
774e9dbad6fSeschrock 					    zfs_prop_to_name(
775e9dbad6fSeschrock 					    ZFS_PROP_MOUNTPOINT),
776fa9e4066Sahrens 					    mountpoint) == 0);
777fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
778da6c28aaSamw 					ret = zfs_shareall(pool);
779fa9e4066Sahrens 				zfs_close(pool);
780fa9e4066Sahrens 			}
78199653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
78299653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
78399653d4eSeschrock 			    "been omitted\n"));
784fa9e4066Sahrens 		}
785fa9e4066Sahrens 	}
786fa9e4066Sahrens 
787990b4856Slling errout:
788fa9e4066Sahrens 	nvlist_free(nvroot);
7890a48a24eStimh 	nvlist_free(fsprops);
790990b4856Slling 	nvlist_free(props);
791fa9e4066Sahrens 	return (ret);
792990b4856Slling badusage:
7930a48a24eStimh 	nvlist_free(fsprops);
794990b4856Slling 	nvlist_free(props);
795990b4856Slling 	usage(B_FALSE);
796990b4856Slling 	return (2);
797fa9e4066Sahrens }
798fa9e4066Sahrens 
799fa9e4066Sahrens /*
800fa9e4066Sahrens  * zpool destroy <pool>
801fa9e4066Sahrens  *
802fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
803fa9e4066Sahrens  *
804fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
805fa9e4066Sahrens  */
806fa9e4066Sahrens int
807fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
808fa9e4066Sahrens {
80999653d4eSeschrock 	boolean_t force = B_FALSE;
810fa9e4066Sahrens 	int c;
811fa9e4066Sahrens 	char *pool;
812fa9e4066Sahrens 	zpool_handle_t *zhp;
813fa9e4066Sahrens 	int ret;
814fa9e4066Sahrens 
815fa9e4066Sahrens 	/* check options */
816fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
817fa9e4066Sahrens 		switch (c) {
818fa9e4066Sahrens 		case 'f':
81999653d4eSeschrock 			force = B_TRUE;
820fa9e4066Sahrens 			break;
821fa9e4066Sahrens 		case '?':
822fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
823fa9e4066Sahrens 			    optopt);
82499653d4eSeschrock 			usage(B_FALSE);
825fa9e4066Sahrens 		}
826fa9e4066Sahrens 	}
827fa9e4066Sahrens 
828fa9e4066Sahrens 	argc -= optind;
829fa9e4066Sahrens 	argv += optind;
830fa9e4066Sahrens 
831fa9e4066Sahrens 	/* check arguments */
832fa9e4066Sahrens 	if (argc < 1) {
833fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
83499653d4eSeschrock 		usage(B_FALSE);
835fa9e4066Sahrens 	}
836fa9e4066Sahrens 	if (argc > 1) {
837fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
83899653d4eSeschrock 		usage(B_FALSE);
839fa9e4066Sahrens 	}
840fa9e4066Sahrens 
841fa9e4066Sahrens 	pool = argv[0];
842fa9e4066Sahrens 
84399653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
844fa9e4066Sahrens 		/*
845fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
846fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
847fa9e4066Sahrens 		 */
848fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
849fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
850fa9e4066Sahrens 			    "destroy a dataset\n"));
851fa9e4066Sahrens 		return (1);
852fa9e4066Sahrens 	}
853fa9e4066Sahrens 
854f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
855fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
856fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
857fa9e4066Sahrens 		return (1);
858fa9e4066Sahrens 	}
859fa9e4066Sahrens 
860fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
861fa9e4066Sahrens 
862fa9e4066Sahrens 	zpool_close(zhp);
863fa9e4066Sahrens 
864fa9e4066Sahrens 	return (ret);
865fa9e4066Sahrens }
866fa9e4066Sahrens 
867fa9e4066Sahrens /*
868fa9e4066Sahrens  * zpool export [-f] <pool> ...
869fa9e4066Sahrens  *
870fa9e4066Sahrens  *	-f	Forcefully unmount datasets
871fa9e4066Sahrens  *
872b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
873fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
874fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
875fa9e4066Sahrens  */
876fa9e4066Sahrens int
877fa9e4066Sahrens zpool_do_export(int argc, char **argv)
878fa9e4066Sahrens {
87999653d4eSeschrock 	boolean_t force = B_FALSE;
880fa9e4066Sahrens 	int c;
881fa9e4066Sahrens 	zpool_handle_t *zhp;
882fa9e4066Sahrens 	int ret;
883fa9e4066Sahrens 	int i;
884fa9e4066Sahrens 
885fa9e4066Sahrens 	/* check options */
886fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
887fa9e4066Sahrens 		switch (c) {
888fa9e4066Sahrens 		case 'f':
88999653d4eSeschrock 			force = B_TRUE;
890fa9e4066Sahrens 			break;
891fa9e4066Sahrens 		case '?':
892fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
893fa9e4066Sahrens 			    optopt);
89499653d4eSeschrock 			usage(B_FALSE);
895fa9e4066Sahrens 		}
896fa9e4066Sahrens 	}
897fa9e4066Sahrens 
898fa9e4066Sahrens 	argc -= optind;
899fa9e4066Sahrens 	argv += optind;
900fa9e4066Sahrens 
901fa9e4066Sahrens 	/* check arguments */
902fa9e4066Sahrens 	if (argc < 1) {
903fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
90499653d4eSeschrock 		usage(B_FALSE);
905fa9e4066Sahrens 	}
906fa9e4066Sahrens 
907fa9e4066Sahrens 	ret = 0;
908fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
90999653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
910fa9e4066Sahrens 			ret = 1;
911fa9e4066Sahrens 			continue;
912fa9e4066Sahrens 		}
913fa9e4066Sahrens 
914f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
915fa9e4066Sahrens 			ret = 1;
916fa9e4066Sahrens 			zpool_close(zhp);
917fa9e4066Sahrens 			continue;
918fa9e4066Sahrens 		}
919fa9e4066Sahrens 
92089a89ebfSlling 		if (zpool_export(zhp, force) != 0)
921fa9e4066Sahrens 			ret = 1;
922fa9e4066Sahrens 
923fa9e4066Sahrens 		zpool_close(zhp);
924fa9e4066Sahrens 	}
925fa9e4066Sahrens 
926fa9e4066Sahrens 	return (ret);
927fa9e4066Sahrens }
928fa9e4066Sahrens 
929fa9e4066Sahrens /*
930fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
931fa9e4066Sahrens  * name column.
932fa9e4066Sahrens  */
933fa9e4066Sahrens static int
934c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
935fa9e4066Sahrens {
93699653d4eSeschrock 	char *name = zpool_vdev_name(g_zfs, zhp, nv);
937fa9e4066Sahrens 	nvlist_t **child;
938fa9e4066Sahrens 	uint_t c, children;
939fa9e4066Sahrens 	int ret;
940fa9e4066Sahrens 
941fa9e4066Sahrens 	if (strlen(name) + depth > max)
942fa9e4066Sahrens 		max = strlen(name) + depth;
943fa9e4066Sahrens 
944afefbcddSeschrock 	free(name);
945afefbcddSeschrock 
94699653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
94799653d4eSeschrock 	    &child, &children) == 0) {
948fa9e4066Sahrens 		for (c = 0; c < children; c++)
94999653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
95099653d4eSeschrock 			    max)) > max)
951fa9e4066Sahrens 				max = ret;
95299653d4eSeschrock 	}
95399653d4eSeschrock 
954fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
955fa94a07fSbrendan 	    &child, &children) == 0) {
956fa94a07fSbrendan 		for (c = 0; c < children; c++)
957fa94a07fSbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
958fa94a07fSbrendan 			    max)) > max)
959fa94a07fSbrendan 				max = ret;
960fa94a07fSbrendan 	}
961fa94a07fSbrendan 
96299653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
96399653d4eSeschrock 	    &child, &children) == 0) {
96499653d4eSeschrock 		for (c = 0; c < children; c++)
96599653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
96699653d4eSeschrock 			    max)) > max)
96799653d4eSeschrock 				max = ret;
96899653d4eSeschrock 	}
96999653d4eSeschrock 
970fa9e4066Sahrens 
971fa9e4066Sahrens 	return (max);
972fa9e4066Sahrens }
973fa9e4066Sahrens 
974fa9e4066Sahrens 
975fa9e4066Sahrens /*
976fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
977fa9e4066Sahrens  * pool, printing out the name and status for each one.
978fa9e4066Sahrens  */
979fa9e4066Sahrens void
9808654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
9818654d025Sperrin     boolean_t print_logs)
982fa9e4066Sahrens {
983fa9e4066Sahrens 	nvlist_t **child;
984fa9e4066Sahrens 	uint_t c, children;
985fa9e4066Sahrens 	vdev_stat_t *vs;
986afefbcddSeschrock 	char *type, *vname;
987fa9e4066Sahrens 
988fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
989fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
990fa9e4066Sahrens 		return;
991fa9e4066Sahrens 
992fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
993fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
994fa9e4066Sahrens 
995fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
996990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
997fa9e4066Sahrens 
998fa9e4066Sahrens 	if (vs->vs_aux != 0) {
9993d7072f8Seschrock 		(void) printf("  ");
1000fa9e4066Sahrens 
1001fa9e4066Sahrens 		switch (vs->vs_aux) {
1002fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
1003fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
1004fa9e4066Sahrens 			break;
1005fa9e4066Sahrens 
1006fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
1007fa9e4066Sahrens 			(void) printf(gettext("missing device"));
1008fa9e4066Sahrens 			break;
1009fa9e4066Sahrens 
1010fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
1011fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
1012fa9e4066Sahrens 			break;
1013fa9e4066Sahrens 
1014eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
1015eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
1016eaca9bbdSeschrock 			break;
1017eaca9bbdSeschrock 
10183d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
10193d7072f8Seschrock 			(void) printf(gettext("too many errors"));
10203d7072f8Seschrock 			break;
10213d7072f8Seschrock 
1022fa9e4066Sahrens 		default:
1023fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
1024fa9e4066Sahrens 			break;
1025fa9e4066Sahrens 		}
1026fa9e4066Sahrens 	}
1027fa9e4066Sahrens 	(void) printf("\n");
1028fa9e4066Sahrens 
1029fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1030fa9e4066Sahrens 	    &child, &children) != 0)
1031fa9e4066Sahrens 		return;
1032fa9e4066Sahrens 
1033afefbcddSeschrock 	for (c = 0; c < children; c++) {
10348654d025Sperrin 		uint64_t is_log = B_FALSE;
10358654d025Sperrin 
10368654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
10378654d025Sperrin 		    &is_log);
10388654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
10398654d025Sperrin 			continue;
10408654d025Sperrin 
104199653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1042afefbcddSeschrock 		print_import_config(vname, child[c],
10438654d025Sperrin 		    namewidth, depth + 2, B_FALSE);
1044afefbcddSeschrock 		free(vname);
1045afefbcddSeschrock 	}
104699653d4eSeschrock 
1047fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1048fa94a07fSbrendan 	    &child, &children) == 0) {
1049fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
1050fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1051fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1052fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1053fa94a07fSbrendan 			free(vname);
1054fa94a07fSbrendan 		}
1055fa94a07fSbrendan 	}
105699653d4eSeschrock 
1057fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1058fa94a07fSbrendan 	    &child, &children) == 0) {
105999653d4eSeschrock 		(void) printf(gettext("\tspares\n"));
106099653d4eSeschrock 		for (c = 0; c < children; c++) {
106199653d4eSeschrock 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
106299653d4eSeschrock 			(void) printf("\t  %s\n", vname);
106399653d4eSeschrock 			free(vname);
106499653d4eSeschrock 		}
1065fa9e4066Sahrens 	}
1066fa94a07fSbrendan }
1067fa9e4066Sahrens 
1068fa9e4066Sahrens /*
1069fa9e4066Sahrens  * Display the status for the given pool.
1070fa9e4066Sahrens  */
1071fa9e4066Sahrens static void
1072fa9e4066Sahrens show_import(nvlist_t *config)
1073fa9e4066Sahrens {
1074fa9e4066Sahrens 	uint64_t pool_state;
1075fa9e4066Sahrens 	vdev_stat_t *vs;
1076fa9e4066Sahrens 	char *name;
1077fa9e4066Sahrens 	uint64_t guid;
1078fa9e4066Sahrens 	char *msgid;
1079fa9e4066Sahrens 	nvlist_t *nvroot;
1080fa9e4066Sahrens 	int reason;
108146657f8dSmmusante 	const char *health;
1082fa9e4066Sahrens 	uint_t vsc;
1083fa9e4066Sahrens 	int namewidth;
1084fa9e4066Sahrens 
1085fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1086fa9e4066Sahrens 	    &name) == 0);
1087fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1088fa9e4066Sahrens 	    &guid) == 0);
1089fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1090fa9e4066Sahrens 	    &pool_state) == 0);
1091fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1092fa9e4066Sahrens 	    &nvroot) == 0);
1093fa9e4066Sahrens 
1094fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1095fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1096990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1097fa9e4066Sahrens 
1098fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1099fa9e4066Sahrens 
110046657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
110146657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
110246657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
11034c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
110446657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
11054c58d714Sdarrenm 	(void) printf("\n");
1106fa9e4066Sahrens 
1107fa9e4066Sahrens 	switch (reason) {
1108fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1109fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1110fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1111fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1112fa9e4066Sahrens 		    "from the system.\n"));
1113fa9e4066Sahrens 		break;
1114fa9e4066Sahrens 
1115fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1116fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1117fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1118fa9e4066Sahrens 		    "corrupted data.\n"));
1119fa9e4066Sahrens 		break;
1120fa9e4066Sahrens 
1121fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1122fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1123fa9e4066Sahrens 		break;
1124fa9e4066Sahrens 
1125441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1126441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1127441d80aaSlling 		    "are offlined.\n"));
1128441d80aaSlling 		break;
1129441d80aaSlling 
1130ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1131ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1132ea8dc4b6Seschrock 		    "corrupted.\n"));
1133ea8dc4b6Seschrock 		break;
1134ea8dc4b6Seschrock 
1135eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1136eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1137eaca9bbdSeschrock 		    "older on-disk version.\n"));
1138eaca9bbdSeschrock 		break;
1139eaca9bbdSeschrock 
1140eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1141eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1142eaca9bbdSeschrock 		    "incompatible version.\n"));
1143eaca9bbdSeschrock 		break;
1144b87f3af3Sperrin 
114595173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
114695173954Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
114795173954Sek110237 		    "another system.\n"));
114895173954Sek110237 		break;
1149b87f3af3Sperrin 
11503d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
11513d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
11523d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
11533d7072f8Seschrock 		    "faulted.\n"));
11543d7072f8Seschrock 		break;
11553d7072f8Seschrock 
1156b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
1157b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record cannot be "
1158b87f3af3Sperrin 		    "read.\n"));
1159b87f3af3Sperrin 		break;
1160b87f3af3Sperrin 
1161fa9e4066Sahrens 	default:
1162fa9e4066Sahrens 		/*
1163fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1164fa9e4066Sahrens 		 */
1165fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1166fa9e4066Sahrens 	}
1167fa9e4066Sahrens 
1168fa9e4066Sahrens 	/*
1169fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1170fa9e4066Sahrens 	 */
117146657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1172eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1173eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1174eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1175eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1176eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
117795173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
117895173954Sek110237 			(void) printf(gettext("action: The pool can be "
117995173954Sek110237 			    "imported using its name or numeric "
118095173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1181fa9e4066Sahrens 		else
1182eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1183eaca9bbdSeschrock 			    "imported using its name or numeric "
1184eaca9bbdSeschrock 			    "identifier.\n"));
118546657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1186fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1187fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1188eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1189fa9e4066Sahrens 	} else {
1190eaca9bbdSeschrock 		switch (reason) {
1191eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1192eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1193eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1194eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1195eaca9bbdSeschrock 			    "backup.\n"));
1196eaca9bbdSeschrock 			break;
1197eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1198eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1199eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1200fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1201fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1202fa9e4066Sahrens 			    "again.\n"));
1203eaca9bbdSeschrock 			break;
1204eaca9bbdSeschrock 		default:
1205fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1206fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1207fa9e4066Sahrens 		}
1208eaca9bbdSeschrock 	}
1209eaca9bbdSeschrock 
121046657f8dSmmusante 	/*
121146657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
121246657f8dSmmusante 	 * is "corrupt data":
121346657f8dSmmusante 	 */
121446657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
121546657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
121646657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1217eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1218eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1219eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1220eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1221eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
122218ce54dfSek110237 			    "another system, but can be imported using\n\t"
1223eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1224eaca9bbdSeschrock 	}
1225fa9e4066Sahrens 
1226fa9e4066Sahrens 	if (msgid != NULL)
1227fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1228fa9e4066Sahrens 		    msgid);
1229fa9e4066Sahrens 
1230fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1231fa9e4066Sahrens 
1232c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1233fa9e4066Sahrens 	if (namewidth < 10)
1234fa9e4066Sahrens 		namewidth = 10;
12358654d025Sperrin 
12368654d025Sperrin 	print_import_config(name, nvroot, namewidth, 0, B_FALSE);
12378654d025Sperrin 	if (num_logs(nvroot) > 0) {
12388654d025Sperrin 		(void) printf(gettext("\tlogs\n"));
12398654d025Sperrin 		print_import_config(name, nvroot, namewidth, 0, B_TRUE);
12408654d025Sperrin 	}
1241fa9e4066Sahrens 
1242fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
124346657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1244fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
124546657f8dSmmusante 		    "configuration cannot be determined.\n"));
1246fa9e4066Sahrens 	}
1247fa9e4066Sahrens }
1248fa9e4066Sahrens 
1249fa9e4066Sahrens /*
1250fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1251990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1252990b4856Slling  * within the pool.
1253fa9e4066Sahrens  */
1254fa9e4066Sahrens static int
1255fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
1256c5904d13Seschrock     int force, nvlist_t *props, boolean_t allowfaulted)
1257fa9e4066Sahrens {
1258fa9e4066Sahrens 	zpool_handle_t *zhp;
1259fa9e4066Sahrens 	char *name;
1260fa9e4066Sahrens 	uint64_t state;
1261eaca9bbdSeschrock 	uint64_t version;
1262ecd6cf80Smarks 	int error = 0;
1263fa9e4066Sahrens 
1264fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1265fa9e4066Sahrens 	    &name) == 0);
1266fa9e4066Sahrens 
1267fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1268fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1269eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1270eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1271e7437265Sahrens 	if (version > SPA_VERSION) {
1272eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1273eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1274eaca9bbdSeschrock 		return (1);
1275eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
127695173954Sek110237 		uint64_t hostid;
127795173954Sek110237 
127895173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
127995173954Sek110237 		    &hostid) == 0) {
128095173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
128195173954Sek110237 				char *hostname;
128295173954Sek110237 				uint64_t timestamp;
128395173954Sek110237 				time_t t;
128495173954Sek110237 
128595173954Sek110237 				verify(nvlist_lookup_string(config,
128695173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
128795173954Sek110237 				verify(nvlist_lookup_uint64(config,
128895173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
128995173954Sek110237 				t = timestamp;
129095173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
129195173954Sek110237 				    "'%s': pool may be in use from other "
129295173954Sek110237 				    "system, it was last accessed by %s "
129395173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
129495173954Sek110237 				    (unsigned long)hostid,
129595173954Sek110237 				    asctime(localtime(&t)));
129695173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
129795173954Sek110237 				    "import anyway\n"));
1298fa9e4066Sahrens 				return (1);
1299fa9e4066Sahrens 			}
130095173954Sek110237 		} else {
130195173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
130295173954Sek110237 			    "pool may be in use from other system\n"), name);
130395173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
130495173954Sek110237 			    "anyway\n"));
130595173954Sek110237 			return (1);
130695173954Sek110237 		}
130795173954Sek110237 	}
1308fa9e4066Sahrens 
1309c5904d13Seschrock 	if (zpool_import_props(g_zfs, config, newname, props,
1310c5904d13Seschrock 	    allowfaulted) != 0)
1311fa9e4066Sahrens 		return (1);
1312fa9e4066Sahrens 
1313fa9e4066Sahrens 	if (newname != NULL)
1314fa9e4066Sahrens 		name = (char *)newname;
1315fa9e4066Sahrens 
1316c5904d13Seschrock 	verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL);
1317fa9e4066Sahrens 
1318f3861e1aSahl 	if (zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1319fa9e4066Sahrens 		zpool_close(zhp);
1320fa9e4066Sahrens 		return (1);
1321fa9e4066Sahrens 	}
1322fa9e4066Sahrens 
1323fa9e4066Sahrens 	zpool_close(zhp);
1324ecd6cf80Smarks 	return (error);
1325fa9e4066Sahrens }
1326fa9e4066Sahrens 
1327fa9e4066Sahrens /*
13284c58d714Sdarrenm  * zpool import [-d dir] [-D]
13292f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
13302f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
13312f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
13322f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] <pool | id> [newpool]
13332f8aaab3Seschrock  *
13342f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
13352f8aaab3Seschrock  *		devices.
1336fa9e4066Sahrens  *
1337fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1338fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1339fa9e4066Sahrens  *
13404c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
13414c58d714Sdarrenm  *              specified destroyed pools.
13424c58d714Sdarrenm  *
1343fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1344fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1345fa9e4066Sahrens  *		is rebooted.
1346fa9e4066Sahrens  *
1347fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1348fa9e4066Sahrens  *
1349c5904d13Seschrock  *       -F	Import even in the presence of faulted vdevs.  This is an
1350c5904d13Seschrock  *       	intentionally undocumented option for testing purposes, and
1351c5904d13Seschrock  *       	treats the pool configuration as complete, leaving any bad
1352c5904d13Seschrock  *		vdevs in the FAULTED state.
1353c5904d13Seschrock  *
1354fa9e4066Sahrens  *       -a	Import all pools found.
1355fa9e4066Sahrens  *
1356990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1357ecd6cf80Smarks  *
1358fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1359fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1360fa9e4066Sahrens  */
1361fa9e4066Sahrens int
1362fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1363fa9e4066Sahrens {
1364fa9e4066Sahrens 	char **searchdirs = NULL;
1365fa9e4066Sahrens 	int nsearch = 0;
1366fa9e4066Sahrens 	int c;
1367fa9e4066Sahrens 	int err;
13682f8aaab3Seschrock 	nvlist_t *pools = NULL;
136999653d4eSeschrock 	boolean_t do_all = B_FALSE;
137099653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1371fa9e4066Sahrens 	char *mntopts = NULL;
137299653d4eSeschrock 	boolean_t do_force = B_FALSE;
1373fa9e4066Sahrens 	nvpair_t *elem;
1374fa9e4066Sahrens 	nvlist_t *config;
137524e697d4Sck153898 	uint64_t searchguid = 0;
137624e697d4Sck153898 	char *searchname = NULL;
1377990b4856Slling 	char *propval;
1378fa9e4066Sahrens 	nvlist_t *found_config;
1379ecd6cf80Smarks 	nvlist_t *props = NULL;
138099653d4eSeschrock 	boolean_t first;
1381c5904d13Seschrock 	boolean_t allow_faulted = B_FALSE;
13824c58d714Sdarrenm 	uint64_t pool_state;
13832f8aaab3Seschrock 	char *cachefile = NULL;
1384fa9e4066Sahrens 
1385fa9e4066Sahrens 	/* check options */
1386c5904d13Seschrock 	while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) {
1387fa9e4066Sahrens 		switch (c) {
1388fa9e4066Sahrens 		case 'a':
138999653d4eSeschrock 			do_all = B_TRUE;
1390fa9e4066Sahrens 			break;
13912f8aaab3Seschrock 		case 'c':
13922f8aaab3Seschrock 			cachefile = optarg;
13932f8aaab3Seschrock 			break;
1394fa9e4066Sahrens 		case 'd':
1395fa9e4066Sahrens 			if (searchdirs == NULL) {
1396fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1397fa9e4066Sahrens 			} else {
1398fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1399fa9e4066Sahrens 				    sizeof (char *));
1400fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1401fa9e4066Sahrens 				    sizeof (char *));
1402fa9e4066Sahrens 				free(searchdirs);
1403fa9e4066Sahrens 				searchdirs = tmp;
1404fa9e4066Sahrens 			}
1405fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1406fa9e4066Sahrens 			break;
14074c58d714Sdarrenm 		case 'D':
140899653d4eSeschrock 			do_destroyed = B_TRUE;
14094c58d714Sdarrenm 			break;
1410fa9e4066Sahrens 		case 'f':
141199653d4eSeschrock 			do_force = B_TRUE;
1412fa9e4066Sahrens 			break;
1413c5904d13Seschrock 		case 'F':
1414c5904d13Seschrock 			allow_faulted = B_TRUE;
1415c5904d13Seschrock 			break;
1416fa9e4066Sahrens 		case 'o':
1417990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1418990b4856Slling 				*propval = '\0';
1419990b4856Slling 				propval++;
14200a48a24eStimh 				if (add_prop_list(optarg, propval,
14210a48a24eStimh 				    &props, B_TRUE))
1422990b4856Slling 					goto error;
1423990b4856Slling 			} else {
1424fa9e4066Sahrens 				mntopts = optarg;
1425990b4856Slling 			}
1426fa9e4066Sahrens 			break;
1427fa9e4066Sahrens 		case 'R':
1428990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
14290a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1430990b4856Slling 				goto error;
14312f8aaab3Seschrock 			if (nvlist_lookup_string(props,
14322f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
14332f8aaab3Seschrock 			    &propval) == 0)
14342f8aaab3Seschrock 				break;
1435990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
14360a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1437990b4856Slling 				goto error;
1438fa9e4066Sahrens 			break;
1439fa9e4066Sahrens 		case ':':
1440fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1441fa9e4066Sahrens 			    "'%c' option\n"), optopt);
144299653d4eSeschrock 			usage(B_FALSE);
1443fa9e4066Sahrens 			break;
1444fa9e4066Sahrens 		case '?':
1445fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1446fa9e4066Sahrens 			    optopt);
144799653d4eSeschrock 			usage(B_FALSE);
1448fa9e4066Sahrens 		}
1449fa9e4066Sahrens 	}
1450fa9e4066Sahrens 
1451fa9e4066Sahrens 	argc -= optind;
1452fa9e4066Sahrens 	argv += optind;
1453fa9e4066Sahrens 
14542f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
14552f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
14562f8aaab3Seschrock 		usage(B_FALSE);
14572f8aaab3Seschrock 	}
14582f8aaab3Seschrock 
1459fa9e4066Sahrens 	if (searchdirs == NULL) {
1460fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1461fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1462fa9e4066Sahrens 		nsearch = 1;
1463fa9e4066Sahrens 	}
1464fa9e4066Sahrens 
1465fa9e4066Sahrens 	/* check argument count */
1466fa9e4066Sahrens 	if (do_all) {
1467fa9e4066Sahrens 		if (argc != 0) {
1468fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
146999653d4eSeschrock 			usage(B_FALSE);
1470fa9e4066Sahrens 		}
1471fa9e4066Sahrens 	} else {
1472fa9e4066Sahrens 		if (argc > 2) {
1473fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
147499653d4eSeschrock 			usage(B_FALSE);
1475fa9e4066Sahrens 		}
1476fa9e4066Sahrens 
1477fa9e4066Sahrens 		/*
1478fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1479fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1480fa9e4066Sahrens 		 * silently fail.
1481fa9e4066Sahrens 		 */
1482fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1483fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1484fa9e4066Sahrens 			    "discover pools: permission denied\n"));
148599653d4eSeschrock 			free(searchdirs);
1486fa9e4066Sahrens 			return (1);
1487fa9e4066Sahrens 		}
1488fa9e4066Sahrens 	}
1489fa9e4066Sahrens 
1490fa9e4066Sahrens 	/*
1491fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1492fa9e4066Sahrens 	 *
1493fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1494fa9e4066Sahrens 	 *		each one.
1495fa9e4066Sahrens 	 *
1496fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1497fa9e4066Sahrens 	 *
1498fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1499fa9e4066Sahrens 	 *		name and import that one.
15004c58d714Sdarrenm 	 *
15014c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1502fa9e4066Sahrens 	 */
1503fa9e4066Sahrens 	if (argc != 0) {
1504fa9e4066Sahrens 		char *endptr;
1505fa9e4066Sahrens 
1506fa9e4066Sahrens 		errno = 0;
1507fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1508fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1509fa9e4066Sahrens 			searchname = argv[0];
1510fa9e4066Sahrens 		found_config = NULL;
1511fa9e4066Sahrens 	}
1512fa9e4066Sahrens 
151324e697d4Sck153898 	if (cachefile) {
1514e829d913Sck153898 		pools = zpool_find_import_cached(g_zfs, cachefile, searchname,
1515e829d913Sck153898 		    searchguid);
151624e697d4Sck153898 	} else if (searchname != NULL) {
151724e697d4Sck153898 		pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs,
151824e697d4Sck153898 		    searchname);
151924e697d4Sck153898 	} else {
152024e697d4Sck153898 		/*
152124e697d4Sck153898 		 * It's OK to search by guid even if searchguid is 0.
152224e697d4Sck153898 		 */
152324e697d4Sck153898 		pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs,
152424e697d4Sck153898 		    searchguid);
152524e697d4Sck153898 	}
152624e697d4Sck153898 
152724e697d4Sck153898 	if (pools == NULL) {
152824e697d4Sck153898 		if (argc != 0) {
152924e697d4Sck153898 			(void) fprintf(stderr, gettext("cannot import '%s': "
153024e697d4Sck153898 			    "no such pool available\n"), argv[0]);
153124e697d4Sck153898 		}
153224e697d4Sck153898 		free(searchdirs);
153324e697d4Sck153898 		return (1);
153424e697d4Sck153898 	}
153524e697d4Sck153898 
153624e697d4Sck153898 	/*
153724e697d4Sck153898 	 * At this point we have a list of import candidate configs. Even if
153824e697d4Sck153898 	 * we were searching by pool name or guid, we still need to
153924e697d4Sck153898 	 * post-process the list to deal with pool state and possible
154024e697d4Sck153898 	 * duplicate names.
154124e697d4Sck153898 	 */
1542fa9e4066Sahrens 	err = 0;
1543fa9e4066Sahrens 	elem = NULL;
154499653d4eSeschrock 	first = B_TRUE;
1545fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1546fa9e4066Sahrens 
1547fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1548fa9e4066Sahrens 
15494c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
15504c58d714Sdarrenm 		    &pool_state) == 0);
15514c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
15524c58d714Sdarrenm 			continue;
15534c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
15544c58d714Sdarrenm 			continue;
15554c58d714Sdarrenm 
1556fa9e4066Sahrens 		if (argc == 0) {
1557fa9e4066Sahrens 			if (first)
155899653d4eSeschrock 				first = B_FALSE;
15593bb79becSeschrock 			else if (!do_all)
1560fa9e4066Sahrens 				(void) printf("\n");
1561fa9e4066Sahrens 
1562fa9e4066Sahrens 			if (do_all)
1563fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1564c5904d13Seschrock 				    do_force, props, allow_faulted);
1565fa9e4066Sahrens 			else
1566fa9e4066Sahrens 				show_import(config);
1567fa9e4066Sahrens 		} else if (searchname != NULL) {
1568fa9e4066Sahrens 			char *name;
1569fa9e4066Sahrens 
1570fa9e4066Sahrens 			/*
1571fa9e4066Sahrens 			 * We are searching for a pool based on name.
1572fa9e4066Sahrens 			 */
1573fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1574fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1575fa9e4066Sahrens 
1576fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1577fa9e4066Sahrens 				if (found_config != NULL) {
1578fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1579fa9e4066Sahrens 					    "cannot import '%s': more than "
1580fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1581fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1582fa9e4066Sahrens 					    "import by numeric ID instead\n"));
158399653d4eSeschrock 					err = B_TRUE;
1584fa9e4066Sahrens 				}
1585fa9e4066Sahrens 				found_config = config;
1586fa9e4066Sahrens 			}
1587fa9e4066Sahrens 		} else {
1588fa9e4066Sahrens 			uint64_t guid;
1589fa9e4066Sahrens 
1590fa9e4066Sahrens 			/*
1591fa9e4066Sahrens 			 * Search for a pool by guid.
1592fa9e4066Sahrens 			 */
1593fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1594fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1595fa9e4066Sahrens 
1596fa9e4066Sahrens 			if (guid == searchguid)
1597fa9e4066Sahrens 				found_config = config;
1598fa9e4066Sahrens 		}
1599fa9e4066Sahrens 	}
1600fa9e4066Sahrens 
1601fa9e4066Sahrens 	/*
1602fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1603fa9e4066Sahrens 	 * pool, and then do the import.
1604fa9e4066Sahrens 	 */
1605fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1606fa9e4066Sahrens 		if (found_config == NULL) {
1607fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1608fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
160999653d4eSeschrock 			err = B_TRUE;
1610fa9e4066Sahrens 		} else {
1611fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1612c5904d13Seschrock 			    argv[1], mntopts, do_force, props, allow_faulted);
1613fa9e4066Sahrens 		}
1614fa9e4066Sahrens 	}
1615fa9e4066Sahrens 
1616fa9e4066Sahrens 	/*
1617fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1618fa9e4066Sahrens 	 * found.
1619fa9e4066Sahrens 	 */
1620fa9e4066Sahrens 	if (argc == 0 && first)
1621fa9e4066Sahrens 		(void) fprintf(stderr,
1622fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1623fa9e4066Sahrens 
1624ecd6cf80Smarks error:
1625ecd6cf80Smarks 	nvlist_free(props);
1626fa9e4066Sahrens 	nvlist_free(pools);
162799653d4eSeschrock 	free(searchdirs);
1628fa9e4066Sahrens 
1629fa9e4066Sahrens 	return (err ? 1 : 0);
1630fa9e4066Sahrens }
1631fa9e4066Sahrens 
1632fa9e4066Sahrens typedef struct iostat_cbdata {
1633fa9e4066Sahrens 	zpool_list_t *cb_list;
1634fa9e4066Sahrens 	int cb_verbose;
1635fa9e4066Sahrens 	int cb_iteration;
1636fa9e4066Sahrens 	int cb_namewidth;
1637fa9e4066Sahrens } iostat_cbdata_t;
1638fa9e4066Sahrens 
1639fa9e4066Sahrens static void
1640fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1641fa9e4066Sahrens {
1642fa9e4066Sahrens 	int i = 0;
1643fa9e4066Sahrens 
1644fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1645fa9e4066Sahrens 		(void) printf("-");
1646fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1647fa9e4066Sahrens }
1648fa9e4066Sahrens 
1649fa9e4066Sahrens static void
1650fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1651fa9e4066Sahrens {
1652fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1653fa9e4066Sahrens 	    cb->cb_namewidth, "");
1654fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1655fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1656fa9e4066Sahrens 	print_iostat_separator(cb);
1657fa9e4066Sahrens }
1658fa9e4066Sahrens 
1659fa9e4066Sahrens /*
1660fa9e4066Sahrens  * Display a single statistic.
1661fa9e4066Sahrens  */
1662990b4856Slling static void
1663fa9e4066Sahrens print_one_stat(uint64_t value)
1664fa9e4066Sahrens {
1665fa9e4066Sahrens 	char buf[64];
1666fa9e4066Sahrens 
1667fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1668fa9e4066Sahrens 	(void) printf("  %5s", buf);
1669fa9e4066Sahrens }
1670fa9e4066Sahrens 
1671fa9e4066Sahrens /*
1672fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1673fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1674fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1675fa9e4066Sahrens  */
1676fa9e4066Sahrens void
1677c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1678c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1679fa9e4066Sahrens {
1680fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1681fa9e4066Sahrens 	uint_t c, children;
1682fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1683fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1684fa9e4066Sahrens 	uint64_t tdelta;
1685fa9e4066Sahrens 	double scale;
1686afefbcddSeschrock 	char *vname;
1687fa9e4066Sahrens 
1688fa9e4066Sahrens 	if (oldnv != NULL) {
1689fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1690fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1691fa9e4066Sahrens 	} else {
1692fa9e4066Sahrens 		oldvs = &zerovs;
1693fa9e4066Sahrens 	}
1694fa9e4066Sahrens 
1695fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1696fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1697fa9e4066Sahrens 
1698fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1699fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1700fa9e4066Sahrens 	else
1701fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1702fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1703fa9e4066Sahrens 
1704fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1705fa9e4066Sahrens 
1706fa9e4066Sahrens 	if (tdelta == 0)
1707fa9e4066Sahrens 		scale = 1.0;
1708fa9e4066Sahrens 	else
1709fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1710fa9e4066Sahrens 
1711fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1712fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1713fa9e4066Sahrens 		(void) printf("      -      -");
1714fa9e4066Sahrens 	} else {
1715fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1716fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1717fa9e4066Sahrens 	}
1718fa9e4066Sahrens 
1719fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1720fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1721fa9e4066Sahrens 
1722fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1723fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1724fa9e4066Sahrens 
1725fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1726fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1727fa9e4066Sahrens 
1728fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1729fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1730fa9e4066Sahrens 
1731fa9e4066Sahrens 	(void) printf("\n");
1732fa9e4066Sahrens 
1733fa9e4066Sahrens 	if (!cb->cb_verbose)
1734fa9e4066Sahrens 		return;
1735fa9e4066Sahrens 
1736fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1737fa9e4066Sahrens 	    &newchild, &children) != 0)
1738fa9e4066Sahrens 		return;
1739fa9e4066Sahrens 
1740fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1741fa9e4066Sahrens 	    &oldchild, &c) != 0)
1742fa9e4066Sahrens 		return;
1743fa9e4066Sahrens 
1744afefbcddSeschrock 	for (c = 0; c < children; c++) {
174599653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1746c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1747afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1748afefbcddSeschrock 		free(vname);
1749afefbcddSeschrock 	}
1750fa94a07fSbrendan 
1751fa94a07fSbrendan 	/*
1752fa94a07fSbrendan 	 * Include level 2 ARC devices in iostat output
1753fa94a07fSbrendan 	 */
1754fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
1755fa94a07fSbrendan 	    &newchild, &children) != 0)
1756fa94a07fSbrendan 		return;
1757fa94a07fSbrendan 
1758fa94a07fSbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
1759fa94a07fSbrendan 	    &oldchild, &c) != 0)
1760fa94a07fSbrendan 		return;
1761fa94a07fSbrendan 
1762fa94a07fSbrendan 	if (children > 0) {
1763fa94a07fSbrendan 		(void) printf("%-*s      -      -      -      -      -      "
1764fa94a07fSbrendan 		    "-\n", cb->cb_namewidth, "cache");
1765fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1766fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1767fa94a07fSbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1768fa94a07fSbrendan 			    newchild[c], cb, depth + 2);
1769fa94a07fSbrendan 			free(vname);
1770fa94a07fSbrendan 		}
1771fa94a07fSbrendan 	}
1772fa9e4066Sahrens }
1773fa9e4066Sahrens 
1774088e9d47Seschrock static int
1775088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
1776088e9d47Seschrock {
1777088e9d47Seschrock 	iostat_cbdata_t *cb = data;
177894de1d4cSeschrock 	boolean_t missing;
1779088e9d47Seschrock 
1780088e9d47Seschrock 	/*
1781088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
1782088e9d47Seschrock 	 */
178394de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
178494de1d4cSeschrock 		return (-1);
178594de1d4cSeschrock 
178694de1d4cSeschrock 	if (missing)
1787088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
1788088e9d47Seschrock 
1789088e9d47Seschrock 	return (0);
1790088e9d47Seschrock }
1791088e9d47Seschrock 
1792fa9e4066Sahrens /*
1793fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
1794fa9e4066Sahrens  */
1795fa9e4066Sahrens int
1796fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
1797fa9e4066Sahrens {
1798fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1799fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
1800fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
1801fa9e4066Sahrens 
1802088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
1803fa9e4066Sahrens 
1804088e9d47Seschrock 	if (cb->cb_iteration == 1)
1805fa9e4066Sahrens 		oldconfig = NULL;
1806fa9e4066Sahrens 
1807fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1808fa9e4066Sahrens 	    &newnvroot) == 0);
1809fa9e4066Sahrens 
1810088e9d47Seschrock 	if (oldconfig == NULL)
1811fa9e4066Sahrens 		oldnvroot = NULL;
1812088e9d47Seschrock 	else
1813088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
1814088e9d47Seschrock 		    &oldnvroot) == 0);
1815fa9e4066Sahrens 
1816fa9e4066Sahrens 	/*
1817fa9e4066Sahrens 	 * Print out the statistics for the pool.
1818fa9e4066Sahrens 	 */
1819c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1820fa9e4066Sahrens 
1821fa9e4066Sahrens 	if (cb->cb_verbose)
1822fa9e4066Sahrens 		print_iostat_separator(cb);
1823fa9e4066Sahrens 
1824fa9e4066Sahrens 	return (0);
1825fa9e4066Sahrens }
1826fa9e4066Sahrens 
1827fa9e4066Sahrens int
1828fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
1829fa9e4066Sahrens {
1830fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1831fa9e4066Sahrens 	nvlist_t *config, *nvroot;
1832fa9e4066Sahrens 
1833088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
1834fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1835fa9e4066Sahrens 		    &nvroot) == 0);
1836fa9e4066Sahrens 		if (!cb->cb_verbose)
1837fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1838fa9e4066Sahrens 		else
1839c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
1840fa9e4066Sahrens 	}
1841fa9e4066Sahrens 
1842fa9e4066Sahrens 	/*
1843fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
1844fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
1845fa9e4066Sahrens 	 */
1846fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
1847fa9e4066Sahrens 		cb->cb_namewidth = 10;
1848fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
1849fa9e4066Sahrens 		cb->cb_namewidth = 38;
1850fa9e4066Sahrens 
1851fa9e4066Sahrens 	return (0);
1852fa9e4066Sahrens }
1853fa9e4066Sahrens 
1854fa9e4066Sahrens /*
1855fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
1856fa9e4066Sahrens  *
1857fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
1858fa9e4066Sahrens  *
1859fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
1860fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
1861fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1862fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
1863fa9e4066Sahrens  * changes are all handled within libzfs.
1864fa9e4066Sahrens  */
1865fa9e4066Sahrens int
1866fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
1867fa9e4066Sahrens {
1868fa9e4066Sahrens 	int c;
1869fa9e4066Sahrens 	int ret;
1870fa9e4066Sahrens 	int npools;
1871fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
1872fa9e4066Sahrens 	zpool_list_t *list;
187399653d4eSeschrock 	boolean_t verbose = B_FALSE;
1874fa9e4066Sahrens 	iostat_cbdata_t cb;
1875fa9e4066Sahrens 
1876fa9e4066Sahrens 	/* check options */
1877fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
1878fa9e4066Sahrens 		switch (c) {
1879fa9e4066Sahrens 		case 'v':
188099653d4eSeschrock 			verbose = B_TRUE;
1881fa9e4066Sahrens 			break;
1882fa9e4066Sahrens 		case '?':
1883fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1884fa9e4066Sahrens 			    optopt);
188599653d4eSeschrock 			usage(B_FALSE);
1886fa9e4066Sahrens 		}
1887fa9e4066Sahrens 	}
1888fa9e4066Sahrens 
1889fa9e4066Sahrens 	argc -= optind;
1890fa9e4066Sahrens 	argv += optind;
1891fa9e4066Sahrens 
1892fa9e4066Sahrens 	/*
1893fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
1894fa9e4066Sahrens 	 */
1895fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1896fa9e4066Sahrens 		char *end;
1897fa9e4066Sahrens 
1898fa9e4066Sahrens 		errno = 0;
1899fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1900fa9e4066Sahrens 
1901fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1902fa9e4066Sahrens 			if (interval == 0) {
1903fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1904fa9e4066Sahrens 				    "cannot be zero\n"));
190599653d4eSeschrock 				usage(B_FALSE);
1906fa9e4066Sahrens 			}
1907fa9e4066Sahrens 
1908fa9e4066Sahrens 			/*
1909fa9e4066Sahrens 			 * Ignore the last parameter
1910fa9e4066Sahrens 			 */
1911fa9e4066Sahrens 			argc--;
1912fa9e4066Sahrens 		} else {
1913fa9e4066Sahrens 			/*
1914fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
1915fa9e4066Sahrens 			 * user will get a more informative error message later
1916fa9e4066Sahrens 			 * on.
1917fa9e4066Sahrens 			 */
1918fa9e4066Sahrens 			interval = 0;
1919fa9e4066Sahrens 		}
1920fa9e4066Sahrens 	}
1921fa9e4066Sahrens 
1922fa9e4066Sahrens 	/*
1923fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
1924fa9e4066Sahrens 	 * and an integer.
1925fa9e4066Sahrens 	 */
1926fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1927fa9e4066Sahrens 		char *end;
1928fa9e4066Sahrens 
1929fa9e4066Sahrens 		errno = 0;
1930fa9e4066Sahrens 		count = interval;
1931fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1932fa9e4066Sahrens 
1933fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1934fa9e4066Sahrens 			if (interval == 0) {
1935fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1936fa9e4066Sahrens 				    "cannot be zero\n"));
193799653d4eSeschrock 				usage(B_FALSE);
1938fa9e4066Sahrens 			}
1939fa9e4066Sahrens 
1940fa9e4066Sahrens 			/*
1941fa9e4066Sahrens 			 * Ignore the last parameter
1942fa9e4066Sahrens 			 */
1943fa9e4066Sahrens 			argc--;
1944fa9e4066Sahrens 		} else {
1945fa9e4066Sahrens 			interval = 0;
1946fa9e4066Sahrens 		}
1947fa9e4066Sahrens 	}
1948fa9e4066Sahrens 
1949fa9e4066Sahrens 	/*
1950fa9e4066Sahrens 	 * Construct the list of all interesting pools.
1951fa9e4066Sahrens 	 */
1952fa9e4066Sahrens 	ret = 0;
1953b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
1954fa9e4066Sahrens 		return (1);
1955fa9e4066Sahrens 
195699653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
195799653d4eSeschrock 		pool_list_free(list);
1958fa9e4066Sahrens 		return (1);
195999653d4eSeschrock 	}
1960fa9e4066Sahrens 
1961fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
196299653d4eSeschrock 		pool_list_free(list);
1963fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
1964fa9e4066Sahrens 		return (1);
1965fa9e4066Sahrens 	}
1966fa9e4066Sahrens 
1967fa9e4066Sahrens 	/*
1968fa9e4066Sahrens 	 * Enter the main iostat loop.
1969fa9e4066Sahrens 	 */
1970fa9e4066Sahrens 	cb.cb_list = list;
1971fa9e4066Sahrens 	cb.cb_verbose = verbose;
1972fa9e4066Sahrens 	cb.cb_iteration = 0;
1973fa9e4066Sahrens 	cb.cb_namewidth = 0;
1974fa9e4066Sahrens 
1975fa9e4066Sahrens 	for (;;) {
1976fa9e4066Sahrens 		pool_list_update(list);
1977fa9e4066Sahrens 
1978fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
1979fa9e4066Sahrens 			break;
1980fa9e4066Sahrens 
1981fa9e4066Sahrens 		/*
1982088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
1983088e9d47Seschrock 		 * before calculating the maximum name width, so that any
1984088e9d47Seschrock 		 * configuration changes are properly accounted for.
1985088e9d47Seschrock 		 */
198699653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
1987088e9d47Seschrock 
1988088e9d47Seschrock 		/*
1989fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
1990fa9e4066Sahrens 		 * for the pool / device name column across all pools.
1991fa9e4066Sahrens 		 */
1992fa9e4066Sahrens 		cb.cb_namewidth = 0;
199399653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
1994fa9e4066Sahrens 
1995fa9e4066Sahrens 		/*
1996fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
1997fa9e4066Sahrens 		 */
1998fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
1999fa9e4066Sahrens 			print_iostat_header(&cb);
2000fa9e4066Sahrens 
200199653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2002fa9e4066Sahrens 
2003fa9e4066Sahrens 		/*
2004fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
2005fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
2006fa9e4066Sahrens 		 */
2007fa9e4066Sahrens 		if (npools > 1 && !verbose)
2008fa9e4066Sahrens 			print_iostat_separator(&cb);
2009fa9e4066Sahrens 
2010fa9e4066Sahrens 		if (verbose)
2011fa9e4066Sahrens 			(void) printf("\n");
2012fa9e4066Sahrens 
201339c23413Seschrock 		/*
201439c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
201539c23413Seschrock 		 * indefinitely.
201639c23413Seschrock 		 */
201739c23413Seschrock 		(void) fflush(stdout);
201839c23413Seschrock 
2019fa9e4066Sahrens 		if (interval == 0)
2020fa9e4066Sahrens 			break;
2021fa9e4066Sahrens 
2022fa9e4066Sahrens 		if (count != 0 && --count == 0)
2023fa9e4066Sahrens 			break;
2024fa9e4066Sahrens 
2025fa9e4066Sahrens 		(void) sleep(interval);
2026fa9e4066Sahrens 	}
2027fa9e4066Sahrens 
2028fa9e4066Sahrens 	pool_list_free(list);
2029fa9e4066Sahrens 
2030fa9e4066Sahrens 	return (ret);
2031fa9e4066Sahrens }
2032fa9e4066Sahrens 
2033fa9e4066Sahrens typedef struct list_cbdata {
203499653d4eSeschrock 	boolean_t	cb_scripted;
203599653d4eSeschrock 	boolean_t	cb_first;
2036990b4856Slling 	zprop_list_t	*cb_proplist;
2037fa9e4066Sahrens } list_cbdata_t;
2038fa9e4066Sahrens 
2039fa9e4066Sahrens /*
2040fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
2041fa9e4066Sahrens  */
2042990b4856Slling static void
2043990b4856Slling print_header(zprop_list_t *pl)
2044fa9e4066Sahrens {
2045990b4856Slling 	const char *header;
2046990b4856Slling 	boolean_t first = B_TRUE;
2047990b4856Slling 	boolean_t right_justify;
2048fa9e4066Sahrens 
2049990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2050990b4856Slling 		if (pl->pl_prop == ZPROP_INVAL)
2051990b4856Slling 			continue;
2052990b4856Slling 
2053990b4856Slling 		if (!first)
2054fa9e4066Sahrens 			(void) printf("  ");
2055fa9e4066Sahrens 		else
2056990b4856Slling 			first = B_FALSE;
2057fa9e4066Sahrens 
2058990b4856Slling 		header = zpool_prop_column_name(pl->pl_prop);
2059990b4856Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
2060990b4856Slling 
2061990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
2062990b4856Slling 			(void) printf("%s", header);
2063990b4856Slling 		else if (right_justify)
2064990b4856Slling 			(void) printf("%*s", pl->pl_width, header);
2065990b4856Slling 		else
2066990b4856Slling 			(void) printf("%-*s", pl->pl_width, header);
2067fa9e4066Sahrens 	}
2068fa9e4066Sahrens 
2069fa9e4066Sahrens 	(void) printf("\n");
2070fa9e4066Sahrens }
2071fa9e4066Sahrens 
2072990b4856Slling /*
2073990b4856Slling  * Given a pool and a list of properties, print out all the properties according
2074990b4856Slling  * to the described layout.
2075990b4856Slling  */
2076990b4856Slling static void
2077990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
2078990b4856Slling {
2079990b4856Slling 	boolean_t first = B_TRUE;
2080990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
2081990b4856Slling 	char *propstr;
2082990b4856Slling 	boolean_t right_justify;
2083990b4856Slling 	int width;
2084990b4856Slling 
2085990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2086990b4856Slling 		if (!first) {
2087990b4856Slling 			if (scripted)
2088990b4856Slling 				(void) printf("\t");
2089990b4856Slling 			else
2090990b4856Slling 				(void) printf("  ");
2091990b4856Slling 		} else {
2092990b4856Slling 			first = B_FALSE;
2093990b4856Slling 		}
2094990b4856Slling 
2095990b4856Slling 		right_justify = B_FALSE;
2096990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
2097990b4856Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
2098990b4856Slling 			    sizeof (property), NULL) != 0)
2099990b4856Slling 				propstr = "-";
2100990b4856Slling 			else
2101990b4856Slling 				propstr = property;
2102990b4856Slling 
2103990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2104990b4856Slling 		} else {
2105990b4856Slling 			propstr = "-";
2106990b4856Slling 		}
2107990b4856Slling 
2108990b4856Slling 		width = pl->pl_width;
2109990b4856Slling 
2110990b4856Slling 		/*
2111990b4856Slling 		 * If this is being called in scripted mode, or if this is the
2112990b4856Slling 		 * last column and it is left-justified, don't include a width
2113990b4856Slling 		 * format specifier.
2114990b4856Slling 		 */
2115990b4856Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
2116990b4856Slling 			(void) printf("%s", propstr);
2117990b4856Slling 		else if (right_justify)
2118990b4856Slling 			(void) printf("%*s", width, propstr);
2119990b4856Slling 		else
2120990b4856Slling 			(void) printf("%-*s", width, propstr);
2121990b4856Slling 	}
2122990b4856Slling 
2123990b4856Slling 	(void) printf("\n");
2124990b4856Slling }
2125990b4856Slling 
2126990b4856Slling /*
2127990b4856Slling  * Generic callback function to list a pool.
2128990b4856Slling  */
2129fa9e4066Sahrens int
2130fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2131fa9e4066Sahrens {
2132fa9e4066Sahrens 	list_cbdata_t *cbp = data;
2133fa9e4066Sahrens 
2134fa9e4066Sahrens 	if (cbp->cb_first) {
2135fa9e4066Sahrens 		if (!cbp->cb_scripted)
2136990b4856Slling 			print_header(cbp->cb_proplist);
213799653d4eSeschrock 		cbp->cb_first = B_FALSE;
2138fa9e4066Sahrens 	}
2139fa9e4066Sahrens 
2140990b4856Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2141fa9e4066Sahrens 
2142fa9e4066Sahrens 	return (0);
2143fa9e4066Sahrens }
2144fa9e4066Sahrens 
2145fa9e4066Sahrens /*
2146990b4856Slling  * zpool list [-H] [-o prop[,prop]*] [pool] ...
2147fa9e4066Sahrens  *
2148990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2149990b4856Slling  *		by a single tab.
2150990b4856Slling  *	-o	List of properties to display.  Defaults to
2151990b4856Slling  *		"name,size,used,available,capacity,health,altroot"
2152fa9e4066Sahrens  *
2153fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2154fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2155fa9e4066Sahrens  */
2156fa9e4066Sahrens int
2157fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2158fa9e4066Sahrens {
2159fa9e4066Sahrens 	int c;
2160fa9e4066Sahrens 	int ret;
2161fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2162990b4856Slling 	static char default_props[] =
2163990b4856Slling 	    "name,size,used,available,capacity,health,altroot";
2164990b4856Slling 	char *props = default_props;
2165fa9e4066Sahrens 
2166fa9e4066Sahrens 	/* check options */
2167fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2168fa9e4066Sahrens 		switch (c) {
2169fa9e4066Sahrens 		case 'H':
217099653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2171fa9e4066Sahrens 			break;
2172fa9e4066Sahrens 		case 'o':
2173990b4856Slling 			props = optarg;
2174fa9e4066Sahrens 			break;
2175fa9e4066Sahrens 		case ':':
2176fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2177fa9e4066Sahrens 			    "'%c' option\n"), optopt);
217899653d4eSeschrock 			usage(B_FALSE);
2179fa9e4066Sahrens 			break;
2180fa9e4066Sahrens 		case '?':
2181fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2182fa9e4066Sahrens 			    optopt);
218399653d4eSeschrock 			usage(B_FALSE);
2184fa9e4066Sahrens 		}
2185fa9e4066Sahrens 	}
2186fa9e4066Sahrens 
2187fa9e4066Sahrens 	argc -= optind;
2188fa9e4066Sahrens 	argv += optind;
2189fa9e4066Sahrens 
2190990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
219199653d4eSeschrock 		usage(B_FALSE);
2192fa9e4066Sahrens 
219399653d4eSeschrock 	cb.cb_first = B_TRUE;
2194fa9e4066Sahrens 
2195990b4856Slling 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2196990b4856Slling 	    list_callback, &cb);
2197990b4856Slling 
2198990b4856Slling 	zprop_free_list(cb.cb_proplist);
2199fa9e4066Sahrens 
2200fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2201fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2202fa9e4066Sahrens 		return (0);
2203fa9e4066Sahrens 	}
2204fa9e4066Sahrens 
2205fa9e4066Sahrens 	return (ret);
2206fa9e4066Sahrens }
2207fa9e4066Sahrens 
2208fa9e4066Sahrens static nvlist_t *
2209fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2210fa9e4066Sahrens {
2211fa9e4066Sahrens 	nvlist_t **child;
2212fa9e4066Sahrens 	uint_t c, children;
2213fa9e4066Sahrens 	nvlist_t *match;
2214fa9e4066Sahrens 	char *path;
2215fa9e4066Sahrens 
2216fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2217fa9e4066Sahrens 	    &child, &children) != 0) {
2218fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2219fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2220fa9e4066Sahrens 			name += 9;
2221fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2222fa9e4066Sahrens 			path += 9;
2223fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2224fa9e4066Sahrens 			return (nv);
2225fa9e4066Sahrens 		return (NULL);
2226fa9e4066Sahrens 	}
2227fa9e4066Sahrens 
2228fa9e4066Sahrens 	for (c = 0; c < children; c++)
2229fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2230fa9e4066Sahrens 			return (match);
2231fa9e4066Sahrens 
2232fa9e4066Sahrens 	return (NULL);
2233fa9e4066Sahrens }
2234fa9e4066Sahrens 
2235fa9e4066Sahrens static int
2236fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2237fa9e4066Sahrens {
223899653d4eSeschrock 	boolean_t force = B_FALSE;
2239fa9e4066Sahrens 	int c;
2240fa9e4066Sahrens 	nvlist_t *nvroot;
2241fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2242fa9e4066Sahrens 	zpool_handle_t *zhp;
224399653d4eSeschrock 	int ret;
2244fa9e4066Sahrens 
2245fa9e4066Sahrens 	/* check options */
2246fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2247fa9e4066Sahrens 		switch (c) {
2248fa9e4066Sahrens 		case 'f':
224999653d4eSeschrock 			force = B_TRUE;
2250fa9e4066Sahrens 			break;
2251fa9e4066Sahrens 		case '?':
2252fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2253fa9e4066Sahrens 			    optopt);
225499653d4eSeschrock 			usage(B_FALSE);
2255fa9e4066Sahrens 		}
2256fa9e4066Sahrens 	}
2257fa9e4066Sahrens 
2258fa9e4066Sahrens 	argc -= optind;
2259fa9e4066Sahrens 	argv += optind;
2260fa9e4066Sahrens 
2261fa9e4066Sahrens 	/* get pool name and check number of arguments */
2262fa9e4066Sahrens 	if (argc < 1) {
2263fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
226499653d4eSeschrock 		usage(B_FALSE);
2265fa9e4066Sahrens 	}
2266fa9e4066Sahrens 
2267fa9e4066Sahrens 	poolname = argv[0];
2268fa9e4066Sahrens 
2269fa9e4066Sahrens 	if (argc < 2) {
2270fa9e4066Sahrens 		(void) fprintf(stderr,
2271fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
227299653d4eSeschrock 		usage(B_FALSE);
2273fa9e4066Sahrens 	}
2274fa9e4066Sahrens 
2275fa9e4066Sahrens 	old_disk = argv[1];
2276fa9e4066Sahrens 
2277fa9e4066Sahrens 	if (argc < 3) {
2278fa9e4066Sahrens 		if (!replacing) {
2279fa9e4066Sahrens 			(void) fprintf(stderr,
2280fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
228199653d4eSeschrock 			usage(B_FALSE);
2282fa9e4066Sahrens 		}
2283fa9e4066Sahrens 		new_disk = old_disk;
2284fa9e4066Sahrens 		argc -= 1;
2285fa9e4066Sahrens 		argv += 1;
2286fa9e4066Sahrens 	} else {
2287fa9e4066Sahrens 		new_disk = argv[2];
2288fa9e4066Sahrens 		argc -= 2;
2289fa9e4066Sahrens 		argv += 2;
2290fa9e4066Sahrens 	}
2291fa9e4066Sahrens 
2292fa9e4066Sahrens 	if (argc > 1) {
2293fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
229499653d4eSeschrock 		usage(B_FALSE);
2295fa9e4066Sahrens 	}
2296fa9e4066Sahrens 
229799653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2298fa9e4066Sahrens 		return (1);
2299fa9e4066Sahrens 
23008488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2301fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2302fa9e4066Sahrens 		    poolname);
2303fa9e4066Sahrens 		zpool_close(zhp);
2304fa9e4066Sahrens 		return (1);
2305fa9e4066Sahrens 	}
2306fa9e4066Sahrens 
2307705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
2308705040edSEric Taylor 	    argc, argv);
2309fa9e4066Sahrens 	if (nvroot == NULL) {
2310fa9e4066Sahrens 		zpool_close(zhp);
2311fa9e4066Sahrens 		return (1);
2312fa9e4066Sahrens 	}
2313fa9e4066Sahrens 
231499653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
231599653d4eSeschrock 
231699653d4eSeschrock 	nvlist_free(nvroot);
231799653d4eSeschrock 	zpool_close(zhp);
231899653d4eSeschrock 
231999653d4eSeschrock 	return (ret);
2320fa9e4066Sahrens }
2321fa9e4066Sahrens 
2322fa9e4066Sahrens /*
2323fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2324fa9e4066Sahrens  *
2325fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2326fa9e4066Sahrens  *
2327fa9e4066Sahrens  * Replace <device> with <new_device>.
2328fa9e4066Sahrens  */
2329fa9e4066Sahrens /* ARGSUSED */
2330fa9e4066Sahrens int
2331fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2332fa9e4066Sahrens {
2333fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2334fa9e4066Sahrens }
2335fa9e4066Sahrens 
2336fa9e4066Sahrens /*
2337fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2338fa9e4066Sahrens  *
2339fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2340fa9e4066Sahrens  *
2341fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2342fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2343fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2344fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2345fa9e4066Sahrens  */
2346fa9e4066Sahrens int
2347fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2348fa9e4066Sahrens {
2349fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2350fa9e4066Sahrens }
2351fa9e4066Sahrens 
2352fa9e4066Sahrens /*
2353fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2354fa9e4066Sahrens  *
2355fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2356fa9e4066Sahrens  *		(not supported yet)
2357fa9e4066Sahrens  *
2358fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2359fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2360fa9e4066Sahrens  * has the only valid copy of some data.
2361fa9e4066Sahrens  */
2362fa9e4066Sahrens /* ARGSUSED */
2363fa9e4066Sahrens int
2364fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2365fa9e4066Sahrens {
2366fa9e4066Sahrens 	int c;
2367fa9e4066Sahrens 	char *poolname, *path;
2368fa9e4066Sahrens 	zpool_handle_t *zhp;
236999653d4eSeschrock 	int ret;
2370fa9e4066Sahrens 
2371fa9e4066Sahrens 	/* check options */
2372fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2373fa9e4066Sahrens 		switch (c) {
2374fa9e4066Sahrens 		case 'f':
2375fa9e4066Sahrens 		case '?':
2376fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2377fa9e4066Sahrens 			    optopt);
237899653d4eSeschrock 			usage(B_FALSE);
2379fa9e4066Sahrens 		}
2380fa9e4066Sahrens 	}
2381fa9e4066Sahrens 
2382fa9e4066Sahrens 	argc -= optind;
2383fa9e4066Sahrens 	argv += optind;
2384fa9e4066Sahrens 
2385fa9e4066Sahrens 	/* get pool name and check number of arguments */
2386fa9e4066Sahrens 	if (argc < 1) {
2387fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
238899653d4eSeschrock 		usage(B_FALSE);
2389fa9e4066Sahrens 	}
2390fa9e4066Sahrens 
2391fa9e4066Sahrens 	if (argc < 2) {
2392fa9e4066Sahrens 		(void) fprintf(stderr,
2393fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
239499653d4eSeschrock 		usage(B_FALSE);
2395fa9e4066Sahrens 	}
2396fa9e4066Sahrens 
2397fa9e4066Sahrens 	poolname = argv[0];
2398fa9e4066Sahrens 	path = argv[1];
2399fa9e4066Sahrens 
240099653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2401fa9e4066Sahrens 		return (1);
2402fa9e4066Sahrens 
240399653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
240499653d4eSeschrock 
240599653d4eSeschrock 	zpool_close(zhp);
240699653d4eSeschrock 
240799653d4eSeschrock 	return (ret);
2408fa9e4066Sahrens }
2409fa9e4066Sahrens 
2410fa9e4066Sahrens /*
2411441d80aaSlling  * zpool online <pool> <device> ...
2412fa9e4066Sahrens  */
2413fa9e4066Sahrens int
2414fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2415fa9e4066Sahrens {
2416fa9e4066Sahrens 	int c, i;
2417fa9e4066Sahrens 	char *poolname;
2418fa9e4066Sahrens 	zpool_handle_t *zhp;
2419fa9e4066Sahrens 	int ret = 0;
24203d7072f8Seschrock 	vdev_state_t newstate;
2421fa9e4066Sahrens 
2422fa9e4066Sahrens 	/* check options */
2423fa9e4066Sahrens 	while ((c = getopt(argc, argv, "t")) != -1) {
2424fa9e4066Sahrens 		switch (c) {
2425fa9e4066Sahrens 		case 't':
2426fa9e4066Sahrens 		case '?':
2427fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2428fa9e4066Sahrens 			    optopt);
242999653d4eSeschrock 			usage(B_FALSE);
2430fa9e4066Sahrens 		}
2431fa9e4066Sahrens 	}
2432fa9e4066Sahrens 
2433fa9e4066Sahrens 	argc -= optind;
2434fa9e4066Sahrens 	argv += optind;
2435fa9e4066Sahrens 
2436fa9e4066Sahrens 	/* get pool name and check number of arguments */
2437fa9e4066Sahrens 	if (argc < 1) {
2438fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
243999653d4eSeschrock 		usage(B_FALSE);
2440fa9e4066Sahrens 	}
2441fa9e4066Sahrens 	if (argc < 2) {
2442fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
244399653d4eSeschrock 		usage(B_FALSE);
2444fa9e4066Sahrens 	}
2445fa9e4066Sahrens 
2446fa9e4066Sahrens 	poolname = argv[0];
2447fa9e4066Sahrens 
244899653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2449fa9e4066Sahrens 		return (1);
2450fa9e4066Sahrens 
24513d7072f8Seschrock 	for (i = 1; i < argc; i++) {
24523d7072f8Seschrock 		if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
24533d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
24543d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
24553d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
2456fa9e4066Sahrens 				    argv[i]);
24573d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
24583d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24593d7072f8Seschrock 					    "clear' to restore a faulted "
24603d7072f8Seschrock 					    "device\n"));
2461fa9e4066Sahrens 				else
24623d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24633d7072f8Seschrock 					    "replace' to replace devices "
24643d7072f8Seschrock 					    "that are no longer present\n"));
24653d7072f8Seschrock 			}
24663d7072f8Seschrock 		} else {
2467fa9e4066Sahrens 			ret = 1;
24683d7072f8Seschrock 		}
24693d7072f8Seschrock 	}
2470fa9e4066Sahrens 
247199653d4eSeschrock 	zpool_close(zhp);
247299653d4eSeschrock 
2473fa9e4066Sahrens 	return (ret);
2474fa9e4066Sahrens }
2475fa9e4066Sahrens 
2476fa9e4066Sahrens /*
2477441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2478fa9e4066Sahrens  *
2479fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2480fa9e4066Sahrens  *		so would appear to compromise pool availability.
2481fa9e4066Sahrens  *		(not supported yet)
2482fa9e4066Sahrens  *
2483fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2484fa9e4066Sahrens  *		state will not be persistent across reboots.
2485fa9e4066Sahrens  */
2486fa9e4066Sahrens /* ARGSUSED */
2487fa9e4066Sahrens int
2488fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2489fa9e4066Sahrens {
2490fa9e4066Sahrens 	int c, i;
2491fa9e4066Sahrens 	char *poolname;
2492fa9e4066Sahrens 	zpool_handle_t *zhp;
249399653d4eSeschrock 	int ret = 0;
249499653d4eSeschrock 	boolean_t istmp = B_FALSE;
2495fa9e4066Sahrens 
2496fa9e4066Sahrens 	/* check options */
2497fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2498fa9e4066Sahrens 		switch (c) {
2499fa9e4066Sahrens 		case 't':
250099653d4eSeschrock 			istmp = B_TRUE;
2501441d80aaSlling 			break;
2502441d80aaSlling 		case 'f':
2503fa9e4066Sahrens 		case '?':
2504fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2505fa9e4066Sahrens 			    optopt);
250699653d4eSeschrock 			usage(B_FALSE);
2507fa9e4066Sahrens 		}
2508fa9e4066Sahrens 	}
2509fa9e4066Sahrens 
2510fa9e4066Sahrens 	argc -= optind;
2511fa9e4066Sahrens 	argv += optind;
2512fa9e4066Sahrens 
2513fa9e4066Sahrens 	/* get pool name and check number of arguments */
2514fa9e4066Sahrens 	if (argc < 1) {
2515fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
251699653d4eSeschrock 		usage(B_FALSE);
2517fa9e4066Sahrens 	}
2518fa9e4066Sahrens 	if (argc < 2) {
2519fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
252099653d4eSeschrock 		usage(B_FALSE);
2521fa9e4066Sahrens 	}
2522fa9e4066Sahrens 
2523fa9e4066Sahrens 	poolname = argv[0];
2524fa9e4066Sahrens 
252599653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2526fa9e4066Sahrens 		return (1);
2527fa9e4066Sahrens 
25283d7072f8Seschrock 	for (i = 1; i < argc; i++) {
25293d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2530fa9e4066Sahrens 			ret = 1;
25313d7072f8Seschrock 	}
2532fa9e4066Sahrens 
253399653d4eSeschrock 	zpool_close(zhp);
253499653d4eSeschrock 
2535fa9e4066Sahrens 	return (ret);
2536fa9e4066Sahrens }
2537fa9e4066Sahrens 
2538ea8dc4b6Seschrock /*
2539ea8dc4b6Seschrock  * zpool clear <pool> [device]
2540ea8dc4b6Seschrock  *
2541ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2542ea8dc4b6Seschrock  */
2543ea8dc4b6Seschrock int
2544ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2545ea8dc4b6Seschrock {
2546ea8dc4b6Seschrock 	int ret = 0;
2547ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2548ea8dc4b6Seschrock 	char *pool, *device;
2549ea8dc4b6Seschrock 
2550ea8dc4b6Seschrock 	if (argc < 2) {
2551ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
255299653d4eSeschrock 		usage(B_FALSE);
2553ea8dc4b6Seschrock 	}
2554ea8dc4b6Seschrock 
2555ea8dc4b6Seschrock 	if (argc > 3) {
2556ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
255799653d4eSeschrock 		usage(B_FALSE);
2558ea8dc4b6Seschrock 	}
2559ea8dc4b6Seschrock 
2560ea8dc4b6Seschrock 	pool = argv[1];
2561ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2562ea8dc4b6Seschrock 
2563b87f3af3Sperrin 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
2564ea8dc4b6Seschrock 		return (1);
2565ea8dc4b6Seschrock 
2566ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2567ea8dc4b6Seschrock 		ret = 1;
2568ea8dc4b6Seschrock 
2569ea8dc4b6Seschrock 	zpool_close(zhp);
2570ea8dc4b6Seschrock 
2571ea8dc4b6Seschrock 	return (ret);
2572ea8dc4b6Seschrock }
2573ea8dc4b6Seschrock 
2574fa9e4066Sahrens typedef struct scrub_cbdata {
2575fa9e4066Sahrens 	int	cb_type;
257606eeb2adSek110237 	int	cb_argc;
257706eeb2adSek110237 	char	**cb_argv;
2578fa9e4066Sahrens } scrub_cbdata_t;
2579fa9e4066Sahrens 
2580fa9e4066Sahrens int
2581fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2582fa9e4066Sahrens {
2583fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
258406eeb2adSek110237 	int err;
2585fa9e4066Sahrens 
2586ea8dc4b6Seschrock 	/*
2587ea8dc4b6Seschrock 	 * Ignore faulted pools.
2588ea8dc4b6Seschrock 	 */
2589ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2590ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2591ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2592ea8dc4b6Seschrock 		return (1);
2593ea8dc4b6Seschrock 	}
2594ea8dc4b6Seschrock 
259506eeb2adSek110237 	err = zpool_scrub(zhp, cb->cb_type);
259606eeb2adSek110237 
259706eeb2adSek110237 	return (err != 0);
2598fa9e4066Sahrens }
2599fa9e4066Sahrens 
2600fa9e4066Sahrens /*
2601fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2602fa9e4066Sahrens  *
2603fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2604fa9e4066Sahrens  */
2605fa9e4066Sahrens int
2606fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2607fa9e4066Sahrens {
2608fa9e4066Sahrens 	int c;
2609fa9e4066Sahrens 	scrub_cbdata_t cb;
2610fa9e4066Sahrens 
2611fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2612fa9e4066Sahrens 
2613fa9e4066Sahrens 	/* check options */
2614fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2615fa9e4066Sahrens 		switch (c) {
2616fa9e4066Sahrens 		case 's':
2617fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2618fa9e4066Sahrens 			break;
2619fa9e4066Sahrens 		case '?':
2620fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2621fa9e4066Sahrens 			    optopt);
262299653d4eSeschrock 			usage(B_FALSE);
2623fa9e4066Sahrens 		}
2624fa9e4066Sahrens 	}
2625fa9e4066Sahrens 
262606eeb2adSek110237 	cb.cb_argc = argc;
262706eeb2adSek110237 	cb.cb_argv = argv;
2628fa9e4066Sahrens 	argc -= optind;
2629fa9e4066Sahrens 	argv += optind;
2630fa9e4066Sahrens 
2631fa9e4066Sahrens 	if (argc < 1) {
2632fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
263399653d4eSeschrock 		usage(B_FALSE);
2634fa9e4066Sahrens 	}
2635fa9e4066Sahrens 
2636b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2637fa9e4066Sahrens }
2638fa9e4066Sahrens 
2639fa9e4066Sahrens typedef struct status_cbdata {
2640fa9e4066Sahrens 	int		cb_count;
2641e9dbad6fSeschrock 	boolean_t	cb_allpools;
264299653d4eSeschrock 	boolean_t	cb_verbose;
264399653d4eSeschrock 	boolean_t	cb_explain;
264499653d4eSeschrock 	boolean_t	cb_first;
2645fa9e4066Sahrens } status_cbdata_t;
2646fa9e4066Sahrens 
2647fa9e4066Sahrens /*
2648fa9e4066Sahrens  * Print out detailed scrub status.
2649fa9e4066Sahrens  */
2650fa9e4066Sahrens void
2651fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2652fa9e4066Sahrens {
2653fa9e4066Sahrens 	vdev_stat_t *vs;
2654fa9e4066Sahrens 	uint_t vsc;
2655fa9e4066Sahrens 	time_t start, end, now;
2656fa9e4066Sahrens 	double fraction_done;
265718ce54dfSek110237 	uint64_t examined, total, minutes_left, minutes_taken;
2658fa9e4066Sahrens 	char *scrub_type;
2659fa9e4066Sahrens 
2660fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2661fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2662fa9e4066Sahrens 
2663fa9e4066Sahrens 	/*
2664fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2665fa9e4066Sahrens 	 */
2666fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2667fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2668fa9e4066Sahrens 		return;
2669fa9e4066Sahrens 	}
2670fa9e4066Sahrens 
2671fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2672fa9e4066Sahrens 	    "resilver" : "scrub";
2673fa9e4066Sahrens 
2674fa9e4066Sahrens 	start = vs->vs_scrub_start;
2675fa9e4066Sahrens 	end = vs->vs_scrub_end;
2676fa9e4066Sahrens 	now = time(NULL);
2677fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2678fa9e4066Sahrens 	total = vs->vs_alloc;
2679fa9e4066Sahrens 
2680fa9e4066Sahrens 	if (end != 0) {
268118ce54dfSek110237 		minutes_taken = (uint64_t)((end - start) / 60);
268218ce54dfSek110237 
268318ce54dfSek110237 		(void) printf(gettext("%s %s after %lluh%um with %llu errors "
268418ce54dfSek110237 		    "on %s"),
2685fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
268618ce54dfSek110237 		    (u_longlong_t)(minutes_taken / 60),
268718ce54dfSek110237 		    (uint_t)(minutes_taken % 60),
2688fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2689fa9e4066Sahrens 		return;
2690fa9e4066Sahrens 	}
2691fa9e4066Sahrens 
2692fa9e4066Sahrens 	if (examined == 0)
2693fa9e4066Sahrens 		examined = 1;
2694fa9e4066Sahrens 	if (examined > total)
2695fa9e4066Sahrens 		total = examined;
2696fa9e4066Sahrens 
2697fa9e4066Sahrens 	fraction_done = (double)examined / total;
2698fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2699fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
270018ce54dfSek110237 	minutes_taken = (uint64_t)((now - start) / 60);
2701fa9e4066Sahrens 
270218ce54dfSek110237 	(void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, "
270318ce54dfSek110237 	    "%lluh%um to go\n"),
270418ce54dfSek110237 	    scrub_type, (u_longlong_t)(minutes_taken / 60),
270518ce54dfSek110237 	    (uint_t)(minutes_taken % 60), 100 * fraction_done,
2706fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2707fa9e4066Sahrens }
2708fa9e4066Sahrens 
270999653d4eSeschrock typedef struct spare_cbdata {
271099653d4eSeschrock 	uint64_t	cb_guid;
271199653d4eSeschrock 	zpool_handle_t	*cb_zhp;
271299653d4eSeschrock } spare_cbdata_t;
271399653d4eSeschrock 
271499653d4eSeschrock static boolean_t
271599653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search)
271699653d4eSeschrock {
271799653d4eSeschrock 	uint64_t guid;
271899653d4eSeschrock 	nvlist_t **child;
271999653d4eSeschrock 	uint_t c, children;
272099653d4eSeschrock 
272199653d4eSeschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
272299653d4eSeschrock 	    search == guid)
272399653d4eSeschrock 		return (B_TRUE);
272499653d4eSeschrock 
272599653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
272699653d4eSeschrock 	    &child, &children) == 0) {
272799653d4eSeschrock 		for (c = 0; c < children; c++)
272899653d4eSeschrock 			if (find_vdev(child[c], search))
272999653d4eSeschrock 				return (B_TRUE);
273099653d4eSeschrock 	}
273199653d4eSeschrock 
273299653d4eSeschrock 	return (B_FALSE);
273399653d4eSeschrock }
273499653d4eSeschrock 
273599653d4eSeschrock static int
273699653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data)
273799653d4eSeschrock {
273899653d4eSeschrock 	spare_cbdata_t *cbp = data;
273999653d4eSeschrock 	nvlist_t *config, *nvroot;
274099653d4eSeschrock 
274199653d4eSeschrock 	config = zpool_get_config(zhp, NULL);
274299653d4eSeschrock 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
274399653d4eSeschrock 	    &nvroot) == 0);
274499653d4eSeschrock 
274599653d4eSeschrock 	if (find_vdev(nvroot, cbp->cb_guid)) {
274699653d4eSeschrock 		cbp->cb_zhp = zhp;
274799653d4eSeschrock 		return (1);
274899653d4eSeschrock 	}
274999653d4eSeschrock 
275099653d4eSeschrock 	zpool_close(zhp);
275199653d4eSeschrock 	return (0);
275299653d4eSeschrock }
275399653d4eSeschrock 
2754fa9e4066Sahrens /*
2755fa9e4066Sahrens  * Print out configuration state as requested by status_callback.
2756fa9e4066Sahrens  */
2757fa9e4066Sahrens void
2758c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
27598654d025Sperrin     int namewidth, int depth, boolean_t isspare, boolean_t print_logs)
2760fa9e4066Sahrens {
2761fa9e4066Sahrens 	nvlist_t **child;
2762fa9e4066Sahrens 	uint_t c, children;
2763fa9e4066Sahrens 	vdev_stat_t *vs;
2764ea8dc4b6Seschrock 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
2765afefbcddSeschrock 	char *vname;
2766ea8dc4b6Seschrock 	uint64_t notpresent;
276799653d4eSeschrock 	spare_cbdata_t cb;
2768990b4856Slling 	char *state;
2769fa9e4066Sahrens 
2770fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2771fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2772fa9e4066Sahrens 
2773fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2774fa9e4066Sahrens 	    &child, &children) != 0)
2775fa9e4066Sahrens 		children = 0;
2776fa9e4066Sahrens 
2777990b4856Slling 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
277899653d4eSeschrock 	if (isspare) {
277999653d4eSeschrock 		/*
278099653d4eSeschrock 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
278199653d4eSeschrock 		 * online drives.
278299653d4eSeschrock 		 */
278399653d4eSeschrock 		if (vs->vs_aux == VDEV_AUX_SPARED)
278499653d4eSeschrock 			state = "INUSE";
278599653d4eSeschrock 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
278699653d4eSeschrock 			state = "AVAIL";
278799653d4eSeschrock 	}
2788fa9e4066Sahrens 
278999653d4eSeschrock 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
279099653d4eSeschrock 	    name, state);
279199653d4eSeschrock 
279299653d4eSeschrock 	if (!isspare) {
2793fa9e4066Sahrens 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
2794fa9e4066Sahrens 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
2795fa9e4066Sahrens 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
2796fa9e4066Sahrens 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
279799653d4eSeschrock 	}
2798fa9e4066Sahrens 
2799ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2800ea8dc4b6Seschrock 	    &notpresent) == 0) {
2801ea8dc4b6Seschrock 		char *path;
2802ea8dc4b6Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
28030917b783Seschrock 		(void) printf("  was %s", path);
2804ea8dc4b6Seschrock 	} else if (vs->vs_aux != 0) {
2805fa9e4066Sahrens 		(void) printf("  ");
2806fa9e4066Sahrens 
2807fa9e4066Sahrens 		switch (vs->vs_aux) {
2808fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2809fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2810fa9e4066Sahrens 			break;
2811fa9e4066Sahrens 
2812fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2813fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2814fa9e4066Sahrens 			break;
2815fa9e4066Sahrens 
2816fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2817fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2818fa9e4066Sahrens 			break;
2819fa9e4066Sahrens 
2820eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
2821eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
2822eaca9bbdSeschrock 			break;
2823eaca9bbdSeschrock 
282499653d4eSeschrock 		case VDEV_AUX_SPARED:
282599653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
282699653d4eSeschrock 			    &cb.cb_guid) == 0);
282799653d4eSeschrock 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
282899653d4eSeschrock 				if (strcmp(zpool_get_name(cb.cb_zhp),
282999653d4eSeschrock 				    zpool_get_name(zhp)) == 0)
283099653d4eSeschrock 					(void) printf(gettext("currently in "
283199653d4eSeschrock 					    "use"));
283299653d4eSeschrock 				else
283399653d4eSeschrock 					(void) printf(gettext("in use by "
283499653d4eSeschrock 					    "pool '%s'"),
283599653d4eSeschrock 					    zpool_get_name(cb.cb_zhp));
283699653d4eSeschrock 				zpool_close(cb.cb_zhp);
283799653d4eSeschrock 			} else {
283899653d4eSeschrock 				(void) printf(gettext("currently in use"));
283999653d4eSeschrock 			}
284099653d4eSeschrock 			break;
284199653d4eSeschrock 
28423d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
28433d7072f8Seschrock 			(void) printf(gettext("too many errors"));
28443d7072f8Seschrock 			break;
28453d7072f8Seschrock 
284632b87932Sek110237 		case VDEV_AUX_IO_FAILURE:
284732b87932Sek110237 			(void) printf(gettext("experienced I/O failures"));
284832b87932Sek110237 			break;
284932b87932Sek110237 
2850b87f3af3Sperrin 		case VDEV_AUX_BAD_LOG:
2851b87f3af3Sperrin 			(void) printf(gettext("bad intent log"));
2852b87f3af3Sperrin 			break;
2853b87f3af3Sperrin 
2854fa9e4066Sahrens 		default:
2855fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2856fa9e4066Sahrens 			break;
2857fa9e4066Sahrens 		}
2858fa9e4066Sahrens 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2859fa9e4066Sahrens 		/*
2860fa9e4066Sahrens 		 * Report bytes resilvered/repaired on leaf devices.
2861fa9e4066Sahrens 		 */
2862fa9e4066Sahrens 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2863fa9e4066Sahrens 		(void) printf(gettext("  %s %s"), repaired,
2864fa9e4066Sahrens 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2865fa9e4066Sahrens 		    "resilvered" : "repaired");
2866fa9e4066Sahrens 	}
2867fa9e4066Sahrens 
2868fa9e4066Sahrens 	(void) printf("\n");
2869fa9e4066Sahrens 
2870afefbcddSeschrock 	for (c = 0; c < children; c++) {
28718654d025Sperrin 		uint64_t is_log = B_FALSE;
28728654d025Sperrin 
28738654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
28748654d025Sperrin 		    &is_log);
28758654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
28768654d025Sperrin 			continue;
287799653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
2878c67d9675Seschrock 		print_status_config(zhp, vname, child[c],
28798654d025Sperrin 		    namewidth, depth + 2, isspare, B_FALSE);
2880afefbcddSeschrock 		free(vname);
2881afefbcddSeschrock 	}
2882fa9e4066Sahrens }
2883fa9e4066Sahrens 
2884ea8dc4b6Seschrock static void
2885ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
2886ea8dc4b6Seschrock {
288775519f38Sek110237 	nvlist_t *nverrlist = NULL;
288855434c77Sek110237 	nvpair_t *elem;
288955434c77Sek110237 	char *pathname;
289055434c77Sek110237 	size_t len = MAXPATHLEN * 2;
2891ea8dc4b6Seschrock 
289255434c77Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2893ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
2894ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
2895ea8dc4b6Seschrock 		return;
2896ea8dc4b6Seschrock 	}
2897ea8dc4b6Seschrock 
289855434c77Sek110237 	(void) printf("errors: Permanent errors have been "
289955434c77Sek110237 	    "detected in the following files:\n\n");
2900ea8dc4b6Seschrock 
290155434c77Sek110237 	pathname = safe_malloc(len);
290255434c77Sek110237 	elem = NULL;
290355434c77Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
290455434c77Sek110237 		nvlist_t *nv;
290555434c77Sek110237 		uint64_t dsobj, obj;
2906ea8dc4b6Seschrock 
290755434c77Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
290855434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
290955434c77Sek110237 		    &dsobj) == 0);
291055434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
291155434c77Sek110237 		    &obj) == 0);
291255434c77Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
291355434c77Sek110237 		(void) printf("%7s %s\n", "", pathname);
2914ea8dc4b6Seschrock 	}
291555434c77Sek110237 	free(pathname);
291655434c77Sek110237 	nvlist_free(nverrlist);
2917ea8dc4b6Seschrock }
2918ea8dc4b6Seschrock 
291999653d4eSeschrock static void
292099653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
292199653d4eSeschrock     int namewidth)
292299653d4eSeschrock {
292399653d4eSeschrock 	uint_t i;
292499653d4eSeschrock 	char *name;
292599653d4eSeschrock 
292699653d4eSeschrock 	if (nspares == 0)
292799653d4eSeschrock 		return;
292899653d4eSeschrock 
292999653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
293099653d4eSeschrock 
293199653d4eSeschrock 	for (i = 0; i < nspares; i++) {
293299653d4eSeschrock 		name = zpool_vdev_name(g_zfs, zhp, spares[i]);
293399653d4eSeschrock 		print_status_config(zhp, name, spares[i],
29348654d025Sperrin 		    namewidth, 2, B_TRUE, B_FALSE);
293599653d4eSeschrock 		free(name);
293699653d4eSeschrock 	}
293799653d4eSeschrock }
293899653d4eSeschrock 
2939fa94a07fSbrendan static void
2940fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
2941fa94a07fSbrendan     int namewidth)
2942fa94a07fSbrendan {
2943fa94a07fSbrendan 	uint_t i;
2944fa94a07fSbrendan 	char *name;
2945fa94a07fSbrendan 
2946fa94a07fSbrendan 	if (nl2cache == 0)
2947fa94a07fSbrendan 		return;
2948fa94a07fSbrendan 
2949fa94a07fSbrendan 	(void) printf(gettext("\tcache\n"));
2950fa94a07fSbrendan 
2951fa94a07fSbrendan 	for (i = 0; i < nl2cache; i++) {
2952fa94a07fSbrendan 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i]);
2953fa94a07fSbrendan 		print_status_config(zhp, name, l2cache[i],
2954fa94a07fSbrendan 		    namewidth, 2, B_FALSE, B_FALSE);
2955fa94a07fSbrendan 		free(name);
2956fa94a07fSbrendan 	}
2957fa94a07fSbrendan }
2958fa94a07fSbrendan 
2959fa9e4066Sahrens /*
2960fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
2961fa9e4066Sahrens  *
2962fa9e4066Sahrens  *        pool: tank
2963fa9e4066Sahrens  *	status: DEGRADED
2964fa9e4066Sahrens  *	reason: One or more devices ...
2965fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
2966fa9e4066Sahrens  *	config:
2967fa9e4066Sahrens  *		mirror		DEGRADED
2968fa9e4066Sahrens  *                c1t0d0	OK
2969ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
2970fa9e4066Sahrens  *
2971fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
2972fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
2973fa9e4066Sahrens  */
2974fa9e4066Sahrens int
2975fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
2976fa9e4066Sahrens {
2977fa9e4066Sahrens 	status_cbdata_t *cbp = data;
2978fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2979fa9e4066Sahrens 	char *msgid;
2980fa9e4066Sahrens 	int reason;
298146657f8dSmmusante 	const char *health;
298246657f8dSmmusante 	uint_t c;
298346657f8dSmmusante 	vdev_stat_t *vs;
2984fa9e4066Sahrens 
2985088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
2986fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
2987fa9e4066Sahrens 
2988fa9e4066Sahrens 	cbp->cb_count++;
2989fa9e4066Sahrens 
2990fa9e4066Sahrens 	/*
2991fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
2992fa9e4066Sahrens 	 * problems.
2993fa9e4066Sahrens 	 */
2994e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
2995e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
2996e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
2997e9dbad6fSeschrock 			    zpool_get_name(zhp));
2998e9dbad6fSeschrock 			if (cbp->cb_first)
2999e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
3000e9dbad6fSeschrock 		}
3001fa9e4066Sahrens 		return (0);
3002e9dbad6fSeschrock 	}
3003fa9e4066Sahrens 
3004fa9e4066Sahrens 	if (cbp->cb_first)
300599653d4eSeschrock 		cbp->cb_first = B_FALSE;
3006fa9e4066Sahrens 	else
3007fa9e4066Sahrens 		(void) printf("\n");
3008fa9e4066Sahrens 
300946657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
301046657f8dSmmusante 	    &nvroot) == 0);
301146657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
301246657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
3013990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3014fa9e4066Sahrens 
3015fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
3016fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
3017fa9e4066Sahrens 
3018fa9e4066Sahrens 	switch (reason) {
3019fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
3020fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3021fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
3022fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
3023fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3024fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3025fa9e4066Sahrens 		break;
3026fa9e4066Sahrens 
3027fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
3028fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3029fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
3030fa9e4066Sahrens 		    "pool to continue functioning.\n"));
3031fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3032fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3033fa9e4066Sahrens 		break;
3034fa9e4066Sahrens 
3035fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
3036fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3037fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
3038fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
3039fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
3040fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
3041fa9e4066Sahrens 		    "'zpool replace'.\n"));
3042fa9e4066Sahrens 		break;
3043fa9e4066Sahrens 
3044fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3045fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3046b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
3047fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
3048fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
3049fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
3050fa9e4066Sahrens 		    "from a backup source.\n"));
3051fa9e4066Sahrens 		break;
3052fa9e4066Sahrens 
3053fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
3054fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3055fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
3056fa9e4066Sahrens 		    "made to correct the error.  Applications are "
3057fa9e4066Sahrens 		    "unaffected.\n"));
3058fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
3059fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
3060ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
3061fa9e4066Sahrens 		    "replace'.\n"));
3062fa9e4066Sahrens 		break;
3063fa9e4066Sahrens 
3064fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
3065fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3066d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
3067fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
3068fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
3069fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
3070fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
3071fa9e4066Sahrens 		    "replace'.\n"));
3072fa9e4066Sahrens 		break;
3073fa9e4066Sahrens 
3074fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
3075fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
3076fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3077fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
3078fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3079fa9e4066Sahrens 		    "complete.\n"));
3080fa9e4066Sahrens 		break;
3081fa9e4066Sahrens 
3082ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3083ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3084ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3085ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3086ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3087ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3088ea8dc4b6Seschrock 		    "backup.\n"));
3089ea8dc4b6Seschrock 		break;
3090ea8dc4b6Seschrock 
3091ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3092ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3093ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3094ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
3095ea8dc4b6Seschrock 		    "from a backup source.\n"));
3096ea8dc4b6Seschrock 		break;
3097ea8dc4b6Seschrock 
3098eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3099eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3100eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3101eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3102eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3103eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3104eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3105eaca9bbdSeschrock 		break;
3106eaca9bbdSeschrock 
3107eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3108eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3109eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3110eaca9bbdSeschrock 		    "be accessed on this system.\n"));
3111eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
3112eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
3113eaca9bbdSeschrock 		    "backup.\n"));
3114eaca9bbdSeschrock 		break;
3115eaca9bbdSeschrock 
31163d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
31173d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
31183d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
31193d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
31203d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
31213d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
31223d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
31233d7072f8Seschrock 		break;
31243d7072f8Seschrock 
31253d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
31263d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
31273d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
31283d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
31293d7072f8Seschrock 		    "functioning.\n"));
31303d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
31313d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
31323d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
31333d7072f8Seschrock 		    "to be recovered.\n"));
31343d7072f8Seschrock 		break;
31353d7072f8Seschrock 
313632b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_WAIT:
313732b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
313832b87932Sek110237 		(void) printf(gettext("status: One or more devices are "
31398a79c1b5Sek110237 		    "faulted in response to IO failures.\n"));
314032b87932Sek110237 		(void) printf(gettext("action: Make sure the affected devices "
314132b87932Sek110237 		    "are connected, then run 'zpool clear'.\n"));
314232b87932Sek110237 		break;
314332b87932Sek110237 
3144b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
3145b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record "
3146b87f3af3Sperrin 		    "could not be read.\n"
3147b87f3af3Sperrin 		    "\tWaiting for adminstrator intervention to fix the "
3148b87f3af3Sperrin 		    "faulted pool.\n"));
3149b87f3af3Sperrin 		(void) printf(gettext("action: Either restore the affected "
3150b87f3af3Sperrin 		    "device(s) and run 'zpool online',\n"
3151b87f3af3Sperrin 		    "\tor ignore the intent log records by running "
3152b87f3af3Sperrin 		    "'zpool clear'.\n"));
3153b87f3af3Sperrin 		break;
3154b87f3af3Sperrin 
3155fa9e4066Sahrens 	default:
3156fa9e4066Sahrens 		/*
3157fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
3158fa9e4066Sahrens 		 */
3159fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
3160fa9e4066Sahrens 	}
3161fa9e4066Sahrens 
3162fa9e4066Sahrens 	if (msgid != NULL)
3163fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3164fa9e4066Sahrens 		    msgid);
3165fa9e4066Sahrens 
3166fa9e4066Sahrens 	if (config != NULL) {
3167fa9e4066Sahrens 		int namewidth;
3168ea8dc4b6Seschrock 		uint64_t nerr;
3169fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
3170fa94a07fSbrendan 		uint_t nspares, nl2cache;
3171fa9e4066Sahrens 
3172fa9e4066Sahrens 
3173fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
3174fa9e4066Sahrens 		print_scrub_status(nvroot);
3175fa9e4066Sahrens 
3176c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3177fa9e4066Sahrens 		if (namewidth < 10)
3178fa9e4066Sahrens 			namewidth = 10;
3179fa9e4066Sahrens 
3180fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
3181fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3182fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3183c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
31848654d025Sperrin 		    namewidth, 0, B_FALSE, B_FALSE);
31858654d025Sperrin 		if (num_logs(nvroot) > 0)
31868654d025Sperrin 			print_status_config(zhp, "logs", nvroot, namewidth, 0,
31878654d025Sperrin 			    B_FALSE, B_TRUE);
318899653d4eSeschrock 
3189fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
3190fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
3191fa94a07fSbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
3192fa94a07fSbrendan 
319399653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
319499653d4eSeschrock 		    &spares, &nspares) == 0)
319599653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
3196ea8dc4b6Seschrock 
3197ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3198ea8dc4b6Seschrock 		    &nerr) == 0) {
319955434c77Sek110237 			nvlist_t *nverrlist = NULL;
320055434c77Sek110237 
3201ea8dc4b6Seschrock 			/*
3202ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3203ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3204ea8dc4b6Seschrock 			 * uniquifying the results.
3205ea8dc4b6Seschrock 			 */
320675519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
320755434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
320855434c77Sek110237 				nvpair_t *elem;
320955434c77Sek110237 
321055434c77Sek110237 				elem = NULL;
321155434c77Sek110237 				nerr = 0;
321255434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
321355434c77Sek110237 				    elem)) != NULL) {
321455434c77Sek110237 					nerr++;
321555434c77Sek110237 				}
321655434c77Sek110237 			}
321755434c77Sek110237 			nvlist_free(nverrlist);
3218ea8dc4b6Seschrock 
3219ea8dc4b6Seschrock 			(void) printf("\n");
322099653d4eSeschrock 
3221ea8dc4b6Seschrock 			if (nerr == 0)
3222ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3223ea8dc4b6Seschrock 				    "errors\n"));
3224ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3225e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
32265ad82045Snd150628 				    "errors, use '-v' for a list\n"),
32275ad82045Snd150628 				    (u_longlong_t)nerr);
3228ea8dc4b6Seschrock 			else
3229ea8dc4b6Seschrock 				print_error_log(zhp);
3230ea8dc4b6Seschrock 		}
3231fa9e4066Sahrens 	} else {
3232fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3233fa9e4066Sahrens 		    "determined.\n"));
3234fa9e4066Sahrens 	}
3235fa9e4066Sahrens 
3236fa9e4066Sahrens 	return (0);
3237fa9e4066Sahrens }
3238fa9e4066Sahrens 
3239fa9e4066Sahrens /*
3240fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3241fa9e4066Sahrens  *
3242fa9e4066Sahrens  *	-v	Display complete error logs
3243fa9e4066Sahrens  *	-x	Display only pools with potential problems
3244fa9e4066Sahrens  *
3245fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3246fa9e4066Sahrens  */
3247fa9e4066Sahrens int
3248fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3249fa9e4066Sahrens {
3250fa9e4066Sahrens 	int c;
3251fa9e4066Sahrens 	int ret;
3252fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3253fa9e4066Sahrens 
3254fa9e4066Sahrens 	/* check options */
3255fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3256fa9e4066Sahrens 		switch (c) {
3257fa9e4066Sahrens 		case 'v':
325899653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3259fa9e4066Sahrens 			break;
3260fa9e4066Sahrens 		case 'x':
326199653d4eSeschrock 			cb.cb_explain = B_TRUE;
3262fa9e4066Sahrens 			break;
3263fa9e4066Sahrens 		case '?':
3264fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3265fa9e4066Sahrens 			    optopt);
326699653d4eSeschrock 			usage(B_FALSE);
3267fa9e4066Sahrens 		}
3268fa9e4066Sahrens 	}
3269fa9e4066Sahrens 
3270fa9e4066Sahrens 	argc -= optind;
3271fa9e4066Sahrens 	argv += optind;
3272fa9e4066Sahrens 
327399653d4eSeschrock 	cb.cb_first = B_TRUE;
3274fa9e4066Sahrens 
3275e9dbad6fSeschrock 	if (argc == 0)
3276e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3277e9dbad6fSeschrock 
3278b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3279fa9e4066Sahrens 
3280fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3281fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3282e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3283fa9e4066Sahrens 		(void) printf(gettext("all pools are healthy\n"));
3284fa9e4066Sahrens 
3285fa9e4066Sahrens 	return (ret);
3286fa9e4066Sahrens }
3287fa9e4066Sahrens 
3288eaca9bbdSeschrock typedef struct upgrade_cbdata {
3289eaca9bbdSeschrock 	int	cb_all;
3290eaca9bbdSeschrock 	int	cb_first;
3291eaca9bbdSeschrock 	int	cb_newer;
329206eeb2adSek110237 	int	cb_argc;
3293990b4856Slling 	uint64_t cb_version;
329406eeb2adSek110237 	char	**cb_argv;
3295eaca9bbdSeschrock } upgrade_cbdata_t;
3296eaca9bbdSeschrock 
3297eaca9bbdSeschrock static int
3298eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3299eaca9bbdSeschrock {
3300eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3301eaca9bbdSeschrock 	nvlist_t *config;
3302eaca9bbdSeschrock 	uint64_t version;
3303eaca9bbdSeschrock 	int ret = 0;
3304eaca9bbdSeschrock 
3305eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3306eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3307eaca9bbdSeschrock 	    &version) == 0);
3308eaca9bbdSeschrock 
3309e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3310eaca9bbdSeschrock 		if (!cbp->cb_all) {
3311eaca9bbdSeschrock 			if (cbp->cb_first) {
3312eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3313eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3314eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3315eaca9bbdSeschrock 				    "longer be accessible by older software "
3316eaca9bbdSeschrock 				    "versions.\n\n"));
3317eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3318eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
331999653d4eSeschrock 				cbp->cb_first = B_FALSE;
3320eaca9bbdSeschrock 			}
3321eaca9bbdSeschrock 
33225ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3323eaca9bbdSeschrock 			    zpool_get_name(zhp));
3324eaca9bbdSeschrock 		} else {
332599653d4eSeschrock 			cbp->cb_first = B_FALSE;
3326990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
332706eeb2adSek110237 			if (!ret) {
3328eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3329990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
3330eaca9bbdSeschrock 			}
333106eeb2adSek110237 		}
3332e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3333eaca9bbdSeschrock 		assert(!cbp->cb_all);
3334eaca9bbdSeschrock 
3335eaca9bbdSeschrock 		if (cbp->cb_first) {
3336eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3337eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3338eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3339eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3340eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
334199653d4eSeschrock 			cbp->cb_first = B_FALSE;
3342eaca9bbdSeschrock 		}
3343eaca9bbdSeschrock 
33445ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3345eaca9bbdSeschrock 		    zpool_get_name(zhp));
3346eaca9bbdSeschrock 	}
3347eaca9bbdSeschrock 
3348eaca9bbdSeschrock 	zpool_close(zhp);
3349eaca9bbdSeschrock 	return (ret);
3350eaca9bbdSeschrock }
3351eaca9bbdSeschrock 
3352eaca9bbdSeschrock /* ARGSUSED */
3353eaca9bbdSeschrock static int
335406eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
3355eaca9bbdSeschrock {
3356990b4856Slling 	upgrade_cbdata_t *cbp = data;
3357990b4856Slling 	uint64_t cur_version;
3358eaca9bbdSeschrock 	int ret;
3359eaca9bbdSeschrock 
33608654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
33618654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
33628654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
33638654d025Sperrin 		    " to upgrade.\n"));
33648654d025Sperrin 		return (1);
33658654d025Sperrin 	}
3366990b4856Slling 
3367990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3368e6c728e1Sbrendan 	if (cur_version > cbp->cb_version) {
3369eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3370e6c728e1Sbrendan 		    "using more current version '%llu'.\n"),
3371e6c728e1Sbrendan 		    zpool_get_name(zhp), cur_version);
3372e6c728e1Sbrendan 		return (0);
3373e6c728e1Sbrendan 	}
3374e6c728e1Sbrendan 	if (cur_version == cbp->cb_version) {
3375e6c728e1Sbrendan 		(void) printf(gettext("Pool '%s' is already formatted "
3376e6c728e1Sbrendan 		    "using the current version.\n"), zpool_get_name(zhp));
3377eaca9bbdSeschrock 		return (0);
3378eaca9bbdSeschrock 	}
3379eaca9bbdSeschrock 
3380990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
338106eeb2adSek110237 
338206eeb2adSek110237 	if (!ret) {
338344cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
3384990b4856Slling 		    "from version %llu to version %llu\n\n"),
3385990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3386990b4856Slling 		    (u_longlong_t)cbp->cb_version);
338706eeb2adSek110237 	}
3388eaca9bbdSeschrock 
3389eaca9bbdSeschrock 	return (ret != 0);
3390eaca9bbdSeschrock }
3391eaca9bbdSeschrock 
3392eaca9bbdSeschrock /*
3393eaca9bbdSeschrock  * zpool upgrade
3394eaca9bbdSeschrock  * zpool upgrade -v
3395990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
3396eaca9bbdSeschrock  *
3397eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3398eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3399eaca9bbdSeschrock  * upgrade all pools.
3400eaca9bbdSeschrock  */
3401eaca9bbdSeschrock int
3402eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3403eaca9bbdSeschrock {
3404eaca9bbdSeschrock 	int c;
3405eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3406eaca9bbdSeschrock 	int ret = 0;
3407eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3408990b4856Slling 	char *end;
3409990b4856Slling 
3410eaca9bbdSeschrock 
3411eaca9bbdSeschrock 	/* check options */
3412990b4856Slling 	while ((c = getopt(argc, argv, "avV:")) != -1) {
3413eaca9bbdSeschrock 		switch (c) {
3414eaca9bbdSeschrock 		case 'a':
341599653d4eSeschrock 			cb.cb_all = B_TRUE;
3416eaca9bbdSeschrock 			break;
3417eaca9bbdSeschrock 		case 'v':
3418eaca9bbdSeschrock 			showversions = B_TRUE;
3419eaca9bbdSeschrock 			break;
3420990b4856Slling 		case 'V':
3421990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
3422351420b3Slling 			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
3423351420b3Slling 			    cb.cb_version < SPA_VERSION_1) {
3424990b4856Slling 				(void) fprintf(stderr,
3425990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
3426990b4856Slling 				usage(B_FALSE);
3427990b4856Slling 			}
3428990b4856Slling 			break;
3429eaca9bbdSeschrock 		case '?':
3430eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3431eaca9bbdSeschrock 			    optopt);
343299653d4eSeschrock 			usage(B_FALSE);
3433eaca9bbdSeschrock 		}
3434eaca9bbdSeschrock 	}
3435eaca9bbdSeschrock 
343606eeb2adSek110237 	cb.cb_argc = argc;
343706eeb2adSek110237 	cb.cb_argv = argv;
3438eaca9bbdSeschrock 	argc -= optind;
3439eaca9bbdSeschrock 	argv += optind;
3440eaca9bbdSeschrock 
3441351420b3Slling 	if (cb.cb_version == 0) {
3442351420b3Slling 		cb.cb_version = SPA_VERSION;
3443351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
3444351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
3445351420b3Slling 		    "incompatible with other arguments\n"));
3446351420b3Slling 		usage(B_FALSE);
3447351420b3Slling 	}
3448351420b3Slling 
3449eaca9bbdSeschrock 	if (showversions) {
3450eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3451eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3452eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
345399653d4eSeschrock 			usage(B_FALSE);
3454eaca9bbdSeschrock 		}
3455eaca9bbdSeschrock 	} else if (cb.cb_all) {
3456eaca9bbdSeschrock 		if (argc != 0) {
3457351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
3458351420b3Slling 			    "be used along with a pool name\n"));
345999653d4eSeschrock 			usage(B_FALSE);
3460eaca9bbdSeschrock 		}
3461eaca9bbdSeschrock 	}
3462eaca9bbdSeschrock 
3463e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3464e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
346599653d4eSeschrock 	cb.cb_first = B_TRUE;
3466eaca9bbdSeschrock 	if (showversions) {
3467eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3468d7d4af51Smmusante 		    "supported:\n\n"));
3469eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3470eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3471eaca9bbdSeschrock 		    "---------------\n");
347299653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
347344cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
347444cd46caSbillm 		    "(replicated metadata)\n"));
347599653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
347699653d4eSeschrock 		    "RAID-Z\n"));
3477d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
3478c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3479c9431fa1Sahl 		    "algorithm\n"));
3480990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
34818654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3482ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
3483a9799022Sck153898 		(void) printf(gettext(" 9   refquota and refreservation "
3484a9799022Sck153898 		    "properties\n"));
3485fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
3486088f3894Sahrens 		(void) printf(gettext(" 11  Improved scrub performance\n"));
3487bb0ade09Sahrens 		(void) printf(gettext(" 12  Snapshot properties\n"));
3488*74e7dc98SMatthew Ahrens 		(void) printf(gettext(" 13  snapused property\n"));
34898654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3490eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3491eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3492eaca9bbdSeschrock 		    "version/N\n\n");
3493eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3494eaca9bbdSeschrock 	} else if (argc == 0) {
3495eaca9bbdSeschrock 		int notfound;
3496eaca9bbdSeschrock 
349799653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3498eaca9bbdSeschrock 		notfound = cb.cb_first;
3499eaca9bbdSeschrock 
3500eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3501eaca9bbdSeschrock 			if (!cb.cb_first)
3502eaca9bbdSeschrock 				(void) printf("\n");
3503eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3504eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
350599653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3506eaca9bbdSeschrock 			if (!cb.cb_first) {
3507eaca9bbdSeschrock 				notfound = B_FALSE;
3508eaca9bbdSeschrock 				(void) printf("\n");
3509eaca9bbdSeschrock 			}
3510eaca9bbdSeschrock 		}
3511eaca9bbdSeschrock 
3512eaca9bbdSeschrock 		if (ret == 0) {
3513eaca9bbdSeschrock 			if (notfound)
3514eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3515eaca9bbdSeschrock 				    "using this version.\n"));
3516eaca9bbdSeschrock 			else if (!cb.cb_all)
3517eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3518eaca9bbdSeschrock 				    "for a list of available versions and "
3519eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3520eaca9bbdSeschrock 		}
3521eaca9bbdSeschrock 	} else {
3522b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3523b1b8ab34Slling 		    upgrade_one, &cb);
352406eeb2adSek110237 	}
352506eeb2adSek110237 
352606eeb2adSek110237 	return (ret);
352706eeb2adSek110237 }
352806eeb2adSek110237 
3529ecd6cf80Smarks typedef struct hist_cbdata {
3530ecd6cf80Smarks 	boolean_t first;
3531ecd6cf80Smarks 	int longfmt;
3532ecd6cf80Smarks 	int internal;
3533ecd6cf80Smarks } hist_cbdata_t;
3534ecd6cf80Smarks 
3535ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3536ecd6cf80Smarks 	"invalid event",
3537ecd6cf80Smarks 	"pool create",
3538ecd6cf80Smarks 	"vdev add",
3539ecd6cf80Smarks 	"pool remove",
3540ecd6cf80Smarks 	"pool destroy",
3541ecd6cf80Smarks 	"pool export",
3542ecd6cf80Smarks 	"pool import",
3543ecd6cf80Smarks 	"vdev attach",
3544ecd6cf80Smarks 	"vdev replace",
3545ecd6cf80Smarks 	"vdev detach",
3546ecd6cf80Smarks 	"vdev online",
3547ecd6cf80Smarks 	"vdev offline",
3548ecd6cf80Smarks 	"vdev upgrade",
3549ecd6cf80Smarks 	"pool clear",
3550ecd6cf80Smarks 	"pool scrub",
3551ecd6cf80Smarks 	"pool property set",
3552ecd6cf80Smarks 	"create",
3553ecd6cf80Smarks 	"clone",
3554ecd6cf80Smarks 	"destroy",
3555ecd6cf80Smarks 	"destroy_begin_sync",
3556ecd6cf80Smarks 	"inherit",
3557ecd6cf80Smarks 	"property set",
3558ecd6cf80Smarks 	"quota set",
3559ecd6cf80Smarks 	"permission update",
3560ecd6cf80Smarks 	"permission remove",
3561ecd6cf80Smarks 	"permission who remove",
3562ecd6cf80Smarks 	"promote",
3563ecd6cf80Smarks 	"receive",
3564ecd6cf80Smarks 	"rename",
3565ecd6cf80Smarks 	"reservation set",
3566ecd6cf80Smarks 	"replay_inc_sync",
3567ecd6cf80Smarks 	"replay_full_sync",
3568ecd6cf80Smarks 	"rollback",
3569ecd6cf80Smarks 	"snapshot",
3570e7437265Sahrens 	"filesystem version upgrade",
3571a9799022Sck153898 	"refquota set",
3572a9799022Sck153898 	"refreservation set",
3573088f3894Sahrens 	"pool scrub done",
3574ecd6cf80Smarks };
3575ecd6cf80Smarks 
357606eeb2adSek110237 /*
357706eeb2adSek110237  * Print out the command history for a specific pool.
357806eeb2adSek110237  */
357906eeb2adSek110237 static int
358006eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
358106eeb2adSek110237 {
358206eeb2adSek110237 	nvlist_t *nvhis;
358306eeb2adSek110237 	nvlist_t **records;
358406eeb2adSek110237 	uint_t numrecords;
358506eeb2adSek110237 	char *cmdstr;
3586ecd6cf80Smarks 	char *pathstr;
358706eeb2adSek110237 	uint64_t dst_time;
358806eeb2adSek110237 	time_t tsec;
358906eeb2adSek110237 	struct tm t;
359006eeb2adSek110237 	char tbuf[30];
359106eeb2adSek110237 	int ret, i;
3592ecd6cf80Smarks 	uint64_t who;
3593ecd6cf80Smarks 	struct passwd *pwd;
3594ecd6cf80Smarks 	char *hostname;
3595ecd6cf80Smarks 	char *zonename;
3596ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3597ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3598ecd6cf80Smarks 	uint64_t txg;
3599ecd6cf80Smarks 	uint64_t ievent;
360006eeb2adSek110237 
3601ecd6cf80Smarks 	cb->first = B_FALSE;
360206eeb2adSek110237 
360306eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
360406eeb2adSek110237 
360506eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
360606eeb2adSek110237 		return (ret);
360706eeb2adSek110237 
360806eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
360906eeb2adSek110237 	    &records, &numrecords) == 0);
361006eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
361106eeb2adSek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3612ecd6cf80Smarks 		    &dst_time) != 0)
3613ecd6cf80Smarks 			continue;
3614ecd6cf80Smarks 
3615ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3616ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3617ecd6cf80Smarks 		    &cmdstr) != 0) {
3618ecd6cf80Smarks 			if (cb->internal == 0)
3619ecd6cf80Smarks 				continue;
3620ecd6cf80Smarks 
3621ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3622ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3623ecd6cf80Smarks 				continue;
3624ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3625ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3626ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3627ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3628088f3894Sahrens 			if (ievent >= LOG_END)
3629ecd6cf80Smarks 				continue;
3630ecd6cf80Smarks 			(void) snprintf(internalstr,
3631ecd6cf80Smarks 			    sizeof (internalstr),
3632ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3633ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3634ecd6cf80Smarks 			    pathstr);
3635ecd6cf80Smarks 			cmdstr = internalstr;
3636ecd6cf80Smarks 		}
363706eeb2adSek110237 		tsec = dst_time;
363806eeb2adSek110237 		(void) localtime_r(&tsec, &t);
363906eeb2adSek110237 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3640ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3641ecd6cf80Smarks 
3642ecd6cf80Smarks 		if (!cb->longfmt) {
3643ecd6cf80Smarks 			(void) printf("\n");
3644ecd6cf80Smarks 			continue;
364506eeb2adSek110237 		}
3646ecd6cf80Smarks 		(void) printf(" [");
3647ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3648ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3649ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3650ecd6cf80Smarks 			if (pwd)
3651ecd6cf80Smarks 				(void) printf("user %s on",
3652ecd6cf80Smarks 				    pwd->pw_name);
3653ecd6cf80Smarks 			else
3654ecd6cf80Smarks 				(void) printf("user %d on",
3655ecd6cf80Smarks 				    (int)who);
3656ecd6cf80Smarks 		} else {
3657ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3658ecd6cf80Smarks 			continue;
3659ecd6cf80Smarks 		}
3660ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3661ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3662ecd6cf80Smarks 			(void) printf(" %s", hostname);
3663ecd6cf80Smarks 		}
3664ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3665ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3666ecd6cf80Smarks 			(void) printf(":%s", zonename);
3667ecd6cf80Smarks 		}
3668ecd6cf80Smarks 
3669ecd6cf80Smarks 		(void) printf("]");
3670ecd6cf80Smarks 		(void) printf("\n");
367106eeb2adSek110237 	}
367206eeb2adSek110237 	(void) printf("\n");
367306eeb2adSek110237 	nvlist_free(nvhis);
367406eeb2adSek110237 
367506eeb2adSek110237 	return (ret);
367606eeb2adSek110237 }
367706eeb2adSek110237 
367806eeb2adSek110237 /*
367906eeb2adSek110237  * zpool history <pool>
368006eeb2adSek110237  *
368106eeb2adSek110237  * Displays the history of commands that modified pools.
368206eeb2adSek110237  */
3683ecd6cf80Smarks 
3684ecd6cf80Smarks 
368506eeb2adSek110237 int
368606eeb2adSek110237 zpool_do_history(int argc, char **argv)
368706eeb2adSek110237 {
3688ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
368906eeb2adSek110237 	int ret;
3690ecd6cf80Smarks 	int c;
369106eeb2adSek110237 
3692ecd6cf80Smarks 	cbdata.first = B_TRUE;
3693ecd6cf80Smarks 	/* check options */
3694ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3695ecd6cf80Smarks 		switch (c) {
3696ecd6cf80Smarks 		case 'l':
3697ecd6cf80Smarks 			cbdata.longfmt = 1;
3698ecd6cf80Smarks 			break;
3699ecd6cf80Smarks 		case 'i':
3700ecd6cf80Smarks 			cbdata.internal = 1;
3701ecd6cf80Smarks 			break;
3702ecd6cf80Smarks 		case '?':
3703ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3704ecd6cf80Smarks 			    optopt);
3705ecd6cf80Smarks 			usage(B_FALSE);
3706ecd6cf80Smarks 		}
3707ecd6cf80Smarks 	}
370806eeb2adSek110237 	argc -= optind;
370906eeb2adSek110237 	argv += optind;
371006eeb2adSek110237 
3711b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3712ecd6cf80Smarks 	    &cbdata);
371306eeb2adSek110237 
3714ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
371506eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
371606eeb2adSek110237 		return (0);
3717eaca9bbdSeschrock 	}
3718eaca9bbdSeschrock 
3719eaca9bbdSeschrock 	return (ret);
3720eaca9bbdSeschrock }
3721eaca9bbdSeschrock 
3722b1b8ab34Slling static int
3723b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3724b1b8ab34Slling {
3725990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3726b1b8ab34Slling 	char value[MAXNAMELEN];
3727990b4856Slling 	zprop_source_t srctype;
3728990b4856Slling 	zprop_list_t *pl;
3729b1b8ab34Slling 
3730b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3731b1b8ab34Slling 
3732b1b8ab34Slling 		/*
3733990b4856Slling 		 * Skip the special fake placeholder. This will also skip
3734990b4856Slling 		 * over the name property when 'all' is specified.
3735b1b8ab34Slling 		 */
3736990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3737b1b8ab34Slling 		    pl == cbp->cb_proplist)
3738b1b8ab34Slling 			continue;
3739b1b8ab34Slling 
3740b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3741b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3742b1b8ab34Slling 			continue;
3743b1b8ab34Slling 
3744990b4856Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
3745b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3746b1b8ab34Slling 	}
3747b1b8ab34Slling 	return (0);
3748b1b8ab34Slling }
3749b1b8ab34Slling 
3750b1b8ab34Slling int
3751b1b8ab34Slling zpool_do_get(int argc, char **argv)
3752b1b8ab34Slling {
3753990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
3754990b4856Slling 	zprop_list_t fake_name = { 0 };
3755b1b8ab34Slling 	int ret;
3756b1b8ab34Slling 
3757b1b8ab34Slling 	if (argc < 3)
3758b1b8ab34Slling 		usage(B_FALSE);
3759b1b8ab34Slling 
3760b1b8ab34Slling 	cb.cb_first = B_TRUE;
3761990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
3762b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3763b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3764b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3765b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3766990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
3767b1b8ab34Slling 
3768990b4856Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3769990b4856Slling 	    ZFS_TYPE_POOL) != 0)
3770b1b8ab34Slling 		usage(B_FALSE);
3771b1b8ab34Slling 
3772b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3773990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
3774b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3775b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3776b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3777b1b8ab34Slling 	}
3778b1b8ab34Slling 
3779b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3780b1b8ab34Slling 	    get_callback, &cb);
3781b1b8ab34Slling 
3782b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3783990b4856Slling 		zprop_free_list(fake_name.pl_next);
3784b1b8ab34Slling 	else
3785990b4856Slling 		zprop_free_list(cb.cb_proplist);
3786b1b8ab34Slling 
3787b1b8ab34Slling 	return (ret);
3788b1b8ab34Slling }
3789b1b8ab34Slling 
3790b1b8ab34Slling typedef struct set_cbdata {
3791b1b8ab34Slling 	char *cb_propname;
3792b1b8ab34Slling 	char *cb_value;
3793b1b8ab34Slling 	boolean_t cb_any_successful;
3794b1b8ab34Slling } set_cbdata_t;
3795b1b8ab34Slling 
3796b1b8ab34Slling int
3797b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3798b1b8ab34Slling {
3799b1b8ab34Slling 	int error;
3800b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3801b1b8ab34Slling 
3802b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3803b1b8ab34Slling 
3804b1b8ab34Slling 	if (!error)
3805b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3806b1b8ab34Slling 
3807b1b8ab34Slling 	return (error);
3808b1b8ab34Slling }
3809b1b8ab34Slling 
3810b1b8ab34Slling int
3811b1b8ab34Slling zpool_do_set(int argc, char **argv)
3812b1b8ab34Slling {
3813b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3814b1b8ab34Slling 	int error;
3815b1b8ab34Slling 
3816b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3817b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3818b1b8ab34Slling 		    argv[1][1]);
3819b1b8ab34Slling 		usage(B_FALSE);
3820b1b8ab34Slling 	}
3821b1b8ab34Slling 
3822b1b8ab34Slling 	if (argc < 2) {
3823b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3824b1b8ab34Slling 		    "argument\n"));
3825b1b8ab34Slling 		usage(B_FALSE);
3826b1b8ab34Slling 	}
3827b1b8ab34Slling 
3828b1b8ab34Slling 	if (argc < 3) {
3829b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3830b1b8ab34Slling 		usage(B_FALSE);
3831b1b8ab34Slling 	}
3832b1b8ab34Slling 
3833b1b8ab34Slling 	if (argc > 3) {
3834b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3835b1b8ab34Slling 		usage(B_FALSE);
3836b1b8ab34Slling 	}
3837b1b8ab34Slling 
3838b1b8ab34Slling 	cb.cb_propname = argv[1];
3839b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3840b1b8ab34Slling 	if (cb.cb_value == NULL) {
3841b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3842b1b8ab34Slling 		    "property=value argument\n"));
3843b1b8ab34Slling 		usage(B_FALSE);
3844b1b8ab34Slling 	}
3845b1b8ab34Slling 
3846b1b8ab34Slling 	*(cb.cb_value) = '\0';
3847b1b8ab34Slling 	cb.cb_value++;
3848b1b8ab34Slling 
3849b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3850b1b8ab34Slling 	    set_callback, &cb);
3851b1b8ab34Slling 
3852b1b8ab34Slling 	return (error);
3853b1b8ab34Slling }
3854b1b8ab34Slling 
3855b1b8ab34Slling static int
3856b1b8ab34Slling find_command_idx(char *command, int *idx)
3857b1b8ab34Slling {
3858b1b8ab34Slling 	int i;
3859b1b8ab34Slling 
3860b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3861b1b8ab34Slling 		if (command_table[i].name == NULL)
3862b1b8ab34Slling 			continue;
3863b1b8ab34Slling 
3864b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3865b1b8ab34Slling 			*idx = i;
3866b1b8ab34Slling 			return (0);
3867b1b8ab34Slling 		}
3868b1b8ab34Slling 	}
3869b1b8ab34Slling 	return (1);
3870b1b8ab34Slling }
3871b1b8ab34Slling 
3872fa9e4066Sahrens int
3873fa9e4066Sahrens main(int argc, char **argv)
3874fa9e4066Sahrens {
3875fa9e4066Sahrens 	int ret;
3876fa9e4066Sahrens 	int i;
3877fa9e4066Sahrens 	char *cmdname;
3878fa9e4066Sahrens 
3879fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3880fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3881fa9e4066Sahrens 
388299653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
388399653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3884203a47d8Snd150628 		    "initialize ZFS library\n"));
388599653d4eSeschrock 		return (1);
388699653d4eSeschrock 	}
388799653d4eSeschrock 
388899653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
388999653d4eSeschrock 
3890fa9e4066Sahrens 	opterr = 0;
3891fa9e4066Sahrens 
3892fa9e4066Sahrens 	/*
3893fa9e4066Sahrens 	 * Make sure the user has specified some command.
3894fa9e4066Sahrens 	 */
3895fa9e4066Sahrens 	if (argc < 2) {
3896fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
389799653d4eSeschrock 		usage(B_FALSE);
3898fa9e4066Sahrens 	}
3899fa9e4066Sahrens 
3900fa9e4066Sahrens 	cmdname = argv[1];
3901fa9e4066Sahrens 
3902fa9e4066Sahrens 	/*
3903fa9e4066Sahrens 	 * Special case '-?'
3904fa9e4066Sahrens 	 */
3905fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
390699653d4eSeschrock 		usage(B_TRUE);
3907fa9e4066Sahrens 
39082a6b87f0Sek110237 	zpool_set_history_str("zpool", argc, argv, history_str);
39092a6b87f0Sek110237 	verify(zpool_stage_history(g_zfs, history_str) == 0);
39102a6b87f0Sek110237 
3911fa9e4066Sahrens 	/*
3912fa9e4066Sahrens 	 * Run the appropriate command.
3913fa9e4066Sahrens 	 */
3914b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
3915fa9e4066Sahrens 		current_command = &command_table[i];
3916fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
391791ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
391891ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
391991ebeef5Sahrens 		current_command = &command_table[i];
392091ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
392191ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
3922fa9e4066Sahrens 		/*
392391ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
392491ebeef5Sahrens 		 * it as such.
3925fa9e4066Sahrens 		 */
3926ea8dc4b6Seschrock 		char buf[16384];
3927ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
3928fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
3929fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
393091ebeef5Sahrens 	} else {
3931fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
3932fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
393399653d4eSeschrock 		usage(B_FALSE);
3934fa9e4066Sahrens 	}
3935fa9e4066Sahrens 
393699653d4eSeschrock 	libzfs_fini(g_zfs);
393799653d4eSeschrock 
3938fa9e4066Sahrens 	/*
3939fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3940fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
3941fa9e4066Sahrens 	 */
3942fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
3943fa9e4066Sahrens 		(void) printf("dumping core by request\n");
3944fa9e4066Sahrens 		abort();
3945fa9e4066Sahrens 	}
3946fa9e4066Sahrens 
3947fa9e4066Sahrens 	return (ret);
3948fa9e4066Sahrens }
3949