xref: /titanic_54/usr/src/cmd/zpool/zpool_main.c (revision 379c004d1f26b343f034bba8a350290691d00d38)
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 /*
23*379c004dSEric Schrock  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #include <assert.h>
28fa9e4066Sahrens #include <ctype.h>
29fa9e4066Sahrens #include <dirent.h>
30fa9e4066Sahrens #include <errno.h>
31fa9e4066Sahrens #include <fcntl.h>
32fa9e4066Sahrens #include <libgen.h>
33fa9e4066Sahrens #include <libintl.h>
34fa9e4066Sahrens #include <libuutil.h>
35fa9e4066Sahrens #include <locale.h>
36fa9e4066Sahrens #include <stdio.h>
37fa9e4066Sahrens #include <stdlib.h>
38fa9e4066Sahrens #include <string.h>
39fa9e4066Sahrens #include <strings.h>
40fa9e4066Sahrens #include <unistd.h>
41fa9e4066Sahrens #include <priv.h>
42ecd6cf80Smarks #include <pwd.h>
43ecd6cf80Smarks #include <zone.h>
44b1b8ab34Slling #include <sys/fs/zfs.h>
45fa9e4066Sahrens 
46fa9e4066Sahrens #include <sys/stat.h>
47fa9e4066Sahrens 
48fa9e4066Sahrens #include <libzfs.h>
49fa9e4066Sahrens 
50fa9e4066Sahrens #include "zpool_util.h"
51b7b97454Sperrin #include "zfs_comutil.h"
52fa9e4066Sahrens 
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;
880394ab0cbSGeorge Wilson 	boolean_t hardforce = B_FALSE;
881fa9e4066Sahrens 	int c;
882fa9e4066Sahrens 	zpool_handle_t *zhp;
883fa9e4066Sahrens 	int ret;
884fa9e4066Sahrens 	int i;
885fa9e4066Sahrens 
886fa9e4066Sahrens 	/* check options */
887394ab0cbSGeorge Wilson 	while ((c = getopt(argc, argv, "fF")) != -1) {
888fa9e4066Sahrens 		switch (c) {
889fa9e4066Sahrens 		case 'f':
89099653d4eSeschrock 			force = B_TRUE;
891fa9e4066Sahrens 			break;
892394ab0cbSGeorge Wilson 		case 'F':
893394ab0cbSGeorge Wilson 			hardforce = B_TRUE;
894394ab0cbSGeorge Wilson 			break;
895fa9e4066Sahrens 		case '?':
896fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
897fa9e4066Sahrens 			    optopt);
89899653d4eSeschrock 			usage(B_FALSE);
899fa9e4066Sahrens 		}
900fa9e4066Sahrens 	}
901fa9e4066Sahrens 
902fa9e4066Sahrens 	argc -= optind;
903fa9e4066Sahrens 	argv += optind;
904fa9e4066Sahrens 
905fa9e4066Sahrens 	/* check arguments */
906fa9e4066Sahrens 	if (argc < 1) {
907fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
90899653d4eSeschrock 		usage(B_FALSE);
909fa9e4066Sahrens 	}
910fa9e4066Sahrens 
911fa9e4066Sahrens 	ret = 0;
912fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
91399653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
914fa9e4066Sahrens 			ret = 1;
915fa9e4066Sahrens 			continue;
916fa9e4066Sahrens 		}
917fa9e4066Sahrens 
918f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
919fa9e4066Sahrens 			ret = 1;
920fa9e4066Sahrens 			zpool_close(zhp);
921fa9e4066Sahrens 			continue;
922fa9e4066Sahrens 		}
923fa9e4066Sahrens 
924394ab0cbSGeorge Wilson 		if (hardforce) {
925394ab0cbSGeorge Wilson 			if (zpool_export_force(zhp) != 0)
926fa9e4066Sahrens 				ret = 1;
927394ab0cbSGeorge Wilson 		} else if (zpool_export(zhp, force) != 0) {
928394ab0cbSGeorge Wilson 			ret = 1;
929394ab0cbSGeorge Wilson 		}
930fa9e4066Sahrens 
931fa9e4066Sahrens 		zpool_close(zhp);
932fa9e4066Sahrens 	}
933fa9e4066Sahrens 
934fa9e4066Sahrens 	return (ret);
935fa9e4066Sahrens }
936fa9e4066Sahrens 
937fa9e4066Sahrens /*
938fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
939fa9e4066Sahrens  * name column.
940fa9e4066Sahrens  */
941fa9e4066Sahrens static int
942c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
943fa9e4066Sahrens {
94499653d4eSeschrock 	char *name = zpool_vdev_name(g_zfs, zhp, nv);
945fa9e4066Sahrens 	nvlist_t **child;
946fa9e4066Sahrens 	uint_t c, children;
947fa9e4066Sahrens 	int ret;
948fa9e4066Sahrens 
949fa9e4066Sahrens 	if (strlen(name) + depth > max)
950fa9e4066Sahrens 		max = strlen(name) + depth;
951fa9e4066Sahrens 
952afefbcddSeschrock 	free(name);
953afefbcddSeschrock 
95499653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
95599653d4eSeschrock 	    &child, &children) == 0) {
956fa9e4066Sahrens 		for (c = 0; c < children; c++)
95799653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
95899653d4eSeschrock 			    max)) > max)
959fa9e4066Sahrens 				max = ret;
96099653d4eSeschrock 	}
96199653d4eSeschrock 
962fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
963fa94a07fSbrendan 	    &child, &children) == 0) {
964fa94a07fSbrendan 		for (c = 0; c < children; c++)
965fa94a07fSbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
966fa94a07fSbrendan 			    max)) > max)
967fa94a07fSbrendan 				max = ret;
968fa94a07fSbrendan 	}
969fa94a07fSbrendan 
97099653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
97199653d4eSeschrock 	    &child, &children) == 0) {
97299653d4eSeschrock 		for (c = 0; c < children; c++)
97399653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
97499653d4eSeschrock 			    max)) > max)
97599653d4eSeschrock 				max = ret;
97699653d4eSeschrock 	}
97799653d4eSeschrock 
978fa9e4066Sahrens 
979fa9e4066Sahrens 	return (max);
980fa9e4066Sahrens }
981fa9e4066Sahrens 
982fa9e4066Sahrens 
983fa9e4066Sahrens /*
984fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
985fa9e4066Sahrens  * pool, printing out the name and status for each one.
986fa9e4066Sahrens  */
987fa9e4066Sahrens void
9888654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
9898654d025Sperrin     boolean_t print_logs)
990fa9e4066Sahrens {
991fa9e4066Sahrens 	nvlist_t **child;
992fa9e4066Sahrens 	uint_t c, children;
993fa9e4066Sahrens 	vdev_stat_t *vs;
994afefbcddSeschrock 	char *type, *vname;
995fa9e4066Sahrens 
996fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
997fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
998fa9e4066Sahrens 		return;
999fa9e4066Sahrens 
1000fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
1001fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
1002fa9e4066Sahrens 
1003fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
1004990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1005fa9e4066Sahrens 
1006fa9e4066Sahrens 	if (vs->vs_aux != 0) {
10073d7072f8Seschrock 		(void) printf("  ");
1008fa9e4066Sahrens 
1009fa9e4066Sahrens 		switch (vs->vs_aux) {
1010fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
1011fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
1012fa9e4066Sahrens 			break;
1013fa9e4066Sahrens 
1014fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
1015fa9e4066Sahrens 			(void) printf(gettext("missing device"));
1016fa9e4066Sahrens 			break;
1017fa9e4066Sahrens 
1018fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
1019fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
1020fa9e4066Sahrens 			break;
1021fa9e4066Sahrens 
1022eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
1023eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
1024eaca9bbdSeschrock 			break;
1025eaca9bbdSeschrock 
10263d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
10273d7072f8Seschrock 			(void) printf(gettext("too many errors"));
10283d7072f8Seschrock 			break;
10293d7072f8Seschrock 
1030fa9e4066Sahrens 		default:
1031fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
1032fa9e4066Sahrens 			break;
1033fa9e4066Sahrens 		}
1034fa9e4066Sahrens 	}
1035fa9e4066Sahrens 	(void) printf("\n");
1036fa9e4066Sahrens 
1037fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1038fa9e4066Sahrens 	    &child, &children) != 0)
1039fa9e4066Sahrens 		return;
1040fa9e4066Sahrens 
1041afefbcddSeschrock 	for (c = 0; c < children; c++) {
10428654d025Sperrin 		uint64_t is_log = B_FALSE;
10438654d025Sperrin 
10448654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
10458654d025Sperrin 		    &is_log);
10468654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
10478654d025Sperrin 			continue;
10488654d025Sperrin 
104999653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1050afefbcddSeschrock 		print_import_config(vname, child[c],
10518654d025Sperrin 		    namewidth, depth + 2, B_FALSE);
1052afefbcddSeschrock 		free(vname);
1053afefbcddSeschrock 	}
105499653d4eSeschrock 
1055fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1056fa94a07fSbrendan 	    &child, &children) == 0) {
1057fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
1058fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1059fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1060fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1061fa94a07fSbrendan 			free(vname);
1062fa94a07fSbrendan 		}
1063fa94a07fSbrendan 	}
106499653d4eSeschrock 
1065fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1066fa94a07fSbrendan 	    &child, &children) == 0) {
106799653d4eSeschrock 		(void) printf(gettext("\tspares\n"));
106899653d4eSeschrock 		for (c = 0; c < children; c++) {
106999653d4eSeschrock 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
107099653d4eSeschrock 			(void) printf("\t  %s\n", vname);
107199653d4eSeschrock 			free(vname);
107299653d4eSeschrock 		}
1073fa9e4066Sahrens 	}
1074fa94a07fSbrendan }
1075fa9e4066Sahrens 
1076fa9e4066Sahrens /*
1077fa9e4066Sahrens  * Display the status for the given pool.
1078fa9e4066Sahrens  */
1079fa9e4066Sahrens static void
1080fa9e4066Sahrens show_import(nvlist_t *config)
1081fa9e4066Sahrens {
1082fa9e4066Sahrens 	uint64_t pool_state;
1083fa9e4066Sahrens 	vdev_stat_t *vs;
1084fa9e4066Sahrens 	char *name;
1085fa9e4066Sahrens 	uint64_t guid;
1086fa9e4066Sahrens 	char *msgid;
1087fa9e4066Sahrens 	nvlist_t *nvroot;
1088fa9e4066Sahrens 	int reason;
108946657f8dSmmusante 	const char *health;
1090fa9e4066Sahrens 	uint_t vsc;
1091fa9e4066Sahrens 	int namewidth;
1092fa9e4066Sahrens 
1093fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1094fa9e4066Sahrens 	    &name) == 0);
1095fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1096fa9e4066Sahrens 	    &guid) == 0);
1097fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1098fa9e4066Sahrens 	    &pool_state) == 0);
1099fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1100fa9e4066Sahrens 	    &nvroot) == 0);
1101fa9e4066Sahrens 
1102fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1103fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1104990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1105fa9e4066Sahrens 
1106fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1107fa9e4066Sahrens 
110846657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
110946657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
111046657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
11114c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
111246657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
11134c58d714Sdarrenm 	(void) printf("\n");
1114fa9e4066Sahrens 
1115fa9e4066Sahrens 	switch (reason) {
1116fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1117fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1118fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1119fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1120fa9e4066Sahrens 		    "from the system.\n"));
1121fa9e4066Sahrens 		break;
1122fa9e4066Sahrens 
1123fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1124fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1125fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1126fa9e4066Sahrens 		    "corrupted data.\n"));
1127fa9e4066Sahrens 		break;
1128fa9e4066Sahrens 
1129fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1130fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1131fa9e4066Sahrens 		break;
1132fa9e4066Sahrens 
1133441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1134441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1135441d80aaSlling 		    "are offlined.\n"));
1136441d80aaSlling 		break;
1137441d80aaSlling 
1138ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1139ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1140ea8dc4b6Seschrock 		    "corrupted.\n"));
1141ea8dc4b6Seschrock 		break;
1142ea8dc4b6Seschrock 
1143eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1144eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1145eaca9bbdSeschrock 		    "older on-disk version.\n"));
1146eaca9bbdSeschrock 		break;
1147eaca9bbdSeschrock 
1148eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1149eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1150eaca9bbdSeschrock 		    "incompatible version.\n"));
1151eaca9bbdSeschrock 		break;
1152b87f3af3Sperrin 
115395173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
115495173954Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
115595173954Sek110237 		    "another system.\n"));
115695173954Sek110237 		break;
1157b87f3af3Sperrin 
11583d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
11593d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
11603d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
11613d7072f8Seschrock 		    "faulted.\n"));
11623d7072f8Seschrock 		break;
11633d7072f8Seschrock 
1164b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
1165b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record cannot be "
1166b87f3af3Sperrin 		    "read.\n"));
1167b87f3af3Sperrin 		break;
1168b87f3af3Sperrin 
1169fa9e4066Sahrens 	default:
1170fa9e4066Sahrens 		/*
1171fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1172fa9e4066Sahrens 		 */
1173fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1174fa9e4066Sahrens 	}
1175fa9e4066Sahrens 
1176fa9e4066Sahrens 	/*
1177fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1178fa9e4066Sahrens 	 */
117946657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1180eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1181eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1182eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1183eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1184eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
118595173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
118695173954Sek110237 			(void) printf(gettext("action: The pool can be "
118795173954Sek110237 			    "imported using its name or numeric "
118895173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1189fa9e4066Sahrens 		else
1190eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1191eaca9bbdSeschrock 			    "imported using its name or numeric "
1192eaca9bbdSeschrock 			    "identifier.\n"));
119346657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1194fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1195fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1196eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1197fa9e4066Sahrens 	} else {
1198eaca9bbdSeschrock 		switch (reason) {
1199eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1200eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1201eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1202eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1203eaca9bbdSeschrock 			    "backup.\n"));
1204eaca9bbdSeschrock 			break;
1205eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1206eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1207eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1208fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1209fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1210fa9e4066Sahrens 			    "again.\n"));
1211eaca9bbdSeschrock 			break;
1212eaca9bbdSeschrock 		default:
1213fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1214fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1215fa9e4066Sahrens 		}
1216eaca9bbdSeschrock 	}
1217eaca9bbdSeschrock 
121846657f8dSmmusante 	/*
121946657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
122046657f8dSmmusante 	 * is "corrupt data":
122146657f8dSmmusante 	 */
122246657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
122346657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
122446657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1225eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1226eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1227eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1228eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1229eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
123018ce54dfSek110237 			    "another system, but can be imported using\n\t"
1231eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1232eaca9bbdSeschrock 	}
1233fa9e4066Sahrens 
1234fa9e4066Sahrens 	if (msgid != NULL)
1235fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1236fa9e4066Sahrens 		    msgid);
1237fa9e4066Sahrens 
1238fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1239fa9e4066Sahrens 
1240c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1241fa9e4066Sahrens 	if (namewidth < 10)
1242fa9e4066Sahrens 		namewidth = 10;
12438654d025Sperrin 
12448654d025Sperrin 	print_import_config(name, nvroot, namewidth, 0, B_FALSE);
12458654d025Sperrin 	if (num_logs(nvroot) > 0) {
12468654d025Sperrin 		(void) printf(gettext("\tlogs\n"));
12478654d025Sperrin 		print_import_config(name, nvroot, namewidth, 0, B_TRUE);
12488654d025Sperrin 	}
1249fa9e4066Sahrens 
1250fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
125146657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1252fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
125346657f8dSmmusante 		    "configuration cannot be determined.\n"));
1254fa9e4066Sahrens 	}
1255fa9e4066Sahrens }
1256fa9e4066Sahrens 
1257fa9e4066Sahrens /*
1258fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1259990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1260990b4856Slling  * within the pool.
1261fa9e4066Sahrens  */
1262fa9e4066Sahrens static int
1263fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
1264c5904d13Seschrock     int force, nvlist_t *props, boolean_t allowfaulted)
1265fa9e4066Sahrens {
1266fa9e4066Sahrens 	zpool_handle_t *zhp;
1267fa9e4066Sahrens 	char *name;
1268fa9e4066Sahrens 	uint64_t state;
1269eaca9bbdSeschrock 	uint64_t version;
1270ecd6cf80Smarks 	int error = 0;
1271fa9e4066Sahrens 
1272fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1273fa9e4066Sahrens 	    &name) == 0);
1274fa9e4066Sahrens 
1275fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1276fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1277eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1278eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1279e7437265Sahrens 	if (version > SPA_VERSION) {
1280eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1281eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1282eaca9bbdSeschrock 		return (1);
1283eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
128495173954Sek110237 		uint64_t hostid;
128595173954Sek110237 
128695173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
128795173954Sek110237 		    &hostid) == 0) {
128895173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
128995173954Sek110237 				char *hostname;
129095173954Sek110237 				uint64_t timestamp;
129195173954Sek110237 				time_t t;
129295173954Sek110237 
129395173954Sek110237 				verify(nvlist_lookup_string(config,
129495173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
129595173954Sek110237 				verify(nvlist_lookup_uint64(config,
129695173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
129795173954Sek110237 				t = timestamp;
129895173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
129995173954Sek110237 				    "'%s': pool may be in use from other "
130095173954Sek110237 				    "system, it was last accessed by %s "
130195173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
130295173954Sek110237 				    (unsigned long)hostid,
130395173954Sek110237 				    asctime(localtime(&t)));
130495173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
130595173954Sek110237 				    "import anyway\n"));
1306fa9e4066Sahrens 				return (1);
1307fa9e4066Sahrens 			}
130895173954Sek110237 		} else {
130995173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
131095173954Sek110237 			    "pool may be in use from other system\n"), name);
131195173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
131295173954Sek110237 			    "anyway\n"));
131395173954Sek110237 			return (1);
131495173954Sek110237 		}
131595173954Sek110237 	}
1316fa9e4066Sahrens 
1317c5904d13Seschrock 	if (zpool_import_props(g_zfs, config, newname, props,
1318c5904d13Seschrock 	    allowfaulted) != 0)
1319fa9e4066Sahrens 		return (1);
1320fa9e4066Sahrens 
1321fa9e4066Sahrens 	if (newname != NULL)
1322fa9e4066Sahrens 		name = (char *)newname;
1323fa9e4066Sahrens 
1324c5904d13Seschrock 	verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL);
1325fa9e4066Sahrens 
1326*379c004dSEric Schrock 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
1327*379c004dSEric Schrock 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1328fa9e4066Sahrens 		zpool_close(zhp);
1329fa9e4066Sahrens 		return (1);
1330fa9e4066Sahrens 	}
1331fa9e4066Sahrens 
1332fa9e4066Sahrens 	zpool_close(zhp);
1333ecd6cf80Smarks 	return (error);
1334fa9e4066Sahrens }
1335fa9e4066Sahrens 
1336fa9e4066Sahrens /*
13374c58d714Sdarrenm  * zpool import [-d dir] [-D]
13382f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
13392f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
13402f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
13412f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] <pool | id> [newpool]
13422f8aaab3Seschrock  *
13432f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
13442f8aaab3Seschrock  *		devices.
1345fa9e4066Sahrens  *
1346fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1347fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1348fa9e4066Sahrens  *
13494c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
13504c58d714Sdarrenm  *              specified destroyed pools.
13514c58d714Sdarrenm  *
1352fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1353fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1354fa9e4066Sahrens  *		is rebooted.
1355fa9e4066Sahrens  *
1356fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1357fa9e4066Sahrens  *
1358c5904d13Seschrock  *       -F	Import even in the presence of faulted vdevs.  This is an
1359c5904d13Seschrock  *       	intentionally undocumented option for testing purposes, and
1360c5904d13Seschrock  *       	treats the pool configuration as complete, leaving any bad
1361c5904d13Seschrock  *		vdevs in the FAULTED state.
1362c5904d13Seschrock  *
1363fa9e4066Sahrens  *       -a	Import all pools found.
1364fa9e4066Sahrens  *
1365990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1366ecd6cf80Smarks  *
1367fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1368fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1369fa9e4066Sahrens  */
1370fa9e4066Sahrens int
1371fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1372fa9e4066Sahrens {
1373fa9e4066Sahrens 	char **searchdirs = NULL;
1374fa9e4066Sahrens 	int nsearch = 0;
1375fa9e4066Sahrens 	int c;
1376fa9e4066Sahrens 	int err;
13772f8aaab3Seschrock 	nvlist_t *pools = NULL;
137899653d4eSeschrock 	boolean_t do_all = B_FALSE;
137999653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1380fa9e4066Sahrens 	char *mntopts = NULL;
138199653d4eSeschrock 	boolean_t do_force = B_FALSE;
1382fa9e4066Sahrens 	nvpair_t *elem;
1383fa9e4066Sahrens 	nvlist_t *config;
138424e697d4Sck153898 	uint64_t searchguid = 0;
138524e697d4Sck153898 	char *searchname = NULL;
1386990b4856Slling 	char *propval;
1387fa9e4066Sahrens 	nvlist_t *found_config;
1388ecd6cf80Smarks 	nvlist_t *props = NULL;
138999653d4eSeschrock 	boolean_t first;
1390c5904d13Seschrock 	boolean_t allow_faulted = B_FALSE;
13914c58d714Sdarrenm 	uint64_t pool_state;
13922f8aaab3Seschrock 	char *cachefile = NULL;
1393fa9e4066Sahrens 
1394fa9e4066Sahrens 	/* check options */
1395c5904d13Seschrock 	while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) {
1396fa9e4066Sahrens 		switch (c) {
1397fa9e4066Sahrens 		case 'a':
139899653d4eSeschrock 			do_all = B_TRUE;
1399fa9e4066Sahrens 			break;
14002f8aaab3Seschrock 		case 'c':
14012f8aaab3Seschrock 			cachefile = optarg;
14022f8aaab3Seschrock 			break;
1403fa9e4066Sahrens 		case 'd':
1404fa9e4066Sahrens 			if (searchdirs == NULL) {
1405fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1406fa9e4066Sahrens 			} else {
1407fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1408fa9e4066Sahrens 				    sizeof (char *));
1409fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1410fa9e4066Sahrens 				    sizeof (char *));
1411fa9e4066Sahrens 				free(searchdirs);
1412fa9e4066Sahrens 				searchdirs = tmp;
1413fa9e4066Sahrens 			}
1414fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1415fa9e4066Sahrens 			break;
14164c58d714Sdarrenm 		case 'D':
141799653d4eSeschrock 			do_destroyed = B_TRUE;
14184c58d714Sdarrenm 			break;
1419fa9e4066Sahrens 		case 'f':
142099653d4eSeschrock 			do_force = B_TRUE;
1421fa9e4066Sahrens 			break;
1422c5904d13Seschrock 		case 'F':
1423c5904d13Seschrock 			allow_faulted = B_TRUE;
1424c5904d13Seschrock 			break;
1425fa9e4066Sahrens 		case 'o':
1426990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1427990b4856Slling 				*propval = '\0';
1428990b4856Slling 				propval++;
14290a48a24eStimh 				if (add_prop_list(optarg, propval,
14300a48a24eStimh 				    &props, B_TRUE))
1431990b4856Slling 					goto error;
1432990b4856Slling 			} else {
1433fa9e4066Sahrens 				mntopts = optarg;
1434990b4856Slling 			}
1435fa9e4066Sahrens 			break;
1436fa9e4066Sahrens 		case 'R':
1437990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
14380a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1439990b4856Slling 				goto error;
14402f8aaab3Seschrock 			if (nvlist_lookup_string(props,
14412f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
14422f8aaab3Seschrock 			    &propval) == 0)
14432f8aaab3Seschrock 				break;
1444990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
14450a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1446990b4856Slling 				goto error;
1447fa9e4066Sahrens 			break;
1448fa9e4066Sahrens 		case ':':
1449fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1450fa9e4066Sahrens 			    "'%c' option\n"), optopt);
145199653d4eSeschrock 			usage(B_FALSE);
1452fa9e4066Sahrens 			break;
1453fa9e4066Sahrens 		case '?':
1454fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1455fa9e4066Sahrens 			    optopt);
145699653d4eSeschrock 			usage(B_FALSE);
1457fa9e4066Sahrens 		}
1458fa9e4066Sahrens 	}
1459fa9e4066Sahrens 
1460fa9e4066Sahrens 	argc -= optind;
1461fa9e4066Sahrens 	argv += optind;
1462fa9e4066Sahrens 
14632f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
14642f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
14652f8aaab3Seschrock 		usage(B_FALSE);
14662f8aaab3Seschrock 	}
14672f8aaab3Seschrock 
1468fa9e4066Sahrens 	if (searchdirs == NULL) {
1469fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1470fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1471fa9e4066Sahrens 		nsearch = 1;
1472fa9e4066Sahrens 	}
1473fa9e4066Sahrens 
1474fa9e4066Sahrens 	/* check argument count */
1475fa9e4066Sahrens 	if (do_all) {
1476fa9e4066Sahrens 		if (argc != 0) {
1477fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
147899653d4eSeschrock 			usage(B_FALSE);
1479fa9e4066Sahrens 		}
1480fa9e4066Sahrens 	} else {
1481fa9e4066Sahrens 		if (argc > 2) {
1482fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
148399653d4eSeschrock 			usage(B_FALSE);
1484fa9e4066Sahrens 		}
1485fa9e4066Sahrens 
1486fa9e4066Sahrens 		/*
1487fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1488fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1489fa9e4066Sahrens 		 * silently fail.
1490fa9e4066Sahrens 		 */
1491fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1492fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1493fa9e4066Sahrens 			    "discover pools: permission denied\n"));
149499653d4eSeschrock 			free(searchdirs);
1495fa9e4066Sahrens 			return (1);
1496fa9e4066Sahrens 		}
1497fa9e4066Sahrens 	}
1498fa9e4066Sahrens 
1499fa9e4066Sahrens 	/*
1500fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1501fa9e4066Sahrens 	 *
1502fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1503fa9e4066Sahrens 	 *		each one.
1504fa9e4066Sahrens 	 *
1505fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1506fa9e4066Sahrens 	 *
1507fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1508fa9e4066Sahrens 	 *		name and import that one.
15094c58d714Sdarrenm 	 *
15104c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1511fa9e4066Sahrens 	 */
1512fa9e4066Sahrens 	if (argc != 0) {
1513fa9e4066Sahrens 		char *endptr;
1514fa9e4066Sahrens 
1515fa9e4066Sahrens 		errno = 0;
1516fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1517fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1518fa9e4066Sahrens 			searchname = argv[0];
1519fa9e4066Sahrens 		found_config = NULL;
1520fa9e4066Sahrens 	}
1521fa9e4066Sahrens 
152224e697d4Sck153898 	if (cachefile) {
1523e829d913Sck153898 		pools = zpool_find_import_cached(g_zfs, cachefile, searchname,
1524e829d913Sck153898 		    searchguid);
152524e697d4Sck153898 	} else if (searchname != NULL) {
152624e697d4Sck153898 		pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs,
152724e697d4Sck153898 		    searchname);
152824e697d4Sck153898 	} else {
152924e697d4Sck153898 		/*
153024e697d4Sck153898 		 * It's OK to search by guid even if searchguid is 0.
153124e697d4Sck153898 		 */
153224e697d4Sck153898 		pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs,
153324e697d4Sck153898 		    searchguid);
153424e697d4Sck153898 	}
153524e697d4Sck153898 
153624e697d4Sck153898 	if (pools == NULL) {
153724e697d4Sck153898 		if (argc != 0) {
153824e697d4Sck153898 			(void) fprintf(stderr, gettext("cannot import '%s': "
153924e697d4Sck153898 			    "no such pool available\n"), argv[0]);
154024e697d4Sck153898 		}
154124e697d4Sck153898 		free(searchdirs);
154224e697d4Sck153898 		return (1);
154324e697d4Sck153898 	}
154424e697d4Sck153898 
154524e697d4Sck153898 	/*
154624e697d4Sck153898 	 * At this point we have a list of import candidate configs. Even if
154724e697d4Sck153898 	 * we were searching by pool name or guid, we still need to
154824e697d4Sck153898 	 * post-process the list to deal with pool state and possible
154924e697d4Sck153898 	 * duplicate names.
155024e697d4Sck153898 	 */
1551fa9e4066Sahrens 	err = 0;
1552fa9e4066Sahrens 	elem = NULL;
155399653d4eSeschrock 	first = B_TRUE;
1554fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1555fa9e4066Sahrens 
1556fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1557fa9e4066Sahrens 
15584c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
15594c58d714Sdarrenm 		    &pool_state) == 0);
15604c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
15614c58d714Sdarrenm 			continue;
15624c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
15634c58d714Sdarrenm 			continue;
15644c58d714Sdarrenm 
1565fa9e4066Sahrens 		if (argc == 0) {
1566fa9e4066Sahrens 			if (first)
156799653d4eSeschrock 				first = B_FALSE;
15683bb79becSeschrock 			else if (!do_all)
1569fa9e4066Sahrens 				(void) printf("\n");
1570fa9e4066Sahrens 
1571fa9e4066Sahrens 			if (do_all)
1572fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1573c5904d13Seschrock 				    do_force, props, allow_faulted);
1574fa9e4066Sahrens 			else
1575fa9e4066Sahrens 				show_import(config);
1576fa9e4066Sahrens 		} else if (searchname != NULL) {
1577fa9e4066Sahrens 			char *name;
1578fa9e4066Sahrens 
1579fa9e4066Sahrens 			/*
1580fa9e4066Sahrens 			 * We are searching for a pool based on name.
1581fa9e4066Sahrens 			 */
1582fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1583fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1584fa9e4066Sahrens 
1585fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1586fa9e4066Sahrens 				if (found_config != NULL) {
1587fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1588fa9e4066Sahrens 					    "cannot import '%s': more than "
1589fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1590fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1591fa9e4066Sahrens 					    "import by numeric ID instead\n"));
159299653d4eSeschrock 					err = B_TRUE;
1593fa9e4066Sahrens 				}
1594fa9e4066Sahrens 				found_config = config;
1595fa9e4066Sahrens 			}
1596fa9e4066Sahrens 		} else {
1597fa9e4066Sahrens 			uint64_t guid;
1598fa9e4066Sahrens 
1599fa9e4066Sahrens 			/*
1600fa9e4066Sahrens 			 * Search for a pool by guid.
1601fa9e4066Sahrens 			 */
1602fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1603fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1604fa9e4066Sahrens 
1605fa9e4066Sahrens 			if (guid == searchguid)
1606fa9e4066Sahrens 				found_config = config;
1607fa9e4066Sahrens 		}
1608fa9e4066Sahrens 	}
1609fa9e4066Sahrens 
1610fa9e4066Sahrens 	/*
1611fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1612fa9e4066Sahrens 	 * pool, and then do the import.
1613fa9e4066Sahrens 	 */
1614fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1615fa9e4066Sahrens 		if (found_config == NULL) {
1616fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1617fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
161899653d4eSeschrock 			err = B_TRUE;
1619fa9e4066Sahrens 		} else {
1620fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1621c5904d13Seschrock 			    argv[1], mntopts, do_force, props, allow_faulted);
1622fa9e4066Sahrens 		}
1623fa9e4066Sahrens 	}
1624fa9e4066Sahrens 
1625fa9e4066Sahrens 	/*
1626fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1627fa9e4066Sahrens 	 * found.
1628fa9e4066Sahrens 	 */
1629fa9e4066Sahrens 	if (argc == 0 && first)
1630fa9e4066Sahrens 		(void) fprintf(stderr,
1631fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1632fa9e4066Sahrens 
1633ecd6cf80Smarks error:
1634ecd6cf80Smarks 	nvlist_free(props);
1635fa9e4066Sahrens 	nvlist_free(pools);
163699653d4eSeschrock 	free(searchdirs);
1637fa9e4066Sahrens 
1638fa9e4066Sahrens 	return (err ? 1 : 0);
1639fa9e4066Sahrens }
1640fa9e4066Sahrens 
1641fa9e4066Sahrens typedef struct iostat_cbdata {
1642fa9e4066Sahrens 	zpool_list_t *cb_list;
1643fa9e4066Sahrens 	int cb_verbose;
1644fa9e4066Sahrens 	int cb_iteration;
1645fa9e4066Sahrens 	int cb_namewidth;
1646fa9e4066Sahrens } iostat_cbdata_t;
1647fa9e4066Sahrens 
1648fa9e4066Sahrens static void
1649fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1650fa9e4066Sahrens {
1651fa9e4066Sahrens 	int i = 0;
1652fa9e4066Sahrens 
1653fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1654fa9e4066Sahrens 		(void) printf("-");
1655fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1656fa9e4066Sahrens }
1657fa9e4066Sahrens 
1658fa9e4066Sahrens static void
1659fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1660fa9e4066Sahrens {
1661fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1662fa9e4066Sahrens 	    cb->cb_namewidth, "");
1663fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1664fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1665fa9e4066Sahrens 	print_iostat_separator(cb);
1666fa9e4066Sahrens }
1667fa9e4066Sahrens 
1668fa9e4066Sahrens /*
1669fa9e4066Sahrens  * Display a single statistic.
1670fa9e4066Sahrens  */
1671990b4856Slling static void
1672fa9e4066Sahrens print_one_stat(uint64_t value)
1673fa9e4066Sahrens {
1674fa9e4066Sahrens 	char buf[64];
1675fa9e4066Sahrens 
1676fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1677fa9e4066Sahrens 	(void) printf("  %5s", buf);
1678fa9e4066Sahrens }
1679fa9e4066Sahrens 
1680fa9e4066Sahrens /*
1681fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1682fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1683fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1684fa9e4066Sahrens  */
1685fa9e4066Sahrens void
1686c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1687c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1688fa9e4066Sahrens {
1689fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1690fa9e4066Sahrens 	uint_t c, children;
1691fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1692fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1693fa9e4066Sahrens 	uint64_t tdelta;
1694fa9e4066Sahrens 	double scale;
1695afefbcddSeschrock 	char *vname;
1696fa9e4066Sahrens 
1697fa9e4066Sahrens 	if (oldnv != NULL) {
1698fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1699fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1700fa9e4066Sahrens 	} else {
1701fa9e4066Sahrens 		oldvs = &zerovs;
1702fa9e4066Sahrens 	}
1703fa9e4066Sahrens 
1704fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1705fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1706fa9e4066Sahrens 
1707fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1708fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1709fa9e4066Sahrens 	else
1710fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1711fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1712fa9e4066Sahrens 
1713fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1714fa9e4066Sahrens 
1715fa9e4066Sahrens 	if (tdelta == 0)
1716fa9e4066Sahrens 		scale = 1.0;
1717fa9e4066Sahrens 	else
1718fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1719fa9e4066Sahrens 
1720fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1721fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1722fa9e4066Sahrens 		(void) printf("      -      -");
1723fa9e4066Sahrens 	} else {
1724fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1725fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1726fa9e4066Sahrens 	}
1727fa9e4066Sahrens 
1728fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1729fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1730fa9e4066Sahrens 
1731fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1732fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1733fa9e4066Sahrens 
1734fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1735fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1736fa9e4066Sahrens 
1737fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1738fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1739fa9e4066Sahrens 
1740fa9e4066Sahrens 	(void) printf("\n");
1741fa9e4066Sahrens 
1742fa9e4066Sahrens 	if (!cb->cb_verbose)
1743fa9e4066Sahrens 		return;
1744fa9e4066Sahrens 
1745fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1746fa9e4066Sahrens 	    &newchild, &children) != 0)
1747fa9e4066Sahrens 		return;
1748fa9e4066Sahrens 
1749fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1750fa9e4066Sahrens 	    &oldchild, &c) != 0)
1751fa9e4066Sahrens 		return;
1752fa9e4066Sahrens 
1753afefbcddSeschrock 	for (c = 0; c < children; c++) {
175499653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1755c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1756afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1757afefbcddSeschrock 		free(vname);
1758afefbcddSeschrock 	}
1759fa94a07fSbrendan 
1760fa94a07fSbrendan 	/*
1761fa94a07fSbrendan 	 * Include level 2 ARC devices in iostat output
1762fa94a07fSbrendan 	 */
1763fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
1764fa94a07fSbrendan 	    &newchild, &children) != 0)
1765fa94a07fSbrendan 		return;
1766fa94a07fSbrendan 
1767fa94a07fSbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
1768fa94a07fSbrendan 	    &oldchild, &c) != 0)
1769fa94a07fSbrendan 		return;
1770fa94a07fSbrendan 
1771fa94a07fSbrendan 	if (children > 0) {
1772fa94a07fSbrendan 		(void) printf("%-*s      -      -      -      -      -      "
1773fa94a07fSbrendan 		    "-\n", cb->cb_namewidth, "cache");
1774fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1775fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1776fa94a07fSbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1777fa94a07fSbrendan 			    newchild[c], cb, depth + 2);
1778fa94a07fSbrendan 			free(vname);
1779fa94a07fSbrendan 		}
1780fa94a07fSbrendan 	}
1781fa9e4066Sahrens }
1782fa9e4066Sahrens 
1783088e9d47Seschrock static int
1784088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
1785088e9d47Seschrock {
1786088e9d47Seschrock 	iostat_cbdata_t *cb = data;
178794de1d4cSeschrock 	boolean_t missing;
1788088e9d47Seschrock 
1789088e9d47Seschrock 	/*
1790088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
1791088e9d47Seschrock 	 */
179294de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
179394de1d4cSeschrock 		return (-1);
179494de1d4cSeschrock 
179594de1d4cSeschrock 	if (missing)
1796088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
1797088e9d47Seschrock 
1798088e9d47Seschrock 	return (0);
1799088e9d47Seschrock }
1800088e9d47Seschrock 
1801fa9e4066Sahrens /*
1802fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
1803fa9e4066Sahrens  */
1804fa9e4066Sahrens int
1805fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
1806fa9e4066Sahrens {
1807fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1808fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
1809fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
1810fa9e4066Sahrens 
1811088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
1812fa9e4066Sahrens 
1813088e9d47Seschrock 	if (cb->cb_iteration == 1)
1814fa9e4066Sahrens 		oldconfig = NULL;
1815fa9e4066Sahrens 
1816fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1817fa9e4066Sahrens 	    &newnvroot) == 0);
1818fa9e4066Sahrens 
1819088e9d47Seschrock 	if (oldconfig == NULL)
1820fa9e4066Sahrens 		oldnvroot = NULL;
1821088e9d47Seschrock 	else
1822088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
1823088e9d47Seschrock 		    &oldnvroot) == 0);
1824fa9e4066Sahrens 
1825fa9e4066Sahrens 	/*
1826fa9e4066Sahrens 	 * Print out the statistics for the pool.
1827fa9e4066Sahrens 	 */
1828c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1829fa9e4066Sahrens 
1830fa9e4066Sahrens 	if (cb->cb_verbose)
1831fa9e4066Sahrens 		print_iostat_separator(cb);
1832fa9e4066Sahrens 
1833fa9e4066Sahrens 	return (0);
1834fa9e4066Sahrens }
1835fa9e4066Sahrens 
1836fa9e4066Sahrens int
1837fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
1838fa9e4066Sahrens {
1839fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1840fa9e4066Sahrens 	nvlist_t *config, *nvroot;
1841fa9e4066Sahrens 
1842088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
1843fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1844fa9e4066Sahrens 		    &nvroot) == 0);
1845fa9e4066Sahrens 		if (!cb->cb_verbose)
1846fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1847fa9e4066Sahrens 		else
1848c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
1849fa9e4066Sahrens 	}
1850fa9e4066Sahrens 
1851fa9e4066Sahrens 	/*
1852fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
1853fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
1854fa9e4066Sahrens 	 */
1855fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
1856fa9e4066Sahrens 		cb->cb_namewidth = 10;
1857fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
1858fa9e4066Sahrens 		cb->cb_namewidth = 38;
1859fa9e4066Sahrens 
1860fa9e4066Sahrens 	return (0);
1861fa9e4066Sahrens }
1862fa9e4066Sahrens 
1863fa9e4066Sahrens /*
1864fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
1865fa9e4066Sahrens  *
1866fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
1867fa9e4066Sahrens  *
1868fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
1869fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
1870fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1871fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
1872fa9e4066Sahrens  * changes are all handled within libzfs.
1873fa9e4066Sahrens  */
1874fa9e4066Sahrens int
1875fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
1876fa9e4066Sahrens {
1877fa9e4066Sahrens 	int c;
1878fa9e4066Sahrens 	int ret;
1879fa9e4066Sahrens 	int npools;
1880fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
1881fa9e4066Sahrens 	zpool_list_t *list;
188299653d4eSeschrock 	boolean_t verbose = B_FALSE;
1883fa9e4066Sahrens 	iostat_cbdata_t cb;
1884fa9e4066Sahrens 
1885fa9e4066Sahrens 	/* check options */
1886fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
1887fa9e4066Sahrens 		switch (c) {
1888fa9e4066Sahrens 		case 'v':
188999653d4eSeschrock 			verbose = B_TRUE;
1890fa9e4066Sahrens 			break;
1891fa9e4066Sahrens 		case '?':
1892fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1893fa9e4066Sahrens 			    optopt);
189499653d4eSeschrock 			usage(B_FALSE);
1895fa9e4066Sahrens 		}
1896fa9e4066Sahrens 	}
1897fa9e4066Sahrens 
1898fa9e4066Sahrens 	argc -= optind;
1899fa9e4066Sahrens 	argv += optind;
1900fa9e4066Sahrens 
1901fa9e4066Sahrens 	/*
1902fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
1903fa9e4066Sahrens 	 */
1904fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1905fa9e4066Sahrens 		char *end;
1906fa9e4066Sahrens 
1907fa9e4066Sahrens 		errno = 0;
1908fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1909fa9e4066Sahrens 
1910fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1911fa9e4066Sahrens 			if (interval == 0) {
1912fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1913fa9e4066Sahrens 				    "cannot be zero\n"));
191499653d4eSeschrock 				usage(B_FALSE);
1915fa9e4066Sahrens 			}
1916fa9e4066Sahrens 
1917fa9e4066Sahrens 			/*
1918fa9e4066Sahrens 			 * Ignore the last parameter
1919fa9e4066Sahrens 			 */
1920fa9e4066Sahrens 			argc--;
1921fa9e4066Sahrens 		} else {
1922fa9e4066Sahrens 			/*
1923fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
1924fa9e4066Sahrens 			 * user will get a more informative error message later
1925fa9e4066Sahrens 			 * on.
1926fa9e4066Sahrens 			 */
1927fa9e4066Sahrens 			interval = 0;
1928fa9e4066Sahrens 		}
1929fa9e4066Sahrens 	}
1930fa9e4066Sahrens 
1931fa9e4066Sahrens 	/*
1932fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
1933fa9e4066Sahrens 	 * and an integer.
1934fa9e4066Sahrens 	 */
1935fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1936fa9e4066Sahrens 		char *end;
1937fa9e4066Sahrens 
1938fa9e4066Sahrens 		errno = 0;
1939fa9e4066Sahrens 		count = interval;
1940fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1941fa9e4066Sahrens 
1942fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1943fa9e4066Sahrens 			if (interval == 0) {
1944fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1945fa9e4066Sahrens 				    "cannot be zero\n"));
194699653d4eSeschrock 				usage(B_FALSE);
1947fa9e4066Sahrens 			}
1948fa9e4066Sahrens 
1949fa9e4066Sahrens 			/*
1950fa9e4066Sahrens 			 * Ignore the last parameter
1951fa9e4066Sahrens 			 */
1952fa9e4066Sahrens 			argc--;
1953fa9e4066Sahrens 		} else {
1954fa9e4066Sahrens 			interval = 0;
1955fa9e4066Sahrens 		}
1956fa9e4066Sahrens 	}
1957fa9e4066Sahrens 
1958fa9e4066Sahrens 	/*
1959fa9e4066Sahrens 	 * Construct the list of all interesting pools.
1960fa9e4066Sahrens 	 */
1961fa9e4066Sahrens 	ret = 0;
1962b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
1963fa9e4066Sahrens 		return (1);
1964fa9e4066Sahrens 
196599653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
196699653d4eSeschrock 		pool_list_free(list);
1967fa9e4066Sahrens 		return (1);
196899653d4eSeschrock 	}
1969fa9e4066Sahrens 
1970fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
197199653d4eSeschrock 		pool_list_free(list);
1972fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
1973fa9e4066Sahrens 		return (1);
1974fa9e4066Sahrens 	}
1975fa9e4066Sahrens 
1976fa9e4066Sahrens 	/*
1977fa9e4066Sahrens 	 * Enter the main iostat loop.
1978fa9e4066Sahrens 	 */
1979fa9e4066Sahrens 	cb.cb_list = list;
1980fa9e4066Sahrens 	cb.cb_verbose = verbose;
1981fa9e4066Sahrens 	cb.cb_iteration = 0;
1982fa9e4066Sahrens 	cb.cb_namewidth = 0;
1983fa9e4066Sahrens 
1984fa9e4066Sahrens 	for (;;) {
1985fa9e4066Sahrens 		pool_list_update(list);
1986fa9e4066Sahrens 
1987fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
1988fa9e4066Sahrens 			break;
1989fa9e4066Sahrens 
1990fa9e4066Sahrens 		/*
1991088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
1992088e9d47Seschrock 		 * before calculating the maximum name width, so that any
1993088e9d47Seschrock 		 * configuration changes are properly accounted for.
1994088e9d47Seschrock 		 */
199599653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
1996088e9d47Seschrock 
1997088e9d47Seschrock 		/*
1998fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
1999fa9e4066Sahrens 		 * for the pool / device name column across all pools.
2000fa9e4066Sahrens 		 */
2001fa9e4066Sahrens 		cb.cb_namewidth = 0;
200299653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2003fa9e4066Sahrens 
2004fa9e4066Sahrens 		/*
2005fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
2006fa9e4066Sahrens 		 */
2007fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
2008fa9e4066Sahrens 			print_iostat_header(&cb);
2009fa9e4066Sahrens 
201099653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2011fa9e4066Sahrens 
2012fa9e4066Sahrens 		/*
2013fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
2014fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
2015fa9e4066Sahrens 		 */
2016fa9e4066Sahrens 		if (npools > 1 && !verbose)
2017fa9e4066Sahrens 			print_iostat_separator(&cb);
2018fa9e4066Sahrens 
2019fa9e4066Sahrens 		if (verbose)
2020fa9e4066Sahrens 			(void) printf("\n");
2021fa9e4066Sahrens 
202239c23413Seschrock 		/*
202339c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
202439c23413Seschrock 		 * indefinitely.
202539c23413Seschrock 		 */
202639c23413Seschrock 		(void) fflush(stdout);
202739c23413Seschrock 
2028fa9e4066Sahrens 		if (interval == 0)
2029fa9e4066Sahrens 			break;
2030fa9e4066Sahrens 
2031fa9e4066Sahrens 		if (count != 0 && --count == 0)
2032fa9e4066Sahrens 			break;
2033fa9e4066Sahrens 
2034fa9e4066Sahrens 		(void) sleep(interval);
2035fa9e4066Sahrens 	}
2036fa9e4066Sahrens 
2037fa9e4066Sahrens 	pool_list_free(list);
2038fa9e4066Sahrens 
2039fa9e4066Sahrens 	return (ret);
2040fa9e4066Sahrens }
2041fa9e4066Sahrens 
2042fa9e4066Sahrens typedef struct list_cbdata {
204399653d4eSeschrock 	boolean_t	cb_scripted;
204499653d4eSeschrock 	boolean_t	cb_first;
2045990b4856Slling 	zprop_list_t	*cb_proplist;
2046fa9e4066Sahrens } list_cbdata_t;
2047fa9e4066Sahrens 
2048fa9e4066Sahrens /*
2049fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
2050fa9e4066Sahrens  */
2051990b4856Slling static void
2052990b4856Slling print_header(zprop_list_t *pl)
2053fa9e4066Sahrens {
2054990b4856Slling 	const char *header;
2055990b4856Slling 	boolean_t first = B_TRUE;
2056990b4856Slling 	boolean_t right_justify;
2057fa9e4066Sahrens 
2058990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2059990b4856Slling 		if (pl->pl_prop == ZPROP_INVAL)
2060990b4856Slling 			continue;
2061990b4856Slling 
2062990b4856Slling 		if (!first)
2063fa9e4066Sahrens 			(void) printf("  ");
2064fa9e4066Sahrens 		else
2065990b4856Slling 			first = B_FALSE;
2066fa9e4066Sahrens 
2067990b4856Slling 		header = zpool_prop_column_name(pl->pl_prop);
2068990b4856Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
2069990b4856Slling 
2070990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
2071990b4856Slling 			(void) printf("%s", header);
2072990b4856Slling 		else if (right_justify)
2073990b4856Slling 			(void) printf("%*s", pl->pl_width, header);
2074990b4856Slling 		else
2075990b4856Slling 			(void) printf("%-*s", pl->pl_width, header);
2076fa9e4066Sahrens 	}
2077fa9e4066Sahrens 
2078fa9e4066Sahrens 	(void) printf("\n");
2079fa9e4066Sahrens }
2080fa9e4066Sahrens 
2081990b4856Slling /*
2082990b4856Slling  * Given a pool and a list of properties, print out all the properties according
2083990b4856Slling  * to the described layout.
2084990b4856Slling  */
2085990b4856Slling static void
2086990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
2087990b4856Slling {
2088990b4856Slling 	boolean_t first = B_TRUE;
2089990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
2090990b4856Slling 	char *propstr;
2091990b4856Slling 	boolean_t right_justify;
2092990b4856Slling 	int width;
2093990b4856Slling 
2094990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2095990b4856Slling 		if (!first) {
2096990b4856Slling 			if (scripted)
2097990b4856Slling 				(void) printf("\t");
2098990b4856Slling 			else
2099990b4856Slling 				(void) printf("  ");
2100990b4856Slling 		} else {
2101990b4856Slling 			first = B_FALSE;
2102990b4856Slling 		}
2103990b4856Slling 
2104990b4856Slling 		right_justify = B_FALSE;
2105990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
2106990b4856Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
2107990b4856Slling 			    sizeof (property), NULL) != 0)
2108990b4856Slling 				propstr = "-";
2109990b4856Slling 			else
2110990b4856Slling 				propstr = property;
2111990b4856Slling 
2112990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2113990b4856Slling 		} else {
2114990b4856Slling 			propstr = "-";
2115990b4856Slling 		}
2116990b4856Slling 
2117990b4856Slling 		width = pl->pl_width;
2118990b4856Slling 
2119990b4856Slling 		/*
2120990b4856Slling 		 * If this is being called in scripted mode, or if this is the
2121990b4856Slling 		 * last column and it is left-justified, don't include a width
2122990b4856Slling 		 * format specifier.
2123990b4856Slling 		 */
2124990b4856Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
2125990b4856Slling 			(void) printf("%s", propstr);
2126990b4856Slling 		else if (right_justify)
2127990b4856Slling 			(void) printf("%*s", width, propstr);
2128990b4856Slling 		else
2129990b4856Slling 			(void) printf("%-*s", width, propstr);
2130990b4856Slling 	}
2131990b4856Slling 
2132990b4856Slling 	(void) printf("\n");
2133990b4856Slling }
2134990b4856Slling 
2135990b4856Slling /*
2136990b4856Slling  * Generic callback function to list a pool.
2137990b4856Slling  */
2138fa9e4066Sahrens int
2139fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2140fa9e4066Sahrens {
2141fa9e4066Sahrens 	list_cbdata_t *cbp = data;
2142fa9e4066Sahrens 
2143fa9e4066Sahrens 	if (cbp->cb_first) {
2144fa9e4066Sahrens 		if (!cbp->cb_scripted)
2145990b4856Slling 			print_header(cbp->cb_proplist);
214699653d4eSeschrock 		cbp->cb_first = B_FALSE;
2147fa9e4066Sahrens 	}
2148fa9e4066Sahrens 
2149990b4856Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2150fa9e4066Sahrens 
2151fa9e4066Sahrens 	return (0);
2152fa9e4066Sahrens }
2153fa9e4066Sahrens 
2154fa9e4066Sahrens /*
2155990b4856Slling  * zpool list [-H] [-o prop[,prop]*] [pool] ...
2156fa9e4066Sahrens  *
2157990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2158990b4856Slling  *		by a single tab.
2159990b4856Slling  *	-o	List of properties to display.  Defaults to
2160990b4856Slling  *		"name,size,used,available,capacity,health,altroot"
2161fa9e4066Sahrens  *
2162fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2163fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2164fa9e4066Sahrens  */
2165fa9e4066Sahrens int
2166fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2167fa9e4066Sahrens {
2168fa9e4066Sahrens 	int c;
2169fa9e4066Sahrens 	int ret;
2170fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2171990b4856Slling 	static char default_props[] =
2172990b4856Slling 	    "name,size,used,available,capacity,health,altroot";
2173990b4856Slling 	char *props = default_props;
2174fa9e4066Sahrens 
2175fa9e4066Sahrens 	/* check options */
2176fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2177fa9e4066Sahrens 		switch (c) {
2178fa9e4066Sahrens 		case 'H':
217999653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2180fa9e4066Sahrens 			break;
2181fa9e4066Sahrens 		case 'o':
2182990b4856Slling 			props = optarg;
2183fa9e4066Sahrens 			break;
2184fa9e4066Sahrens 		case ':':
2185fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2186fa9e4066Sahrens 			    "'%c' option\n"), optopt);
218799653d4eSeschrock 			usage(B_FALSE);
2188fa9e4066Sahrens 			break;
2189fa9e4066Sahrens 		case '?':
2190fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2191fa9e4066Sahrens 			    optopt);
219299653d4eSeschrock 			usage(B_FALSE);
2193fa9e4066Sahrens 		}
2194fa9e4066Sahrens 	}
2195fa9e4066Sahrens 
2196fa9e4066Sahrens 	argc -= optind;
2197fa9e4066Sahrens 	argv += optind;
2198fa9e4066Sahrens 
2199990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
220099653d4eSeschrock 		usage(B_FALSE);
2201fa9e4066Sahrens 
220299653d4eSeschrock 	cb.cb_first = B_TRUE;
2203fa9e4066Sahrens 
2204990b4856Slling 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2205990b4856Slling 	    list_callback, &cb);
2206990b4856Slling 
2207990b4856Slling 	zprop_free_list(cb.cb_proplist);
2208fa9e4066Sahrens 
2209fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2210fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2211fa9e4066Sahrens 		return (0);
2212fa9e4066Sahrens 	}
2213fa9e4066Sahrens 
2214fa9e4066Sahrens 	return (ret);
2215fa9e4066Sahrens }
2216fa9e4066Sahrens 
2217fa9e4066Sahrens static nvlist_t *
2218fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2219fa9e4066Sahrens {
2220fa9e4066Sahrens 	nvlist_t **child;
2221fa9e4066Sahrens 	uint_t c, children;
2222fa9e4066Sahrens 	nvlist_t *match;
2223fa9e4066Sahrens 	char *path;
2224fa9e4066Sahrens 
2225fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2226fa9e4066Sahrens 	    &child, &children) != 0) {
2227fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2228fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2229fa9e4066Sahrens 			name += 9;
2230fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2231fa9e4066Sahrens 			path += 9;
2232fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2233fa9e4066Sahrens 			return (nv);
2234fa9e4066Sahrens 		return (NULL);
2235fa9e4066Sahrens 	}
2236fa9e4066Sahrens 
2237fa9e4066Sahrens 	for (c = 0; c < children; c++)
2238fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2239fa9e4066Sahrens 			return (match);
2240fa9e4066Sahrens 
2241fa9e4066Sahrens 	return (NULL);
2242fa9e4066Sahrens }
2243fa9e4066Sahrens 
2244fa9e4066Sahrens static int
2245fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2246fa9e4066Sahrens {
224799653d4eSeschrock 	boolean_t force = B_FALSE;
2248fa9e4066Sahrens 	int c;
2249fa9e4066Sahrens 	nvlist_t *nvroot;
2250fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2251fa9e4066Sahrens 	zpool_handle_t *zhp;
225299653d4eSeschrock 	int ret;
2253fa9e4066Sahrens 
2254fa9e4066Sahrens 	/* check options */
2255fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2256fa9e4066Sahrens 		switch (c) {
2257fa9e4066Sahrens 		case 'f':
225899653d4eSeschrock 			force = B_TRUE;
2259fa9e4066Sahrens 			break;
2260fa9e4066Sahrens 		case '?':
2261fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2262fa9e4066Sahrens 			    optopt);
226399653d4eSeschrock 			usage(B_FALSE);
2264fa9e4066Sahrens 		}
2265fa9e4066Sahrens 	}
2266fa9e4066Sahrens 
2267fa9e4066Sahrens 	argc -= optind;
2268fa9e4066Sahrens 	argv += optind;
2269fa9e4066Sahrens 
2270fa9e4066Sahrens 	/* get pool name and check number of arguments */
2271fa9e4066Sahrens 	if (argc < 1) {
2272fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
227399653d4eSeschrock 		usage(B_FALSE);
2274fa9e4066Sahrens 	}
2275fa9e4066Sahrens 
2276fa9e4066Sahrens 	poolname = argv[0];
2277fa9e4066Sahrens 
2278fa9e4066Sahrens 	if (argc < 2) {
2279fa9e4066Sahrens 		(void) fprintf(stderr,
2280fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
228199653d4eSeschrock 		usage(B_FALSE);
2282fa9e4066Sahrens 	}
2283fa9e4066Sahrens 
2284fa9e4066Sahrens 	old_disk = argv[1];
2285fa9e4066Sahrens 
2286fa9e4066Sahrens 	if (argc < 3) {
2287fa9e4066Sahrens 		if (!replacing) {
2288fa9e4066Sahrens 			(void) fprintf(stderr,
2289fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
229099653d4eSeschrock 			usage(B_FALSE);
2291fa9e4066Sahrens 		}
2292fa9e4066Sahrens 		new_disk = old_disk;
2293fa9e4066Sahrens 		argc -= 1;
2294fa9e4066Sahrens 		argv += 1;
2295fa9e4066Sahrens 	} else {
2296fa9e4066Sahrens 		new_disk = argv[2];
2297fa9e4066Sahrens 		argc -= 2;
2298fa9e4066Sahrens 		argv += 2;
2299fa9e4066Sahrens 	}
2300fa9e4066Sahrens 
2301fa9e4066Sahrens 	if (argc > 1) {
2302fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
230399653d4eSeschrock 		usage(B_FALSE);
2304fa9e4066Sahrens 	}
2305fa9e4066Sahrens 
230699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2307fa9e4066Sahrens 		return (1);
2308fa9e4066Sahrens 
23098488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2310fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2311fa9e4066Sahrens 		    poolname);
2312fa9e4066Sahrens 		zpool_close(zhp);
2313fa9e4066Sahrens 		return (1);
2314fa9e4066Sahrens 	}
2315fa9e4066Sahrens 
2316705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
2317705040edSEric Taylor 	    argc, argv);
2318fa9e4066Sahrens 	if (nvroot == NULL) {
2319fa9e4066Sahrens 		zpool_close(zhp);
2320fa9e4066Sahrens 		return (1);
2321fa9e4066Sahrens 	}
2322fa9e4066Sahrens 
232399653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
232499653d4eSeschrock 
232599653d4eSeschrock 	nvlist_free(nvroot);
232699653d4eSeschrock 	zpool_close(zhp);
232799653d4eSeschrock 
232899653d4eSeschrock 	return (ret);
2329fa9e4066Sahrens }
2330fa9e4066Sahrens 
2331fa9e4066Sahrens /*
2332fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2333fa9e4066Sahrens  *
2334fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2335fa9e4066Sahrens  *
2336fa9e4066Sahrens  * Replace <device> with <new_device>.
2337fa9e4066Sahrens  */
2338fa9e4066Sahrens /* ARGSUSED */
2339fa9e4066Sahrens int
2340fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2341fa9e4066Sahrens {
2342fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2343fa9e4066Sahrens }
2344fa9e4066Sahrens 
2345fa9e4066Sahrens /*
2346fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2347fa9e4066Sahrens  *
2348fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2349fa9e4066Sahrens  *
2350fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2351fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2352fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2353fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2354fa9e4066Sahrens  */
2355fa9e4066Sahrens int
2356fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2357fa9e4066Sahrens {
2358fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2359fa9e4066Sahrens }
2360fa9e4066Sahrens 
2361fa9e4066Sahrens /*
2362fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2363fa9e4066Sahrens  *
2364fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2365fa9e4066Sahrens  *		(not supported yet)
2366fa9e4066Sahrens  *
2367fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2368fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2369fa9e4066Sahrens  * has the only valid copy of some data.
2370fa9e4066Sahrens  */
2371fa9e4066Sahrens /* ARGSUSED */
2372fa9e4066Sahrens int
2373fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2374fa9e4066Sahrens {
2375fa9e4066Sahrens 	int c;
2376fa9e4066Sahrens 	char *poolname, *path;
2377fa9e4066Sahrens 	zpool_handle_t *zhp;
237899653d4eSeschrock 	int ret;
2379fa9e4066Sahrens 
2380fa9e4066Sahrens 	/* check options */
2381fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2382fa9e4066Sahrens 		switch (c) {
2383fa9e4066Sahrens 		case 'f':
2384fa9e4066Sahrens 		case '?':
2385fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2386fa9e4066Sahrens 			    optopt);
238799653d4eSeschrock 			usage(B_FALSE);
2388fa9e4066Sahrens 		}
2389fa9e4066Sahrens 	}
2390fa9e4066Sahrens 
2391fa9e4066Sahrens 	argc -= optind;
2392fa9e4066Sahrens 	argv += optind;
2393fa9e4066Sahrens 
2394fa9e4066Sahrens 	/* get pool name and check number of arguments */
2395fa9e4066Sahrens 	if (argc < 1) {
2396fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
239799653d4eSeschrock 		usage(B_FALSE);
2398fa9e4066Sahrens 	}
2399fa9e4066Sahrens 
2400fa9e4066Sahrens 	if (argc < 2) {
2401fa9e4066Sahrens 		(void) fprintf(stderr,
2402fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
240399653d4eSeschrock 		usage(B_FALSE);
2404fa9e4066Sahrens 	}
2405fa9e4066Sahrens 
2406fa9e4066Sahrens 	poolname = argv[0];
2407fa9e4066Sahrens 	path = argv[1];
2408fa9e4066Sahrens 
240999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2410fa9e4066Sahrens 		return (1);
2411fa9e4066Sahrens 
241299653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
241399653d4eSeschrock 
241499653d4eSeschrock 	zpool_close(zhp);
241599653d4eSeschrock 
241699653d4eSeschrock 	return (ret);
2417fa9e4066Sahrens }
2418fa9e4066Sahrens 
2419fa9e4066Sahrens /*
2420441d80aaSlling  * zpool online <pool> <device> ...
2421fa9e4066Sahrens  */
2422fa9e4066Sahrens int
2423fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2424fa9e4066Sahrens {
2425fa9e4066Sahrens 	int c, i;
2426fa9e4066Sahrens 	char *poolname;
2427fa9e4066Sahrens 	zpool_handle_t *zhp;
2428fa9e4066Sahrens 	int ret = 0;
24293d7072f8Seschrock 	vdev_state_t newstate;
2430fa9e4066Sahrens 
2431fa9e4066Sahrens 	/* check options */
2432fa9e4066Sahrens 	while ((c = getopt(argc, argv, "t")) != -1) {
2433fa9e4066Sahrens 		switch (c) {
2434fa9e4066Sahrens 		case 't':
2435fa9e4066Sahrens 		case '?':
2436fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2437fa9e4066Sahrens 			    optopt);
243899653d4eSeschrock 			usage(B_FALSE);
2439fa9e4066Sahrens 		}
2440fa9e4066Sahrens 	}
2441fa9e4066Sahrens 
2442fa9e4066Sahrens 	argc -= optind;
2443fa9e4066Sahrens 	argv += optind;
2444fa9e4066Sahrens 
2445fa9e4066Sahrens 	/* get pool name and check number of arguments */
2446fa9e4066Sahrens 	if (argc < 1) {
2447fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
244899653d4eSeschrock 		usage(B_FALSE);
2449fa9e4066Sahrens 	}
2450fa9e4066Sahrens 	if (argc < 2) {
2451fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
245299653d4eSeschrock 		usage(B_FALSE);
2453fa9e4066Sahrens 	}
2454fa9e4066Sahrens 
2455fa9e4066Sahrens 	poolname = argv[0];
2456fa9e4066Sahrens 
245799653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2458fa9e4066Sahrens 		return (1);
2459fa9e4066Sahrens 
24603d7072f8Seschrock 	for (i = 1; i < argc; i++) {
24613d7072f8Seschrock 		if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
24623d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
24633d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
24643d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
2465fa9e4066Sahrens 				    argv[i]);
24663d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
24673d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24683d7072f8Seschrock 					    "clear' to restore a faulted "
24693d7072f8Seschrock 					    "device\n"));
2470fa9e4066Sahrens 				else
24713d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24723d7072f8Seschrock 					    "replace' to replace devices "
24733d7072f8Seschrock 					    "that are no longer present\n"));
24743d7072f8Seschrock 			}
24753d7072f8Seschrock 		} else {
2476fa9e4066Sahrens 			ret = 1;
24773d7072f8Seschrock 		}
24783d7072f8Seschrock 	}
2479fa9e4066Sahrens 
248099653d4eSeschrock 	zpool_close(zhp);
248199653d4eSeschrock 
2482fa9e4066Sahrens 	return (ret);
2483fa9e4066Sahrens }
2484fa9e4066Sahrens 
2485fa9e4066Sahrens /*
2486441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2487fa9e4066Sahrens  *
2488fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2489fa9e4066Sahrens  *		so would appear to compromise pool availability.
2490fa9e4066Sahrens  *		(not supported yet)
2491fa9e4066Sahrens  *
2492fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2493fa9e4066Sahrens  *		state will not be persistent across reboots.
2494fa9e4066Sahrens  */
2495fa9e4066Sahrens /* ARGSUSED */
2496fa9e4066Sahrens int
2497fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2498fa9e4066Sahrens {
2499fa9e4066Sahrens 	int c, i;
2500fa9e4066Sahrens 	char *poolname;
2501fa9e4066Sahrens 	zpool_handle_t *zhp;
250299653d4eSeschrock 	int ret = 0;
250399653d4eSeschrock 	boolean_t istmp = B_FALSE;
2504fa9e4066Sahrens 
2505fa9e4066Sahrens 	/* check options */
2506fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2507fa9e4066Sahrens 		switch (c) {
2508fa9e4066Sahrens 		case 't':
250999653d4eSeschrock 			istmp = B_TRUE;
2510441d80aaSlling 			break;
2511441d80aaSlling 		case 'f':
2512fa9e4066Sahrens 		case '?':
2513fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2514fa9e4066Sahrens 			    optopt);
251599653d4eSeschrock 			usage(B_FALSE);
2516fa9e4066Sahrens 		}
2517fa9e4066Sahrens 	}
2518fa9e4066Sahrens 
2519fa9e4066Sahrens 	argc -= optind;
2520fa9e4066Sahrens 	argv += optind;
2521fa9e4066Sahrens 
2522fa9e4066Sahrens 	/* get pool name and check number of arguments */
2523fa9e4066Sahrens 	if (argc < 1) {
2524fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
252599653d4eSeschrock 		usage(B_FALSE);
2526fa9e4066Sahrens 	}
2527fa9e4066Sahrens 	if (argc < 2) {
2528fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
252999653d4eSeschrock 		usage(B_FALSE);
2530fa9e4066Sahrens 	}
2531fa9e4066Sahrens 
2532fa9e4066Sahrens 	poolname = argv[0];
2533fa9e4066Sahrens 
253499653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2535fa9e4066Sahrens 		return (1);
2536fa9e4066Sahrens 
25373d7072f8Seschrock 	for (i = 1; i < argc; i++) {
25383d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2539fa9e4066Sahrens 			ret = 1;
25403d7072f8Seschrock 	}
2541fa9e4066Sahrens 
254299653d4eSeschrock 	zpool_close(zhp);
254399653d4eSeschrock 
2544fa9e4066Sahrens 	return (ret);
2545fa9e4066Sahrens }
2546fa9e4066Sahrens 
2547ea8dc4b6Seschrock /*
2548ea8dc4b6Seschrock  * zpool clear <pool> [device]
2549ea8dc4b6Seschrock  *
2550ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2551ea8dc4b6Seschrock  */
2552ea8dc4b6Seschrock int
2553ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2554ea8dc4b6Seschrock {
2555ea8dc4b6Seschrock 	int ret = 0;
2556ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2557ea8dc4b6Seschrock 	char *pool, *device;
2558ea8dc4b6Seschrock 
2559ea8dc4b6Seschrock 	if (argc < 2) {
2560ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
256199653d4eSeschrock 		usage(B_FALSE);
2562ea8dc4b6Seschrock 	}
2563ea8dc4b6Seschrock 
2564ea8dc4b6Seschrock 	if (argc > 3) {
2565ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
256699653d4eSeschrock 		usage(B_FALSE);
2567ea8dc4b6Seschrock 	}
2568ea8dc4b6Seschrock 
2569ea8dc4b6Seschrock 	pool = argv[1];
2570ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2571ea8dc4b6Seschrock 
2572b87f3af3Sperrin 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
2573ea8dc4b6Seschrock 		return (1);
2574ea8dc4b6Seschrock 
2575ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2576ea8dc4b6Seschrock 		ret = 1;
2577ea8dc4b6Seschrock 
2578ea8dc4b6Seschrock 	zpool_close(zhp);
2579ea8dc4b6Seschrock 
2580ea8dc4b6Seschrock 	return (ret);
2581ea8dc4b6Seschrock }
2582ea8dc4b6Seschrock 
2583fa9e4066Sahrens typedef struct scrub_cbdata {
2584fa9e4066Sahrens 	int	cb_type;
258506eeb2adSek110237 	int	cb_argc;
258606eeb2adSek110237 	char	**cb_argv;
2587fa9e4066Sahrens } scrub_cbdata_t;
2588fa9e4066Sahrens 
2589fa9e4066Sahrens int
2590fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2591fa9e4066Sahrens {
2592fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
259306eeb2adSek110237 	int err;
2594fa9e4066Sahrens 
2595ea8dc4b6Seschrock 	/*
2596ea8dc4b6Seschrock 	 * Ignore faulted pools.
2597ea8dc4b6Seschrock 	 */
2598ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2599ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2600ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2601ea8dc4b6Seschrock 		return (1);
2602ea8dc4b6Seschrock 	}
2603ea8dc4b6Seschrock 
260406eeb2adSek110237 	err = zpool_scrub(zhp, cb->cb_type);
260506eeb2adSek110237 
260606eeb2adSek110237 	return (err != 0);
2607fa9e4066Sahrens }
2608fa9e4066Sahrens 
2609fa9e4066Sahrens /*
2610fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2611fa9e4066Sahrens  *
2612fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2613fa9e4066Sahrens  */
2614fa9e4066Sahrens int
2615fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2616fa9e4066Sahrens {
2617fa9e4066Sahrens 	int c;
2618fa9e4066Sahrens 	scrub_cbdata_t cb;
2619fa9e4066Sahrens 
2620fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2621fa9e4066Sahrens 
2622fa9e4066Sahrens 	/* check options */
2623fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2624fa9e4066Sahrens 		switch (c) {
2625fa9e4066Sahrens 		case 's':
2626fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2627fa9e4066Sahrens 			break;
2628fa9e4066Sahrens 		case '?':
2629fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2630fa9e4066Sahrens 			    optopt);
263199653d4eSeschrock 			usage(B_FALSE);
2632fa9e4066Sahrens 		}
2633fa9e4066Sahrens 	}
2634fa9e4066Sahrens 
263506eeb2adSek110237 	cb.cb_argc = argc;
263606eeb2adSek110237 	cb.cb_argv = argv;
2637fa9e4066Sahrens 	argc -= optind;
2638fa9e4066Sahrens 	argv += optind;
2639fa9e4066Sahrens 
2640fa9e4066Sahrens 	if (argc < 1) {
2641fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
264299653d4eSeschrock 		usage(B_FALSE);
2643fa9e4066Sahrens 	}
2644fa9e4066Sahrens 
2645b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2646fa9e4066Sahrens }
2647fa9e4066Sahrens 
2648fa9e4066Sahrens typedef struct status_cbdata {
2649fa9e4066Sahrens 	int		cb_count;
2650e9dbad6fSeschrock 	boolean_t	cb_allpools;
265199653d4eSeschrock 	boolean_t	cb_verbose;
265299653d4eSeschrock 	boolean_t	cb_explain;
265399653d4eSeschrock 	boolean_t	cb_first;
2654fa9e4066Sahrens } status_cbdata_t;
2655fa9e4066Sahrens 
2656fa9e4066Sahrens /*
2657fa9e4066Sahrens  * Print out detailed scrub status.
2658fa9e4066Sahrens  */
2659fa9e4066Sahrens void
2660fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2661fa9e4066Sahrens {
2662fa9e4066Sahrens 	vdev_stat_t *vs;
2663fa9e4066Sahrens 	uint_t vsc;
2664fa9e4066Sahrens 	time_t start, end, now;
2665fa9e4066Sahrens 	double fraction_done;
266618ce54dfSek110237 	uint64_t examined, total, minutes_left, minutes_taken;
2667fa9e4066Sahrens 	char *scrub_type;
2668fa9e4066Sahrens 
2669fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2670fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2671fa9e4066Sahrens 
2672fa9e4066Sahrens 	/*
2673fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2674fa9e4066Sahrens 	 */
2675fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2676fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2677fa9e4066Sahrens 		return;
2678fa9e4066Sahrens 	}
2679fa9e4066Sahrens 
2680fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2681fa9e4066Sahrens 	    "resilver" : "scrub";
2682fa9e4066Sahrens 
2683fa9e4066Sahrens 	start = vs->vs_scrub_start;
2684fa9e4066Sahrens 	end = vs->vs_scrub_end;
2685fa9e4066Sahrens 	now = time(NULL);
2686fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2687fa9e4066Sahrens 	total = vs->vs_alloc;
2688fa9e4066Sahrens 
2689fa9e4066Sahrens 	if (end != 0) {
269018ce54dfSek110237 		minutes_taken = (uint64_t)((end - start) / 60);
269118ce54dfSek110237 
269218ce54dfSek110237 		(void) printf(gettext("%s %s after %lluh%um with %llu errors "
269318ce54dfSek110237 		    "on %s"),
2694fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
269518ce54dfSek110237 		    (u_longlong_t)(minutes_taken / 60),
269618ce54dfSek110237 		    (uint_t)(minutes_taken % 60),
2697fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2698fa9e4066Sahrens 		return;
2699fa9e4066Sahrens 	}
2700fa9e4066Sahrens 
2701fa9e4066Sahrens 	if (examined == 0)
2702fa9e4066Sahrens 		examined = 1;
2703fa9e4066Sahrens 	if (examined > total)
2704fa9e4066Sahrens 		total = examined;
2705fa9e4066Sahrens 
2706fa9e4066Sahrens 	fraction_done = (double)examined / total;
2707fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2708fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
270918ce54dfSek110237 	minutes_taken = (uint64_t)((now - start) / 60);
2710fa9e4066Sahrens 
271118ce54dfSek110237 	(void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, "
271218ce54dfSek110237 	    "%lluh%um to go\n"),
271318ce54dfSek110237 	    scrub_type, (u_longlong_t)(minutes_taken / 60),
271418ce54dfSek110237 	    (uint_t)(minutes_taken % 60), 100 * fraction_done,
2715fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2716fa9e4066Sahrens }
2717fa9e4066Sahrens 
271899653d4eSeschrock typedef struct spare_cbdata {
271999653d4eSeschrock 	uint64_t	cb_guid;
272099653d4eSeschrock 	zpool_handle_t	*cb_zhp;
272199653d4eSeschrock } spare_cbdata_t;
272299653d4eSeschrock 
272399653d4eSeschrock static boolean_t
272499653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search)
272599653d4eSeschrock {
272699653d4eSeschrock 	uint64_t guid;
272799653d4eSeschrock 	nvlist_t **child;
272899653d4eSeschrock 	uint_t c, children;
272999653d4eSeschrock 
273099653d4eSeschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
273199653d4eSeschrock 	    search == guid)
273299653d4eSeschrock 		return (B_TRUE);
273399653d4eSeschrock 
273499653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
273599653d4eSeschrock 	    &child, &children) == 0) {
273699653d4eSeschrock 		for (c = 0; c < children; c++)
273799653d4eSeschrock 			if (find_vdev(child[c], search))
273899653d4eSeschrock 				return (B_TRUE);
273999653d4eSeschrock 	}
274099653d4eSeschrock 
274199653d4eSeschrock 	return (B_FALSE);
274299653d4eSeschrock }
274399653d4eSeschrock 
274499653d4eSeschrock static int
274599653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data)
274699653d4eSeschrock {
274799653d4eSeschrock 	spare_cbdata_t *cbp = data;
274899653d4eSeschrock 	nvlist_t *config, *nvroot;
274999653d4eSeschrock 
275099653d4eSeschrock 	config = zpool_get_config(zhp, NULL);
275199653d4eSeschrock 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
275299653d4eSeschrock 	    &nvroot) == 0);
275399653d4eSeschrock 
275499653d4eSeschrock 	if (find_vdev(nvroot, cbp->cb_guid)) {
275599653d4eSeschrock 		cbp->cb_zhp = zhp;
275699653d4eSeschrock 		return (1);
275799653d4eSeschrock 	}
275899653d4eSeschrock 
275999653d4eSeschrock 	zpool_close(zhp);
276099653d4eSeschrock 	return (0);
276199653d4eSeschrock }
276299653d4eSeschrock 
2763fa9e4066Sahrens /*
2764fa9e4066Sahrens  * Print out configuration state as requested by status_callback.
2765fa9e4066Sahrens  */
2766fa9e4066Sahrens void
2767c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
27688654d025Sperrin     int namewidth, int depth, boolean_t isspare, boolean_t print_logs)
2769fa9e4066Sahrens {
2770fa9e4066Sahrens 	nvlist_t **child;
2771fa9e4066Sahrens 	uint_t c, children;
2772fa9e4066Sahrens 	vdev_stat_t *vs;
2773ea8dc4b6Seschrock 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
2774afefbcddSeschrock 	char *vname;
2775ea8dc4b6Seschrock 	uint64_t notpresent;
277699653d4eSeschrock 	spare_cbdata_t cb;
2777990b4856Slling 	char *state;
2778fa9e4066Sahrens 
2779fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2780fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2781fa9e4066Sahrens 
2782fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2783fa9e4066Sahrens 	    &child, &children) != 0)
2784fa9e4066Sahrens 		children = 0;
2785fa9e4066Sahrens 
2786990b4856Slling 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
278799653d4eSeschrock 	if (isspare) {
278899653d4eSeschrock 		/*
278999653d4eSeschrock 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
279099653d4eSeschrock 		 * online drives.
279199653d4eSeschrock 		 */
279299653d4eSeschrock 		if (vs->vs_aux == VDEV_AUX_SPARED)
279399653d4eSeschrock 			state = "INUSE";
279499653d4eSeschrock 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
279599653d4eSeschrock 			state = "AVAIL";
279699653d4eSeschrock 	}
2797fa9e4066Sahrens 
279899653d4eSeschrock 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
279999653d4eSeschrock 	    name, state);
280099653d4eSeschrock 
280199653d4eSeschrock 	if (!isspare) {
2802fa9e4066Sahrens 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
2803fa9e4066Sahrens 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
2804fa9e4066Sahrens 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
2805fa9e4066Sahrens 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
280699653d4eSeschrock 	}
2807fa9e4066Sahrens 
2808ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2809ea8dc4b6Seschrock 	    &notpresent) == 0) {
2810ea8dc4b6Seschrock 		char *path;
2811ea8dc4b6Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
28120917b783Seschrock 		(void) printf("  was %s", path);
2813ea8dc4b6Seschrock 	} else if (vs->vs_aux != 0) {
2814fa9e4066Sahrens 		(void) printf("  ");
2815fa9e4066Sahrens 
2816fa9e4066Sahrens 		switch (vs->vs_aux) {
2817fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2818fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2819fa9e4066Sahrens 			break;
2820fa9e4066Sahrens 
2821fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2822fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2823fa9e4066Sahrens 			break;
2824fa9e4066Sahrens 
2825fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2826fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2827fa9e4066Sahrens 			break;
2828fa9e4066Sahrens 
2829eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
2830eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
2831eaca9bbdSeschrock 			break;
2832eaca9bbdSeschrock 
283399653d4eSeschrock 		case VDEV_AUX_SPARED:
283499653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
283599653d4eSeschrock 			    &cb.cb_guid) == 0);
283699653d4eSeschrock 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
283799653d4eSeschrock 				if (strcmp(zpool_get_name(cb.cb_zhp),
283899653d4eSeschrock 				    zpool_get_name(zhp)) == 0)
283999653d4eSeschrock 					(void) printf(gettext("currently in "
284099653d4eSeschrock 					    "use"));
284199653d4eSeschrock 				else
284299653d4eSeschrock 					(void) printf(gettext("in use by "
284399653d4eSeschrock 					    "pool '%s'"),
284499653d4eSeschrock 					    zpool_get_name(cb.cb_zhp));
284599653d4eSeschrock 				zpool_close(cb.cb_zhp);
284699653d4eSeschrock 			} else {
284799653d4eSeschrock 				(void) printf(gettext("currently in use"));
284899653d4eSeschrock 			}
284999653d4eSeschrock 			break;
285099653d4eSeschrock 
28513d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
28523d7072f8Seschrock 			(void) printf(gettext("too many errors"));
28533d7072f8Seschrock 			break;
28543d7072f8Seschrock 
285532b87932Sek110237 		case VDEV_AUX_IO_FAILURE:
285632b87932Sek110237 			(void) printf(gettext("experienced I/O failures"));
285732b87932Sek110237 			break;
285832b87932Sek110237 
2859b87f3af3Sperrin 		case VDEV_AUX_BAD_LOG:
2860b87f3af3Sperrin 			(void) printf(gettext("bad intent log"));
2861b87f3af3Sperrin 			break;
2862b87f3af3Sperrin 
2863fa9e4066Sahrens 		default:
2864fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2865fa9e4066Sahrens 			break;
2866fa9e4066Sahrens 		}
2867fa9e4066Sahrens 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2868fa9e4066Sahrens 		/*
2869fa9e4066Sahrens 		 * Report bytes resilvered/repaired on leaf devices.
2870fa9e4066Sahrens 		 */
2871fa9e4066Sahrens 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2872fa9e4066Sahrens 		(void) printf(gettext("  %s %s"), repaired,
2873fa9e4066Sahrens 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2874fa9e4066Sahrens 		    "resilvered" : "repaired");
2875fa9e4066Sahrens 	}
2876fa9e4066Sahrens 
2877fa9e4066Sahrens 	(void) printf("\n");
2878fa9e4066Sahrens 
2879afefbcddSeschrock 	for (c = 0; c < children; c++) {
28808654d025Sperrin 		uint64_t is_log = B_FALSE;
28818654d025Sperrin 
28828654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
28838654d025Sperrin 		    &is_log);
28848654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
28858654d025Sperrin 			continue;
288699653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
2887c67d9675Seschrock 		print_status_config(zhp, vname, child[c],
28888654d025Sperrin 		    namewidth, depth + 2, isspare, B_FALSE);
2889afefbcddSeschrock 		free(vname);
2890afefbcddSeschrock 	}
2891fa9e4066Sahrens }
2892fa9e4066Sahrens 
2893ea8dc4b6Seschrock static void
2894ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
2895ea8dc4b6Seschrock {
289675519f38Sek110237 	nvlist_t *nverrlist = NULL;
289755434c77Sek110237 	nvpair_t *elem;
289855434c77Sek110237 	char *pathname;
289955434c77Sek110237 	size_t len = MAXPATHLEN * 2;
2900ea8dc4b6Seschrock 
290155434c77Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2902ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
2903ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
2904ea8dc4b6Seschrock 		return;
2905ea8dc4b6Seschrock 	}
2906ea8dc4b6Seschrock 
290755434c77Sek110237 	(void) printf("errors: Permanent errors have been "
290855434c77Sek110237 	    "detected in the following files:\n\n");
2909ea8dc4b6Seschrock 
291055434c77Sek110237 	pathname = safe_malloc(len);
291155434c77Sek110237 	elem = NULL;
291255434c77Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
291355434c77Sek110237 		nvlist_t *nv;
291455434c77Sek110237 		uint64_t dsobj, obj;
2915ea8dc4b6Seschrock 
291655434c77Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
291755434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
291855434c77Sek110237 		    &dsobj) == 0);
291955434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
292055434c77Sek110237 		    &obj) == 0);
292155434c77Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
292255434c77Sek110237 		(void) printf("%7s %s\n", "", pathname);
2923ea8dc4b6Seschrock 	}
292455434c77Sek110237 	free(pathname);
292555434c77Sek110237 	nvlist_free(nverrlist);
2926ea8dc4b6Seschrock }
2927ea8dc4b6Seschrock 
292899653d4eSeschrock static void
292999653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
293099653d4eSeschrock     int namewidth)
293199653d4eSeschrock {
293299653d4eSeschrock 	uint_t i;
293399653d4eSeschrock 	char *name;
293499653d4eSeschrock 
293599653d4eSeschrock 	if (nspares == 0)
293699653d4eSeschrock 		return;
293799653d4eSeschrock 
293899653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
293999653d4eSeschrock 
294099653d4eSeschrock 	for (i = 0; i < nspares; i++) {
294199653d4eSeschrock 		name = zpool_vdev_name(g_zfs, zhp, spares[i]);
294299653d4eSeschrock 		print_status_config(zhp, name, spares[i],
29438654d025Sperrin 		    namewidth, 2, B_TRUE, B_FALSE);
294499653d4eSeschrock 		free(name);
294599653d4eSeschrock 	}
294699653d4eSeschrock }
294799653d4eSeschrock 
2948fa94a07fSbrendan static void
2949fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
2950fa94a07fSbrendan     int namewidth)
2951fa94a07fSbrendan {
2952fa94a07fSbrendan 	uint_t i;
2953fa94a07fSbrendan 	char *name;
2954fa94a07fSbrendan 
2955fa94a07fSbrendan 	if (nl2cache == 0)
2956fa94a07fSbrendan 		return;
2957fa94a07fSbrendan 
2958fa94a07fSbrendan 	(void) printf(gettext("\tcache\n"));
2959fa94a07fSbrendan 
2960fa94a07fSbrendan 	for (i = 0; i < nl2cache; i++) {
2961fa94a07fSbrendan 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i]);
2962fa94a07fSbrendan 		print_status_config(zhp, name, l2cache[i],
2963fa94a07fSbrendan 		    namewidth, 2, B_FALSE, B_FALSE);
2964fa94a07fSbrendan 		free(name);
2965fa94a07fSbrendan 	}
2966fa94a07fSbrendan }
2967fa94a07fSbrendan 
2968fa9e4066Sahrens /*
2969fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
2970fa9e4066Sahrens  *
2971fa9e4066Sahrens  *        pool: tank
2972fa9e4066Sahrens  *	status: DEGRADED
2973fa9e4066Sahrens  *	reason: One or more devices ...
2974fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
2975fa9e4066Sahrens  *	config:
2976fa9e4066Sahrens  *		mirror		DEGRADED
2977fa9e4066Sahrens  *                c1t0d0	OK
2978ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
2979fa9e4066Sahrens  *
2980fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
2981fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
2982fa9e4066Sahrens  */
2983fa9e4066Sahrens int
2984fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
2985fa9e4066Sahrens {
2986fa9e4066Sahrens 	status_cbdata_t *cbp = data;
2987fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2988fa9e4066Sahrens 	char *msgid;
2989fa9e4066Sahrens 	int reason;
299046657f8dSmmusante 	const char *health;
299146657f8dSmmusante 	uint_t c;
299246657f8dSmmusante 	vdev_stat_t *vs;
2993fa9e4066Sahrens 
2994088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
2995fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
2996fa9e4066Sahrens 
2997fa9e4066Sahrens 	cbp->cb_count++;
2998fa9e4066Sahrens 
2999fa9e4066Sahrens 	/*
3000fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
3001fa9e4066Sahrens 	 * problems.
3002fa9e4066Sahrens 	 */
3003e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
3004e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
3005e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
3006e9dbad6fSeschrock 			    zpool_get_name(zhp));
3007e9dbad6fSeschrock 			if (cbp->cb_first)
3008e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
3009e9dbad6fSeschrock 		}
3010fa9e4066Sahrens 		return (0);
3011e9dbad6fSeschrock 	}
3012fa9e4066Sahrens 
3013fa9e4066Sahrens 	if (cbp->cb_first)
301499653d4eSeschrock 		cbp->cb_first = B_FALSE;
3015fa9e4066Sahrens 	else
3016fa9e4066Sahrens 		(void) printf("\n");
3017fa9e4066Sahrens 
301846657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
301946657f8dSmmusante 	    &nvroot) == 0);
302046657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
302146657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
3022990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3023fa9e4066Sahrens 
3024fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
3025fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
3026fa9e4066Sahrens 
3027fa9e4066Sahrens 	switch (reason) {
3028fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
3029fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3030fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
3031fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
3032fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3033fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3034fa9e4066Sahrens 		break;
3035fa9e4066Sahrens 
3036fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
3037fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3038fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
3039fa9e4066Sahrens 		    "pool to continue functioning.\n"));
3040fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3041fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3042fa9e4066Sahrens 		break;
3043fa9e4066Sahrens 
3044fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
3045fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3046fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
3047fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
3048fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
3049fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
3050fa9e4066Sahrens 		    "'zpool replace'.\n"));
3051fa9e4066Sahrens 		break;
3052fa9e4066Sahrens 
3053fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3054fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3055b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
3056fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
3057fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
3058fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
3059fa9e4066Sahrens 		    "from a backup source.\n"));
3060fa9e4066Sahrens 		break;
3061fa9e4066Sahrens 
3062fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
3063fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3064fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
3065fa9e4066Sahrens 		    "made to correct the error.  Applications are "
3066fa9e4066Sahrens 		    "unaffected.\n"));
3067fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
3068fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
3069ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
3070fa9e4066Sahrens 		    "replace'.\n"));
3071fa9e4066Sahrens 		break;
3072fa9e4066Sahrens 
3073fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
3074fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3075d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
3076fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
3077fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
3078fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
3079fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
3080fa9e4066Sahrens 		    "replace'.\n"));
3081fa9e4066Sahrens 		break;
3082fa9e4066Sahrens 
3083fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
3084fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
3085fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3086fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
3087fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3088fa9e4066Sahrens 		    "complete.\n"));
3089fa9e4066Sahrens 		break;
3090fa9e4066Sahrens 
3091ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3092ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3093ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3094ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3095ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3096ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3097ea8dc4b6Seschrock 		    "backup.\n"));
3098ea8dc4b6Seschrock 		break;
3099ea8dc4b6Seschrock 
3100ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3101ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3102ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3103ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
3104ea8dc4b6Seschrock 		    "from a backup source.\n"));
3105ea8dc4b6Seschrock 		break;
3106ea8dc4b6Seschrock 
3107eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3108eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3109eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3110eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3111eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3112eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3113eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3114eaca9bbdSeschrock 		break;
3115eaca9bbdSeschrock 
3116eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3117eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3118eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3119eaca9bbdSeschrock 		    "be accessed on this system.\n"));
3120eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
3121eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
3122eaca9bbdSeschrock 		    "backup.\n"));
3123eaca9bbdSeschrock 		break;
3124eaca9bbdSeschrock 
31253d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
31263d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
31273d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
31283d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
31293d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
31303d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
31313d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
31323d7072f8Seschrock 		break;
31333d7072f8Seschrock 
31343d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
31353d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
31363d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
31373d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
31383d7072f8Seschrock 		    "functioning.\n"));
31393d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
31403d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
31413d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
31423d7072f8Seschrock 		    "to be recovered.\n"));
31433d7072f8Seschrock 		break;
31443d7072f8Seschrock 
314532b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_WAIT:
314632b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
314732b87932Sek110237 		(void) printf(gettext("status: One or more devices are "
31488a79c1b5Sek110237 		    "faulted in response to IO failures.\n"));
314932b87932Sek110237 		(void) printf(gettext("action: Make sure the affected devices "
315032b87932Sek110237 		    "are connected, then run 'zpool clear'.\n"));
315132b87932Sek110237 		break;
315232b87932Sek110237 
3153b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
3154b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record "
3155b87f3af3Sperrin 		    "could not be read.\n"
3156b87f3af3Sperrin 		    "\tWaiting for adminstrator intervention to fix the "
3157b87f3af3Sperrin 		    "faulted pool.\n"));
3158b87f3af3Sperrin 		(void) printf(gettext("action: Either restore the affected "
3159b87f3af3Sperrin 		    "device(s) and run 'zpool online',\n"
3160b87f3af3Sperrin 		    "\tor ignore the intent log records by running "
3161b87f3af3Sperrin 		    "'zpool clear'.\n"));
3162b87f3af3Sperrin 		break;
3163b87f3af3Sperrin 
3164fa9e4066Sahrens 	default:
3165fa9e4066Sahrens 		/*
3166fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
3167fa9e4066Sahrens 		 */
3168fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
3169fa9e4066Sahrens 	}
3170fa9e4066Sahrens 
3171fa9e4066Sahrens 	if (msgid != NULL)
3172fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3173fa9e4066Sahrens 		    msgid);
3174fa9e4066Sahrens 
3175fa9e4066Sahrens 	if (config != NULL) {
3176fa9e4066Sahrens 		int namewidth;
3177ea8dc4b6Seschrock 		uint64_t nerr;
3178fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
3179fa94a07fSbrendan 		uint_t nspares, nl2cache;
3180fa9e4066Sahrens 
3181fa9e4066Sahrens 
3182fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
3183fa9e4066Sahrens 		print_scrub_status(nvroot);
3184fa9e4066Sahrens 
3185c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3186fa9e4066Sahrens 		if (namewidth < 10)
3187fa9e4066Sahrens 			namewidth = 10;
3188fa9e4066Sahrens 
3189fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
3190fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3191fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3192c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
31938654d025Sperrin 		    namewidth, 0, B_FALSE, B_FALSE);
31948654d025Sperrin 		if (num_logs(nvroot) > 0)
31958654d025Sperrin 			print_status_config(zhp, "logs", nvroot, namewidth, 0,
31968654d025Sperrin 			    B_FALSE, B_TRUE);
319799653d4eSeschrock 
3198fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
3199fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
3200fa94a07fSbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
3201fa94a07fSbrendan 
320299653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
320399653d4eSeschrock 		    &spares, &nspares) == 0)
320499653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
3205ea8dc4b6Seschrock 
3206ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3207ea8dc4b6Seschrock 		    &nerr) == 0) {
320855434c77Sek110237 			nvlist_t *nverrlist = NULL;
320955434c77Sek110237 
3210ea8dc4b6Seschrock 			/*
3211ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3212ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3213ea8dc4b6Seschrock 			 * uniquifying the results.
3214ea8dc4b6Seschrock 			 */
321575519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
321655434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
321755434c77Sek110237 				nvpair_t *elem;
321855434c77Sek110237 
321955434c77Sek110237 				elem = NULL;
322055434c77Sek110237 				nerr = 0;
322155434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
322255434c77Sek110237 				    elem)) != NULL) {
322355434c77Sek110237 					nerr++;
322455434c77Sek110237 				}
322555434c77Sek110237 			}
322655434c77Sek110237 			nvlist_free(nverrlist);
3227ea8dc4b6Seschrock 
3228ea8dc4b6Seschrock 			(void) printf("\n");
322999653d4eSeschrock 
3230ea8dc4b6Seschrock 			if (nerr == 0)
3231ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3232ea8dc4b6Seschrock 				    "errors\n"));
3233ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3234e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
32355ad82045Snd150628 				    "errors, use '-v' for a list\n"),
32365ad82045Snd150628 				    (u_longlong_t)nerr);
3237ea8dc4b6Seschrock 			else
3238ea8dc4b6Seschrock 				print_error_log(zhp);
3239ea8dc4b6Seschrock 		}
3240fa9e4066Sahrens 	} else {
3241fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3242fa9e4066Sahrens 		    "determined.\n"));
3243fa9e4066Sahrens 	}
3244fa9e4066Sahrens 
3245fa9e4066Sahrens 	return (0);
3246fa9e4066Sahrens }
3247fa9e4066Sahrens 
3248fa9e4066Sahrens /*
3249fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3250fa9e4066Sahrens  *
3251fa9e4066Sahrens  *	-v	Display complete error logs
3252fa9e4066Sahrens  *	-x	Display only pools with potential problems
3253fa9e4066Sahrens  *
3254fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3255fa9e4066Sahrens  */
3256fa9e4066Sahrens int
3257fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3258fa9e4066Sahrens {
3259fa9e4066Sahrens 	int c;
3260fa9e4066Sahrens 	int ret;
3261fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3262fa9e4066Sahrens 
3263fa9e4066Sahrens 	/* check options */
3264fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3265fa9e4066Sahrens 		switch (c) {
3266fa9e4066Sahrens 		case 'v':
326799653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3268fa9e4066Sahrens 			break;
3269fa9e4066Sahrens 		case 'x':
327099653d4eSeschrock 			cb.cb_explain = B_TRUE;
3271fa9e4066Sahrens 			break;
3272fa9e4066Sahrens 		case '?':
3273fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3274fa9e4066Sahrens 			    optopt);
327599653d4eSeschrock 			usage(B_FALSE);
3276fa9e4066Sahrens 		}
3277fa9e4066Sahrens 	}
3278fa9e4066Sahrens 
3279fa9e4066Sahrens 	argc -= optind;
3280fa9e4066Sahrens 	argv += optind;
3281fa9e4066Sahrens 
328299653d4eSeschrock 	cb.cb_first = B_TRUE;
3283fa9e4066Sahrens 
3284e9dbad6fSeschrock 	if (argc == 0)
3285e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3286e9dbad6fSeschrock 
3287b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3288fa9e4066Sahrens 
3289fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3290fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3291e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3292fa9e4066Sahrens 		(void) printf(gettext("all pools are healthy\n"));
3293fa9e4066Sahrens 
3294fa9e4066Sahrens 	return (ret);
3295fa9e4066Sahrens }
3296fa9e4066Sahrens 
3297eaca9bbdSeschrock typedef struct upgrade_cbdata {
3298eaca9bbdSeschrock 	int	cb_all;
3299eaca9bbdSeschrock 	int	cb_first;
3300eaca9bbdSeschrock 	int	cb_newer;
330106eeb2adSek110237 	int	cb_argc;
3302990b4856Slling 	uint64_t cb_version;
330306eeb2adSek110237 	char	**cb_argv;
3304eaca9bbdSeschrock } upgrade_cbdata_t;
3305eaca9bbdSeschrock 
3306eaca9bbdSeschrock static int
3307eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3308eaca9bbdSeschrock {
3309eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3310eaca9bbdSeschrock 	nvlist_t *config;
3311eaca9bbdSeschrock 	uint64_t version;
3312eaca9bbdSeschrock 	int ret = 0;
3313eaca9bbdSeschrock 
3314eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3315eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3316eaca9bbdSeschrock 	    &version) == 0);
3317eaca9bbdSeschrock 
3318e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3319eaca9bbdSeschrock 		if (!cbp->cb_all) {
3320eaca9bbdSeschrock 			if (cbp->cb_first) {
3321eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3322eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3323eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3324eaca9bbdSeschrock 				    "longer be accessible by older software "
3325eaca9bbdSeschrock 				    "versions.\n\n"));
3326eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3327eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
332899653d4eSeschrock 				cbp->cb_first = B_FALSE;
3329eaca9bbdSeschrock 			}
3330eaca9bbdSeschrock 
33315ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3332eaca9bbdSeschrock 			    zpool_get_name(zhp));
3333eaca9bbdSeschrock 		} else {
333499653d4eSeschrock 			cbp->cb_first = B_FALSE;
3335990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
333606eeb2adSek110237 			if (!ret) {
3337eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3338990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
3339eaca9bbdSeschrock 			}
334006eeb2adSek110237 		}
3341e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3342eaca9bbdSeschrock 		assert(!cbp->cb_all);
3343eaca9bbdSeschrock 
3344eaca9bbdSeschrock 		if (cbp->cb_first) {
3345eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3346eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3347eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3348eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3349eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
335099653d4eSeschrock 			cbp->cb_first = B_FALSE;
3351eaca9bbdSeschrock 		}
3352eaca9bbdSeschrock 
33535ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3354eaca9bbdSeschrock 		    zpool_get_name(zhp));
3355eaca9bbdSeschrock 	}
3356eaca9bbdSeschrock 
3357eaca9bbdSeschrock 	zpool_close(zhp);
3358eaca9bbdSeschrock 	return (ret);
3359eaca9bbdSeschrock }
3360eaca9bbdSeschrock 
3361eaca9bbdSeschrock /* ARGSUSED */
3362eaca9bbdSeschrock static int
336306eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
3364eaca9bbdSeschrock {
3365990b4856Slling 	upgrade_cbdata_t *cbp = data;
3366990b4856Slling 	uint64_t cur_version;
3367eaca9bbdSeschrock 	int ret;
3368eaca9bbdSeschrock 
33698654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
33708654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
33718654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
33728654d025Sperrin 		    " to upgrade.\n"));
33738654d025Sperrin 		return (1);
33748654d025Sperrin 	}
3375990b4856Slling 
3376990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3377e6c728e1Sbrendan 	if (cur_version > cbp->cb_version) {
3378eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3379e6c728e1Sbrendan 		    "using more current version '%llu'.\n"),
3380e6c728e1Sbrendan 		    zpool_get_name(zhp), cur_version);
3381e6c728e1Sbrendan 		return (0);
3382e6c728e1Sbrendan 	}
3383e6c728e1Sbrendan 	if (cur_version == cbp->cb_version) {
3384e6c728e1Sbrendan 		(void) printf(gettext("Pool '%s' is already formatted "
3385e6c728e1Sbrendan 		    "using the current version.\n"), zpool_get_name(zhp));
3386eaca9bbdSeschrock 		return (0);
3387eaca9bbdSeschrock 	}
3388eaca9bbdSeschrock 
3389990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
339006eeb2adSek110237 
339106eeb2adSek110237 	if (!ret) {
339244cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
3393990b4856Slling 		    "from version %llu to version %llu\n\n"),
3394990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3395990b4856Slling 		    (u_longlong_t)cbp->cb_version);
339606eeb2adSek110237 	}
3397eaca9bbdSeschrock 
3398eaca9bbdSeschrock 	return (ret != 0);
3399eaca9bbdSeschrock }
3400eaca9bbdSeschrock 
3401eaca9bbdSeschrock /*
3402eaca9bbdSeschrock  * zpool upgrade
3403eaca9bbdSeschrock  * zpool upgrade -v
3404990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
3405eaca9bbdSeschrock  *
3406eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3407eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3408eaca9bbdSeschrock  * upgrade all pools.
3409eaca9bbdSeschrock  */
3410eaca9bbdSeschrock int
3411eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3412eaca9bbdSeschrock {
3413eaca9bbdSeschrock 	int c;
3414eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3415eaca9bbdSeschrock 	int ret = 0;
3416eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3417990b4856Slling 	char *end;
3418990b4856Slling 
3419eaca9bbdSeschrock 
3420eaca9bbdSeschrock 	/* check options */
3421990b4856Slling 	while ((c = getopt(argc, argv, "avV:")) != -1) {
3422eaca9bbdSeschrock 		switch (c) {
3423eaca9bbdSeschrock 		case 'a':
342499653d4eSeschrock 			cb.cb_all = B_TRUE;
3425eaca9bbdSeschrock 			break;
3426eaca9bbdSeschrock 		case 'v':
3427eaca9bbdSeschrock 			showversions = B_TRUE;
3428eaca9bbdSeschrock 			break;
3429990b4856Slling 		case 'V':
3430990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
3431351420b3Slling 			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
3432351420b3Slling 			    cb.cb_version < SPA_VERSION_1) {
3433990b4856Slling 				(void) fprintf(stderr,
3434990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
3435990b4856Slling 				usage(B_FALSE);
3436990b4856Slling 			}
3437990b4856Slling 			break;
3438eaca9bbdSeschrock 		case '?':
3439eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3440eaca9bbdSeschrock 			    optopt);
344199653d4eSeschrock 			usage(B_FALSE);
3442eaca9bbdSeschrock 		}
3443eaca9bbdSeschrock 	}
3444eaca9bbdSeschrock 
344506eeb2adSek110237 	cb.cb_argc = argc;
344606eeb2adSek110237 	cb.cb_argv = argv;
3447eaca9bbdSeschrock 	argc -= optind;
3448eaca9bbdSeschrock 	argv += optind;
3449eaca9bbdSeschrock 
3450351420b3Slling 	if (cb.cb_version == 0) {
3451351420b3Slling 		cb.cb_version = SPA_VERSION;
3452351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
3453351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
3454351420b3Slling 		    "incompatible with other arguments\n"));
3455351420b3Slling 		usage(B_FALSE);
3456351420b3Slling 	}
3457351420b3Slling 
3458eaca9bbdSeschrock 	if (showversions) {
3459eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3460eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3461eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
346299653d4eSeschrock 			usage(B_FALSE);
3463eaca9bbdSeschrock 		}
3464eaca9bbdSeschrock 	} else if (cb.cb_all) {
3465eaca9bbdSeschrock 		if (argc != 0) {
3466351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
3467351420b3Slling 			    "be used along with a pool name\n"));
346899653d4eSeschrock 			usage(B_FALSE);
3469eaca9bbdSeschrock 		}
3470eaca9bbdSeschrock 	}
3471eaca9bbdSeschrock 
3472e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3473e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
347499653d4eSeschrock 	cb.cb_first = B_TRUE;
3475eaca9bbdSeschrock 	if (showversions) {
3476eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3477d7d4af51Smmusante 		    "supported:\n\n"));
3478eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3479eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3480eaca9bbdSeschrock 		    "---------------\n");
348199653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
348244cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
348344cd46caSbillm 		    "(replicated metadata)\n"));
348499653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
348599653d4eSeschrock 		    "RAID-Z\n"));
3486d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
3487c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3488c9431fa1Sahl 		    "algorithm\n"));
3489990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
34908654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3491ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
3492a9799022Sck153898 		(void) printf(gettext(" 9   refquota and refreservation "
3493a9799022Sck153898 		    "properties\n"));
3494fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
3495088f3894Sahrens 		(void) printf(gettext(" 11  Improved scrub performance\n"));
3496bb0ade09Sahrens 		(void) printf(gettext(" 12  Snapshot properties\n"));
349774e7dc98SMatthew Ahrens 		(void) printf(gettext(" 13  snapused property\n"));
3498d0f3f37eSMark Shellenbaum 		(void) printf(gettext(" 14  passthrough-x aclinherit "
3499d0f3f37eSMark Shellenbaum 		    "support\n"));
35008654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3501eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3502eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3503eaca9bbdSeschrock 		    "version/N\n\n");
3504eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3505eaca9bbdSeschrock 	} else if (argc == 0) {
3506eaca9bbdSeschrock 		int notfound;
3507eaca9bbdSeschrock 
350899653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3509eaca9bbdSeschrock 		notfound = cb.cb_first;
3510eaca9bbdSeschrock 
3511eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3512eaca9bbdSeschrock 			if (!cb.cb_first)
3513eaca9bbdSeschrock 				(void) printf("\n");
3514eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3515eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
351699653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3517eaca9bbdSeschrock 			if (!cb.cb_first) {
3518eaca9bbdSeschrock 				notfound = B_FALSE;
3519eaca9bbdSeschrock 				(void) printf("\n");
3520eaca9bbdSeschrock 			}
3521eaca9bbdSeschrock 		}
3522eaca9bbdSeschrock 
3523eaca9bbdSeschrock 		if (ret == 0) {
3524eaca9bbdSeschrock 			if (notfound)
3525eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3526eaca9bbdSeschrock 				    "using this version.\n"));
3527eaca9bbdSeschrock 			else if (!cb.cb_all)
3528eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3529eaca9bbdSeschrock 				    "for a list of available versions and "
3530eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3531eaca9bbdSeschrock 		}
3532eaca9bbdSeschrock 	} else {
3533b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3534b1b8ab34Slling 		    upgrade_one, &cb);
353506eeb2adSek110237 	}
353606eeb2adSek110237 
353706eeb2adSek110237 	return (ret);
353806eeb2adSek110237 }
353906eeb2adSek110237 
3540ecd6cf80Smarks typedef struct hist_cbdata {
3541ecd6cf80Smarks 	boolean_t first;
3542ecd6cf80Smarks 	int longfmt;
3543ecd6cf80Smarks 	int internal;
3544ecd6cf80Smarks } hist_cbdata_t;
3545ecd6cf80Smarks 
3546ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3547ecd6cf80Smarks 	"invalid event",
3548ecd6cf80Smarks 	"pool create",
3549ecd6cf80Smarks 	"vdev add",
3550ecd6cf80Smarks 	"pool remove",
3551ecd6cf80Smarks 	"pool destroy",
3552ecd6cf80Smarks 	"pool export",
3553ecd6cf80Smarks 	"pool import",
3554ecd6cf80Smarks 	"vdev attach",
3555ecd6cf80Smarks 	"vdev replace",
3556ecd6cf80Smarks 	"vdev detach",
3557ecd6cf80Smarks 	"vdev online",
3558ecd6cf80Smarks 	"vdev offline",
3559ecd6cf80Smarks 	"vdev upgrade",
3560ecd6cf80Smarks 	"pool clear",
3561ecd6cf80Smarks 	"pool scrub",
3562ecd6cf80Smarks 	"pool property set",
3563ecd6cf80Smarks 	"create",
3564ecd6cf80Smarks 	"clone",
3565ecd6cf80Smarks 	"destroy",
3566ecd6cf80Smarks 	"destroy_begin_sync",
3567ecd6cf80Smarks 	"inherit",
3568ecd6cf80Smarks 	"property set",
3569ecd6cf80Smarks 	"quota set",
3570ecd6cf80Smarks 	"permission update",
3571ecd6cf80Smarks 	"permission remove",
3572ecd6cf80Smarks 	"permission who remove",
3573ecd6cf80Smarks 	"promote",
3574ecd6cf80Smarks 	"receive",
3575ecd6cf80Smarks 	"rename",
3576ecd6cf80Smarks 	"reservation set",
3577ecd6cf80Smarks 	"replay_inc_sync",
3578ecd6cf80Smarks 	"replay_full_sync",
3579ecd6cf80Smarks 	"rollback",
3580ecd6cf80Smarks 	"snapshot",
3581e7437265Sahrens 	"filesystem version upgrade",
3582a9799022Sck153898 	"refquota set",
3583a9799022Sck153898 	"refreservation set",
3584088f3894Sahrens 	"pool scrub done",
3585ecd6cf80Smarks };
3586ecd6cf80Smarks 
358706eeb2adSek110237 /*
358806eeb2adSek110237  * Print out the command history for a specific pool.
358906eeb2adSek110237  */
359006eeb2adSek110237 static int
359106eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
359206eeb2adSek110237 {
359306eeb2adSek110237 	nvlist_t *nvhis;
359406eeb2adSek110237 	nvlist_t **records;
359506eeb2adSek110237 	uint_t numrecords;
359606eeb2adSek110237 	char *cmdstr;
3597ecd6cf80Smarks 	char *pathstr;
359806eeb2adSek110237 	uint64_t dst_time;
359906eeb2adSek110237 	time_t tsec;
360006eeb2adSek110237 	struct tm t;
360106eeb2adSek110237 	char tbuf[30];
360206eeb2adSek110237 	int ret, i;
3603ecd6cf80Smarks 	uint64_t who;
3604ecd6cf80Smarks 	struct passwd *pwd;
3605ecd6cf80Smarks 	char *hostname;
3606ecd6cf80Smarks 	char *zonename;
3607ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3608ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3609ecd6cf80Smarks 	uint64_t txg;
3610ecd6cf80Smarks 	uint64_t ievent;
361106eeb2adSek110237 
3612ecd6cf80Smarks 	cb->first = B_FALSE;
361306eeb2adSek110237 
361406eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
361506eeb2adSek110237 
361606eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
361706eeb2adSek110237 		return (ret);
361806eeb2adSek110237 
361906eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
362006eeb2adSek110237 	    &records, &numrecords) == 0);
362106eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
362206eeb2adSek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3623ecd6cf80Smarks 		    &dst_time) != 0)
3624ecd6cf80Smarks 			continue;
3625ecd6cf80Smarks 
3626ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3627ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3628ecd6cf80Smarks 		    &cmdstr) != 0) {
3629ecd6cf80Smarks 			if (cb->internal == 0)
3630ecd6cf80Smarks 				continue;
3631ecd6cf80Smarks 
3632ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3633ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3634ecd6cf80Smarks 				continue;
3635ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3636ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3637ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3638ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3639088f3894Sahrens 			if (ievent >= LOG_END)
3640ecd6cf80Smarks 				continue;
3641ecd6cf80Smarks 			(void) snprintf(internalstr,
3642ecd6cf80Smarks 			    sizeof (internalstr),
3643ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3644ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3645ecd6cf80Smarks 			    pathstr);
3646ecd6cf80Smarks 			cmdstr = internalstr;
3647ecd6cf80Smarks 		}
364806eeb2adSek110237 		tsec = dst_time;
364906eeb2adSek110237 		(void) localtime_r(&tsec, &t);
365006eeb2adSek110237 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3651ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3652ecd6cf80Smarks 
3653ecd6cf80Smarks 		if (!cb->longfmt) {
3654ecd6cf80Smarks 			(void) printf("\n");
3655ecd6cf80Smarks 			continue;
365606eeb2adSek110237 		}
3657ecd6cf80Smarks 		(void) printf(" [");
3658ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3659ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3660ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3661ecd6cf80Smarks 			if (pwd)
3662ecd6cf80Smarks 				(void) printf("user %s on",
3663ecd6cf80Smarks 				    pwd->pw_name);
3664ecd6cf80Smarks 			else
3665ecd6cf80Smarks 				(void) printf("user %d on",
3666ecd6cf80Smarks 				    (int)who);
3667ecd6cf80Smarks 		} else {
3668ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3669ecd6cf80Smarks 			continue;
3670ecd6cf80Smarks 		}
3671ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3672ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3673ecd6cf80Smarks 			(void) printf(" %s", hostname);
3674ecd6cf80Smarks 		}
3675ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3676ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3677ecd6cf80Smarks 			(void) printf(":%s", zonename);
3678ecd6cf80Smarks 		}
3679ecd6cf80Smarks 
3680ecd6cf80Smarks 		(void) printf("]");
3681ecd6cf80Smarks 		(void) printf("\n");
368206eeb2adSek110237 	}
368306eeb2adSek110237 	(void) printf("\n");
368406eeb2adSek110237 	nvlist_free(nvhis);
368506eeb2adSek110237 
368606eeb2adSek110237 	return (ret);
368706eeb2adSek110237 }
368806eeb2adSek110237 
368906eeb2adSek110237 /*
369006eeb2adSek110237  * zpool history <pool>
369106eeb2adSek110237  *
369206eeb2adSek110237  * Displays the history of commands that modified pools.
369306eeb2adSek110237  */
3694ecd6cf80Smarks 
3695ecd6cf80Smarks 
369606eeb2adSek110237 int
369706eeb2adSek110237 zpool_do_history(int argc, char **argv)
369806eeb2adSek110237 {
3699ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
370006eeb2adSek110237 	int ret;
3701ecd6cf80Smarks 	int c;
370206eeb2adSek110237 
3703ecd6cf80Smarks 	cbdata.first = B_TRUE;
3704ecd6cf80Smarks 	/* check options */
3705ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3706ecd6cf80Smarks 		switch (c) {
3707ecd6cf80Smarks 		case 'l':
3708ecd6cf80Smarks 			cbdata.longfmt = 1;
3709ecd6cf80Smarks 			break;
3710ecd6cf80Smarks 		case 'i':
3711ecd6cf80Smarks 			cbdata.internal = 1;
3712ecd6cf80Smarks 			break;
3713ecd6cf80Smarks 		case '?':
3714ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3715ecd6cf80Smarks 			    optopt);
3716ecd6cf80Smarks 			usage(B_FALSE);
3717ecd6cf80Smarks 		}
3718ecd6cf80Smarks 	}
371906eeb2adSek110237 	argc -= optind;
372006eeb2adSek110237 	argv += optind;
372106eeb2adSek110237 
3722b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3723ecd6cf80Smarks 	    &cbdata);
372406eeb2adSek110237 
3725ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
372606eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
372706eeb2adSek110237 		return (0);
3728eaca9bbdSeschrock 	}
3729eaca9bbdSeschrock 
3730eaca9bbdSeschrock 	return (ret);
3731eaca9bbdSeschrock }
3732eaca9bbdSeschrock 
3733b1b8ab34Slling static int
3734b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3735b1b8ab34Slling {
3736990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3737b1b8ab34Slling 	char value[MAXNAMELEN];
3738990b4856Slling 	zprop_source_t srctype;
3739990b4856Slling 	zprop_list_t *pl;
3740b1b8ab34Slling 
3741b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3742b1b8ab34Slling 
3743b1b8ab34Slling 		/*
3744990b4856Slling 		 * Skip the special fake placeholder. This will also skip
3745990b4856Slling 		 * over the name property when 'all' is specified.
3746b1b8ab34Slling 		 */
3747990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3748b1b8ab34Slling 		    pl == cbp->cb_proplist)
3749b1b8ab34Slling 			continue;
3750b1b8ab34Slling 
3751b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3752b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3753b1b8ab34Slling 			continue;
3754b1b8ab34Slling 
3755990b4856Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
3756b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3757b1b8ab34Slling 	}
3758b1b8ab34Slling 	return (0);
3759b1b8ab34Slling }
3760b1b8ab34Slling 
3761b1b8ab34Slling int
3762b1b8ab34Slling zpool_do_get(int argc, char **argv)
3763b1b8ab34Slling {
3764990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
3765990b4856Slling 	zprop_list_t fake_name = { 0 };
3766b1b8ab34Slling 	int ret;
3767b1b8ab34Slling 
3768b1b8ab34Slling 	if (argc < 3)
3769b1b8ab34Slling 		usage(B_FALSE);
3770b1b8ab34Slling 
3771b1b8ab34Slling 	cb.cb_first = B_TRUE;
3772990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
3773b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3774b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3775b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3776b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3777990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
3778b1b8ab34Slling 
3779990b4856Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3780990b4856Slling 	    ZFS_TYPE_POOL) != 0)
3781b1b8ab34Slling 		usage(B_FALSE);
3782b1b8ab34Slling 
3783b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3784990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
3785b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3786b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3787b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3788b1b8ab34Slling 	}
3789b1b8ab34Slling 
3790b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3791b1b8ab34Slling 	    get_callback, &cb);
3792b1b8ab34Slling 
3793b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3794990b4856Slling 		zprop_free_list(fake_name.pl_next);
3795b1b8ab34Slling 	else
3796990b4856Slling 		zprop_free_list(cb.cb_proplist);
3797b1b8ab34Slling 
3798b1b8ab34Slling 	return (ret);
3799b1b8ab34Slling }
3800b1b8ab34Slling 
3801b1b8ab34Slling typedef struct set_cbdata {
3802b1b8ab34Slling 	char *cb_propname;
3803b1b8ab34Slling 	char *cb_value;
3804b1b8ab34Slling 	boolean_t cb_any_successful;
3805b1b8ab34Slling } set_cbdata_t;
3806b1b8ab34Slling 
3807b1b8ab34Slling int
3808b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3809b1b8ab34Slling {
3810b1b8ab34Slling 	int error;
3811b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3812b1b8ab34Slling 
3813b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3814b1b8ab34Slling 
3815b1b8ab34Slling 	if (!error)
3816b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3817b1b8ab34Slling 
3818b1b8ab34Slling 	return (error);
3819b1b8ab34Slling }
3820b1b8ab34Slling 
3821b1b8ab34Slling int
3822b1b8ab34Slling zpool_do_set(int argc, char **argv)
3823b1b8ab34Slling {
3824b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3825b1b8ab34Slling 	int error;
3826b1b8ab34Slling 
3827b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3828b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3829b1b8ab34Slling 		    argv[1][1]);
3830b1b8ab34Slling 		usage(B_FALSE);
3831b1b8ab34Slling 	}
3832b1b8ab34Slling 
3833b1b8ab34Slling 	if (argc < 2) {
3834b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3835b1b8ab34Slling 		    "argument\n"));
3836b1b8ab34Slling 		usage(B_FALSE);
3837b1b8ab34Slling 	}
3838b1b8ab34Slling 
3839b1b8ab34Slling 	if (argc < 3) {
3840b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3841b1b8ab34Slling 		usage(B_FALSE);
3842b1b8ab34Slling 	}
3843b1b8ab34Slling 
3844b1b8ab34Slling 	if (argc > 3) {
3845b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3846b1b8ab34Slling 		usage(B_FALSE);
3847b1b8ab34Slling 	}
3848b1b8ab34Slling 
3849b1b8ab34Slling 	cb.cb_propname = argv[1];
3850b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3851b1b8ab34Slling 	if (cb.cb_value == NULL) {
3852b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3853b1b8ab34Slling 		    "property=value argument\n"));
3854b1b8ab34Slling 		usage(B_FALSE);
3855b1b8ab34Slling 	}
3856b1b8ab34Slling 
3857b1b8ab34Slling 	*(cb.cb_value) = '\0';
3858b1b8ab34Slling 	cb.cb_value++;
3859b1b8ab34Slling 
3860b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3861b1b8ab34Slling 	    set_callback, &cb);
3862b1b8ab34Slling 
3863b1b8ab34Slling 	return (error);
3864b1b8ab34Slling }
3865b1b8ab34Slling 
3866b1b8ab34Slling static int
3867b1b8ab34Slling find_command_idx(char *command, int *idx)
3868b1b8ab34Slling {
3869b1b8ab34Slling 	int i;
3870b1b8ab34Slling 
3871b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3872b1b8ab34Slling 		if (command_table[i].name == NULL)
3873b1b8ab34Slling 			continue;
3874b1b8ab34Slling 
3875b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3876b1b8ab34Slling 			*idx = i;
3877b1b8ab34Slling 			return (0);
3878b1b8ab34Slling 		}
3879b1b8ab34Slling 	}
3880b1b8ab34Slling 	return (1);
3881b1b8ab34Slling }
3882b1b8ab34Slling 
3883fa9e4066Sahrens int
3884fa9e4066Sahrens main(int argc, char **argv)
3885fa9e4066Sahrens {
3886fa9e4066Sahrens 	int ret;
3887fa9e4066Sahrens 	int i;
3888fa9e4066Sahrens 	char *cmdname;
3889fa9e4066Sahrens 
3890fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3891fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3892fa9e4066Sahrens 
389399653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
389499653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3895203a47d8Snd150628 		    "initialize ZFS library\n"));
389699653d4eSeschrock 		return (1);
389799653d4eSeschrock 	}
389899653d4eSeschrock 
389999653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
390099653d4eSeschrock 
3901fa9e4066Sahrens 	opterr = 0;
3902fa9e4066Sahrens 
3903fa9e4066Sahrens 	/*
3904fa9e4066Sahrens 	 * Make sure the user has specified some command.
3905fa9e4066Sahrens 	 */
3906fa9e4066Sahrens 	if (argc < 2) {
3907fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
390899653d4eSeschrock 		usage(B_FALSE);
3909fa9e4066Sahrens 	}
3910fa9e4066Sahrens 
3911fa9e4066Sahrens 	cmdname = argv[1];
3912fa9e4066Sahrens 
3913fa9e4066Sahrens 	/*
3914fa9e4066Sahrens 	 * Special case '-?'
3915fa9e4066Sahrens 	 */
3916fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
391799653d4eSeschrock 		usage(B_TRUE);
3918fa9e4066Sahrens 
39192a6b87f0Sek110237 	zpool_set_history_str("zpool", argc, argv, history_str);
39202a6b87f0Sek110237 	verify(zpool_stage_history(g_zfs, history_str) == 0);
39212a6b87f0Sek110237 
3922fa9e4066Sahrens 	/*
3923fa9e4066Sahrens 	 * Run the appropriate command.
3924fa9e4066Sahrens 	 */
3925b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
3926fa9e4066Sahrens 		current_command = &command_table[i];
3927fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
392891ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
392991ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
393091ebeef5Sahrens 		current_command = &command_table[i];
393191ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
393291ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
3933fa9e4066Sahrens 		/*
393491ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
393591ebeef5Sahrens 		 * it as such.
3936fa9e4066Sahrens 		 */
3937ea8dc4b6Seschrock 		char buf[16384];
3938ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
3939fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
3940fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
394191ebeef5Sahrens 	} else {
3942fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
3943fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
394499653d4eSeschrock 		usage(B_FALSE);
3945fa9e4066Sahrens 	}
3946fa9e4066Sahrens 
394799653d4eSeschrock 	libzfs_fini(g_zfs);
394899653d4eSeschrock 
3949fa9e4066Sahrens 	/*
3950fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3951fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
3952fa9e4066Sahrens 	 */
3953fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
3954fa9e4066Sahrens 		(void) printf("dumping core by request\n");
3955fa9e4066Sahrens 		abort();
3956fa9e4066Sahrens 	}
3957fa9e4066Sahrens 
3958fa9e4066Sahrens 	return (ret);
3959fa9e4066Sahrens }
3960