xref: /titanic_53/usr/src/cmd/zpool/zpool_main.c (revision 148434217c040ea38dc844384f6ba68d9b325906)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5441d80aaSlling  * Common Development and Distribution License (the "License").
6441d80aaSlling  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
2199653d4eSeschrock 
22fa9e4066Sahrens /*
23379c004dSEric Schrock  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #include <assert.h>
28fa9e4066Sahrens #include <ctype.h>
29fa9e4066Sahrens #include <dirent.h>
30fa9e4066Sahrens #include <errno.h>
31fa9e4066Sahrens #include <fcntl.h>
32fa9e4066Sahrens #include <libgen.h>
33fa9e4066Sahrens #include <libintl.h>
34fa9e4066Sahrens #include <libuutil.h>
35fa9e4066Sahrens #include <locale.h>
36fa9e4066Sahrens #include <stdio.h>
37fa9e4066Sahrens #include <stdlib.h>
38fa9e4066Sahrens #include <string.h>
39fa9e4066Sahrens #include <strings.h>
40fa9e4066Sahrens #include <unistd.h>
41fa9e4066Sahrens #include <priv.h>
42ecd6cf80Smarks #include <pwd.h>
43ecd6cf80Smarks #include <zone.h>
44b1b8ab34Slling #include <sys/fs/zfs.h>
45fa9e4066Sahrens 
46fa9e4066Sahrens #include <sys/stat.h>
47fa9e4066Sahrens 
48fa9e4066Sahrens #include <libzfs.h>
49fa9e4066Sahrens 
50fa9e4066Sahrens #include "zpool_util.h"
51b7b97454Sperrin #include "zfs_comutil.h"
52fa9e4066Sahrens 
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 {
379*14843421SMatthew Ahrens 		if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
3800a48a24eStimh 			normnm = zfs_prop_to_name(fprop);
381*14843421SMatthew Ahrens 		} else {
382*14843421SMatthew Ahrens 			normnm = propname;
383*14843421SMatthew Ahrens 		}
3840a48a24eStimh 	}
385990b4856Slling 
3860a48a24eStimh 	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
3870a48a24eStimh 	    prop != ZPOOL_PROP_CACHEFILE) {
388990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' "
389990b4856Slling 		    "specified multiple times\n"), propname);
390990b4856Slling 		return (2);
391990b4856Slling 	}
392990b4856Slling 
3930a48a24eStimh 	if (nvlist_add_string(proplist, normnm, propval) != 0) {
394990b4856Slling 		(void) fprintf(stderr, gettext("internal "
395990b4856Slling 		    "error: out of memory\n"));
396990b4856Slling 		return (1);
397990b4856Slling 	}
398990b4856Slling 
399990b4856Slling 	return (0);
400990b4856Slling }
401990b4856Slling 
402990b4856Slling /*
403fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
404fa9e4066Sahrens  *
405fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
406fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
407fa9e4066Sahrens  *		they were to be added.
408fa9e4066Sahrens  *
409fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
410fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
411fa9e4066Sahrens  * libzfs.
412fa9e4066Sahrens  */
413fa9e4066Sahrens int
414fa9e4066Sahrens zpool_do_add(int argc, char **argv)
415fa9e4066Sahrens {
41699653d4eSeschrock 	boolean_t force = B_FALSE;
41799653d4eSeschrock 	boolean_t dryrun = B_FALSE;
418fa9e4066Sahrens 	int c;
419fa9e4066Sahrens 	nvlist_t *nvroot;
420fa9e4066Sahrens 	char *poolname;
421fa9e4066Sahrens 	int ret;
422fa9e4066Sahrens 	zpool_handle_t *zhp;
423fa9e4066Sahrens 	nvlist_t *config;
424fa9e4066Sahrens 
425fa9e4066Sahrens 	/* check options */
426fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
427fa9e4066Sahrens 		switch (c) {
428fa9e4066Sahrens 		case 'f':
42999653d4eSeschrock 			force = B_TRUE;
430fa9e4066Sahrens 			break;
431fa9e4066Sahrens 		case 'n':
43299653d4eSeschrock 			dryrun = B_TRUE;
433fa9e4066Sahrens 			break;
434fa9e4066Sahrens 		case '?':
435fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
436fa9e4066Sahrens 			    optopt);
43799653d4eSeschrock 			usage(B_FALSE);
438fa9e4066Sahrens 		}
439fa9e4066Sahrens 	}
440fa9e4066Sahrens 
441fa9e4066Sahrens 	argc -= optind;
442fa9e4066Sahrens 	argv += optind;
443fa9e4066Sahrens 
444fa9e4066Sahrens 	/* get pool name and check number of arguments */
445fa9e4066Sahrens 	if (argc < 1) {
446fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
44799653d4eSeschrock 		usage(B_FALSE);
448fa9e4066Sahrens 	}
449fa9e4066Sahrens 	if (argc < 2) {
450fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
45199653d4eSeschrock 		usage(B_FALSE);
452fa9e4066Sahrens 	}
453fa9e4066Sahrens 
454fa9e4066Sahrens 	poolname = argv[0];
455fa9e4066Sahrens 
456fa9e4066Sahrens 	argc--;
457fa9e4066Sahrens 	argv++;
458fa9e4066Sahrens 
45999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
460fa9e4066Sahrens 		return (1);
461fa9e4066Sahrens 
462088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
463fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
464fa9e4066Sahrens 		    poolname);
465fa9e4066Sahrens 		zpool_close(zhp);
466fa9e4066Sahrens 		return (1);
467fa9e4066Sahrens 	}
468fa9e4066Sahrens 
469fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
470705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
471705040edSEric Taylor 	    argc, argv);
472fa9e4066Sahrens 	if (nvroot == NULL) {
473fa9e4066Sahrens 		zpool_close(zhp);
474fa9e4066Sahrens 		return (1);
475fa9e4066Sahrens 	}
476fa9e4066Sahrens 
477fa9e4066Sahrens 	if (dryrun) {
478fa9e4066Sahrens 		nvlist_t *poolnvroot;
479fa9e4066Sahrens 
480fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
481fa9e4066Sahrens 		    &poolnvroot) == 0);
482fa9e4066Sahrens 
483fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
484fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
485fa9e4066Sahrens 
4868654d025Sperrin 		/* print original main pool and new tree */
4878654d025Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
4888654d025Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
4898654d025Sperrin 
4908654d025Sperrin 		/* Do the same for the logs */
4918654d025Sperrin 		if (num_logs(poolnvroot) > 0) {
4928654d025Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
4938654d025Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
4948654d025Sperrin 		} else if (num_logs(nvroot) > 0) {
4958654d025Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
4968654d025Sperrin 		}
497fa9e4066Sahrens 
498fa9e4066Sahrens 		ret = 0;
499fa9e4066Sahrens 	} else {
500fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
501fa9e4066Sahrens 	}
502fa9e4066Sahrens 
50399653d4eSeschrock 	nvlist_free(nvroot);
50499653d4eSeschrock 	zpool_close(zhp);
50599653d4eSeschrock 
50699653d4eSeschrock 	return (ret);
50799653d4eSeschrock }
50899653d4eSeschrock 
50999653d4eSeschrock /*
510fa94a07fSbrendan  * zpool remove <pool> <vdev> ...
51199653d4eSeschrock  *
51299653d4eSeschrock  * Removes the given vdev from the pool.  Currently, this only supports removing
513fa94a07fSbrendan  * spares and cache devices from the pool.  Eventually, we'll want to support
514fa94a07fSbrendan  * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs.
51599653d4eSeschrock  */
51699653d4eSeschrock int
51799653d4eSeschrock zpool_do_remove(int argc, char **argv)
51899653d4eSeschrock {
51999653d4eSeschrock 	char *poolname;
520fa94a07fSbrendan 	int i, ret = 0;
52199653d4eSeschrock 	zpool_handle_t *zhp;
52299653d4eSeschrock 
52399653d4eSeschrock 	argc--;
52499653d4eSeschrock 	argv++;
52599653d4eSeschrock 
52699653d4eSeschrock 	/* get pool name and check number of arguments */
52799653d4eSeschrock 	if (argc < 1) {
52899653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
52999653d4eSeschrock 		usage(B_FALSE);
53099653d4eSeschrock 	}
53199653d4eSeschrock 	if (argc < 2) {
53299653d4eSeschrock 		(void) fprintf(stderr, gettext("missing device\n"));
53399653d4eSeschrock 		usage(B_FALSE);
53499653d4eSeschrock 	}
53599653d4eSeschrock 
53699653d4eSeschrock 	poolname = argv[0];
53799653d4eSeschrock 
53899653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
53999653d4eSeschrock 		return (1);
54099653d4eSeschrock 
541fa94a07fSbrendan 	for (i = 1; i < argc; i++) {
542fa94a07fSbrendan 		if (zpool_vdev_remove(zhp, argv[i]) != 0)
543fa94a07fSbrendan 			ret = 1;
544fa94a07fSbrendan 	}
54599653d4eSeschrock 
546fa9e4066Sahrens 	return (ret);
547fa9e4066Sahrens }
548fa9e4066Sahrens 
549fa9e4066Sahrens /*
5500a48a24eStimh  * zpool create [-fn] [-o property=value] ...
5510a48a24eStimh  *		[-O file-system-property=value] ...
5520a48a24eStimh  *		[-R root] [-m mountpoint] <pool> <dev> ...
553fa9e4066Sahrens  *
554fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
555fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
556fa9e4066Sahrens  *		were to be created.
557fa9e4066Sahrens  *      -R	Create a pool under an alternate root
558fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
559fa9e4066Sahrens  *      	'/<pool>'
560990b4856Slling  *	-o	Set property=value.
5610a48a24eStimh  *	-O	Set fsproperty=value in the pool's root file system
562fa9e4066Sahrens  *
563b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
564fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
565fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
566fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
567fa9e4066Sahrens  */
568fa9e4066Sahrens int
569fa9e4066Sahrens zpool_do_create(int argc, char **argv)
570fa9e4066Sahrens {
57199653d4eSeschrock 	boolean_t force = B_FALSE;
57299653d4eSeschrock 	boolean_t dryrun = B_FALSE;
573fa9e4066Sahrens 	int c;
574990b4856Slling 	nvlist_t *nvroot = NULL;
575fa9e4066Sahrens 	char *poolname;
576990b4856Slling 	int ret = 1;
577fa9e4066Sahrens 	char *altroot = NULL;
578fa9e4066Sahrens 	char *mountpoint = NULL;
5790a48a24eStimh 	nvlist_t *fsprops = NULL;
580990b4856Slling 	nvlist_t *props = NULL;
5812f8aaab3Seschrock 	char *propval;
582fa9e4066Sahrens 
583fa9e4066Sahrens 	/* check options */
5840a48a24eStimh 	while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) {
585fa9e4066Sahrens 		switch (c) {
586fa9e4066Sahrens 		case 'f':
58799653d4eSeschrock 			force = B_TRUE;
588fa9e4066Sahrens 			break;
589fa9e4066Sahrens 		case 'n':
59099653d4eSeschrock 			dryrun = B_TRUE;
591fa9e4066Sahrens 			break;
592fa9e4066Sahrens 		case 'R':
593fa9e4066Sahrens 			altroot = optarg;
594990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
5950a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
596990b4856Slling 				goto errout;
5972f8aaab3Seschrock 			if (nvlist_lookup_string(props,
5982f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
5992f8aaab3Seschrock 			    &propval) == 0)
6002f8aaab3Seschrock 				break;
601990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
6020a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
603990b4856Slling 				goto errout;
604fa9e4066Sahrens 			break;
605fa9e4066Sahrens 		case 'm':
606fa9e4066Sahrens 			mountpoint = optarg;
607fa9e4066Sahrens 			break;
608990b4856Slling 		case 'o':
609990b4856Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
610990b4856Slling 				(void) fprintf(stderr, gettext("missing "
611990b4856Slling 				    "'=' for -o option\n"));
612990b4856Slling 				goto errout;
613990b4856Slling 			}
614990b4856Slling 			*propval = '\0';
615990b4856Slling 			propval++;
616990b4856Slling 
6170a48a24eStimh 			if (add_prop_list(optarg, propval, &props, B_TRUE))
6180a48a24eStimh 				goto errout;
6190a48a24eStimh 			break;
6200a48a24eStimh 		case 'O':
6210a48a24eStimh 			if ((propval = strchr(optarg, '=')) == NULL) {
6220a48a24eStimh 				(void) fprintf(stderr, gettext("missing "
6230a48a24eStimh 				    "'=' for -O option\n"));
6240a48a24eStimh 				goto errout;
6250a48a24eStimh 			}
6260a48a24eStimh 			*propval = '\0';
6270a48a24eStimh 			propval++;
6280a48a24eStimh 
6290a48a24eStimh 			if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
630990b4856Slling 				goto errout;
631990b4856Slling 			break;
632fa9e4066Sahrens 		case ':':
633fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
634fa9e4066Sahrens 			    "'%c' option\n"), optopt);
635990b4856Slling 			goto badusage;
636fa9e4066Sahrens 		case '?':
637fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
638fa9e4066Sahrens 			    optopt);
639990b4856Slling 			goto badusage;
640fa9e4066Sahrens 		}
641fa9e4066Sahrens 	}
642fa9e4066Sahrens 
643fa9e4066Sahrens 	argc -= optind;
644fa9e4066Sahrens 	argv += optind;
645fa9e4066Sahrens 
646fa9e4066Sahrens 	/* get pool name and check number of arguments */
647fa9e4066Sahrens 	if (argc < 1) {
648fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
649990b4856Slling 		goto badusage;
650fa9e4066Sahrens 	}
651fa9e4066Sahrens 	if (argc < 2) {
652fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
653990b4856Slling 		goto badusage;
654fa9e4066Sahrens 	}
655fa9e4066Sahrens 
656fa9e4066Sahrens 	poolname = argv[0];
657fa9e4066Sahrens 
658fa9e4066Sahrens 	/*
659fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
660fa9e4066Sahrens 	 * user to use 'zfs create' instead.
661fa9e4066Sahrens 	 */
662fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
663fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
664fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
665fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
666fa9e4066Sahrens 		    "create a dataset\n"));
667990b4856Slling 		goto errout;
668fa9e4066Sahrens 	}
669fa9e4066Sahrens 
670fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
671705040edSEric Taylor 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
672705040edSEric Taylor 	    argc - 1, argv + 1);
673fa9e4066Sahrens 	if (nvroot == NULL)
6740a48a24eStimh 		goto errout;
675fa9e4066Sahrens 
67699653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
677b7b97454Sperrin 	if (!zfs_allocatable_devs(nvroot)) {
67899653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
67999653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
68099653d4eSeschrock 		    "specified\n"));
681990b4856Slling 		goto errout;
68299653d4eSeschrock 	}
68399653d4eSeschrock 
68499653d4eSeschrock 
685fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
686fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
687e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
688990b4856Slling 		goto errout;
689fa9e4066Sahrens 	}
690fa9e4066Sahrens 
691fa9e4066Sahrens 	/*
692fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
693fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
694fa9e4066Sahrens 	 */
695fa9e4066Sahrens 	if (mountpoint == NULL ||
696fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
697fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
698fa9e4066Sahrens 		char buf[MAXPATHLEN];
69911022c7cStimh 		DIR *dirp;
700fa9e4066Sahrens 
701fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
702fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
703fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
704fa9e4066Sahrens 			    "'none'\n"), mountpoint);
705990b4856Slling 			goto errout;
706fa9e4066Sahrens 		}
707fa9e4066Sahrens 
708fa9e4066Sahrens 		if (mountpoint == NULL) {
709fa9e4066Sahrens 			if (altroot != NULL)
710fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
711fa9e4066Sahrens 				    altroot, poolname);
712fa9e4066Sahrens 			else
713fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
714fa9e4066Sahrens 				    poolname);
715fa9e4066Sahrens 		} else {
716fa9e4066Sahrens 			if (altroot != NULL)
717fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
718fa9e4066Sahrens 				    altroot, mountpoint);
719fa9e4066Sahrens 			else
720fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
721fa9e4066Sahrens 				    mountpoint);
722fa9e4066Sahrens 		}
723fa9e4066Sahrens 
72411022c7cStimh 		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
72511022c7cStimh 			(void) fprintf(stderr, gettext("mountpoint '%s' : "
72611022c7cStimh 			    "%s\n"), buf, strerror(errno));
727fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
728fa9e4066Sahrens 			    "option to provide a different default\n"));
729990b4856Slling 			goto errout;
73011022c7cStimh 		} else if (dirp) {
73111022c7cStimh 			int count = 0;
73211022c7cStimh 
73311022c7cStimh 			while (count < 3 && readdir(dirp) != NULL)
73411022c7cStimh 				count++;
73511022c7cStimh 			(void) closedir(dirp);
73611022c7cStimh 
73711022c7cStimh 			if (count > 2) {
73811022c7cStimh 				(void) fprintf(stderr, gettext("mountpoint "
73911022c7cStimh 				    "'%s' exists and is not empty\n"), buf);
74011022c7cStimh 				(void) fprintf(stderr, gettext("use '-m' "
74111022c7cStimh 				    "option to provide a "
74211022c7cStimh 				    "different default\n"));
74311022c7cStimh 				goto errout;
74411022c7cStimh 			}
745fa9e4066Sahrens 		}
746fa9e4066Sahrens 	}
747fa9e4066Sahrens 
748fa9e4066Sahrens 	if (dryrun) {
749fa9e4066Sahrens 		/*
750fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
751fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
752fa9e4066Sahrens 		 * appropriate hierarchy.
753fa9e4066Sahrens 		 */
754fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
755fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
756fa9e4066Sahrens 
7578654d025Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7588654d025Sperrin 		if (num_logs(nvroot) > 0)
7598654d025Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
760fa9e4066Sahrens 
761fa9e4066Sahrens 		ret = 0;
762fa9e4066Sahrens 	} else {
763fa9e4066Sahrens 		/*
764fa9e4066Sahrens 		 * Hand off to libzfs.
765fa9e4066Sahrens 		 */
7660a48a24eStimh 		if (zpool_create(g_zfs, poolname,
7670a48a24eStimh 		    nvroot, props, fsprops) == 0) {
76899653d4eSeschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
769fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
770fa9e4066Sahrens 			if (pool != NULL) {
771fa9e4066Sahrens 				if (mountpoint != NULL)
772fa9e4066Sahrens 					verify(zfs_prop_set(pool,
773e9dbad6fSeschrock 					    zfs_prop_to_name(
774e9dbad6fSeschrock 					    ZFS_PROP_MOUNTPOINT),
775fa9e4066Sahrens 					    mountpoint) == 0);
776fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
777da6c28aaSamw 					ret = zfs_shareall(pool);
778fa9e4066Sahrens 				zfs_close(pool);
779fa9e4066Sahrens 			}
78099653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
78199653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
78299653d4eSeschrock 			    "been omitted\n"));
783fa9e4066Sahrens 		}
784fa9e4066Sahrens 	}
785fa9e4066Sahrens 
786990b4856Slling errout:
787fa9e4066Sahrens 	nvlist_free(nvroot);
7880a48a24eStimh 	nvlist_free(fsprops);
789990b4856Slling 	nvlist_free(props);
790fa9e4066Sahrens 	return (ret);
791990b4856Slling badusage:
7920a48a24eStimh 	nvlist_free(fsprops);
793990b4856Slling 	nvlist_free(props);
794990b4856Slling 	usage(B_FALSE);
795990b4856Slling 	return (2);
796fa9e4066Sahrens }
797fa9e4066Sahrens 
798fa9e4066Sahrens /*
799fa9e4066Sahrens  * zpool destroy <pool>
800fa9e4066Sahrens  *
801fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
802fa9e4066Sahrens  *
803fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
804fa9e4066Sahrens  */
805fa9e4066Sahrens int
806fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
807fa9e4066Sahrens {
80899653d4eSeschrock 	boolean_t force = B_FALSE;
809fa9e4066Sahrens 	int c;
810fa9e4066Sahrens 	char *pool;
811fa9e4066Sahrens 	zpool_handle_t *zhp;
812fa9e4066Sahrens 	int ret;
813fa9e4066Sahrens 
814fa9e4066Sahrens 	/* check options */
815fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
816fa9e4066Sahrens 		switch (c) {
817fa9e4066Sahrens 		case 'f':
81899653d4eSeschrock 			force = B_TRUE;
819fa9e4066Sahrens 			break;
820fa9e4066Sahrens 		case '?':
821fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
822fa9e4066Sahrens 			    optopt);
82399653d4eSeschrock 			usage(B_FALSE);
824fa9e4066Sahrens 		}
825fa9e4066Sahrens 	}
826fa9e4066Sahrens 
827fa9e4066Sahrens 	argc -= optind;
828fa9e4066Sahrens 	argv += optind;
829fa9e4066Sahrens 
830fa9e4066Sahrens 	/* check arguments */
831fa9e4066Sahrens 	if (argc < 1) {
832fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
83399653d4eSeschrock 		usage(B_FALSE);
834fa9e4066Sahrens 	}
835fa9e4066Sahrens 	if (argc > 1) {
836fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
83799653d4eSeschrock 		usage(B_FALSE);
838fa9e4066Sahrens 	}
839fa9e4066Sahrens 
840fa9e4066Sahrens 	pool = argv[0];
841fa9e4066Sahrens 
84299653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
843fa9e4066Sahrens 		/*
844fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
845fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
846fa9e4066Sahrens 		 */
847fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
848fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
849fa9e4066Sahrens 			    "destroy a dataset\n"));
850fa9e4066Sahrens 		return (1);
851fa9e4066Sahrens 	}
852fa9e4066Sahrens 
853f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
854fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
855fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
856fa9e4066Sahrens 		return (1);
857fa9e4066Sahrens 	}
858fa9e4066Sahrens 
859fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
860fa9e4066Sahrens 
861fa9e4066Sahrens 	zpool_close(zhp);
862fa9e4066Sahrens 
863fa9e4066Sahrens 	return (ret);
864fa9e4066Sahrens }
865fa9e4066Sahrens 
866fa9e4066Sahrens /*
867fa9e4066Sahrens  * zpool export [-f] <pool> ...
868fa9e4066Sahrens  *
869fa9e4066Sahrens  *	-f	Forcefully unmount datasets
870fa9e4066Sahrens  *
871b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
872fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
873fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
874fa9e4066Sahrens  */
875fa9e4066Sahrens int
876fa9e4066Sahrens zpool_do_export(int argc, char **argv)
877fa9e4066Sahrens {
87899653d4eSeschrock 	boolean_t force = B_FALSE;
879394ab0cbSGeorge Wilson 	boolean_t hardforce = B_FALSE;
880fa9e4066Sahrens 	int c;
881fa9e4066Sahrens 	zpool_handle_t *zhp;
882fa9e4066Sahrens 	int ret;
883fa9e4066Sahrens 	int i;
884fa9e4066Sahrens 
885fa9e4066Sahrens 	/* check options */
886394ab0cbSGeorge Wilson 	while ((c = getopt(argc, argv, "fF")) != -1) {
887fa9e4066Sahrens 		switch (c) {
888fa9e4066Sahrens 		case 'f':
88999653d4eSeschrock 			force = B_TRUE;
890fa9e4066Sahrens 			break;
891394ab0cbSGeorge Wilson 		case 'F':
892394ab0cbSGeorge Wilson 			hardforce = B_TRUE;
893394ab0cbSGeorge Wilson 			break;
894fa9e4066Sahrens 		case '?':
895fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
896fa9e4066Sahrens 			    optopt);
89799653d4eSeschrock 			usage(B_FALSE);
898fa9e4066Sahrens 		}
899fa9e4066Sahrens 	}
900fa9e4066Sahrens 
901fa9e4066Sahrens 	argc -= optind;
902fa9e4066Sahrens 	argv += optind;
903fa9e4066Sahrens 
904fa9e4066Sahrens 	/* check arguments */
905fa9e4066Sahrens 	if (argc < 1) {
906fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
90799653d4eSeschrock 		usage(B_FALSE);
908fa9e4066Sahrens 	}
909fa9e4066Sahrens 
910fa9e4066Sahrens 	ret = 0;
911fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
91299653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
913fa9e4066Sahrens 			ret = 1;
914fa9e4066Sahrens 			continue;
915fa9e4066Sahrens 		}
916fa9e4066Sahrens 
917f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
918fa9e4066Sahrens 			ret = 1;
919fa9e4066Sahrens 			zpool_close(zhp);
920fa9e4066Sahrens 			continue;
921fa9e4066Sahrens 		}
922fa9e4066Sahrens 
923394ab0cbSGeorge Wilson 		if (hardforce) {
924394ab0cbSGeorge Wilson 			if (zpool_export_force(zhp) != 0)
925fa9e4066Sahrens 				ret = 1;
926394ab0cbSGeorge Wilson 		} else if (zpool_export(zhp, force) != 0) {
927394ab0cbSGeorge Wilson 			ret = 1;
928394ab0cbSGeorge Wilson 		}
929fa9e4066Sahrens 
930fa9e4066Sahrens 		zpool_close(zhp);
931fa9e4066Sahrens 	}
932fa9e4066Sahrens 
933fa9e4066Sahrens 	return (ret);
934fa9e4066Sahrens }
935fa9e4066Sahrens 
936fa9e4066Sahrens /*
937fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
938fa9e4066Sahrens  * name column.
939fa9e4066Sahrens  */
940fa9e4066Sahrens static int
941c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
942fa9e4066Sahrens {
94399653d4eSeschrock 	char *name = zpool_vdev_name(g_zfs, zhp, nv);
944fa9e4066Sahrens 	nvlist_t **child;
945fa9e4066Sahrens 	uint_t c, children;
946fa9e4066Sahrens 	int ret;
947fa9e4066Sahrens 
948fa9e4066Sahrens 	if (strlen(name) + depth > max)
949fa9e4066Sahrens 		max = strlen(name) + depth;
950fa9e4066Sahrens 
951afefbcddSeschrock 	free(name);
952afefbcddSeschrock 
95399653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
95499653d4eSeschrock 	    &child, &children) == 0) {
955fa9e4066Sahrens 		for (c = 0; c < children; c++)
95699653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
95799653d4eSeschrock 			    max)) > max)
958fa9e4066Sahrens 				max = ret;
95999653d4eSeschrock 	}
96099653d4eSeschrock 
961fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
962fa94a07fSbrendan 	    &child, &children) == 0) {
963fa94a07fSbrendan 		for (c = 0; c < children; c++)
964fa94a07fSbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
965fa94a07fSbrendan 			    max)) > max)
966fa94a07fSbrendan 				max = ret;
967fa94a07fSbrendan 	}
968fa94a07fSbrendan 
96999653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
97099653d4eSeschrock 	    &child, &children) == 0) {
97199653d4eSeschrock 		for (c = 0; c < children; c++)
97299653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
97399653d4eSeschrock 			    max)) > max)
97499653d4eSeschrock 				max = ret;
97599653d4eSeschrock 	}
97699653d4eSeschrock 
977fa9e4066Sahrens 
978fa9e4066Sahrens 	return (max);
979fa9e4066Sahrens }
980fa9e4066Sahrens 
981fa9e4066Sahrens 
982fa9e4066Sahrens /*
983fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
984fa9e4066Sahrens  * pool, printing out the name and status for each one.
985fa9e4066Sahrens  */
986fa9e4066Sahrens void
9878654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
9888654d025Sperrin     boolean_t print_logs)
989fa9e4066Sahrens {
990fa9e4066Sahrens 	nvlist_t **child;
991fa9e4066Sahrens 	uint_t c, children;
992fa9e4066Sahrens 	vdev_stat_t *vs;
993afefbcddSeschrock 	char *type, *vname;
994fa9e4066Sahrens 
995fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
996fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
997fa9e4066Sahrens 		return;
998fa9e4066Sahrens 
999fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
1000fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
1001fa9e4066Sahrens 
1002fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
1003990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1004fa9e4066Sahrens 
1005fa9e4066Sahrens 	if (vs->vs_aux != 0) {
10063d7072f8Seschrock 		(void) printf("  ");
1007fa9e4066Sahrens 
1008fa9e4066Sahrens 		switch (vs->vs_aux) {
1009fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
1010fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
1011fa9e4066Sahrens 			break;
1012fa9e4066Sahrens 
1013fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
1014fa9e4066Sahrens 			(void) printf(gettext("missing device"));
1015fa9e4066Sahrens 			break;
1016fa9e4066Sahrens 
1017fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
1018fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
1019fa9e4066Sahrens 			break;
1020fa9e4066Sahrens 
1021eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
1022eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
1023eaca9bbdSeschrock 			break;
1024eaca9bbdSeschrock 
10253d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
10263d7072f8Seschrock 			(void) printf(gettext("too many errors"));
10273d7072f8Seschrock 			break;
10283d7072f8Seschrock 
1029fa9e4066Sahrens 		default:
1030fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
1031fa9e4066Sahrens 			break;
1032fa9e4066Sahrens 		}
1033fa9e4066Sahrens 	}
1034fa9e4066Sahrens 	(void) printf("\n");
1035fa9e4066Sahrens 
1036fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1037fa9e4066Sahrens 	    &child, &children) != 0)
1038fa9e4066Sahrens 		return;
1039fa9e4066Sahrens 
1040afefbcddSeschrock 	for (c = 0; c < children; c++) {
10418654d025Sperrin 		uint64_t is_log = B_FALSE;
10428654d025Sperrin 
10438654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
10448654d025Sperrin 		    &is_log);
10458654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
10468654d025Sperrin 			continue;
10478654d025Sperrin 
104899653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1049afefbcddSeschrock 		print_import_config(vname, child[c],
10508654d025Sperrin 		    namewidth, depth + 2, B_FALSE);
1051afefbcddSeschrock 		free(vname);
1052afefbcddSeschrock 	}
105399653d4eSeschrock 
1054fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1055fa94a07fSbrendan 	    &child, &children) == 0) {
1056fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
1057fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1058fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1059fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1060fa94a07fSbrendan 			free(vname);
1061fa94a07fSbrendan 		}
1062fa94a07fSbrendan 	}
106399653d4eSeschrock 
1064fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1065fa94a07fSbrendan 	    &child, &children) == 0) {
106699653d4eSeschrock 		(void) printf(gettext("\tspares\n"));
106799653d4eSeschrock 		for (c = 0; c < children; c++) {
106899653d4eSeschrock 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
106999653d4eSeschrock 			(void) printf("\t  %s\n", vname);
107099653d4eSeschrock 			free(vname);
107199653d4eSeschrock 		}
1072fa9e4066Sahrens 	}
1073fa94a07fSbrendan }
1074fa9e4066Sahrens 
1075fa9e4066Sahrens /*
1076fa9e4066Sahrens  * Display the status for the given pool.
1077fa9e4066Sahrens  */
1078fa9e4066Sahrens static void
1079fa9e4066Sahrens show_import(nvlist_t *config)
1080fa9e4066Sahrens {
1081fa9e4066Sahrens 	uint64_t pool_state;
1082fa9e4066Sahrens 	vdev_stat_t *vs;
1083fa9e4066Sahrens 	char *name;
1084fa9e4066Sahrens 	uint64_t guid;
1085fa9e4066Sahrens 	char *msgid;
1086fa9e4066Sahrens 	nvlist_t *nvroot;
1087fa9e4066Sahrens 	int reason;
108846657f8dSmmusante 	const char *health;
1089fa9e4066Sahrens 	uint_t vsc;
1090fa9e4066Sahrens 	int namewidth;
1091fa9e4066Sahrens 
1092fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1093fa9e4066Sahrens 	    &name) == 0);
1094fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1095fa9e4066Sahrens 	    &guid) == 0);
1096fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1097fa9e4066Sahrens 	    &pool_state) == 0);
1098fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1099fa9e4066Sahrens 	    &nvroot) == 0);
1100fa9e4066Sahrens 
1101fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1102fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1103990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1104fa9e4066Sahrens 
1105fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1106fa9e4066Sahrens 
110746657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
110846657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
110946657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
11104c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
111146657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
11124c58d714Sdarrenm 	(void) printf("\n");
1113fa9e4066Sahrens 
1114fa9e4066Sahrens 	switch (reason) {
1115fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1116fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1117fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1118fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1119fa9e4066Sahrens 		    "from the system.\n"));
1120fa9e4066Sahrens 		break;
1121fa9e4066Sahrens 
1122fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1123fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1124fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1125fa9e4066Sahrens 		    "corrupted data.\n"));
1126fa9e4066Sahrens 		break;
1127fa9e4066Sahrens 
1128fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1129fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1130fa9e4066Sahrens 		break;
1131fa9e4066Sahrens 
1132441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1133441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1134441d80aaSlling 		    "are offlined.\n"));
1135441d80aaSlling 		break;
1136441d80aaSlling 
1137ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1138ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1139ea8dc4b6Seschrock 		    "corrupted.\n"));
1140ea8dc4b6Seschrock 		break;
1141ea8dc4b6Seschrock 
1142eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1143eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1144eaca9bbdSeschrock 		    "older on-disk version.\n"));
1145eaca9bbdSeschrock 		break;
1146eaca9bbdSeschrock 
1147eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1148eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1149eaca9bbdSeschrock 		    "incompatible version.\n"));
1150eaca9bbdSeschrock 		break;
1151b87f3af3Sperrin 
115295173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
115395173954Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
115495173954Sek110237 		    "another system.\n"));
115595173954Sek110237 		break;
1156b87f3af3Sperrin 
11573d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
11583d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
11593d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
11603d7072f8Seschrock 		    "faulted.\n"));
11613d7072f8Seschrock 		break;
11623d7072f8Seschrock 
1163b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
1164b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record cannot be "
1165b87f3af3Sperrin 		    "read.\n"));
1166b87f3af3Sperrin 		break;
1167b87f3af3Sperrin 
1168fa9e4066Sahrens 	default:
1169fa9e4066Sahrens 		/*
1170fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1171fa9e4066Sahrens 		 */
1172fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1173fa9e4066Sahrens 	}
1174fa9e4066Sahrens 
1175fa9e4066Sahrens 	/*
1176fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1177fa9e4066Sahrens 	 */
117846657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1179eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1180eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1181eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1182eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1183eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
118495173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
118595173954Sek110237 			(void) printf(gettext("action: The pool can be "
118695173954Sek110237 			    "imported using its name or numeric "
118795173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1188fa9e4066Sahrens 		else
1189eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1190eaca9bbdSeschrock 			    "imported using its name or numeric "
1191eaca9bbdSeschrock 			    "identifier.\n"));
119246657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1193fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1194fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1195eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1196fa9e4066Sahrens 	} else {
1197eaca9bbdSeschrock 		switch (reason) {
1198eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1199eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1200eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1201eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1202eaca9bbdSeschrock 			    "backup.\n"));
1203eaca9bbdSeschrock 			break;
1204eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1205eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1206eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1207fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1208fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1209fa9e4066Sahrens 			    "again.\n"));
1210eaca9bbdSeschrock 			break;
1211eaca9bbdSeschrock 		default:
1212fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1213fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1214fa9e4066Sahrens 		}
1215eaca9bbdSeschrock 	}
1216eaca9bbdSeschrock 
121746657f8dSmmusante 	/*
121846657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
121946657f8dSmmusante 	 * is "corrupt data":
122046657f8dSmmusante 	 */
122146657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
122246657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
122346657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1224eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1225eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1226eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1227eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1228eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
122918ce54dfSek110237 			    "another system, but can be imported using\n\t"
1230eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1231eaca9bbdSeschrock 	}
1232fa9e4066Sahrens 
1233fa9e4066Sahrens 	if (msgid != NULL)
1234fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1235fa9e4066Sahrens 		    msgid);
1236fa9e4066Sahrens 
1237fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1238fa9e4066Sahrens 
1239c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1240fa9e4066Sahrens 	if (namewidth < 10)
1241fa9e4066Sahrens 		namewidth = 10;
12428654d025Sperrin 
12438654d025Sperrin 	print_import_config(name, nvroot, namewidth, 0, B_FALSE);
12448654d025Sperrin 	if (num_logs(nvroot) > 0) {
12458654d025Sperrin 		(void) printf(gettext("\tlogs\n"));
12468654d025Sperrin 		print_import_config(name, nvroot, namewidth, 0, B_TRUE);
12478654d025Sperrin 	}
1248fa9e4066Sahrens 
1249fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
125046657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1251fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
125246657f8dSmmusante 		    "configuration cannot be determined.\n"));
1253fa9e4066Sahrens 	}
1254fa9e4066Sahrens }
1255fa9e4066Sahrens 
1256fa9e4066Sahrens /*
1257fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1258990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1259990b4856Slling  * within the pool.
1260fa9e4066Sahrens  */
1261fa9e4066Sahrens static int
1262fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
1263c5904d13Seschrock     int force, nvlist_t *props, boolean_t allowfaulted)
1264fa9e4066Sahrens {
1265fa9e4066Sahrens 	zpool_handle_t *zhp;
1266fa9e4066Sahrens 	char *name;
1267fa9e4066Sahrens 	uint64_t state;
1268eaca9bbdSeschrock 	uint64_t version;
1269ecd6cf80Smarks 	int error = 0;
1270fa9e4066Sahrens 
1271fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1272fa9e4066Sahrens 	    &name) == 0);
1273fa9e4066Sahrens 
1274fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1275fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1276eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1277eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1278e7437265Sahrens 	if (version > SPA_VERSION) {
1279eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1280eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1281eaca9bbdSeschrock 		return (1);
1282eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
128395173954Sek110237 		uint64_t hostid;
128495173954Sek110237 
128595173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
128695173954Sek110237 		    &hostid) == 0) {
128795173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
128895173954Sek110237 				char *hostname;
128995173954Sek110237 				uint64_t timestamp;
129095173954Sek110237 				time_t t;
129195173954Sek110237 
129295173954Sek110237 				verify(nvlist_lookup_string(config,
129395173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
129495173954Sek110237 				verify(nvlist_lookup_uint64(config,
129595173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
129695173954Sek110237 				t = timestamp;
129795173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
129895173954Sek110237 				    "'%s': pool may be in use from other "
129995173954Sek110237 				    "system, it was last accessed by %s "
130095173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
130195173954Sek110237 				    (unsigned long)hostid,
130295173954Sek110237 				    asctime(localtime(&t)));
130395173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
130495173954Sek110237 				    "import anyway\n"));
1305fa9e4066Sahrens 				return (1);
1306fa9e4066Sahrens 			}
130795173954Sek110237 		} else {
130895173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
130995173954Sek110237 			    "pool may be in use from other system\n"), name);
131095173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
131195173954Sek110237 			    "anyway\n"));
131295173954Sek110237 			return (1);
131395173954Sek110237 		}
131495173954Sek110237 	}
1315fa9e4066Sahrens 
1316c5904d13Seschrock 	if (zpool_import_props(g_zfs, config, newname, props,
1317c5904d13Seschrock 	    allowfaulted) != 0)
1318fa9e4066Sahrens 		return (1);
1319fa9e4066Sahrens 
1320fa9e4066Sahrens 	if (newname != NULL)
1321fa9e4066Sahrens 		name = (char *)newname;
1322fa9e4066Sahrens 
1323c5904d13Seschrock 	verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL);
1324fa9e4066Sahrens 
1325379c004dSEric Schrock 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
1326379c004dSEric Schrock 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1327fa9e4066Sahrens 		zpool_close(zhp);
1328fa9e4066Sahrens 		return (1);
1329fa9e4066Sahrens 	}
1330fa9e4066Sahrens 
1331fa9e4066Sahrens 	zpool_close(zhp);
1332ecd6cf80Smarks 	return (error);
1333fa9e4066Sahrens }
1334fa9e4066Sahrens 
1335fa9e4066Sahrens /*
13364c58d714Sdarrenm  * zpool import [-d dir] [-D]
13372f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
13382f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
13392f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
13402f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] <pool | id> [newpool]
13412f8aaab3Seschrock  *
13422f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
13432f8aaab3Seschrock  *		devices.
1344fa9e4066Sahrens  *
1345fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1346fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1347fa9e4066Sahrens  *
13484c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
13494c58d714Sdarrenm  *              specified destroyed pools.
13504c58d714Sdarrenm  *
1351fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1352fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1353fa9e4066Sahrens  *		is rebooted.
1354fa9e4066Sahrens  *
1355fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1356fa9e4066Sahrens  *
1357c5904d13Seschrock  *       -F	Import even in the presence of faulted vdevs.  This is an
1358c5904d13Seschrock  *       	intentionally undocumented option for testing purposes, and
1359c5904d13Seschrock  *       	treats the pool configuration as complete, leaving any bad
1360c5904d13Seschrock  *		vdevs in the FAULTED state.
1361c5904d13Seschrock  *
1362fa9e4066Sahrens  *       -a	Import all pools found.
1363fa9e4066Sahrens  *
1364990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1365ecd6cf80Smarks  *
1366fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1367fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1368fa9e4066Sahrens  */
1369fa9e4066Sahrens int
1370fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1371fa9e4066Sahrens {
1372fa9e4066Sahrens 	char **searchdirs = NULL;
1373fa9e4066Sahrens 	int nsearch = 0;
1374fa9e4066Sahrens 	int c;
1375fa9e4066Sahrens 	int err;
13762f8aaab3Seschrock 	nvlist_t *pools = NULL;
137799653d4eSeschrock 	boolean_t do_all = B_FALSE;
137899653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1379fa9e4066Sahrens 	char *mntopts = NULL;
138099653d4eSeschrock 	boolean_t do_force = B_FALSE;
1381fa9e4066Sahrens 	nvpair_t *elem;
1382fa9e4066Sahrens 	nvlist_t *config;
138324e697d4Sck153898 	uint64_t searchguid = 0;
138424e697d4Sck153898 	char *searchname = NULL;
1385990b4856Slling 	char *propval;
1386fa9e4066Sahrens 	nvlist_t *found_config;
1387ecd6cf80Smarks 	nvlist_t *props = NULL;
138899653d4eSeschrock 	boolean_t first;
1389c5904d13Seschrock 	boolean_t allow_faulted = B_FALSE;
13904c58d714Sdarrenm 	uint64_t pool_state;
13912f8aaab3Seschrock 	char *cachefile = NULL;
1392fa9e4066Sahrens 
1393fa9e4066Sahrens 	/* check options */
1394c5904d13Seschrock 	while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) {
1395fa9e4066Sahrens 		switch (c) {
1396fa9e4066Sahrens 		case 'a':
139799653d4eSeschrock 			do_all = B_TRUE;
1398fa9e4066Sahrens 			break;
13992f8aaab3Seschrock 		case 'c':
14002f8aaab3Seschrock 			cachefile = optarg;
14012f8aaab3Seschrock 			break;
1402fa9e4066Sahrens 		case 'd':
1403fa9e4066Sahrens 			if (searchdirs == NULL) {
1404fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1405fa9e4066Sahrens 			} else {
1406fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1407fa9e4066Sahrens 				    sizeof (char *));
1408fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1409fa9e4066Sahrens 				    sizeof (char *));
1410fa9e4066Sahrens 				free(searchdirs);
1411fa9e4066Sahrens 				searchdirs = tmp;
1412fa9e4066Sahrens 			}
1413fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1414fa9e4066Sahrens 			break;
14154c58d714Sdarrenm 		case 'D':
141699653d4eSeschrock 			do_destroyed = B_TRUE;
14174c58d714Sdarrenm 			break;
1418fa9e4066Sahrens 		case 'f':
141999653d4eSeschrock 			do_force = B_TRUE;
1420fa9e4066Sahrens 			break;
1421c5904d13Seschrock 		case 'F':
1422c5904d13Seschrock 			allow_faulted = B_TRUE;
1423c5904d13Seschrock 			break;
1424fa9e4066Sahrens 		case 'o':
1425990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1426990b4856Slling 				*propval = '\0';
1427990b4856Slling 				propval++;
14280a48a24eStimh 				if (add_prop_list(optarg, propval,
14290a48a24eStimh 				    &props, B_TRUE))
1430990b4856Slling 					goto error;
1431990b4856Slling 			} else {
1432fa9e4066Sahrens 				mntopts = optarg;
1433990b4856Slling 			}
1434fa9e4066Sahrens 			break;
1435fa9e4066Sahrens 		case 'R':
1436990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
14370a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1438990b4856Slling 				goto error;
14392f8aaab3Seschrock 			if (nvlist_lookup_string(props,
14402f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
14412f8aaab3Seschrock 			    &propval) == 0)
14422f8aaab3Seschrock 				break;
1443990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
14440a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1445990b4856Slling 				goto error;
1446fa9e4066Sahrens 			break;
1447fa9e4066Sahrens 		case ':':
1448fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1449fa9e4066Sahrens 			    "'%c' option\n"), optopt);
145099653d4eSeschrock 			usage(B_FALSE);
1451fa9e4066Sahrens 			break;
1452fa9e4066Sahrens 		case '?':
1453fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1454fa9e4066Sahrens 			    optopt);
145599653d4eSeschrock 			usage(B_FALSE);
1456fa9e4066Sahrens 		}
1457fa9e4066Sahrens 	}
1458fa9e4066Sahrens 
1459fa9e4066Sahrens 	argc -= optind;
1460fa9e4066Sahrens 	argv += optind;
1461fa9e4066Sahrens 
14622f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
14632f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
14642f8aaab3Seschrock 		usage(B_FALSE);
14652f8aaab3Seschrock 	}
14662f8aaab3Seschrock 
1467fa9e4066Sahrens 	if (searchdirs == NULL) {
1468fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1469fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1470fa9e4066Sahrens 		nsearch = 1;
1471fa9e4066Sahrens 	}
1472fa9e4066Sahrens 
1473fa9e4066Sahrens 	/* check argument count */
1474fa9e4066Sahrens 	if (do_all) {
1475fa9e4066Sahrens 		if (argc != 0) {
1476fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
147799653d4eSeschrock 			usage(B_FALSE);
1478fa9e4066Sahrens 		}
1479fa9e4066Sahrens 	} else {
1480fa9e4066Sahrens 		if (argc > 2) {
1481fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
148299653d4eSeschrock 			usage(B_FALSE);
1483fa9e4066Sahrens 		}
1484fa9e4066Sahrens 
1485fa9e4066Sahrens 		/*
1486fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1487fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1488fa9e4066Sahrens 		 * silently fail.
1489fa9e4066Sahrens 		 */
1490fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1491fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1492fa9e4066Sahrens 			    "discover pools: permission denied\n"));
149399653d4eSeschrock 			free(searchdirs);
1494fa9e4066Sahrens 			return (1);
1495fa9e4066Sahrens 		}
1496fa9e4066Sahrens 	}
1497fa9e4066Sahrens 
1498fa9e4066Sahrens 	/*
1499fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1500fa9e4066Sahrens 	 *
1501fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1502fa9e4066Sahrens 	 *		each one.
1503fa9e4066Sahrens 	 *
1504fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1505fa9e4066Sahrens 	 *
1506fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1507fa9e4066Sahrens 	 *		name and import that one.
15084c58d714Sdarrenm 	 *
15094c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1510fa9e4066Sahrens 	 */
1511fa9e4066Sahrens 	if (argc != 0) {
1512fa9e4066Sahrens 		char *endptr;
1513fa9e4066Sahrens 
1514fa9e4066Sahrens 		errno = 0;
1515fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1516fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1517fa9e4066Sahrens 			searchname = argv[0];
1518fa9e4066Sahrens 		found_config = NULL;
1519fa9e4066Sahrens 	}
1520fa9e4066Sahrens 
152124e697d4Sck153898 	if (cachefile) {
1522e829d913Sck153898 		pools = zpool_find_import_cached(g_zfs, cachefile, searchname,
1523e829d913Sck153898 		    searchguid);
152424e697d4Sck153898 	} else if (searchname != NULL) {
152524e697d4Sck153898 		pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs,
152624e697d4Sck153898 		    searchname);
152724e697d4Sck153898 	} else {
152824e697d4Sck153898 		/*
152924e697d4Sck153898 		 * It's OK to search by guid even if searchguid is 0.
153024e697d4Sck153898 		 */
153124e697d4Sck153898 		pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs,
153224e697d4Sck153898 		    searchguid);
153324e697d4Sck153898 	}
153424e697d4Sck153898 
153524e697d4Sck153898 	if (pools == NULL) {
153624e697d4Sck153898 		if (argc != 0) {
153724e697d4Sck153898 			(void) fprintf(stderr, gettext("cannot import '%s': "
153824e697d4Sck153898 			    "no such pool available\n"), argv[0]);
153924e697d4Sck153898 		}
154024e697d4Sck153898 		free(searchdirs);
154124e697d4Sck153898 		return (1);
154224e697d4Sck153898 	}
154324e697d4Sck153898 
154424e697d4Sck153898 	/*
154524e697d4Sck153898 	 * At this point we have a list of import candidate configs. Even if
154624e697d4Sck153898 	 * we were searching by pool name or guid, we still need to
154724e697d4Sck153898 	 * post-process the list to deal with pool state and possible
154824e697d4Sck153898 	 * duplicate names.
154924e697d4Sck153898 	 */
1550fa9e4066Sahrens 	err = 0;
1551fa9e4066Sahrens 	elem = NULL;
155299653d4eSeschrock 	first = B_TRUE;
1553fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1554fa9e4066Sahrens 
1555fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1556fa9e4066Sahrens 
15574c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
15584c58d714Sdarrenm 		    &pool_state) == 0);
15594c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
15604c58d714Sdarrenm 			continue;
15614c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
15624c58d714Sdarrenm 			continue;
15634c58d714Sdarrenm 
1564fa9e4066Sahrens 		if (argc == 0) {
1565fa9e4066Sahrens 			if (first)
156699653d4eSeschrock 				first = B_FALSE;
15673bb79becSeschrock 			else if (!do_all)
1568fa9e4066Sahrens 				(void) printf("\n");
1569fa9e4066Sahrens 
1570fa9e4066Sahrens 			if (do_all)
1571fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1572c5904d13Seschrock 				    do_force, props, allow_faulted);
1573fa9e4066Sahrens 			else
1574fa9e4066Sahrens 				show_import(config);
1575fa9e4066Sahrens 		} else if (searchname != NULL) {
1576fa9e4066Sahrens 			char *name;
1577fa9e4066Sahrens 
1578fa9e4066Sahrens 			/*
1579fa9e4066Sahrens 			 * We are searching for a pool based on name.
1580fa9e4066Sahrens 			 */
1581fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1582fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1583fa9e4066Sahrens 
1584fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1585fa9e4066Sahrens 				if (found_config != NULL) {
1586fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1587fa9e4066Sahrens 					    "cannot import '%s': more than "
1588fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1589fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1590fa9e4066Sahrens 					    "import by numeric ID instead\n"));
159199653d4eSeschrock 					err = B_TRUE;
1592fa9e4066Sahrens 				}
1593fa9e4066Sahrens 				found_config = config;
1594fa9e4066Sahrens 			}
1595fa9e4066Sahrens 		} else {
1596fa9e4066Sahrens 			uint64_t guid;
1597fa9e4066Sahrens 
1598fa9e4066Sahrens 			/*
1599fa9e4066Sahrens 			 * Search for a pool by guid.
1600fa9e4066Sahrens 			 */
1601fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1602fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1603fa9e4066Sahrens 
1604fa9e4066Sahrens 			if (guid == searchguid)
1605fa9e4066Sahrens 				found_config = config;
1606fa9e4066Sahrens 		}
1607fa9e4066Sahrens 	}
1608fa9e4066Sahrens 
1609fa9e4066Sahrens 	/*
1610fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1611fa9e4066Sahrens 	 * pool, and then do the import.
1612fa9e4066Sahrens 	 */
1613fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1614fa9e4066Sahrens 		if (found_config == NULL) {
1615fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1616fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
161799653d4eSeschrock 			err = B_TRUE;
1618fa9e4066Sahrens 		} else {
1619fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1620c5904d13Seschrock 			    argv[1], mntopts, do_force, props, allow_faulted);
1621fa9e4066Sahrens 		}
1622fa9e4066Sahrens 	}
1623fa9e4066Sahrens 
1624fa9e4066Sahrens 	/*
1625fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1626fa9e4066Sahrens 	 * found.
1627fa9e4066Sahrens 	 */
1628fa9e4066Sahrens 	if (argc == 0 && first)
1629fa9e4066Sahrens 		(void) fprintf(stderr,
1630fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1631fa9e4066Sahrens 
1632ecd6cf80Smarks error:
1633ecd6cf80Smarks 	nvlist_free(props);
1634fa9e4066Sahrens 	nvlist_free(pools);
163599653d4eSeschrock 	free(searchdirs);
1636fa9e4066Sahrens 
1637fa9e4066Sahrens 	return (err ? 1 : 0);
1638fa9e4066Sahrens }
1639fa9e4066Sahrens 
1640fa9e4066Sahrens typedef struct iostat_cbdata {
1641fa9e4066Sahrens 	zpool_list_t *cb_list;
1642fa9e4066Sahrens 	int cb_verbose;
1643fa9e4066Sahrens 	int cb_iteration;
1644fa9e4066Sahrens 	int cb_namewidth;
1645fa9e4066Sahrens } iostat_cbdata_t;
1646fa9e4066Sahrens 
1647fa9e4066Sahrens static void
1648fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1649fa9e4066Sahrens {
1650fa9e4066Sahrens 	int i = 0;
1651fa9e4066Sahrens 
1652fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1653fa9e4066Sahrens 		(void) printf("-");
1654fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1655fa9e4066Sahrens }
1656fa9e4066Sahrens 
1657fa9e4066Sahrens static void
1658fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1659fa9e4066Sahrens {
1660fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1661fa9e4066Sahrens 	    cb->cb_namewidth, "");
1662fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1663fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1664fa9e4066Sahrens 	print_iostat_separator(cb);
1665fa9e4066Sahrens }
1666fa9e4066Sahrens 
1667fa9e4066Sahrens /*
1668fa9e4066Sahrens  * Display a single statistic.
1669fa9e4066Sahrens  */
1670990b4856Slling static void
1671fa9e4066Sahrens print_one_stat(uint64_t value)
1672fa9e4066Sahrens {
1673fa9e4066Sahrens 	char buf[64];
1674fa9e4066Sahrens 
1675fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1676fa9e4066Sahrens 	(void) printf("  %5s", buf);
1677fa9e4066Sahrens }
1678fa9e4066Sahrens 
1679fa9e4066Sahrens /*
1680fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1681fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1682fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1683fa9e4066Sahrens  */
1684fa9e4066Sahrens void
1685c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1686c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1687fa9e4066Sahrens {
1688fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1689fa9e4066Sahrens 	uint_t c, children;
1690fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1691fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1692fa9e4066Sahrens 	uint64_t tdelta;
1693fa9e4066Sahrens 	double scale;
1694afefbcddSeschrock 	char *vname;
1695fa9e4066Sahrens 
1696fa9e4066Sahrens 	if (oldnv != NULL) {
1697fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1698fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1699fa9e4066Sahrens 	} else {
1700fa9e4066Sahrens 		oldvs = &zerovs;
1701fa9e4066Sahrens 	}
1702fa9e4066Sahrens 
1703fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1704fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1705fa9e4066Sahrens 
1706fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1707fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1708fa9e4066Sahrens 	else
1709fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1710fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1711fa9e4066Sahrens 
1712fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1713fa9e4066Sahrens 
1714fa9e4066Sahrens 	if (tdelta == 0)
1715fa9e4066Sahrens 		scale = 1.0;
1716fa9e4066Sahrens 	else
1717fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1718fa9e4066Sahrens 
1719fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1720fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1721fa9e4066Sahrens 		(void) printf("      -      -");
1722fa9e4066Sahrens 	} else {
1723fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1724fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1725fa9e4066Sahrens 	}
1726fa9e4066Sahrens 
1727fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1728fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1729fa9e4066Sahrens 
1730fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1731fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1732fa9e4066Sahrens 
1733fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1734fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1735fa9e4066Sahrens 
1736fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1737fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1738fa9e4066Sahrens 
1739fa9e4066Sahrens 	(void) printf("\n");
1740fa9e4066Sahrens 
1741fa9e4066Sahrens 	if (!cb->cb_verbose)
1742fa9e4066Sahrens 		return;
1743fa9e4066Sahrens 
1744fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1745fa9e4066Sahrens 	    &newchild, &children) != 0)
1746fa9e4066Sahrens 		return;
1747fa9e4066Sahrens 
1748fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1749fa9e4066Sahrens 	    &oldchild, &c) != 0)
1750fa9e4066Sahrens 		return;
1751fa9e4066Sahrens 
1752afefbcddSeschrock 	for (c = 0; c < children; c++) {
175399653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1754c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1755afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1756afefbcddSeschrock 		free(vname);
1757afefbcddSeschrock 	}
1758fa94a07fSbrendan 
1759fa94a07fSbrendan 	/*
1760fa94a07fSbrendan 	 * Include level 2 ARC devices in iostat output
1761fa94a07fSbrendan 	 */
1762fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
1763fa94a07fSbrendan 	    &newchild, &children) != 0)
1764fa94a07fSbrendan 		return;
1765fa94a07fSbrendan 
1766fa94a07fSbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
1767fa94a07fSbrendan 	    &oldchild, &c) != 0)
1768fa94a07fSbrendan 		return;
1769fa94a07fSbrendan 
1770fa94a07fSbrendan 	if (children > 0) {
1771fa94a07fSbrendan 		(void) printf("%-*s      -      -      -      -      -      "
1772fa94a07fSbrendan 		    "-\n", cb->cb_namewidth, "cache");
1773fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1774fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1775fa94a07fSbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1776fa94a07fSbrendan 			    newchild[c], cb, depth + 2);
1777fa94a07fSbrendan 			free(vname);
1778fa94a07fSbrendan 		}
1779fa94a07fSbrendan 	}
1780fa9e4066Sahrens }
1781fa9e4066Sahrens 
1782088e9d47Seschrock static int
1783088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
1784088e9d47Seschrock {
1785088e9d47Seschrock 	iostat_cbdata_t *cb = data;
178694de1d4cSeschrock 	boolean_t missing;
1787088e9d47Seschrock 
1788088e9d47Seschrock 	/*
1789088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
1790088e9d47Seschrock 	 */
179194de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
179294de1d4cSeschrock 		return (-1);
179394de1d4cSeschrock 
179494de1d4cSeschrock 	if (missing)
1795088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
1796088e9d47Seschrock 
1797088e9d47Seschrock 	return (0);
1798088e9d47Seschrock }
1799088e9d47Seschrock 
1800fa9e4066Sahrens /*
1801fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
1802fa9e4066Sahrens  */
1803fa9e4066Sahrens int
1804fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
1805fa9e4066Sahrens {
1806fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1807fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
1808fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
1809fa9e4066Sahrens 
1810088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
1811fa9e4066Sahrens 
1812088e9d47Seschrock 	if (cb->cb_iteration == 1)
1813fa9e4066Sahrens 		oldconfig = NULL;
1814fa9e4066Sahrens 
1815fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1816fa9e4066Sahrens 	    &newnvroot) == 0);
1817fa9e4066Sahrens 
1818088e9d47Seschrock 	if (oldconfig == NULL)
1819fa9e4066Sahrens 		oldnvroot = NULL;
1820088e9d47Seschrock 	else
1821088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
1822088e9d47Seschrock 		    &oldnvroot) == 0);
1823fa9e4066Sahrens 
1824fa9e4066Sahrens 	/*
1825fa9e4066Sahrens 	 * Print out the statistics for the pool.
1826fa9e4066Sahrens 	 */
1827c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1828fa9e4066Sahrens 
1829fa9e4066Sahrens 	if (cb->cb_verbose)
1830fa9e4066Sahrens 		print_iostat_separator(cb);
1831fa9e4066Sahrens 
1832fa9e4066Sahrens 	return (0);
1833fa9e4066Sahrens }
1834fa9e4066Sahrens 
1835fa9e4066Sahrens int
1836fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
1837fa9e4066Sahrens {
1838fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1839fa9e4066Sahrens 	nvlist_t *config, *nvroot;
1840fa9e4066Sahrens 
1841088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
1842fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1843fa9e4066Sahrens 		    &nvroot) == 0);
1844fa9e4066Sahrens 		if (!cb->cb_verbose)
1845fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1846fa9e4066Sahrens 		else
1847c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
1848fa9e4066Sahrens 	}
1849fa9e4066Sahrens 
1850fa9e4066Sahrens 	/*
1851fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
1852fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
1853fa9e4066Sahrens 	 */
1854fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
1855fa9e4066Sahrens 		cb->cb_namewidth = 10;
1856fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
1857fa9e4066Sahrens 		cb->cb_namewidth = 38;
1858fa9e4066Sahrens 
1859fa9e4066Sahrens 	return (0);
1860fa9e4066Sahrens }
1861fa9e4066Sahrens 
1862fa9e4066Sahrens /*
1863fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
1864fa9e4066Sahrens  *
1865fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
1866fa9e4066Sahrens  *
1867fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
1868fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
1869fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1870fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
1871fa9e4066Sahrens  * changes are all handled within libzfs.
1872fa9e4066Sahrens  */
1873fa9e4066Sahrens int
1874fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
1875fa9e4066Sahrens {
1876fa9e4066Sahrens 	int c;
1877fa9e4066Sahrens 	int ret;
1878fa9e4066Sahrens 	int npools;
1879fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
1880fa9e4066Sahrens 	zpool_list_t *list;
188199653d4eSeschrock 	boolean_t verbose = B_FALSE;
1882fa9e4066Sahrens 	iostat_cbdata_t cb;
1883fa9e4066Sahrens 
1884fa9e4066Sahrens 	/* check options */
1885fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
1886fa9e4066Sahrens 		switch (c) {
1887fa9e4066Sahrens 		case 'v':
188899653d4eSeschrock 			verbose = B_TRUE;
1889fa9e4066Sahrens 			break;
1890fa9e4066Sahrens 		case '?':
1891fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1892fa9e4066Sahrens 			    optopt);
189399653d4eSeschrock 			usage(B_FALSE);
1894fa9e4066Sahrens 		}
1895fa9e4066Sahrens 	}
1896fa9e4066Sahrens 
1897fa9e4066Sahrens 	argc -= optind;
1898fa9e4066Sahrens 	argv += optind;
1899fa9e4066Sahrens 
1900fa9e4066Sahrens 	/*
1901fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
1902fa9e4066Sahrens 	 */
1903fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1904fa9e4066Sahrens 		char *end;
1905fa9e4066Sahrens 
1906fa9e4066Sahrens 		errno = 0;
1907fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1908fa9e4066Sahrens 
1909fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1910fa9e4066Sahrens 			if (interval == 0) {
1911fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1912fa9e4066Sahrens 				    "cannot be zero\n"));
191399653d4eSeschrock 				usage(B_FALSE);
1914fa9e4066Sahrens 			}
1915fa9e4066Sahrens 
1916fa9e4066Sahrens 			/*
1917fa9e4066Sahrens 			 * Ignore the last parameter
1918fa9e4066Sahrens 			 */
1919fa9e4066Sahrens 			argc--;
1920fa9e4066Sahrens 		} else {
1921fa9e4066Sahrens 			/*
1922fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
1923fa9e4066Sahrens 			 * user will get a more informative error message later
1924fa9e4066Sahrens 			 * on.
1925fa9e4066Sahrens 			 */
1926fa9e4066Sahrens 			interval = 0;
1927fa9e4066Sahrens 		}
1928fa9e4066Sahrens 	}
1929fa9e4066Sahrens 
1930fa9e4066Sahrens 	/*
1931fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
1932fa9e4066Sahrens 	 * and an integer.
1933fa9e4066Sahrens 	 */
1934fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1935fa9e4066Sahrens 		char *end;
1936fa9e4066Sahrens 
1937fa9e4066Sahrens 		errno = 0;
1938fa9e4066Sahrens 		count = interval;
1939fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1940fa9e4066Sahrens 
1941fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1942fa9e4066Sahrens 			if (interval == 0) {
1943fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1944fa9e4066Sahrens 				    "cannot be zero\n"));
194599653d4eSeschrock 				usage(B_FALSE);
1946fa9e4066Sahrens 			}
1947fa9e4066Sahrens 
1948fa9e4066Sahrens 			/*
1949fa9e4066Sahrens 			 * Ignore the last parameter
1950fa9e4066Sahrens 			 */
1951fa9e4066Sahrens 			argc--;
1952fa9e4066Sahrens 		} else {
1953fa9e4066Sahrens 			interval = 0;
1954fa9e4066Sahrens 		}
1955fa9e4066Sahrens 	}
1956fa9e4066Sahrens 
1957fa9e4066Sahrens 	/*
1958fa9e4066Sahrens 	 * Construct the list of all interesting pools.
1959fa9e4066Sahrens 	 */
1960fa9e4066Sahrens 	ret = 0;
1961b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
1962fa9e4066Sahrens 		return (1);
1963fa9e4066Sahrens 
196499653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
196599653d4eSeschrock 		pool_list_free(list);
1966fa9e4066Sahrens 		return (1);
196799653d4eSeschrock 	}
1968fa9e4066Sahrens 
1969fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
197099653d4eSeschrock 		pool_list_free(list);
1971fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
1972fa9e4066Sahrens 		return (1);
1973fa9e4066Sahrens 	}
1974fa9e4066Sahrens 
1975fa9e4066Sahrens 	/*
1976fa9e4066Sahrens 	 * Enter the main iostat loop.
1977fa9e4066Sahrens 	 */
1978fa9e4066Sahrens 	cb.cb_list = list;
1979fa9e4066Sahrens 	cb.cb_verbose = verbose;
1980fa9e4066Sahrens 	cb.cb_iteration = 0;
1981fa9e4066Sahrens 	cb.cb_namewidth = 0;
1982fa9e4066Sahrens 
1983fa9e4066Sahrens 	for (;;) {
1984fa9e4066Sahrens 		pool_list_update(list);
1985fa9e4066Sahrens 
1986fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
1987fa9e4066Sahrens 			break;
1988fa9e4066Sahrens 
1989fa9e4066Sahrens 		/*
1990088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
1991088e9d47Seschrock 		 * before calculating the maximum name width, so that any
1992088e9d47Seschrock 		 * configuration changes are properly accounted for.
1993088e9d47Seschrock 		 */
199499653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
1995088e9d47Seschrock 
1996088e9d47Seschrock 		/*
1997fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
1998fa9e4066Sahrens 		 * for the pool / device name column across all pools.
1999fa9e4066Sahrens 		 */
2000fa9e4066Sahrens 		cb.cb_namewidth = 0;
200199653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2002fa9e4066Sahrens 
2003fa9e4066Sahrens 		/*
2004fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
2005fa9e4066Sahrens 		 */
2006fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
2007fa9e4066Sahrens 			print_iostat_header(&cb);
2008fa9e4066Sahrens 
200999653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2010fa9e4066Sahrens 
2011fa9e4066Sahrens 		/*
2012fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
2013fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
2014fa9e4066Sahrens 		 */
2015fa9e4066Sahrens 		if (npools > 1 && !verbose)
2016fa9e4066Sahrens 			print_iostat_separator(&cb);
2017fa9e4066Sahrens 
2018fa9e4066Sahrens 		if (verbose)
2019fa9e4066Sahrens 			(void) printf("\n");
2020fa9e4066Sahrens 
202139c23413Seschrock 		/*
202239c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
202339c23413Seschrock 		 * indefinitely.
202439c23413Seschrock 		 */
202539c23413Seschrock 		(void) fflush(stdout);
202639c23413Seschrock 
2027fa9e4066Sahrens 		if (interval == 0)
2028fa9e4066Sahrens 			break;
2029fa9e4066Sahrens 
2030fa9e4066Sahrens 		if (count != 0 && --count == 0)
2031fa9e4066Sahrens 			break;
2032fa9e4066Sahrens 
2033fa9e4066Sahrens 		(void) sleep(interval);
2034fa9e4066Sahrens 	}
2035fa9e4066Sahrens 
2036fa9e4066Sahrens 	pool_list_free(list);
2037fa9e4066Sahrens 
2038fa9e4066Sahrens 	return (ret);
2039fa9e4066Sahrens }
2040fa9e4066Sahrens 
2041fa9e4066Sahrens typedef struct list_cbdata {
204299653d4eSeschrock 	boolean_t	cb_scripted;
204399653d4eSeschrock 	boolean_t	cb_first;
2044990b4856Slling 	zprop_list_t	*cb_proplist;
2045fa9e4066Sahrens } list_cbdata_t;
2046fa9e4066Sahrens 
2047fa9e4066Sahrens /*
2048fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
2049fa9e4066Sahrens  */
2050990b4856Slling static void
2051990b4856Slling print_header(zprop_list_t *pl)
2052fa9e4066Sahrens {
2053990b4856Slling 	const char *header;
2054990b4856Slling 	boolean_t first = B_TRUE;
2055990b4856Slling 	boolean_t right_justify;
2056fa9e4066Sahrens 
2057990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2058990b4856Slling 		if (pl->pl_prop == ZPROP_INVAL)
2059990b4856Slling 			continue;
2060990b4856Slling 
2061990b4856Slling 		if (!first)
2062fa9e4066Sahrens 			(void) printf("  ");
2063fa9e4066Sahrens 		else
2064990b4856Slling 			first = B_FALSE;
2065fa9e4066Sahrens 
2066990b4856Slling 		header = zpool_prop_column_name(pl->pl_prop);
2067990b4856Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
2068990b4856Slling 
2069990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
2070990b4856Slling 			(void) printf("%s", header);
2071990b4856Slling 		else if (right_justify)
2072990b4856Slling 			(void) printf("%*s", pl->pl_width, header);
2073990b4856Slling 		else
2074990b4856Slling 			(void) printf("%-*s", pl->pl_width, header);
2075fa9e4066Sahrens 	}
2076fa9e4066Sahrens 
2077fa9e4066Sahrens 	(void) printf("\n");
2078fa9e4066Sahrens }
2079fa9e4066Sahrens 
2080990b4856Slling /*
2081990b4856Slling  * Given a pool and a list of properties, print out all the properties according
2082990b4856Slling  * to the described layout.
2083990b4856Slling  */
2084990b4856Slling static void
2085990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
2086990b4856Slling {
2087990b4856Slling 	boolean_t first = B_TRUE;
2088990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
2089990b4856Slling 	char *propstr;
2090990b4856Slling 	boolean_t right_justify;
2091990b4856Slling 	int width;
2092990b4856Slling 
2093990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2094990b4856Slling 		if (!first) {
2095990b4856Slling 			if (scripted)
2096990b4856Slling 				(void) printf("\t");
2097990b4856Slling 			else
2098990b4856Slling 				(void) printf("  ");
2099990b4856Slling 		} else {
2100990b4856Slling 			first = B_FALSE;
2101990b4856Slling 		}
2102990b4856Slling 
2103990b4856Slling 		right_justify = B_FALSE;
2104990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
2105990b4856Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
2106990b4856Slling 			    sizeof (property), NULL) != 0)
2107990b4856Slling 				propstr = "-";
2108990b4856Slling 			else
2109990b4856Slling 				propstr = property;
2110990b4856Slling 
2111990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2112990b4856Slling 		} else {
2113990b4856Slling 			propstr = "-";
2114990b4856Slling 		}
2115990b4856Slling 
2116990b4856Slling 		width = pl->pl_width;
2117990b4856Slling 
2118990b4856Slling 		/*
2119990b4856Slling 		 * If this is being called in scripted mode, or if this is the
2120990b4856Slling 		 * last column and it is left-justified, don't include a width
2121990b4856Slling 		 * format specifier.
2122990b4856Slling 		 */
2123990b4856Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
2124990b4856Slling 			(void) printf("%s", propstr);
2125990b4856Slling 		else if (right_justify)
2126990b4856Slling 			(void) printf("%*s", width, propstr);
2127990b4856Slling 		else
2128990b4856Slling 			(void) printf("%-*s", width, propstr);
2129990b4856Slling 	}
2130990b4856Slling 
2131990b4856Slling 	(void) printf("\n");
2132990b4856Slling }
2133990b4856Slling 
2134990b4856Slling /*
2135990b4856Slling  * Generic callback function to list a pool.
2136990b4856Slling  */
2137fa9e4066Sahrens int
2138fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2139fa9e4066Sahrens {
2140fa9e4066Sahrens 	list_cbdata_t *cbp = data;
2141fa9e4066Sahrens 
2142fa9e4066Sahrens 	if (cbp->cb_first) {
2143fa9e4066Sahrens 		if (!cbp->cb_scripted)
2144990b4856Slling 			print_header(cbp->cb_proplist);
214599653d4eSeschrock 		cbp->cb_first = B_FALSE;
2146fa9e4066Sahrens 	}
2147fa9e4066Sahrens 
2148990b4856Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2149fa9e4066Sahrens 
2150fa9e4066Sahrens 	return (0);
2151fa9e4066Sahrens }
2152fa9e4066Sahrens 
2153fa9e4066Sahrens /*
2154990b4856Slling  * zpool list [-H] [-o prop[,prop]*] [pool] ...
2155fa9e4066Sahrens  *
2156990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2157990b4856Slling  *		by a single tab.
2158990b4856Slling  *	-o	List of properties to display.  Defaults to
2159990b4856Slling  *		"name,size,used,available,capacity,health,altroot"
2160fa9e4066Sahrens  *
2161fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2162fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2163fa9e4066Sahrens  */
2164fa9e4066Sahrens int
2165fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2166fa9e4066Sahrens {
2167fa9e4066Sahrens 	int c;
2168fa9e4066Sahrens 	int ret;
2169fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2170990b4856Slling 	static char default_props[] =
2171990b4856Slling 	    "name,size,used,available,capacity,health,altroot";
2172990b4856Slling 	char *props = default_props;
2173fa9e4066Sahrens 
2174fa9e4066Sahrens 	/* check options */
2175fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2176fa9e4066Sahrens 		switch (c) {
2177fa9e4066Sahrens 		case 'H':
217899653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2179fa9e4066Sahrens 			break;
2180fa9e4066Sahrens 		case 'o':
2181990b4856Slling 			props = optarg;
2182fa9e4066Sahrens 			break;
2183fa9e4066Sahrens 		case ':':
2184fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2185fa9e4066Sahrens 			    "'%c' option\n"), optopt);
218699653d4eSeschrock 			usage(B_FALSE);
2187fa9e4066Sahrens 			break;
2188fa9e4066Sahrens 		case '?':
2189fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2190fa9e4066Sahrens 			    optopt);
219199653d4eSeschrock 			usage(B_FALSE);
2192fa9e4066Sahrens 		}
2193fa9e4066Sahrens 	}
2194fa9e4066Sahrens 
2195fa9e4066Sahrens 	argc -= optind;
2196fa9e4066Sahrens 	argv += optind;
2197fa9e4066Sahrens 
2198990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
219999653d4eSeschrock 		usage(B_FALSE);
2200fa9e4066Sahrens 
220199653d4eSeschrock 	cb.cb_first = B_TRUE;
2202fa9e4066Sahrens 
2203990b4856Slling 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2204990b4856Slling 	    list_callback, &cb);
2205990b4856Slling 
2206990b4856Slling 	zprop_free_list(cb.cb_proplist);
2207fa9e4066Sahrens 
2208fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2209fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2210fa9e4066Sahrens 		return (0);
2211fa9e4066Sahrens 	}
2212fa9e4066Sahrens 
2213fa9e4066Sahrens 	return (ret);
2214fa9e4066Sahrens }
2215fa9e4066Sahrens 
2216fa9e4066Sahrens static nvlist_t *
2217fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2218fa9e4066Sahrens {
2219fa9e4066Sahrens 	nvlist_t **child;
2220fa9e4066Sahrens 	uint_t c, children;
2221fa9e4066Sahrens 	nvlist_t *match;
2222fa9e4066Sahrens 	char *path;
2223fa9e4066Sahrens 
2224fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2225fa9e4066Sahrens 	    &child, &children) != 0) {
2226fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2227fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2228fa9e4066Sahrens 			name += 9;
2229fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2230fa9e4066Sahrens 			path += 9;
2231fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2232fa9e4066Sahrens 			return (nv);
2233fa9e4066Sahrens 		return (NULL);
2234fa9e4066Sahrens 	}
2235fa9e4066Sahrens 
2236fa9e4066Sahrens 	for (c = 0; c < children; c++)
2237fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2238fa9e4066Sahrens 			return (match);
2239fa9e4066Sahrens 
2240fa9e4066Sahrens 	return (NULL);
2241fa9e4066Sahrens }
2242fa9e4066Sahrens 
2243fa9e4066Sahrens static int
2244fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2245fa9e4066Sahrens {
224699653d4eSeschrock 	boolean_t force = B_FALSE;
2247fa9e4066Sahrens 	int c;
2248fa9e4066Sahrens 	nvlist_t *nvroot;
2249fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2250fa9e4066Sahrens 	zpool_handle_t *zhp;
225199653d4eSeschrock 	int ret;
2252fa9e4066Sahrens 
2253fa9e4066Sahrens 	/* check options */
2254fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2255fa9e4066Sahrens 		switch (c) {
2256fa9e4066Sahrens 		case 'f':
225799653d4eSeschrock 			force = B_TRUE;
2258fa9e4066Sahrens 			break;
2259fa9e4066Sahrens 		case '?':
2260fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2261fa9e4066Sahrens 			    optopt);
226299653d4eSeschrock 			usage(B_FALSE);
2263fa9e4066Sahrens 		}
2264fa9e4066Sahrens 	}
2265fa9e4066Sahrens 
2266fa9e4066Sahrens 	argc -= optind;
2267fa9e4066Sahrens 	argv += optind;
2268fa9e4066Sahrens 
2269fa9e4066Sahrens 	/* get pool name and check number of arguments */
2270fa9e4066Sahrens 	if (argc < 1) {
2271fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
227299653d4eSeschrock 		usage(B_FALSE);
2273fa9e4066Sahrens 	}
2274fa9e4066Sahrens 
2275fa9e4066Sahrens 	poolname = argv[0];
2276fa9e4066Sahrens 
2277fa9e4066Sahrens 	if (argc < 2) {
2278fa9e4066Sahrens 		(void) fprintf(stderr,
2279fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
228099653d4eSeschrock 		usage(B_FALSE);
2281fa9e4066Sahrens 	}
2282fa9e4066Sahrens 
2283fa9e4066Sahrens 	old_disk = argv[1];
2284fa9e4066Sahrens 
2285fa9e4066Sahrens 	if (argc < 3) {
2286fa9e4066Sahrens 		if (!replacing) {
2287fa9e4066Sahrens 			(void) fprintf(stderr,
2288fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
228999653d4eSeschrock 			usage(B_FALSE);
2290fa9e4066Sahrens 		}
2291fa9e4066Sahrens 		new_disk = old_disk;
2292fa9e4066Sahrens 		argc -= 1;
2293fa9e4066Sahrens 		argv += 1;
2294fa9e4066Sahrens 	} else {
2295fa9e4066Sahrens 		new_disk = argv[2];
2296fa9e4066Sahrens 		argc -= 2;
2297fa9e4066Sahrens 		argv += 2;
2298fa9e4066Sahrens 	}
2299fa9e4066Sahrens 
2300fa9e4066Sahrens 	if (argc > 1) {
2301fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
230299653d4eSeschrock 		usage(B_FALSE);
2303fa9e4066Sahrens 	}
2304fa9e4066Sahrens 
230599653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2306fa9e4066Sahrens 		return (1);
2307fa9e4066Sahrens 
23088488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2309fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2310fa9e4066Sahrens 		    poolname);
2311fa9e4066Sahrens 		zpool_close(zhp);
2312fa9e4066Sahrens 		return (1);
2313fa9e4066Sahrens 	}
2314fa9e4066Sahrens 
2315705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
2316705040edSEric Taylor 	    argc, argv);
2317fa9e4066Sahrens 	if (nvroot == NULL) {
2318fa9e4066Sahrens 		zpool_close(zhp);
2319fa9e4066Sahrens 		return (1);
2320fa9e4066Sahrens 	}
2321fa9e4066Sahrens 
232299653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
232399653d4eSeschrock 
232499653d4eSeschrock 	nvlist_free(nvroot);
232599653d4eSeschrock 	zpool_close(zhp);
232699653d4eSeschrock 
232799653d4eSeschrock 	return (ret);
2328fa9e4066Sahrens }
2329fa9e4066Sahrens 
2330fa9e4066Sahrens /*
2331fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2332fa9e4066Sahrens  *
2333fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2334fa9e4066Sahrens  *
2335fa9e4066Sahrens  * Replace <device> with <new_device>.
2336fa9e4066Sahrens  */
2337fa9e4066Sahrens /* ARGSUSED */
2338fa9e4066Sahrens int
2339fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2340fa9e4066Sahrens {
2341fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2342fa9e4066Sahrens }
2343fa9e4066Sahrens 
2344fa9e4066Sahrens /*
2345fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2346fa9e4066Sahrens  *
2347fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2348fa9e4066Sahrens  *
2349fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2350fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2351fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2352fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2353fa9e4066Sahrens  */
2354fa9e4066Sahrens int
2355fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2356fa9e4066Sahrens {
2357fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2358fa9e4066Sahrens }
2359fa9e4066Sahrens 
2360fa9e4066Sahrens /*
2361fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2362fa9e4066Sahrens  *
2363fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2364fa9e4066Sahrens  *		(not supported yet)
2365fa9e4066Sahrens  *
2366fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2367fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2368fa9e4066Sahrens  * has the only valid copy of some data.
2369fa9e4066Sahrens  */
2370fa9e4066Sahrens /* ARGSUSED */
2371fa9e4066Sahrens int
2372fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2373fa9e4066Sahrens {
2374fa9e4066Sahrens 	int c;
2375fa9e4066Sahrens 	char *poolname, *path;
2376fa9e4066Sahrens 	zpool_handle_t *zhp;
237799653d4eSeschrock 	int ret;
2378fa9e4066Sahrens 
2379fa9e4066Sahrens 	/* check options */
2380fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2381fa9e4066Sahrens 		switch (c) {
2382fa9e4066Sahrens 		case 'f':
2383fa9e4066Sahrens 		case '?':
2384fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2385fa9e4066Sahrens 			    optopt);
238699653d4eSeschrock 			usage(B_FALSE);
2387fa9e4066Sahrens 		}
2388fa9e4066Sahrens 	}
2389fa9e4066Sahrens 
2390fa9e4066Sahrens 	argc -= optind;
2391fa9e4066Sahrens 	argv += optind;
2392fa9e4066Sahrens 
2393fa9e4066Sahrens 	/* get pool name and check number of arguments */
2394fa9e4066Sahrens 	if (argc < 1) {
2395fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
239699653d4eSeschrock 		usage(B_FALSE);
2397fa9e4066Sahrens 	}
2398fa9e4066Sahrens 
2399fa9e4066Sahrens 	if (argc < 2) {
2400fa9e4066Sahrens 		(void) fprintf(stderr,
2401fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
240299653d4eSeschrock 		usage(B_FALSE);
2403fa9e4066Sahrens 	}
2404fa9e4066Sahrens 
2405fa9e4066Sahrens 	poolname = argv[0];
2406fa9e4066Sahrens 	path = argv[1];
2407fa9e4066Sahrens 
240899653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2409fa9e4066Sahrens 		return (1);
2410fa9e4066Sahrens 
241199653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
241299653d4eSeschrock 
241399653d4eSeschrock 	zpool_close(zhp);
241499653d4eSeschrock 
241599653d4eSeschrock 	return (ret);
2416fa9e4066Sahrens }
2417fa9e4066Sahrens 
2418fa9e4066Sahrens /*
2419441d80aaSlling  * zpool online <pool> <device> ...
2420fa9e4066Sahrens  */
2421fa9e4066Sahrens int
2422fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2423fa9e4066Sahrens {
2424fa9e4066Sahrens 	int c, i;
2425fa9e4066Sahrens 	char *poolname;
2426fa9e4066Sahrens 	zpool_handle_t *zhp;
2427fa9e4066Sahrens 	int ret = 0;
24283d7072f8Seschrock 	vdev_state_t newstate;
2429fa9e4066Sahrens 
2430fa9e4066Sahrens 	/* check options */
2431fa9e4066Sahrens 	while ((c = getopt(argc, argv, "t")) != -1) {
2432fa9e4066Sahrens 		switch (c) {
2433fa9e4066Sahrens 		case 't':
2434fa9e4066Sahrens 		case '?':
2435fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2436fa9e4066Sahrens 			    optopt);
243799653d4eSeschrock 			usage(B_FALSE);
2438fa9e4066Sahrens 		}
2439fa9e4066Sahrens 	}
2440fa9e4066Sahrens 
2441fa9e4066Sahrens 	argc -= optind;
2442fa9e4066Sahrens 	argv += optind;
2443fa9e4066Sahrens 
2444fa9e4066Sahrens 	/* get pool name and check number of arguments */
2445fa9e4066Sahrens 	if (argc < 1) {
2446fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
244799653d4eSeschrock 		usage(B_FALSE);
2448fa9e4066Sahrens 	}
2449fa9e4066Sahrens 	if (argc < 2) {
2450fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
245199653d4eSeschrock 		usage(B_FALSE);
2452fa9e4066Sahrens 	}
2453fa9e4066Sahrens 
2454fa9e4066Sahrens 	poolname = argv[0];
2455fa9e4066Sahrens 
245699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2457fa9e4066Sahrens 		return (1);
2458fa9e4066Sahrens 
24593d7072f8Seschrock 	for (i = 1; i < argc; i++) {
24603d7072f8Seschrock 		if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
24613d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
24623d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
24633d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
2464fa9e4066Sahrens 				    argv[i]);
24653d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
24663d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24673d7072f8Seschrock 					    "clear' to restore a faulted "
24683d7072f8Seschrock 					    "device\n"));
2469fa9e4066Sahrens 				else
24703d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24713d7072f8Seschrock 					    "replace' to replace devices "
24723d7072f8Seschrock 					    "that are no longer present\n"));
24733d7072f8Seschrock 			}
24743d7072f8Seschrock 		} else {
2475fa9e4066Sahrens 			ret = 1;
24763d7072f8Seschrock 		}
24773d7072f8Seschrock 	}
2478fa9e4066Sahrens 
247999653d4eSeschrock 	zpool_close(zhp);
248099653d4eSeschrock 
2481fa9e4066Sahrens 	return (ret);
2482fa9e4066Sahrens }
2483fa9e4066Sahrens 
2484fa9e4066Sahrens /*
2485441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2486fa9e4066Sahrens  *
2487fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2488fa9e4066Sahrens  *		so would appear to compromise pool availability.
2489fa9e4066Sahrens  *		(not supported yet)
2490fa9e4066Sahrens  *
2491fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2492fa9e4066Sahrens  *		state will not be persistent across reboots.
2493fa9e4066Sahrens  */
2494fa9e4066Sahrens /* ARGSUSED */
2495fa9e4066Sahrens int
2496fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2497fa9e4066Sahrens {
2498fa9e4066Sahrens 	int c, i;
2499fa9e4066Sahrens 	char *poolname;
2500fa9e4066Sahrens 	zpool_handle_t *zhp;
250199653d4eSeschrock 	int ret = 0;
250299653d4eSeschrock 	boolean_t istmp = B_FALSE;
2503fa9e4066Sahrens 
2504fa9e4066Sahrens 	/* check options */
2505fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2506fa9e4066Sahrens 		switch (c) {
2507fa9e4066Sahrens 		case 't':
250899653d4eSeschrock 			istmp = B_TRUE;
2509441d80aaSlling 			break;
2510441d80aaSlling 		case 'f':
2511fa9e4066Sahrens 		case '?':
2512fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2513fa9e4066Sahrens 			    optopt);
251499653d4eSeschrock 			usage(B_FALSE);
2515fa9e4066Sahrens 		}
2516fa9e4066Sahrens 	}
2517fa9e4066Sahrens 
2518fa9e4066Sahrens 	argc -= optind;
2519fa9e4066Sahrens 	argv += optind;
2520fa9e4066Sahrens 
2521fa9e4066Sahrens 	/* get pool name and check number of arguments */
2522fa9e4066Sahrens 	if (argc < 1) {
2523fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
252499653d4eSeschrock 		usage(B_FALSE);
2525fa9e4066Sahrens 	}
2526fa9e4066Sahrens 	if (argc < 2) {
2527fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
252899653d4eSeschrock 		usage(B_FALSE);
2529fa9e4066Sahrens 	}
2530fa9e4066Sahrens 
2531fa9e4066Sahrens 	poolname = argv[0];
2532fa9e4066Sahrens 
253399653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2534fa9e4066Sahrens 		return (1);
2535fa9e4066Sahrens 
25363d7072f8Seschrock 	for (i = 1; i < argc; i++) {
25373d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2538fa9e4066Sahrens 			ret = 1;
25393d7072f8Seschrock 	}
2540fa9e4066Sahrens 
254199653d4eSeschrock 	zpool_close(zhp);
254299653d4eSeschrock 
2543fa9e4066Sahrens 	return (ret);
2544fa9e4066Sahrens }
2545fa9e4066Sahrens 
2546ea8dc4b6Seschrock /*
2547ea8dc4b6Seschrock  * zpool clear <pool> [device]
2548ea8dc4b6Seschrock  *
2549ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2550ea8dc4b6Seschrock  */
2551ea8dc4b6Seschrock int
2552ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2553ea8dc4b6Seschrock {
2554ea8dc4b6Seschrock 	int ret = 0;
2555ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2556ea8dc4b6Seschrock 	char *pool, *device;
2557ea8dc4b6Seschrock 
2558ea8dc4b6Seschrock 	if (argc < 2) {
2559ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
256099653d4eSeschrock 		usage(B_FALSE);
2561ea8dc4b6Seschrock 	}
2562ea8dc4b6Seschrock 
2563ea8dc4b6Seschrock 	if (argc > 3) {
2564ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
256599653d4eSeschrock 		usage(B_FALSE);
2566ea8dc4b6Seschrock 	}
2567ea8dc4b6Seschrock 
2568ea8dc4b6Seschrock 	pool = argv[1];
2569ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2570ea8dc4b6Seschrock 
2571b87f3af3Sperrin 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
2572ea8dc4b6Seschrock 		return (1);
2573ea8dc4b6Seschrock 
2574ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2575ea8dc4b6Seschrock 		ret = 1;
2576ea8dc4b6Seschrock 
2577ea8dc4b6Seschrock 	zpool_close(zhp);
2578ea8dc4b6Seschrock 
2579ea8dc4b6Seschrock 	return (ret);
2580ea8dc4b6Seschrock }
2581ea8dc4b6Seschrock 
2582fa9e4066Sahrens typedef struct scrub_cbdata {
2583fa9e4066Sahrens 	int	cb_type;
258406eeb2adSek110237 	int	cb_argc;
258506eeb2adSek110237 	char	**cb_argv;
2586fa9e4066Sahrens } scrub_cbdata_t;
2587fa9e4066Sahrens 
2588fa9e4066Sahrens int
2589fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2590fa9e4066Sahrens {
2591fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
259206eeb2adSek110237 	int err;
2593fa9e4066Sahrens 
2594ea8dc4b6Seschrock 	/*
2595ea8dc4b6Seschrock 	 * Ignore faulted pools.
2596ea8dc4b6Seschrock 	 */
2597ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2598ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2599ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2600ea8dc4b6Seschrock 		return (1);
2601ea8dc4b6Seschrock 	}
2602ea8dc4b6Seschrock 
260306eeb2adSek110237 	err = zpool_scrub(zhp, cb->cb_type);
260406eeb2adSek110237 
260506eeb2adSek110237 	return (err != 0);
2606fa9e4066Sahrens }
2607fa9e4066Sahrens 
2608fa9e4066Sahrens /*
2609fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2610fa9e4066Sahrens  *
2611fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2612fa9e4066Sahrens  */
2613fa9e4066Sahrens int
2614fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2615fa9e4066Sahrens {
2616fa9e4066Sahrens 	int c;
2617fa9e4066Sahrens 	scrub_cbdata_t cb;
2618fa9e4066Sahrens 
2619fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2620fa9e4066Sahrens 
2621fa9e4066Sahrens 	/* check options */
2622fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2623fa9e4066Sahrens 		switch (c) {
2624fa9e4066Sahrens 		case 's':
2625fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2626fa9e4066Sahrens 			break;
2627fa9e4066Sahrens 		case '?':
2628fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2629fa9e4066Sahrens 			    optopt);
263099653d4eSeschrock 			usage(B_FALSE);
2631fa9e4066Sahrens 		}
2632fa9e4066Sahrens 	}
2633fa9e4066Sahrens 
263406eeb2adSek110237 	cb.cb_argc = argc;
263506eeb2adSek110237 	cb.cb_argv = argv;
2636fa9e4066Sahrens 	argc -= optind;
2637fa9e4066Sahrens 	argv += optind;
2638fa9e4066Sahrens 
2639fa9e4066Sahrens 	if (argc < 1) {
2640fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
264199653d4eSeschrock 		usage(B_FALSE);
2642fa9e4066Sahrens 	}
2643fa9e4066Sahrens 
2644b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2645fa9e4066Sahrens }
2646fa9e4066Sahrens 
2647fa9e4066Sahrens typedef struct status_cbdata {
2648fa9e4066Sahrens 	int		cb_count;
2649e9dbad6fSeschrock 	boolean_t	cb_allpools;
265099653d4eSeschrock 	boolean_t	cb_verbose;
265199653d4eSeschrock 	boolean_t	cb_explain;
265299653d4eSeschrock 	boolean_t	cb_first;
2653fa9e4066Sahrens } status_cbdata_t;
2654fa9e4066Sahrens 
2655fa9e4066Sahrens /*
2656fa9e4066Sahrens  * Print out detailed scrub status.
2657fa9e4066Sahrens  */
2658fa9e4066Sahrens void
2659fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2660fa9e4066Sahrens {
2661fa9e4066Sahrens 	vdev_stat_t *vs;
2662fa9e4066Sahrens 	uint_t vsc;
2663fa9e4066Sahrens 	time_t start, end, now;
2664fa9e4066Sahrens 	double fraction_done;
266518ce54dfSek110237 	uint64_t examined, total, minutes_left, minutes_taken;
2666fa9e4066Sahrens 	char *scrub_type;
2667fa9e4066Sahrens 
2668fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2669fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2670fa9e4066Sahrens 
2671fa9e4066Sahrens 	/*
2672fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2673fa9e4066Sahrens 	 */
2674fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2675fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2676fa9e4066Sahrens 		return;
2677fa9e4066Sahrens 	}
2678fa9e4066Sahrens 
2679fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2680fa9e4066Sahrens 	    "resilver" : "scrub";
2681fa9e4066Sahrens 
2682fa9e4066Sahrens 	start = vs->vs_scrub_start;
2683fa9e4066Sahrens 	end = vs->vs_scrub_end;
2684fa9e4066Sahrens 	now = time(NULL);
2685fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2686fa9e4066Sahrens 	total = vs->vs_alloc;
2687fa9e4066Sahrens 
2688fa9e4066Sahrens 	if (end != 0) {
268918ce54dfSek110237 		minutes_taken = (uint64_t)((end - start) / 60);
269018ce54dfSek110237 
269118ce54dfSek110237 		(void) printf(gettext("%s %s after %lluh%um with %llu errors "
269218ce54dfSek110237 		    "on %s"),
2693fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
269418ce54dfSek110237 		    (u_longlong_t)(minutes_taken / 60),
269518ce54dfSek110237 		    (uint_t)(minutes_taken % 60),
2696fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2697fa9e4066Sahrens 		return;
2698fa9e4066Sahrens 	}
2699fa9e4066Sahrens 
2700fa9e4066Sahrens 	if (examined == 0)
2701fa9e4066Sahrens 		examined = 1;
2702fa9e4066Sahrens 	if (examined > total)
2703fa9e4066Sahrens 		total = examined;
2704fa9e4066Sahrens 
2705fa9e4066Sahrens 	fraction_done = (double)examined / total;
2706fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2707fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
270818ce54dfSek110237 	minutes_taken = (uint64_t)((now - start) / 60);
2709fa9e4066Sahrens 
271018ce54dfSek110237 	(void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, "
271118ce54dfSek110237 	    "%lluh%um to go\n"),
271218ce54dfSek110237 	    scrub_type, (u_longlong_t)(minutes_taken / 60),
271318ce54dfSek110237 	    (uint_t)(minutes_taken % 60), 100 * fraction_done,
2714fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2715fa9e4066Sahrens }
2716fa9e4066Sahrens 
271799653d4eSeschrock typedef struct spare_cbdata {
271899653d4eSeschrock 	uint64_t	cb_guid;
271999653d4eSeschrock 	zpool_handle_t	*cb_zhp;
272099653d4eSeschrock } spare_cbdata_t;
272199653d4eSeschrock 
272299653d4eSeschrock static boolean_t
272399653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search)
272499653d4eSeschrock {
272599653d4eSeschrock 	uint64_t guid;
272699653d4eSeschrock 	nvlist_t **child;
272799653d4eSeschrock 	uint_t c, children;
272899653d4eSeschrock 
272999653d4eSeschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
273099653d4eSeschrock 	    search == guid)
273199653d4eSeschrock 		return (B_TRUE);
273299653d4eSeschrock 
273399653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
273499653d4eSeschrock 	    &child, &children) == 0) {
273599653d4eSeschrock 		for (c = 0; c < children; c++)
273699653d4eSeschrock 			if (find_vdev(child[c], search))
273799653d4eSeschrock 				return (B_TRUE);
273899653d4eSeschrock 	}
273999653d4eSeschrock 
274099653d4eSeschrock 	return (B_FALSE);
274199653d4eSeschrock }
274299653d4eSeschrock 
274399653d4eSeschrock static int
274499653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data)
274599653d4eSeschrock {
274699653d4eSeschrock 	spare_cbdata_t *cbp = data;
274799653d4eSeschrock 	nvlist_t *config, *nvroot;
274899653d4eSeschrock 
274999653d4eSeschrock 	config = zpool_get_config(zhp, NULL);
275099653d4eSeschrock 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
275199653d4eSeschrock 	    &nvroot) == 0);
275299653d4eSeschrock 
275399653d4eSeschrock 	if (find_vdev(nvroot, cbp->cb_guid)) {
275499653d4eSeschrock 		cbp->cb_zhp = zhp;
275599653d4eSeschrock 		return (1);
275699653d4eSeschrock 	}
275799653d4eSeschrock 
275899653d4eSeschrock 	zpool_close(zhp);
275999653d4eSeschrock 	return (0);
276099653d4eSeschrock }
276199653d4eSeschrock 
2762fa9e4066Sahrens /*
2763fa9e4066Sahrens  * Print out configuration state as requested by status_callback.
2764fa9e4066Sahrens  */
2765fa9e4066Sahrens void
2766c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
2767aa8cf21aSNeil Perrin     int namewidth, int depth, boolean_t isspare)
2768fa9e4066Sahrens {
2769fa9e4066Sahrens 	nvlist_t **child;
2770fa9e4066Sahrens 	uint_t c, children;
2771fa9e4066Sahrens 	vdev_stat_t *vs;
2772ea8dc4b6Seschrock 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
2773afefbcddSeschrock 	char *vname;
2774ea8dc4b6Seschrock 	uint64_t notpresent;
277599653d4eSeschrock 	spare_cbdata_t cb;
2776990b4856Slling 	char *state;
2777fa9e4066Sahrens 
2778fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2779fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2780fa9e4066Sahrens 
2781fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2782fa9e4066Sahrens 	    &child, &children) != 0)
2783fa9e4066Sahrens 		children = 0;
2784fa9e4066Sahrens 
2785990b4856Slling 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
278699653d4eSeschrock 	if (isspare) {
278799653d4eSeschrock 		/*
278899653d4eSeschrock 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
278999653d4eSeschrock 		 * online drives.
279099653d4eSeschrock 		 */
279199653d4eSeschrock 		if (vs->vs_aux == VDEV_AUX_SPARED)
279299653d4eSeschrock 			state = "INUSE";
279399653d4eSeschrock 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
279499653d4eSeschrock 			state = "AVAIL";
279599653d4eSeschrock 	}
2796fa9e4066Sahrens 
279799653d4eSeschrock 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
279899653d4eSeschrock 	    name, state);
279999653d4eSeschrock 
280099653d4eSeschrock 	if (!isspare) {
2801fa9e4066Sahrens 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
2802fa9e4066Sahrens 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
2803fa9e4066Sahrens 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
2804fa9e4066Sahrens 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
280599653d4eSeschrock 	}
2806fa9e4066Sahrens 
2807ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2808ea8dc4b6Seschrock 	    &notpresent) == 0) {
2809ea8dc4b6Seschrock 		char *path;
2810ea8dc4b6Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
28110917b783Seschrock 		(void) printf("  was %s", path);
2812ea8dc4b6Seschrock 	} else if (vs->vs_aux != 0) {
2813fa9e4066Sahrens 		(void) printf("  ");
2814fa9e4066Sahrens 
2815fa9e4066Sahrens 		switch (vs->vs_aux) {
2816fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2817fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2818fa9e4066Sahrens 			break;
2819fa9e4066Sahrens 
2820fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2821fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2822fa9e4066Sahrens 			break;
2823fa9e4066Sahrens 
2824fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2825fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2826fa9e4066Sahrens 			break;
2827fa9e4066Sahrens 
2828eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
2829eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
2830eaca9bbdSeschrock 			break;
2831eaca9bbdSeschrock 
283299653d4eSeschrock 		case VDEV_AUX_SPARED:
283399653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
283499653d4eSeschrock 			    &cb.cb_guid) == 0);
283599653d4eSeschrock 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
283699653d4eSeschrock 				if (strcmp(zpool_get_name(cb.cb_zhp),
283799653d4eSeschrock 				    zpool_get_name(zhp)) == 0)
283899653d4eSeschrock 					(void) printf(gettext("currently in "
283999653d4eSeschrock 					    "use"));
284099653d4eSeschrock 				else
284199653d4eSeschrock 					(void) printf(gettext("in use by "
284299653d4eSeschrock 					    "pool '%s'"),
284399653d4eSeschrock 					    zpool_get_name(cb.cb_zhp));
284499653d4eSeschrock 				zpool_close(cb.cb_zhp);
284599653d4eSeschrock 			} else {
284699653d4eSeschrock 				(void) printf(gettext("currently in use"));
284799653d4eSeschrock 			}
284899653d4eSeschrock 			break;
284999653d4eSeschrock 
28503d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
28513d7072f8Seschrock 			(void) printf(gettext("too many errors"));
28523d7072f8Seschrock 			break;
28533d7072f8Seschrock 
285432b87932Sek110237 		case VDEV_AUX_IO_FAILURE:
285532b87932Sek110237 			(void) printf(gettext("experienced I/O failures"));
285632b87932Sek110237 			break;
285732b87932Sek110237 
2858b87f3af3Sperrin 		case VDEV_AUX_BAD_LOG:
2859b87f3af3Sperrin 			(void) printf(gettext("bad intent log"));
2860b87f3af3Sperrin 			break;
2861b87f3af3Sperrin 
2862fa9e4066Sahrens 		default:
2863fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2864fa9e4066Sahrens 			break;
2865fa9e4066Sahrens 		}
2866fa9e4066Sahrens 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2867fa9e4066Sahrens 		/*
2868fa9e4066Sahrens 		 * Report bytes resilvered/repaired on leaf devices.
2869fa9e4066Sahrens 		 */
2870fa9e4066Sahrens 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2871fa9e4066Sahrens 		(void) printf(gettext("  %s %s"), repaired,
2872fa9e4066Sahrens 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2873fa9e4066Sahrens 		    "resilvered" : "repaired");
2874fa9e4066Sahrens 	}
2875fa9e4066Sahrens 
2876fa9e4066Sahrens 	(void) printf("\n");
2877fa9e4066Sahrens 
2878afefbcddSeschrock 	for (c = 0; c < children; c++) {
28798654d025Sperrin 		uint64_t is_log = B_FALSE;
28808654d025Sperrin 
2881aa8cf21aSNeil Perrin 		/* Don't print logs here */
28828654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
28838654d025Sperrin 		    &is_log);
2884aa8cf21aSNeil Perrin 		if (is_log)
28858654d025Sperrin 			continue;
288699653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
2887c67d9675Seschrock 		print_status_config(zhp, vname, child[c],
2888aa8cf21aSNeil Perrin 		    namewidth, depth + 2, isspare);
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],
2943aa8cf21aSNeil Perrin 		    namewidth, 2, B_TRUE);
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],
2963aa8cf21aSNeil Perrin 		    namewidth, 2, B_FALSE);
2964aa8cf21aSNeil Perrin 		free(name);
2965aa8cf21aSNeil Perrin 	}
2966aa8cf21aSNeil Perrin }
2967aa8cf21aSNeil Perrin 
2968aa8cf21aSNeil Perrin /*
2969aa8cf21aSNeil Perrin  * Print log vdevs.
2970aa8cf21aSNeil Perrin  * Logs are recorded as top level vdevs in the main pool child array but with
2971aa8cf21aSNeil Perrin  * "is_log" set to 1. We use print_status_config() to print the top level logs
2972aa8cf21aSNeil Perrin  * then any log children (eg mirrored slogs) are printed recursively - which
2973aa8cf21aSNeil Perrin  * works because only the top level vdev is marked "is_log"
2974aa8cf21aSNeil Perrin  */
2975aa8cf21aSNeil Perrin static void
2976aa8cf21aSNeil Perrin print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth)
2977aa8cf21aSNeil Perrin {
2978aa8cf21aSNeil Perrin 	uint_t c, children;
2979aa8cf21aSNeil Perrin 	nvlist_t **child;
2980aa8cf21aSNeil Perrin 
2981aa8cf21aSNeil Perrin 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
2982aa8cf21aSNeil Perrin 	    &children) != 0)
2983aa8cf21aSNeil Perrin 		return;
2984aa8cf21aSNeil Perrin 
2985aa8cf21aSNeil Perrin 	(void) printf(gettext("\tlogs\n"));
2986aa8cf21aSNeil Perrin 
2987aa8cf21aSNeil Perrin 	for (c = 0; c < children; c++) {
2988aa8cf21aSNeil Perrin 		uint64_t is_log = B_FALSE;
2989aa8cf21aSNeil Perrin 		char *name;
2990aa8cf21aSNeil Perrin 
2991aa8cf21aSNeil Perrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
2992aa8cf21aSNeil Perrin 		    &is_log);
2993aa8cf21aSNeil Perrin 		if (!is_log)
2994aa8cf21aSNeil Perrin 			continue;
2995aa8cf21aSNeil Perrin 		name = zpool_vdev_name(g_zfs, zhp, child[c]);
2996aa8cf21aSNeil Perrin 		print_status_config(zhp, name, child[c], namewidth, 2, B_FALSE);
2997fa94a07fSbrendan 		free(name);
2998fa94a07fSbrendan 	}
2999fa94a07fSbrendan }
3000fa94a07fSbrendan 
3001fa9e4066Sahrens /*
3002fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
3003fa9e4066Sahrens  *
3004fa9e4066Sahrens  *        pool: tank
3005fa9e4066Sahrens  *	status: DEGRADED
3006fa9e4066Sahrens  *	reason: One or more devices ...
3007fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
3008fa9e4066Sahrens  *	config:
3009fa9e4066Sahrens  *		mirror		DEGRADED
3010fa9e4066Sahrens  *                c1t0d0	OK
3011ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
3012fa9e4066Sahrens  *
3013fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
3014fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
3015fa9e4066Sahrens  */
3016fa9e4066Sahrens int
3017fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
3018fa9e4066Sahrens {
3019fa9e4066Sahrens 	status_cbdata_t *cbp = data;
3020fa9e4066Sahrens 	nvlist_t *config, *nvroot;
3021fa9e4066Sahrens 	char *msgid;
3022fa9e4066Sahrens 	int reason;
302346657f8dSmmusante 	const char *health;
302446657f8dSmmusante 	uint_t c;
302546657f8dSmmusante 	vdev_stat_t *vs;
3026fa9e4066Sahrens 
3027088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
3028fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
3029fa9e4066Sahrens 
3030fa9e4066Sahrens 	cbp->cb_count++;
3031fa9e4066Sahrens 
3032fa9e4066Sahrens 	/*
3033fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
3034fa9e4066Sahrens 	 * problems.
3035fa9e4066Sahrens 	 */
3036e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
3037e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
3038e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
3039e9dbad6fSeschrock 			    zpool_get_name(zhp));
3040e9dbad6fSeschrock 			if (cbp->cb_first)
3041e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
3042e9dbad6fSeschrock 		}
3043fa9e4066Sahrens 		return (0);
3044e9dbad6fSeschrock 	}
3045fa9e4066Sahrens 
3046fa9e4066Sahrens 	if (cbp->cb_first)
304799653d4eSeschrock 		cbp->cb_first = B_FALSE;
3048fa9e4066Sahrens 	else
3049fa9e4066Sahrens 		(void) printf("\n");
3050fa9e4066Sahrens 
305146657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
305246657f8dSmmusante 	    &nvroot) == 0);
305346657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
305446657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
3055990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3056fa9e4066Sahrens 
3057fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
3058fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
3059fa9e4066Sahrens 
3060fa9e4066Sahrens 	switch (reason) {
3061fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
3062fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3063fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
3064fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
3065fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3066fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3067fa9e4066Sahrens 		break;
3068fa9e4066Sahrens 
3069fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
3070fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3071fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
3072fa9e4066Sahrens 		    "pool to continue functioning.\n"));
3073fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3074fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3075fa9e4066Sahrens 		break;
3076fa9e4066Sahrens 
3077fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
3078fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3079fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
3080fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
3081fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
3082fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
3083fa9e4066Sahrens 		    "'zpool replace'.\n"));
3084fa9e4066Sahrens 		break;
3085fa9e4066Sahrens 
3086fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3087fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3088b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
3089fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
3090fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
3091fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
3092fa9e4066Sahrens 		    "from a backup source.\n"));
3093fa9e4066Sahrens 		break;
3094fa9e4066Sahrens 
3095fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
3096fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3097fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
3098fa9e4066Sahrens 		    "made to correct the error.  Applications are "
3099fa9e4066Sahrens 		    "unaffected.\n"));
3100fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
3101fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
3102ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
3103fa9e4066Sahrens 		    "replace'.\n"));
3104fa9e4066Sahrens 		break;
3105fa9e4066Sahrens 
3106fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
3107fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3108d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
3109fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
3110fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
3111fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
3112fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
3113fa9e4066Sahrens 		    "replace'.\n"));
3114fa9e4066Sahrens 		break;
3115fa9e4066Sahrens 
3116fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
3117fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
3118fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3119fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
3120fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3121fa9e4066Sahrens 		    "complete.\n"));
3122fa9e4066Sahrens 		break;
3123fa9e4066Sahrens 
3124ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3125ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3126ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3127ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3128ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3129ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3130ea8dc4b6Seschrock 		    "backup.\n"));
3131ea8dc4b6Seschrock 		break;
3132ea8dc4b6Seschrock 
3133ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3134ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3135ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3136ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
3137ea8dc4b6Seschrock 		    "from a backup source.\n"));
3138ea8dc4b6Seschrock 		break;
3139ea8dc4b6Seschrock 
3140eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3141eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3142eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3143eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3144eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3145eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3146eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3147eaca9bbdSeschrock 		break;
3148eaca9bbdSeschrock 
3149eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3150eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3151eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3152eaca9bbdSeschrock 		    "be accessed on this system.\n"));
3153eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
3154eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
3155eaca9bbdSeschrock 		    "backup.\n"));
3156eaca9bbdSeschrock 		break;
3157eaca9bbdSeschrock 
31583d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
31593d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
31603d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
31613d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
31623d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
31633d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
31643d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
31653d7072f8Seschrock 		break;
31663d7072f8Seschrock 
31673d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
31683d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
31693d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
31703d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
31713d7072f8Seschrock 		    "functioning.\n"));
31723d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
31733d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
31743d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
31753d7072f8Seschrock 		    "to be recovered.\n"));
31763d7072f8Seschrock 		break;
31773d7072f8Seschrock 
317832b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_WAIT:
317932b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
318032b87932Sek110237 		(void) printf(gettext("status: One or more devices are "
31818a79c1b5Sek110237 		    "faulted in response to IO failures.\n"));
318232b87932Sek110237 		(void) printf(gettext("action: Make sure the affected devices "
318332b87932Sek110237 		    "are connected, then run 'zpool clear'.\n"));
318432b87932Sek110237 		break;
318532b87932Sek110237 
3186b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
3187b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record "
3188b87f3af3Sperrin 		    "could not be read.\n"
3189b87f3af3Sperrin 		    "\tWaiting for adminstrator intervention to fix the "
3190b87f3af3Sperrin 		    "faulted pool.\n"));
3191b87f3af3Sperrin 		(void) printf(gettext("action: Either restore the affected "
3192b87f3af3Sperrin 		    "device(s) and run 'zpool online',\n"
3193b87f3af3Sperrin 		    "\tor ignore the intent log records by running "
3194b87f3af3Sperrin 		    "'zpool clear'.\n"));
3195b87f3af3Sperrin 		break;
3196b87f3af3Sperrin 
3197fa9e4066Sahrens 	default:
3198fa9e4066Sahrens 		/*
3199fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
3200fa9e4066Sahrens 		 */
3201fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
3202fa9e4066Sahrens 	}
3203fa9e4066Sahrens 
3204fa9e4066Sahrens 	if (msgid != NULL)
3205fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3206fa9e4066Sahrens 		    msgid);
3207fa9e4066Sahrens 
3208fa9e4066Sahrens 	if (config != NULL) {
3209fa9e4066Sahrens 		int namewidth;
3210ea8dc4b6Seschrock 		uint64_t nerr;
3211fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
3212fa94a07fSbrendan 		uint_t nspares, nl2cache;
3213fa9e4066Sahrens 
3214fa9e4066Sahrens 
3215fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
3216fa9e4066Sahrens 		print_scrub_status(nvroot);
3217fa9e4066Sahrens 
3218c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3219fa9e4066Sahrens 		if (namewidth < 10)
3220fa9e4066Sahrens 			namewidth = 10;
3221fa9e4066Sahrens 
3222fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
3223fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3224fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3225c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
3226aa8cf21aSNeil Perrin 		    namewidth, 0, B_FALSE);
322799653d4eSeschrock 
3228aa8cf21aSNeil Perrin 		print_logs(zhp, nvroot, namewidth);
3229fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
3230fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
3231fa94a07fSbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
3232fa94a07fSbrendan 
323399653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
323499653d4eSeschrock 		    &spares, &nspares) == 0)
323599653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
3236ea8dc4b6Seschrock 
3237ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3238ea8dc4b6Seschrock 		    &nerr) == 0) {
323955434c77Sek110237 			nvlist_t *nverrlist = NULL;
324055434c77Sek110237 
3241ea8dc4b6Seschrock 			/*
3242ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3243ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3244ea8dc4b6Seschrock 			 * uniquifying the results.
3245ea8dc4b6Seschrock 			 */
324675519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
324755434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
324855434c77Sek110237 				nvpair_t *elem;
324955434c77Sek110237 
325055434c77Sek110237 				elem = NULL;
325155434c77Sek110237 				nerr = 0;
325255434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
325355434c77Sek110237 				    elem)) != NULL) {
325455434c77Sek110237 					nerr++;
325555434c77Sek110237 				}
325655434c77Sek110237 			}
325755434c77Sek110237 			nvlist_free(nverrlist);
3258ea8dc4b6Seschrock 
3259ea8dc4b6Seschrock 			(void) printf("\n");
326099653d4eSeschrock 
3261ea8dc4b6Seschrock 			if (nerr == 0)
3262ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3263ea8dc4b6Seschrock 				    "errors\n"));
3264ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3265e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
32665ad82045Snd150628 				    "errors, use '-v' for a list\n"),
32675ad82045Snd150628 				    (u_longlong_t)nerr);
3268ea8dc4b6Seschrock 			else
3269ea8dc4b6Seschrock 				print_error_log(zhp);
3270ea8dc4b6Seschrock 		}
3271fa9e4066Sahrens 	} else {
3272fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3273fa9e4066Sahrens 		    "determined.\n"));
3274fa9e4066Sahrens 	}
3275fa9e4066Sahrens 
3276fa9e4066Sahrens 	return (0);
3277fa9e4066Sahrens }
3278fa9e4066Sahrens 
3279fa9e4066Sahrens /*
3280fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3281fa9e4066Sahrens  *
3282fa9e4066Sahrens  *	-v	Display complete error logs
3283fa9e4066Sahrens  *	-x	Display only pools with potential problems
3284fa9e4066Sahrens  *
3285fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3286fa9e4066Sahrens  */
3287fa9e4066Sahrens int
3288fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3289fa9e4066Sahrens {
3290fa9e4066Sahrens 	int c;
3291fa9e4066Sahrens 	int ret;
3292fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3293fa9e4066Sahrens 
3294fa9e4066Sahrens 	/* check options */
3295fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3296fa9e4066Sahrens 		switch (c) {
3297fa9e4066Sahrens 		case 'v':
329899653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3299fa9e4066Sahrens 			break;
3300fa9e4066Sahrens 		case 'x':
330199653d4eSeschrock 			cb.cb_explain = B_TRUE;
3302fa9e4066Sahrens 			break;
3303fa9e4066Sahrens 		case '?':
3304fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3305fa9e4066Sahrens 			    optopt);
330699653d4eSeschrock 			usage(B_FALSE);
3307fa9e4066Sahrens 		}
3308fa9e4066Sahrens 	}
3309fa9e4066Sahrens 
3310fa9e4066Sahrens 	argc -= optind;
3311fa9e4066Sahrens 	argv += optind;
3312fa9e4066Sahrens 
331399653d4eSeschrock 	cb.cb_first = B_TRUE;
3314fa9e4066Sahrens 
3315e9dbad6fSeschrock 	if (argc == 0)
3316e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3317e9dbad6fSeschrock 
3318b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3319fa9e4066Sahrens 
3320fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3321fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3322e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3323fa9e4066Sahrens 		(void) printf(gettext("all pools are healthy\n"));
3324fa9e4066Sahrens 
3325fa9e4066Sahrens 	return (ret);
3326fa9e4066Sahrens }
3327fa9e4066Sahrens 
3328eaca9bbdSeschrock typedef struct upgrade_cbdata {
3329eaca9bbdSeschrock 	int	cb_all;
3330eaca9bbdSeschrock 	int	cb_first;
3331eaca9bbdSeschrock 	int	cb_newer;
333206eeb2adSek110237 	int	cb_argc;
3333990b4856Slling 	uint64_t cb_version;
333406eeb2adSek110237 	char	**cb_argv;
3335eaca9bbdSeschrock } upgrade_cbdata_t;
3336eaca9bbdSeschrock 
3337eaca9bbdSeschrock static int
3338eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3339eaca9bbdSeschrock {
3340eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3341eaca9bbdSeschrock 	nvlist_t *config;
3342eaca9bbdSeschrock 	uint64_t version;
3343eaca9bbdSeschrock 	int ret = 0;
3344eaca9bbdSeschrock 
3345eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3346eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3347eaca9bbdSeschrock 	    &version) == 0);
3348eaca9bbdSeschrock 
3349e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3350eaca9bbdSeschrock 		if (!cbp->cb_all) {
3351eaca9bbdSeschrock 			if (cbp->cb_first) {
3352eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3353eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3354eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3355eaca9bbdSeschrock 				    "longer be accessible by older software "
3356eaca9bbdSeschrock 				    "versions.\n\n"));
3357eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3358eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
335999653d4eSeschrock 				cbp->cb_first = B_FALSE;
3360eaca9bbdSeschrock 			}
3361eaca9bbdSeschrock 
33625ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3363eaca9bbdSeschrock 			    zpool_get_name(zhp));
3364eaca9bbdSeschrock 		} else {
336599653d4eSeschrock 			cbp->cb_first = B_FALSE;
3366990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
336706eeb2adSek110237 			if (!ret) {
3368eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3369990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
3370eaca9bbdSeschrock 			}
337106eeb2adSek110237 		}
3372e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3373eaca9bbdSeschrock 		assert(!cbp->cb_all);
3374eaca9bbdSeschrock 
3375eaca9bbdSeschrock 		if (cbp->cb_first) {
3376eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3377eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3378eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3379eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3380eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
338199653d4eSeschrock 			cbp->cb_first = B_FALSE;
3382eaca9bbdSeschrock 		}
3383eaca9bbdSeschrock 
33845ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3385eaca9bbdSeschrock 		    zpool_get_name(zhp));
3386eaca9bbdSeschrock 	}
3387eaca9bbdSeschrock 
3388eaca9bbdSeschrock 	zpool_close(zhp);
3389eaca9bbdSeschrock 	return (ret);
3390eaca9bbdSeschrock }
3391eaca9bbdSeschrock 
3392eaca9bbdSeschrock /* ARGSUSED */
3393eaca9bbdSeschrock static int
339406eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
3395eaca9bbdSeschrock {
3396990b4856Slling 	upgrade_cbdata_t *cbp = data;
3397990b4856Slling 	uint64_t cur_version;
3398eaca9bbdSeschrock 	int ret;
3399eaca9bbdSeschrock 
34008654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
34018654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
34028654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
34038654d025Sperrin 		    " to upgrade.\n"));
34048654d025Sperrin 		return (1);
34058654d025Sperrin 	}
3406990b4856Slling 
3407990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3408e6c728e1Sbrendan 	if (cur_version > cbp->cb_version) {
3409eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3410e6c728e1Sbrendan 		    "using more current version '%llu'.\n"),
3411e6c728e1Sbrendan 		    zpool_get_name(zhp), cur_version);
3412e6c728e1Sbrendan 		return (0);
3413e6c728e1Sbrendan 	}
3414e6c728e1Sbrendan 	if (cur_version == cbp->cb_version) {
3415e6c728e1Sbrendan 		(void) printf(gettext("Pool '%s' is already formatted "
3416e6c728e1Sbrendan 		    "using the current version.\n"), zpool_get_name(zhp));
3417eaca9bbdSeschrock 		return (0);
3418eaca9bbdSeschrock 	}
3419eaca9bbdSeschrock 
3420990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
342106eeb2adSek110237 
342206eeb2adSek110237 	if (!ret) {
342344cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
3424990b4856Slling 		    "from version %llu to version %llu\n\n"),
3425990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3426990b4856Slling 		    (u_longlong_t)cbp->cb_version);
342706eeb2adSek110237 	}
3428eaca9bbdSeschrock 
3429eaca9bbdSeschrock 	return (ret != 0);
3430eaca9bbdSeschrock }
3431eaca9bbdSeschrock 
3432eaca9bbdSeschrock /*
3433eaca9bbdSeschrock  * zpool upgrade
3434eaca9bbdSeschrock  * zpool upgrade -v
3435990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
3436eaca9bbdSeschrock  *
3437eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3438eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3439eaca9bbdSeschrock  * upgrade all pools.
3440eaca9bbdSeschrock  */
3441eaca9bbdSeschrock int
3442eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3443eaca9bbdSeschrock {
3444eaca9bbdSeschrock 	int c;
3445eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3446eaca9bbdSeschrock 	int ret = 0;
3447eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3448990b4856Slling 	char *end;
3449990b4856Slling 
3450eaca9bbdSeschrock 
3451eaca9bbdSeschrock 	/* check options */
3452990b4856Slling 	while ((c = getopt(argc, argv, "avV:")) != -1) {
3453eaca9bbdSeschrock 		switch (c) {
3454eaca9bbdSeschrock 		case 'a':
345599653d4eSeschrock 			cb.cb_all = B_TRUE;
3456eaca9bbdSeschrock 			break;
3457eaca9bbdSeschrock 		case 'v':
3458eaca9bbdSeschrock 			showversions = B_TRUE;
3459eaca9bbdSeschrock 			break;
3460990b4856Slling 		case 'V':
3461990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
3462351420b3Slling 			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
3463351420b3Slling 			    cb.cb_version < SPA_VERSION_1) {
3464990b4856Slling 				(void) fprintf(stderr,
3465990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
3466990b4856Slling 				usage(B_FALSE);
3467990b4856Slling 			}
3468990b4856Slling 			break;
3469eaca9bbdSeschrock 		case '?':
3470eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3471eaca9bbdSeschrock 			    optopt);
347299653d4eSeschrock 			usage(B_FALSE);
3473eaca9bbdSeschrock 		}
3474eaca9bbdSeschrock 	}
3475eaca9bbdSeschrock 
347606eeb2adSek110237 	cb.cb_argc = argc;
347706eeb2adSek110237 	cb.cb_argv = argv;
3478eaca9bbdSeschrock 	argc -= optind;
3479eaca9bbdSeschrock 	argv += optind;
3480eaca9bbdSeschrock 
3481351420b3Slling 	if (cb.cb_version == 0) {
3482351420b3Slling 		cb.cb_version = SPA_VERSION;
3483351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
3484351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
3485351420b3Slling 		    "incompatible with other arguments\n"));
3486351420b3Slling 		usage(B_FALSE);
3487351420b3Slling 	}
3488351420b3Slling 
3489eaca9bbdSeschrock 	if (showversions) {
3490eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3491eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3492eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
349399653d4eSeschrock 			usage(B_FALSE);
3494eaca9bbdSeschrock 		}
3495eaca9bbdSeschrock 	} else if (cb.cb_all) {
3496eaca9bbdSeschrock 		if (argc != 0) {
3497351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
3498351420b3Slling 			    "be used along with a pool name\n"));
349999653d4eSeschrock 			usage(B_FALSE);
3500eaca9bbdSeschrock 		}
3501eaca9bbdSeschrock 	}
3502eaca9bbdSeschrock 
3503e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3504e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
350599653d4eSeschrock 	cb.cb_first = B_TRUE;
3506eaca9bbdSeschrock 	if (showversions) {
3507eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3508d7d4af51Smmusante 		    "supported:\n\n"));
3509eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3510eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3511eaca9bbdSeschrock 		    "---------------\n");
351299653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
351344cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
351444cd46caSbillm 		    "(replicated metadata)\n"));
351599653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
351699653d4eSeschrock 		    "RAID-Z\n"));
3517d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
3518c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3519c9431fa1Sahl 		    "algorithm\n"));
3520990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
35218654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3522ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
3523a9799022Sck153898 		(void) printf(gettext(" 9   refquota and refreservation "
3524a9799022Sck153898 		    "properties\n"));
3525fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
3526088f3894Sahrens 		(void) printf(gettext(" 11  Improved scrub performance\n"));
3527bb0ade09Sahrens 		(void) printf(gettext(" 12  Snapshot properties\n"));
352874e7dc98SMatthew Ahrens 		(void) printf(gettext(" 13  snapused property\n"));
3529*14843421SMatthew Ahrens 		(void) printf(gettext(" 14  passthrough-x aclinherit\n"));
3530*14843421SMatthew Ahrens 		(void) printf(gettext(" 15  user/group space accounting\n"));
35318654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3532eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3533eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3534eaca9bbdSeschrock 		    "version/N\n\n");
3535eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3536eaca9bbdSeschrock 	} else if (argc == 0) {
3537eaca9bbdSeschrock 		int notfound;
3538eaca9bbdSeschrock 
353999653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3540eaca9bbdSeschrock 		notfound = cb.cb_first;
3541eaca9bbdSeschrock 
3542eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3543eaca9bbdSeschrock 			if (!cb.cb_first)
3544eaca9bbdSeschrock 				(void) printf("\n");
3545eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3546eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
354799653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3548eaca9bbdSeschrock 			if (!cb.cb_first) {
3549eaca9bbdSeschrock 				notfound = B_FALSE;
3550eaca9bbdSeschrock 				(void) printf("\n");
3551eaca9bbdSeschrock 			}
3552eaca9bbdSeschrock 		}
3553eaca9bbdSeschrock 
3554eaca9bbdSeschrock 		if (ret == 0) {
3555eaca9bbdSeschrock 			if (notfound)
3556eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3557eaca9bbdSeschrock 				    "using this version.\n"));
3558eaca9bbdSeschrock 			else if (!cb.cb_all)
3559eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3560eaca9bbdSeschrock 				    "for a list of available versions and "
3561eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3562eaca9bbdSeschrock 		}
3563eaca9bbdSeschrock 	} else {
3564b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3565b1b8ab34Slling 		    upgrade_one, &cb);
356606eeb2adSek110237 	}
356706eeb2adSek110237 
356806eeb2adSek110237 	return (ret);
356906eeb2adSek110237 }
357006eeb2adSek110237 
3571ecd6cf80Smarks typedef struct hist_cbdata {
3572ecd6cf80Smarks 	boolean_t first;
3573ecd6cf80Smarks 	int longfmt;
3574ecd6cf80Smarks 	int internal;
3575ecd6cf80Smarks } hist_cbdata_t;
3576ecd6cf80Smarks 
3577ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3578ecd6cf80Smarks 	"invalid event",
3579ecd6cf80Smarks 	"pool create",
3580ecd6cf80Smarks 	"vdev add",
3581ecd6cf80Smarks 	"pool remove",
3582ecd6cf80Smarks 	"pool destroy",
3583ecd6cf80Smarks 	"pool export",
3584ecd6cf80Smarks 	"pool import",
3585ecd6cf80Smarks 	"vdev attach",
3586ecd6cf80Smarks 	"vdev replace",
3587ecd6cf80Smarks 	"vdev detach",
3588ecd6cf80Smarks 	"vdev online",
3589ecd6cf80Smarks 	"vdev offline",
3590ecd6cf80Smarks 	"vdev upgrade",
3591ecd6cf80Smarks 	"pool clear",
3592ecd6cf80Smarks 	"pool scrub",
3593ecd6cf80Smarks 	"pool property set",
3594ecd6cf80Smarks 	"create",
3595ecd6cf80Smarks 	"clone",
3596ecd6cf80Smarks 	"destroy",
3597ecd6cf80Smarks 	"destroy_begin_sync",
3598ecd6cf80Smarks 	"inherit",
3599ecd6cf80Smarks 	"property set",
3600ecd6cf80Smarks 	"quota set",
3601ecd6cf80Smarks 	"permission update",
3602ecd6cf80Smarks 	"permission remove",
3603ecd6cf80Smarks 	"permission who remove",
3604ecd6cf80Smarks 	"promote",
3605ecd6cf80Smarks 	"receive",
3606ecd6cf80Smarks 	"rename",
3607ecd6cf80Smarks 	"reservation set",
3608ecd6cf80Smarks 	"replay_inc_sync",
3609ecd6cf80Smarks 	"replay_full_sync",
3610ecd6cf80Smarks 	"rollback",
3611ecd6cf80Smarks 	"snapshot",
3612e7437265Sahrens 	"filesystem version upgrade",
3613a9799022Sck153898 	"refquota set",
3614a9799022Sck153898 	"refreservation set",
3615088f3894Sahrens 	"pool scrub done",
3616ecd6cf80Smarks };
3617ecd6cf80Smarks 
361806eeb2adSek110237 /*
361906eeb2adSek110237  * Print out the command history for a specific pool.
362006eeb2adSek110237  */
362106eeb2adSek110237 static int
362206eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
362306eeb2adSek110237 {
362406eeb2adSek110237 	nvlist_t *nvhis;
362506eeb2adSek110237 	nvlist_t **records;
362606eeb2adSek110237 	uint_t numrecords;
362706eeb2adSek110237 	char *cmdstr;
3628ecd6cf80Smarks 	char *pathstr;
362906eeb2adSek110237 	uint64_t dst_time;
363006eeb2adSek110237 	time_t tsec;
363106eeb2adSek110237 	struct tm t;
363206eeb2adSek110237 	char tbuf[30];
363306eeb2adSek110237 	int ret, i;
3634ecd6cf80Smarks 	uint64_t who;
3635ecd6cf80Smarks 	struct passwd *pwd;
3636ecd6cf80Smarks 	char *hostname;
3637ecd6cf80Smarks 	char *zonename;
3638ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3639ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3640ecd6cf80Smarks 	uint64_t txg;
3641ecd6cf80Smarks 	uint64_t ievent;
364206eeb2adSek110237 
3643ecd6cf80Smarks 	cb->first = B_FALSE;
364406eeb2adSek110237 
364506eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
364606eeb2adSek110237 
364706eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
364806eeb2adSek110237 		return (ret);
364906eeb2adSek110237 
365006eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
365106eeb2adSek110237 	    &records, &numrecords) == 0);
365206eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
365306eeb2adSek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3654ecd6cf80Smarks 		    &dst_time) != 0)
3655ecd6cf80Smarks 			continue;
3656ecd6cf80Smarks 
3657ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3658ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3659ecd6cf80Smarks 		    &cmdstr) != 0) {
3660ecd6cf80Smarks 			if (cb->internal == 0)
3661ecd6cf80Smarks 				continue;
3662ecd6cf80Smarks 
3663ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3664ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3665ecd6cf80Smarks 				continue;
3666ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3667ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3668ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3669ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3670088f3894Sahrens 			if (ievent >= LOG_END)
3671ecd6cf80Smarks 				continue;
3672ecd6cf80Smarks 			(void) snprintf(internalstr,
3673ecd6cf80Smarks 			    sizeof (internalstr),
3674ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3675ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3676ecd6cf80Smarks 			    pathstr);
3677ecd6cf80Smarks 			cmdstr = internalstr;
3678ecd6cf80Smarks 		}
367906eeb2adSek110237 		tsec = dst_time;
368006eeb2adSek110237 		(void) localtime_r(&tsec, &t);
368106eeb2adSek110237 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3682ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3683ecd6cf80Smarks 
3684ecd6cf80Smarks 		if (!cb->longfmt) {
3685ecd6cf80Smarks 			(void) printf("\n");
3686ecd6cf80Smarks 			continue;
368706eeb2adSek110237 		}
3688ecd6cf80Smarks 		(void) printf(" [");
3689ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3690ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3691ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3692ecd6cf80Smarks 			if (pwd)
3693ecd6cf80Smarks 				(void) printf("user %s on",
3694ecd6cf80Smarks 				    pwd->pw_name);
3695ecd6cf80Smarks 			else
3696ecd6cf80Smarks 				(void) printf("user %d on",
3697ecd6cf80Smarks 				    (int)who);
3698ecd6cf80Smarks 		} else {
3699ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3700ecd6cf80Smarks 			continue;
3701ecd6cf80Smarks 		}
3702ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3703ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3704ecd6cf80Smarks 			(void) printf(" %s", hostname);
3705ecd6cf80Smarks 		}
3706ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3707ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3708ecd6cf80Smarks 			(void) printf(":%s", zonename);
3709ecd6cf80Smarks 		}
3710ecd6cf80Smarks 
3711ecd6cf80Smarks 		(void) printf("]");
3712ecd6cf80Smarks 		(void) printf("\n");
371306eeb2adSek110237 	}
371406eeb2adSek110237 	(void) printf("\n");
371506eeb2adSek110237 	nvlist_free(nvhis);
371606eeb2adSek110237 
371706eeb2adSek110237 	return (ret);
371806eeb2adSek110237 }
371906eeb2adSek110237 
372006eeb2adSek110237 /*
372106eeb2adSek110237  * zpool history <pool>
372206eeb2adSek110237  *
372306eeb2adSek110237  * Displays the history of commands that modified pools.
372406eeb2adSek110237  */
3725ecd6cf80Smarks 
3726ecd6cf80Smarks 
372706eeb2adSek110237 int
372806eeb2adSek110237 zpool_do_history(int argc, char **argv)
372906eeb2adSek110237 {
3730ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
373106eeb2adSek110237 	int ret;
3732ecd6cf80Smarks 	int c;
373306eeb2adSek110237 
3734ecd6cf80Smarks 	cbdata.first = B_TRUE;
3735ecd6cf80Smarks 	/* check options */
3736ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3737ecd6cf80Smarks 		switch (c) {
3738ecd6cf80Smarks 		case 'l':
3739ecd6cf80Smarks 			cbdata.longfmt = 1;
3740ecd6cf80Smarks 			break;
3741ecd6cf80Smarks 		case 'i':
3742ecd6cf80Smarks 			cbdata.internal = 1;
3743ecd6cf80Smarks 			break;
3744ecd6cf80Smarks 		case '?':
3745ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3746ecd6cf80Smarks 			    optopt);
3747ecd6cf80Smarks 			usage(B_FALSE);
3748ecd6cf80Smarks 		}
3749ecd6cf80Smarks 	}
375006eeb2adSek110237 	argc -= optind;
375106eeb2adSek110237 	argv += optind;
375206eeb2adSek110237 
3753b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3754ecd6cf80Smarks 	    &cbdata);
375506eeb2adSek110237 
3756ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
375706eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
375806eeb2adSek110237 		return (0);
3759eaca9bbdSeschrock 	}
3760eaca9bbdSeschrock 
3761eaca9bbdSeschrock 	return (ret);
3762eaca9bbdSeschrock }
3763eaca9bbdSeschrock 
3764b1b8ab34Slling static int
3765b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3766b1b8ab34Slling {
3767990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3768b1b8ab34Slling 	char value[MAXNAMELEN];
3769990b4856Slling 	zprop_source_t srctype;
3770990b4856Slling 	zprop_list_t *pl;
3771b1b8ab34Slling 
3772b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3773b1b8ab34Slling 
3774b1b8ab34Slling 		/*
3775990b4856Slling 		 * Skip the special fake placeholder. This will also skip
3776990b4856Slling 		 * over the name property when 'all' is specified.
3777b1b8ab34Slling 		 */
3778990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3779b1b8ab34Slling 		    pl == cbp->cb_proplist)
3780b1b8ab34Slling 			continue;
3781b1b8ab34Slling 
3782b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3783b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3784b1b8ab34Slling 			continue;
3785b1b8ab34Slling 
3786990b4856Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
3787b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3788b1b8ab34Slling 	}
3789b1b8ab34Slling 	return (0);
3790b1b8ab34Slling }
3791b1b8ab34Slling 
3792b1b8ab34Slling int
3793b1b8ab34Slling zpool_do_get(int argc, char **argv)
3794b1b8ab34Slling {
3795990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
3796990b4856Slling 	zprop_list_t fake_name = { 0 };
3797b1b8ab34Slling 	int ret;
3798b1b8ab34Slling 
3799b1b8ab34Slling 	if (argc < 3)
3800b1b8ab34Slling 		usage(B_FALSE);
3801b1b8ab34Slling 
3802b1b8ab34Slling 	cb.cb_first = B_TRUE;
3803990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
3804b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3805b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3806b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3807b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3808990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
3809b1b8ab34Slling 
3810990b4856Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3811990b4856Slling 	    ZFS_TYPE_POOL) != 0)
3812b1b8ab34Slling 		usage(B_FALSE);
3813b1b8ab34Slling 
3814b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3815990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
3816b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3817b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3818b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3819b1b8ab34Slling 	}
3820b1b8ab34Slling 
3821b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3822b1b8ab34Slling 	    get_callback, &cb);
3823b1b8ab34Slling 
3824b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3825990b4856Slling 		zprop_free_list(fake_name.pl_next);
3826b1b8ab34Slling 	else
3827990b4856Slling 		zprop_free_list(cb.cb_proplist);
3828b1b8ab34Slling 
3829b1b8ab34Slling 	return (ret);
3830b1b8ab34Slling }
3831b1b8ab34Slling 
3832b1b8ab34Slling typedef struct set_cbdata {
3833b1b8ab34Slling 	char *cb_propname;
3834b1b8ab34Slling 	char *cb_value;
3835b1b8ab34Slling 	boolean_t cb_any_successful;
3836b1b8ab34Slling } set_cbdata_t;
3837b1b8ab34Slling 
3838b1b8ab34Slling int
3839b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3840b1b8ab34Slling {
3841b1b8ab34Slling 	int error;
3842b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3843b1b8ab34Slling 
3844b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3845b1b8ab34Slling 
3846b1b8ab34Slling 	if (!error)
3847b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3848b1b8ab34Slling 
3849b1b8ab34Slling 	return (error);
3850b1b8ab34Slling }
3851b1b8ab34Slling 
3852b1b8ab34Slling int
3853b1b8ab34Slling zpool_do_set(int argc, char **argv)
3854b1b8ab34Slling {
3855b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3856b1b8ab34Slling 	int error;
3857b1b8ab34Slling 
3858b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3859b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3860b1b8ab34Slling 		    argv[1][1]);
3861b1b8ab34Slling 		usage(B_FALSE);
3862b1b8ab34Slling 	}
3863b1b8ab34Slling 
3864b1b8ab34Slling 	if (argc < 2) {
3865b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3866b1b8ab34Slling 		    "argument\n"));
3867b1b8ab34Slling 		usage(B_FALSE);
3868b1b8ab34Slling 	}
3869b1b8ab34Slling 
3870b1b8ab34Slling 	if (argc < 3) {
3871b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3872b1b8ab34Slling 		usage(B_FALSE);
3873b1b8ab34Slling 	}
3874b1b8ab34Slling 
3875b1b8ab34Slling 	if (argc > 3) {
3876b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3877b1b8ab34Slling 		usage(B_FALSE);
3878b1b8ab34Slling 	}
3879b1b8ab34Slling 
3880b1b8ab34Slling 	cb.cb_propname = argv[1];
3881b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3882b1b8ab34Slling 	if (cb.cb_value == NULL) {
3883b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3884b1b8ab34Slling 		    "property=value argument\n"));
3885b1b8ab34Slling 		usage(B_FALSE);
3886b1b8ab34Slling 	}
3887b1b8ab34Slling 
3888b1b8ab34Slling 	*(cb.cb_value) = '\0';
3889b1b8ab34Slling 	cb.cb_value++;
3890b1b8ab34Slling 
3891b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3892b1b8ab34Slling 	    set_callback, &cb);
3893b1b8ab34Slling 
3894b1b8ab34Slling 	return (error);
3895b1b8ab34Slling }
3896b1b8ab34Slling 
3897b1b8ab34Slling static int
3898b1b8ab34Slling find_command_idx(char *command, int *idx)
3899b1b8ab34Slling {
3900b1b8ab34Slling 	int i;
3901b1b8ab34Slling 
3902b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3903b1b8ab34Slling 		if (command_table[i].name == NULL)
3904b1b8ab34Slling 			continue;
3905b1b8ab34Slling 
3906b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3907b1b8ab34Slling 			*idx = i;
3908b1b8ab34Slling 			return (0);
3909b1b8ab34Slling 		}
3910b1b8ab34Slling 	}
3911b1b8ab34Slling 	return (1);
3912b1b8ab34Slling }
3913b1b8ab34Slling 
3914fa9e4066Sahrens int
3915fa9e4066Sahrens main(int argc, char **argv)
3916fa9e4066Sahrens {
3917fa9e4066Sahrens 	int ret;
3918fa9e4066Sahrens 	int i;
3919fa9e4066Sahrens 	char *cmdname;
3920fa9e4066Sahrens 
3921fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3922fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3923fa9e4066Sahrens 
392499653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
392599653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3926203a47d8Snd150628 		    "initialize ZFS library\n"));
392799653d4eSeschrock 		return (1);
392899653d4eSeschrock 	}
392999653d4eSeschrock 
393099653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
393199653d4eSeschrock 
3932fa9e4066Sahrens 	opterr = 0;
3933fa9e4066Sahrens 
3934fa9e4066Sahrens 	/*
3935fa9e4066Sahrens 	 * Make sure the user has specified some command.
3936fa9e4066Sahrens 	 */
3937fa9e4066Sahrens 	if (argc < 2) {
3938fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
393999653d4eSeschrock 		usage(B_FALSE);
3940fa9e4066Sahrens 	}
3941fa9e4066Sahrens 
3942fa9e4066Sahrens 	cmdname = argv[1];
3943fa9e4066Sahrens 
3944fa9e4066Sahrens 	/*
3945fa9e4066Sahrens 	 * Special case '-?'
3946fa9e4066Sahrens 	 */
3947fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
394899653d4eSeschrock 		usage(B_TRUE);
3949fa9e4066Sahrens 
39502a6b87f0Sek110237 	zpool_set_history_str("zpool", argc, argv, history_str);
39512a6b87f0Sek110237 	verify(zpool_stage_history(g_zfs, history_str) == 0);
39522a6b87f0Sek110237 
3953fa9e4066Sahrens 	/*
3954fa9e4066Sahrens 	 * Run the appropriate command.
3955fa9e4066Sahrens 	 */
3956b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
3957fa9e4066Sahrens 		current_command = &command_table[i];
3958fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
395991ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
396091ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
396191ebeef5Sahrens 		current_command = &command_table[i];
396291ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
396391ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
3964fa9e4066Sahrens 		/*
396591ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
396691ebeef5Sahrens 		 * it as such.
3967fa9e4066Sahrens 		 */
3968ea8dc4b6Seschrock 		char buf[16384];
3969ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
3970fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
3971fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
397291ebeef5Sahrens 	} else {
3973fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
3974fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
397599653d4eSeschrock 		usage(B_FALSE);
3976fa9e4066Sahrens 	}
3977fa9e4066Sahrens 
397899653d4eSeschrock 	libzfs_fini(g_zfs);
397999653d4eSeschrock 
3980fa9e4066Sahrens 	/*
3981fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3982fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
3983fa9e4066Sahrens 	 */
3984fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
3985fa9e4066Sahrens 		(void) printf("dumping core by request\n");
3986fa9e4066Sahrens 		abort();
3987fa9e4066Sahrens 	}
3988fa9e4066Sahrens 
3989fa9e4066Sahrens 	return (ret);
3990fa9e4066Sahrens }
3991