xref: /titanic_53/usr/src/cmd/zpool/zpool_main.c (revision 573ca77e53dd31dcaebef023e7eb41969e6896c1)
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 {
37914843421SMatthew Ahrens 		if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
3800a48a24eStimh 			normnm = zfs_prop_to_name(fprop);
38114843421SMatthew Ahrens 		} else {
38214843421SMatthew Ahrens 			normnm = propname;
38314843421SMatthew 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 
981e6ca193dSGeorge Wilson typedef struct spare_cbdata {
982e6ca193dSGeorge Wilson 	uint64_t	cb_guid;
983e6ca193dSGeorge Wilson 	zpool_handle_t	*cb_zhp;
984e6ca193dSGeorge Wilson } spare_cbdata_t;
985e6ca193dSGeorge Wilson 
986e6ca193dSGeorge Wilson static boolean_t
987e6ca193dSGeorge Wilson find_vdev(nvlist_t *nv, uint64_t search)
988e6ca193dSGeorge Wilson {
989e6ca193dSGeorge Wilson 	uint64_t guid;
990e6ca193dSGeorge Wilson 	nvlist_t **child;
991e6ca193dSGeorge Wilson 	uint_t c, children;
992e6ca193dSGeorge Wilson 
993e6ca193dSGeorge Wilson 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
994e6ca193dSGeorge Wilson 	    search == guid)
995e6ca193dSGeorge Wilson 		return (B_TRUE);
996e6ca193dSGeorge Wilson 
997e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
998e6ca193dSGeorge Wilson 	    &child, &children) == 0) {
999e6ca193dSGeorge Wilson 		for (c = 0; c < children; c++)
1000e6ca193dSGeorge Wilson 			if (find_vdev(child[c], search))
1001e6ca193dSGeorge Wilson 				return (B_TRUE);
1002e6ca193dSGeorge Wilson 	}
1003e6ca193dSGeorge Wilson 
1004e6ca193dSGeorge Wilson 	return (B_FALSE);
1005e6ca193dSGeorge Wilson }
1006e6ca193dSGeorge Wilson 
1007e6ca193dSGeorge Wilson static int
1008e6ca193dSGeorge Wilson find_spare(zpool_handle_t *zhp, void *data)
1009e6ca193dSGeorge Wilson {
1010e6ca193dSGeorge Wilson 	spare_cbdata_t *cbp = data;
1011e6ca193dSGeorge Wilson 	nvlist_t *config, *nvroot;
1012e6ca193dSGeorge Wilson 
1013e6ca193dSGeorge Wilson 	config = zpool_get_config(zhp, NULL);
1014e6ca193dSGeorge Wilson 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1015e6ca193dSGeorge Wilson 	    &nvroot) == 0);
1016e6ca193dSGeorge Wilson 
1017e6ca193dSGeorge Wilson 	if (find_vdev(nvroot, cbp->cb_guid)) {
1018e6ca193dSGeorge Wilson 		cbp->cb_zhp = zhp;
1019e6ca193dSGeorge Wilson 		return (1);
1020e6ca193dSGeorge Wilson 	}
1021e6ca193dSGeorge Wilson 
1022e6ca193dSGeorge Wilson 	zpool_close(zhp);
1023e6ca193dSGeorge Wilson 	return (0);
1024e6ca193dSGeorge Wilson }
1025e6ca193dSGeorge Wilson 
1026e6ca193dSGeorge Wilson /*
1027e6ca193dSGeorge Wilson  * Print out configuration state as requested by status_callback.
1028e6ca193dSGeorge Wilson  */
1029e6ca193dSGeorge Wilson void
1030e6ca193dSGeorge Wilson print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
1031e6ca193dSGeorge Wilson     int namewidth, int depth, boolean_t isspare)
1032e6ca193dSGeorge Wilson {
1033e6ca193dSGeorge Wilson 	nvlist_t **child;
1034e6ca193dSGeorge Wilson 	uint_t c, children;
1035e6ca193dSGeorge Wilson 	vdev_stat_t *vs;
1036e6ca193dSGeorge Wilson 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
1037e6ca193dSGeorge Wilson 	char *vname;
1038e6ca193dSGeorge Wilson 	uint64_t notpresent;
1039e6ca193dSGeorge Wilson 	spare_cbdata_t cb;
1040e6ca193dSGeorge Wilson 	char *state;
1041e6ca193dSGeorge Wilson 
1042e6ca193dSGeorge Wilson 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
1043e6ca193dSGeorge Wilson 	    (uint64_t **)&vs, &c) == 0);
1044e6ca193dSGeorge Wilson 
1045e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1046e6ca193dSGeorge Wilson 	    &child, &children) != 0)
1047e6ca193dSGeorge Wilson 		children = 0;
1048e6ca193dSGeorge Wilson 
1049e6ca193dSGeorge Wilson 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1050e6ca193dSGeorge Wilson 	if (isspare) {
1051e6ca193dSGeorge Wilson 		/*
1052e6ca193dSGeorge Wilson 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
1053e6ca193dSGeorge Wilson 		 * online drives.
1054e6ca193dSGeorge Wilson 		 */
1055e6ca193dSGeorge Wilson 		if (vs->vs_aux == VDEV_AUX_SPARED)
1056e6ca193dSGeorge Wilson 			state = "INUSE";
1057e6ca193dSGeorge Wilson 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
1058e6ca193dSGeorge Wilson 			state = "AVAIL";
1059e6ca193dSGeorge Wilson 	}
1060e6ca193dSGeorge Wilson 
1061e6ca193dSGeorge Wilson 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
1062e6ca193dSGeorge Wilson 	    name, state);
1063e6ca193dSGeorge Wilson 
1064e6ca193dSGeorge Wilson 	if (!isspare) {
1065e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
1066e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
1067e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
1068e6ca193dSGeorge Wilson 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
1069e6ca193dSGeorge Wilson 	}
1070e6ca193dSGeorge Wilson 
1071e6ca193dSGeorge Wilson 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1072e6ca193dSGeorge Wilson 	    &notpresent) == 0) {
1073e6ca193dSGeorge Wilson 		char *path;
1074e6ca193dSGeorge Wilson 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
1075e6ca193dSGeorge Wilson 		(void) printf("  was %s", path);
1076e6ca193dSGeorge Wilson 	} else if (vs->vs_aux != 0) {
1077e6ca193dSGeorge Wilson 		(void) printf("  ");
1078e6ca193dSGeorge Wilson 
1079e6ca193dSGeorge Wilson 		switch (vs->vs_aux) {
1080e6ca193dSGeorge Wilson 		case VDEV_AUX_OPEN_FAILED:
1081e6ca193dSGeorge Wilson 			(void) printf(gettext("cannot open"));
1082e6ca193dSGeorge Wilson 			break;
1083e6ca193dSGeorge Wilson 
1084e6ca193dSGeorge Wilson 		case VDEV_AUX_BAD_GUID_SUM:
1085e6ca193dSGeorge Wilson 			(void) printf(gettext("missing device"));
1086e6ca193dSGeorge Wilson 			break;
1087e6ca193dSGeorge Wilson 
1088e6ca193dSGeorge Wilson 		case VDEV_AUX_NO_REPLICAS:
1089e6ca193dSGeorge Wilson 			(void) printf(gettext("insufficient replicas"));
1090e6ca193dSGeorge Wilson 			break;
1091e6ca193dSGeorge Wilson 
1092e6ca193dSGeorge Wilson 		case VDEV_AUX_VERSION_NEWER:
1093e6ca193dSGeorge Wilson 			(void) printf(gettext("newer version"));
1094e6ca193dSGeorge Wilson 			break;
1095e6ca193dSGeorge Wilson 
1096e6ca193dSGeorge Wilson 		case VDEV_AUX_SPARED:
1097e6ca193dSGeorge Wilson 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1098e6ca193dSGeorge Wilson 			    &cb.cb_guid) == 0);
1099e6ca193dSGeorge Wilson 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
1100e6ca193dSGeorge Wilson 				if (strcmp(zpool_get_name(cb.cb_zhp),
1101e6ca193dSGeorge Wilson 				    zpool_get_name(zhp)) == 0)
1102e6ca193dSGeorge Wilson 					(void) printf(gettext("currently in "
1103e6ca193dSGeorge Wilson 					    "use"));
1104e6ca193dSGeorge Wilson 				else
1105e6ca193dSGeorge Wilson 					(void) printf(gettext("in use by "
1106e6ca193dSGeorge Wilson 					    "pool '%s'"),
1107e6ca193dSGeorge Wilson 					    zpool_get_name(cb.cb_zhp));
1108e6ca193dSGeorge Wilson 				zpool_close(cb.cb_zhp);
1109e6ca193dSGeorge Wilson 			} else {
1110e6ca193dSGeorge Wilson 				(void) printf(gettext("currently in use"));
1111e6ca193dSGeorge Wilson 			}
1112e6ca193dSGeorge Wilson 			break;
1113e6ca193dSGeorge Wilson 
1114e6ca193dSGeorge Wilson 		case VDEV_AUX_ERR_EXCEEDED:
1115e6ca193dSGeorge Wilson 			(void) printf(gettext("too many errors"));
1116e6ca193dSGeorge Wilson 			break;
1117e6ca193dSGeorge Wilson 
1118e6ca193dSGeorge Wilson 		case VDEV_AUX_IO_FAILURE:
1119e6ca193dSGeorge Wilson 			(void) printf(gettext("experienced I/O failures"));
1120e6ca193dSGeorge Wilson 			break;
1121e6ca193dSGeorge Wilson 
1122e6ca193dSGeorge Wilson 		case VDEV_AUX_BAD_LOG:
1123e6ca193dSGeorge Wilson 			(void) printf(gettext("bad intent log"));
1124e6ca193dSGeorge Wilson 			break;
1125e6ca193dSGeorge Wilson 
1126e6ca193dSGeorge Wilson 		default:
1127e6ca193dSGeorge Wilson 			(void) printf(gettext("corrupted data"));
1128e6ca193dSGeorge Wilson 			break;
1129e6ca193dSGeorge Wilson 		}
1130e6ca193dSGeorge Wilson 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
1131e6ca193dSGeorge Wilson 		/*
1132e6ca193dSGeorge Wilson 		 * Report bytes resilvered/repaired on leaf devices.
1133e6ca193dSGeorge Wilson 		 */
1134e6ca193dSGeorge Wilson 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
1135e6ca193dSGeorge Wilson 		(void) printf(gettext("  %s %s"), repaired,
1136e6ca193dSGeorge Wilson 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
1137e6ca193dSGeorge Wilson 		    "resilvered" : "repaired");
1138e6ca193dSGeorge Wilson 	}
1139e6ca193dSGeorge Wilson 
1140e6ca193dSGeorge Wilson 	(void) printf("\n");
1141e6ca193dSGeorge Wilson 
1142e6ca193dSGeorge Wilson 	for (c = 0; c < children; c++) {
1143e6ca193dSGeorge Wilson 		uint64_t is_log = B_FALSE;
1144e6ca193dSGeorge Wilson 
1145e6ca193dSGeorge Wilson 		/* Don't print logs here */
1146e6ca193dSGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1147e6ca193dSGeorge Wilson 		    &is_log);
1148e6ca193dSGeorge Wilson 		if (is_log)
1149e6ca193dSGeorge Wilson 			continue;
1150e6ca193dSGeorge Wilson 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
1151e6ca193dSGeorge Wilson 		print_status_config(zhp, vname, child[c],
1152e6ca193dSGeorge Wilson 		    namewidth, depth + 2, isspare);
1153e6ca193dSGeorge Wilson 		free(vname);
1154e6ca193dSGeorge Wilson 	}
1155e6ca193dSGeorge Wilson }
1156e6ca193dSGeorge Wilson 
1157fa9e4066Sahrens 
1158fa9e4066Sahrens /*
1159fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
1160fa9e4066Sahrens  * pool, printing out the name and status for each one.
1161fa9e4066Sahrens  */
1162fa9e4066Sahrens void
1163e6ca193dSGeorge Wilson print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
1164fa9e4066Sahrens {
1165fa9e4066Sahrens 	nvlist_t **child;
1166fa9e4066Sahrens 	uint_t c, children;
1167fa9e4066Sahrens 	vdev_stat_t *vs;
1168afefbcddSeschrock 	char *type, *vname;
1169fa9e4066Sahrens 
1170fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
1171fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
1172fa9e4066Sahrens 		return;
1173fa9e4066Sahrens 
1174fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
1175fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
1176fa9e4066Sahrens 
1177fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
1178990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1179fa9e4066Sahrens 
1180fa9e4066Sahrens 	if (vs->vs_aux != 0) {
11813d7072f8Seschrock 		(void) printf("  ");
1182fa9e4066Sahrens 
1183fa9e4066Sahrens 		switch (vs->vs_aux) {
1184fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
1185fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
1186fa9e4066Sahrens 			break;
1187fa9e4066Sahrens 
1188fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
1189fa9e4066Sahrens 			(void) printf(gettext("missing device"));
1190fa9e4066Sahrens 			break;
1191fa9e4066Sahrens 
1192fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
1193fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
1194fa9e4066Sahrens 			break;
1195fa9e4066Sahrens 
1196eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
1197eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
1198eaca9bbdSeschrock 			break;
1199eaca9bbdSeschrock 
12003d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
12013d7072f8Seschrock 			(void) printf(gettext("too many errors"));
12023d7072f8Seschrock 			break;
12033d7072f8Seschrock 
1204fa9e4066Sahrens 		default:
1205fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
1206fa9e4066Sahrens 			break;
1207fa9e4066Sahrens 		}
1208fa9e4066Sahrens 	}
1209fa9e4066Sahrens 	(void) printf("\n");
1210fa9e4066Sahrens 
1211fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1212fa9e4066Sahrens 	    &child, &children) != 0)
1213fa9e4066Sahrens 		return;
1214fa9e4066Sahrens 
1215afefbcddSeschrock 	for (c = 0; c < children; c++) {
12168654d025Sperrin 		uint64_t is_log = B_FALSE;
12178654d025Sperrin 
12188654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
12198654d025Sperrin 		    &is_log);
1220e6ca193dSGeorge Wilson 		if (is_log)
12218654d025Sperrin 			continue;
12228654d025Sperrin 
122399653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1224e6ca193dSGeorge Wilson 		print_import_config(vname, child[c], namewidth, depth + 2);
1225afefbcddSeschrock 		free(vname);
1226afefbcddSeschrock 	}
122799653d4eSeschrock 
1228fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1229fa94a07fSbrendan 	    &child, &children) == 0) {
1230fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
1231fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1232fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1233fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1234fa94a07fSbrendan 			free(vname);
1235fa94a07fSbrendan 		}
1236fa94a07fSbrendan 	}
123799653d4eSeschrock 
1238fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1239fa94a07fSbrendan 	    &child, &children) == 0) {
124099653d4eSeschrock 		(void) printf(gettext("\tspares\n"));
124199653d4eSeschrock 		for (c = 0; c < children; c++) {
124299653d4eSeschrock 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
124399653d4eSeschrock 			(void) printf("\t  %s\n", vname);
124499653d4eSeschrock 			free(vname);
124599653d4eSeschrock 		}
1246fa9e4066Sahrens 	}
1247fa94a07fSbrendan }
1248fa9e4066Sahrens 
1249fa9e4066Sahrens /*
1250e6ca193dSGeorge Wilson  * Print log vdevs.
1251e6ca193dSGeorge Wilson  * Logs are recorded as top level vdevs in the main pool child array
1252e6ca193dSGeorge Wilson  * but with "is_log" set to 1. We use either print_status_config() or
1253e6ca193dSGeorge Wilson  * print_import_config() to print the top level logs then any log
1254e6ca193dSGeorge Wilson  * children (eg mirrored slogs) are printed recursively - which
1255e6ca193dSGeorge Wilson  * works because only the top level vdev is marked "is_log"
1256e6ca193dSGeorge Wilson  */
1257e6ca193dSGeorge Wilson static void
1258e6ca193dSGeorge Wilson print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
1259e6ca193dSGeorge Wilson {
1260e6ca193dSGeorge Wilson 	uint_t c, children;
1261e6ca193dSGeorge Wilson 	nvlist_t **child;
1262e6ca193dSGeorge Wilson 
1263e6ca193dSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1264e6ca193dSGeorge Wilson 	    &children) != 0)
1265e6ca193dSGeorge Wilson 		return;
1266e6ca193dSGeorge Wilson 
1267e6ca193dSGeorge Wilson 	(void) printf(gettext("\tlogs\n"));
1268e6ca193dSGeorge Wilson 
1269e6ca193dSGeorge Wilson 	for (c = 0; c < children; c++) {
1270e6ca193dSGeorge Wilson 		uint64_t is_log = B_FALSE;
1271e6ca193dSGeorge Wilson 		char *name;
1272e6ca193dSGeorge Wilson 
1273e6ca193dSGeorge Wilson 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1274e6ca193dSGeorge Wilson 		    &is_log);
1275e6ca193dSGeorge Wilson 		if (!is_log)
1276e6ca193dSGeorge Wilson 			continue;
1277e6ca193dSGeorge Wilson 		name = zpool_vdev_name(g_zfs, zhp, child[c]);
1278e6ca193dSGeorge Wilson 		if (verbose)
1279e6ca193dSGeorge Wilson 			print_status_config(zhp, name, child[c], namewidth,
1280e6ca193dSGeorge Wilson 			    2, B_FALSE);
1281e6ca193dSGeorge Wilson 		else
1282e6ca193dSGeorge Wilson 			print_import_config(name, child[c], namewidth, 2);
1283e6ca193dSGeorge Wilson 		free(name);
1284e6ca193dSGeorge Wilson 	}
1285e6ca193dSGeorge Wilson }
1286e6ca193dSGeorge Wilson /*
1287fa9e4066Sahrens  * Display the status for the given pool.
1288fa9e4066Sahrens  */
1289fa9e4066Sahrens static void
1290fa9e4066Sahrens show_import(nvlist_t *config)
1291fa9e4066Sahrens {
1292fa9e4066Sahrens 	uint64_t pool_state;
1293fa9e4066Sahrens 	vdev_stat_t *vs;
1294fa9e4066Sahrens 	char *name;
1295fa9e4066Sahrens 	uint64_t guid;
1296fa9e4066Sahrens 	char *msgid;
1297fa9e4066Sahrens 	nvlist_t *nvroot;
1298fa9e4066Sahrens 	int reason;
129946657f8dSmmusante 	const char *health;
1300fa9e4066Sahrens 	uint_t vsc;
1301fa9e4066Sahrens 	int namewidth;
1302fa9e4066Sahrens 
1303fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1304fa9e4066Sahrens 	    &name) == 0);
1305fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1306fa9e4066Sahrens 	    &guid) == 0);
1307fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1308fa9e4066Sahrens 	    &pool_state) == 0);
1309fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1310fa9e4066Sahrens 	    &nvroot) == 0);
1311fa9e4066Sahrens 
1312fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1313fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1314990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1315fa9e4066Sahrens 
1316fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1317fa9e4066Sahrens 
131846657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
131946657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
132046657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
13214c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
132246657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
13234c58d714Sdarrenm 	(void) printf("\n");
1324fa9e4066Sahrens 
1325fa9e4066Sahrens 	switch (reason) {
1326fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1327fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1328fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1329fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1330fa9e4066Sahrens 		    "from the system.\n"));
1331fa9e4066Sahrens 		break;
1332fa9e4066Sahrens 
1333fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1334fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1335fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1336fa9e4066Sahrens 		    "corrupted data.\n"));
1337fa9e4066Sahrens 		break;
1338fa9e4066Sahrens 
1339fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1340fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1341fa9e4066Sahrens 		break;
1342fa9e4066Sahrens 
1343441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1344441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1345441d80aaSlling 		    "are offlined.\n"));
1346441d80aaSlling 		break;
1347441d80aaSlling 
1348ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1349ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1350ea8dc4b6Seschrock 		    "corrupted.\n"));
1351ea8dc4b6Seschrock 		break;
1352ea8dc4b6Seschrock 
1353eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1354eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1355eaca9bbdSeschrock 		    "older on-disk version.\n"));
1356eaca9bbdSeschrock 		break;
1357eaca9bbdSeschrock 
1358eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1359eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1360eaca9bbdSeschrock 		    "incompatible version.\n"));
1361eaca9bbdSeschrock 		break;
1362b87f3af3Sperrin 
136395173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
136495173954Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
136595173954Sek110237 		    "another system.\n"));
136695173954Sek110237 		break;
1367b87f3af3Sperrin 
13683d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
13693d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
13703d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
13713d7072f8Seschrock 		    "faulted.\n"));
13723d7072f8Seschrock 		break;
13733d7072f8Seschrock 
1374b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
1375b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record cannot be "
1376b87f3af3Sperrin 		    "read.\n"));
1377b87f3af3Sperrin 		break;
1378b87f3af3Sperrin 
1379fa9e4066Sahrens 	default:
1380fa9e4066Sahrens 		/*
1381fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1382fa9e4066Sahrens 		 */
1383fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1384fa9e4066Sahrens 	}
1385fa9e4066Sahrens 
1386fa9e4066Sahrens 	/*
1387fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1388fa9e4066Sahrens 	 */
138946657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1390eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1391eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1392eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1393eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1394eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
139595173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
139695173954Sek110237 			(void) printf(gettext("action: The pool can be "
139795173954Sek110237 			    "imported using its name or numeric "
139895173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1399fa9e4066Sahrens 		else
1400eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1401eaca9bbdSeschrock 			    "imported using its name or numeric "
1402eaca9bbdSeschrock 			    "identifier.\n"));
140346657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1404fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1405fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1406eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1407fa9e4066Sahrens 	} else {
1408eaca9bbdSeschrock 		switch (reason) {
1409eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1410eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1411eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1412eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1413eaca9bbdSeschrock 			    "backup.\n"));
1414eaca9bbdSeschrock 			break;
1415eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1416eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1417eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1418fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1419fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1420fa9e4066Sahrens 			    "again.\n"));
1421eaca9bbdSeschrock 			break;
1422eaca9bbdSeschrock 		default:
1423fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1424fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1425fa9e4066Sahrens 		}
1426eaca9bbdSeschrock 	}
1427eaca9bbdSeschrock 
142846657f8dSmmusante 	/*
142946657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
143046657f8dSmmusante 	 * is "corrupt data":
143146657f8dSmmusante 	 */
143246657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
143346657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
143446657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1435eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1436eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1437eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1438eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1439eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
144018ce54dfSek110237 			    "another system, but can be imported using\n\t"
1441eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1442eaca9bbdSeschrock 	}
1443fa9e4066Sahrens 
1444fa9e4066Sahrens 	if (msgid != NULL)
1445fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1446fa9e4066Sahrens 		    msgid);
1447fa9e4066Sahrens 
1448fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1449fa9e4066Sahrens 
1450c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1451fa9e4066Sahrens 	if (namewidth < 10)
1452fa9e4066Sahrens 		namewidth = 10;
14538654d025Sperrin 
1454e6ca193dSGeorge Wilson 	print_import_config(name, nvroot, namewidth, 0);
1455e6ca193dSGeorge Wilson 	if (num_logs(nvroot) > 0)
1456e6ca193dSGeorge Wilson 		print_logs(NULL, nvroot, namewidth, B_FALSE);
1457fa9e4066Sahrens 
1458fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
145946657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1460fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
146146657f8dSmmusante 		    "configuration cannot be determined.\n"));
1462fa9e4066Sahrens 	}
1463fa9e4066Sahrens }
1464fa9e4066Sahrens 
1465fa9e4066Sahrens /*
1466fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1467990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1468990b4856Slling  * within the pool.
1469fa9e4066Sahrens  */
1470fa9e4066Sahrens static int
1471fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
1472c5904d13Seschrock     int force, nvlist_t *props, boolean_t allowfaulted)
1473fa9e4066Sahrens {
1474fa9e4066Sahrens 	zpool_handle_t *zhp;
1475fa9e4066Sahrens 	char *name;
1476fa9e4066Sahrens 	uint64_t state;
1477eaca9bbdSeschrock 	uint64_t version;
1478ecd6cf80Smarks 	int error = 0;
1479fa9e4066Sahrens 
1480fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1481fa9e4066Sahrens 	    &name) == 0);
1482fa9e4066Sahrens 
1483fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1484fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1485eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1486eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1487e7437265Sahrens 	if (version > SPA_VERSION) {
1488eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1489eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1490eaca9bbdSeschrock 		return (1);
1491eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
149295173954Sek110237 		uint64_t hostid;
149395173954Sek110237 
149495173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
149595173954Sek110237 		    &hostid) == 0) {
149695173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
149795173954Sek110237 				char *hostname;
149895173954Sek110237 				uint64_t timestamp;
149995173954Sek110237 				time_t t;
150095173954Sek110237 
150195173954Sek110237 				verify(nvlist_lookup_string(config,
150295173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
150395173954Sek110237 				verify(nvlist_lookup_uint64(config,
150495173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
150595173954Sek110237 				t = timestamp;
150695173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
150795173954Sek110237 				    "'%s': pool may be in use from other "
150895173954Sek110237 				    "system, it was last accessed by %s "
150995173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
151095173954Sek110237 				    (unsigned long)hostid,
151195173954Sek110237 				    asctime(localtime(&t)));
151295173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
151395173954Sek110237 				    "import anyway\n"));
1514fa9e4066Sahrens 				return (1);
1515fa9e4066Sahrens 			}
151695173954Sek110237 		} else {
151795173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
151895173954Sek110237 			    "pool may be in use from other system\n"), name);
151995173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
152095173954Sek110237 			    "anyway\n"));
152195173954Sek110237 			return (1);
152295173954Sek110237 		}
152395173954Sek110237 	}
1524fa9e4066Sahrens 
1525c5904d13Seschrock 	if (zpool_import_props(g_zfs, config, newname, props,
1526c5904d13Seschrock 	    allowfaulted) != 0)
1527fa9e4066Sahrens 		return (1);
1528fa9e4066Sahrens 
1529fa9e4066Sahrens 	if (newname != NULL)
1530fa9e4066Sahrens 		name = (char *)newname;
1531fa9e4066Sahrens 
1532c5904d13Seschrock 	verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL);
1533fa9e4066Sahrens 
1534379c004dSEric Schrock 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
1535379c004dSEric Schrock 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1536fa9e4066Sahrens 		zpool_close(zhp);
1537fa9e4066Sahrens 		return (1);
1538fa9e4066Sahrens 	}
1539fa9e4066Sahrens 
1540fa9e4066Sahrens 	zpool_close(zhp);
1541ecd6cf80Smarks 	return (error);
1542fa9e4066Sahrens }
1543fa9e4066Sahrens 
1544fa9e4066Sahrens /*
15454c58d714Sdarrenm  * zpool import [-d dir] [-D]
15462f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
15472f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
15482f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
15492f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] <pool | id> [newpool]
15502f8aaab3Seschrock  *
15512f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
15522f8aaab3Seschrock  *		devices.
1553fa9e4066Sahrens  *
1554fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1555fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1556fa9e4066Sahrens  *
15574c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
15584c58d714Sdarrenm  *              specified destroyed pools.
15594c58d714Sdarrenm  *
1560fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1561fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1562fa9e4066Sahrens  *		is rebooted.
1563fa9e4066Sahrens  *
1564fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1565fa9e4066Sahrens  *
1566c5904d13Seschrock  *       -F	Import even in the presence of faulted vdevs.  This is an
1567c5904d13Seschrock  *       	intentionally undocumented option for testing purposes, and
1568c5904d13Seschrock  *       	treats the pool configuration as complete, leaving any bad
1569c5904d13Seschrock  *		vdevs in the FAULTED state.
1570c5904d13Seschrock  *
1571fa9e4066Sahrens  *       -a	Import all pools found.
1572fa9e4066Sahrens  *
1573990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1574ecd6cf80Smarks  *
1575fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1576fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1577fa9e4066Sahrens  */
1578fa9e4066Sahrens int
1579fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1580fa9e4066Sahrens {
1581fa9e4066Sahrens 	char **searchdirs = NULL;
1582fa9e4066Sahrens 	int nsearch = 0;
1583fa9e4066Sahrens 	int c;
1584fa9e4066Sahrens 	int err;
15852f8aaab3Seschrock 	nvlist_t *pools = NULL;
158699653d4eSeschrock 	boolean_t do_all = B_FALSE;
158799653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1588fa9e4066Sahrens 	char *mntopts = NULL;
158999653d4eSeschrock 	boolean_t do_force = B_FALSE;
1590fa9e4066Sahrens 	nvpair_t *elem;
1591fa9e4066Sahrens 	nvlist_t *config;
159224e697d4Sck153898 	uint64_t searchguid = 0;
159324e697d4Sck153898 	char *searchname = NULL;
1594990b4856Slling 	char *propval;
1595fa9e4066Sahrens 	nvlist_t *found_config;
1596ecd6cf80Smarks 	nvlist_t *props = NULL;
159799653d4eSeschrock 	boolean_t first;
1598c5904d13Seschrock 	boolean_t allow_faulted = B_FALSE;
15994c58d714Sdarrenm 	uint64_t pool_state;
16002f8aaab3Seschrock 	char *cachefile = NULL;
1601fa9e4066Sahrens 
1602fa9e4066Sahrens 	/* check options */
1603c5904d13Seschrock 	while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) {
1604fa9e4066Sahrens 		switch (c) {
1605fa9e4066Sahrens 		case 'a':
160699653d4eSeschrock 			do_all = B_TRUE;
1607fa9e4066Sahrens 			break;
16082f8aaab3Seschrock 		case 'c':
16092f8aaab3Seschrock 			cachefile = optarg;
16102f8aaab3Seschrock 			break;
1611fa9e4066Sahrens 		case 'd':
1612fa9e4066Sahrens 			if (searchdirs == NULL) {
1613fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1614fa9e4066Sahrens 			} else {
1615fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1616fa9e4066Sahrens 				    sizeof (char *));
1617fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1618fa9e4066Sahrens 				    sizeof (char *));
1619fa9e4066Sahrens 				free(searchdirs);
1620fa9e4066Sahrens 				searchdirs = tmp;
1621fa9e4066Sahrens 			}
1622fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1623fa9e4066Sahrens 			break;
16244c58d714Sdarrenm 		case 'D':
162599653d4eSeschrock 			do_destroyed = B_TRUE;
16264c58d714Sdarrenm 			break;
1627fa9e4066Sahrens 		case 'f':
162899653d4eSeschrock 			do_force = B_TRUE;
1629fa9e4066Sahrens 			break;
1630c5904d13Seschrock 		case 'F':
1631c5904d13Seschrock 			allow_faulted = B_TRUE;
1632c5904d13Seschrock 			break;
1633fa9e4066Sahrens 		case 'o':
1634990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1635990b4856Slling 				*propval = '\0';
1636990b4856Slling 				propval++;
16370a48a24eStimh 				if (add_prop_list(optarg, propval,
16380a48a24eStimh 				    &props, B_TRUE))
1639990b4856Slling 					goto error;
1640990b4856Slling 			} else {
1641fa9e4066Sahrens 				mntopts = optarg;
1642990b4856Slling 			}
1643fa9e4066Sahrens 			break;
1644fa9e4066Sahrens 		case 'R':
1645990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
16460a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1647990b4856Slling 				goto error;
16482f8aaab3Seschrock 			if (nvlist_lookup_string(props,
16492f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
16502f8aaab3Seschrock 			    &propval) == 0)
16512f8aaab3Seschrock 				break;
1652990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
16530a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1654990b4856Slling 				goto error;
1655fa9e4066Sahrens 			break;
1656fa9e4066Sahrens 		case ':':
1657fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1658fa9e4066Sahrens 			    "'%c' option\n"), optopt);
165999653d4eSeschrock 			usage(B_FALSE);
1660fa9e4066Sahrens 			break;
1661fa9e4066Sahrens 		case '?':
1662fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1663fa9e4066Sahrens 			    optopt);
166499653d4eSeschrock 			usage(B_FALSE);
1665fa9e4066Sahrens 		}
1666fa9e4066Sahrens 	}
1667fa9e4066Sahrens 
1668fa9e4066Sahrens 	argc -= optind;
1669fa9e4066Sahrens 	argv += optind;
1670fa9e4066Sahrens 
16712f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
16722f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
16732f8aaab3Seschrock 		usage(B_FALSE);
16742f8aaab3Seschrock 	}
16752f8aaab3Seschrock 
1676fa9e4066Sahrens 	if (searchdirs == NULL) {
1677fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1678fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1679fa9e4066Sahrens 		nsearch = 1;
1680fa9e4066Sahrens 	}
1681fa9e4066Sahrens 
1682fa9e4066Sahrens 	/* check argument count */
1683fa9e4066Sahrens 	if (do_all) {
1684fa9e4066Sahrens 		if (argc != 0) {
1685fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
168699653d4eSeschrock 			usage(B_FALSE);
1687fa9e4066Sahrens 		}
1688fa9e4066Sahrens 	} else {
1689fa9e4066Sahrens 		if (argc > 2) {
1690fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
169199653d4eSeschrock 			usage(B_FALSE);
1692fa9e4066Sahrens 		}
1693fa9e4066Sahrens 
1694fa9e4066Sahrens 		/*
1695fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1696fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1697fa9e4066Sahrens 		 * silently fail.
1698fa9e4066Sahrens 		 */
1699fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1700fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1701fa9e4066Sahrens 			    "discover pools: permission denied\n"));
170299653d4eSeschrock 			free(searchdirs);
1703fa9e4066Sahrens 			return (1);
1704fa9e4066Sahrens 		}
1705fa9e4066Sahrens 	}
1706fa9e4066Sahrens 
1707fa9e4066Sahrens 	/*
1708fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1709fa9e4066Sahrens 	 *
1710fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1711fa9e4066Sahrens 	 *		each one.
1712fa9e4066Sahrens 	 *
1713fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1714fa9e4066Sahrens 	 *
1715fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1716fa9e4066Sahrens 	 *		name and import that one.
17174c58d714Sdarrenm 	 *
17184c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1719fa9e4066Sahrens 	 */
1720fa9e4066Sahrens 	if (argc != 0) {
1721fa9e4066Sahrens 		char *endptr;
1722fa9e4066Sahrens 
1723fa9e4066Sahrens 		errno = 0;
1724fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1725fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1726fa9e4066Sahrens 			searchname = argv[0];
1727fa9e4066Sahrens 		found_config = NULL;
1728fa9e4066Sahrens 	}
1729fa9e4066Sahrens 
173024e697d4Sck153898 	if (cachefile) {
1731e829d913Sck153898 		pools = zpool_find_import_cached(g_zfs, cachefile, searchname,
1732e829d913Sck153898 		    searchguid);
173324e697d4Sck153898 	} else if (searchname != NULL) {
173424e697d4Sck153898 		pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs,
173524e697d4Sck153898 		    searchname);
173624e697d4Sck153898 	} else {
173724e697d4Sck153898 		/*
173824e697d4Sck153898 		 * It's OK to search by guid even if searchguid is 0.
173924e697d4Sck153898 		 */
174024e697d4Sck153898 		pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs,
174124e697d4Sck153898 		    searchguid);
174224e697d4Sck153898 	}
174324e697d4Sck153898 
174424e697d4Sck153898 	if (pools == NULL) {
174524e697d4Sck153898 		if (argc != 0) {
174624e697d4Sck153898 			(void) fprintf(stderr, gettext("cannot import '%s': "
174724e697d4Sck153898 			    "no such pool available\n"), argv[0]);
174824e697d4Sck153898 		}
174924e697d4Sck153898 		free(searchdirs);
175024e697d4Sck153898 		return (1);
175124e697d4Sck153898 	}
175224e697d4Sck153898 
175324e697d4Sck153898 	/*
175424e697d4Sck153898 	 * At this point we have a list of import candidate configs. Even if
175524e697d4Sck153898 	 * we were searching by pool name or guid, we still need to
175624e697d4Sck153898 	 * post-process the list to deal with pool state and possible
175724e697d4Sck153898 	 * duplicate names.
175824e697d4Sck153898 	 */
1759fa9e4066Sahrens 	err = 0;
1760fa9e4066Sahrens 	elem = NULL;
176199653d4eSeschrock 	first = B_TRUE;
1762fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1763fa9e4066Sahrens 
1764fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1765fa9e4066Sahrens 
17664c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
17674c58d714Sdarrenm 		    &pool_state) == 0);
17684c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
17694c58d714Sdarrenm 			continue;
17704c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
17714c58d714Sdarrenm 			continue;
17724c58d714Sdarrenm 
1773fa9e4066Sahrens 		if (argc == 0) {
1774fa9e4066Sahrens 			if (first)
177599653d4eSeschrock 				first = B_FALSE;
17763bb79becSeschrock 			else if (!do_all)
1777fa9e4066Sahrens 				(void) printf("\n");
1778fa9e4066Sahrens 
1779fa9e4066Sahrens 			if (do_all)
1780fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1781c5904d13Seschrock 				    do_force, props, allow_faulted);
1782fa9e4066Sahrens 			else
1783fa9e4066Sahrens 				show_import(config);
1784fa9e4066Sahrens 		} else if (searchname != NULL) {
1785fa9e4066Sahrens 			char *name;
1786fa9e4066Sahrens 
1787fa9e4066Sahrens 			/*
1788fa9e4066Sahrens 			 * We are searching for a pool based on name.
1789fa9e4066Sahrens 			 */
1790fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1791fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1792fa9e4066Sahrens 
1793fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1794fa9e4066Sahrens 				if (found_config != NULL) {
1795fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1796fa9e4066Sahrens 					    "cannot import '%s': more than "
1797fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1798fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1799fa9e4066Sahrens 					    "import by numeric ID instead\n"));
180099653d4eSeschrock 					err = B_TRUE;
1801fa9e4066Sahrens 				}
1802fa9e4066Sahrens 				found_config = config;
1803fa9e4066Sahrens 			}
1804fa9e4066Sahrens 		} else {
1805fa9e4066Sahrens 			uint64_t guid;
1806fa9e4066Sahrens 
1807fa9e4066Sahrens 			/*
1808fa9e4066Sahrens 			 * Search for a pool by guid.
1809fa9e4066Sahrens 			 */
1810fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1811fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1812fa9e4066Sahrens 
1813fa9e4066Sahrens 			if (guid == searchguid)
1814fa9e4066Sahrens 				found_config = config;
1815fa9e4066Sahrens 		}
1816fa9e4066Sahrens 	}
1817fa9e4066Sahrens 
1818fa9e4066Sahrens 	/*
1819fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1820fa9e4066Sahrens 	 * pool, and then do the import.
1821fa9e4066Sahrens 	 */
1822fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1823fa9e4066Sahrens 		if (found_config == NULL) {
1824fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1825fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
182699653d4eSeschrock 			err = B_TRUE;
1827fa9e4066Sahrens 		} else {
1828fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1829c5904d13Seschrock 			    argv[1], mntopts, do_force, props, allow_faulted);
1830fa9e4066Sahrens 		}
1831fa9e4066Sahrens 	}
1832fa9e4066Sahrens 
1833fa9e4066Sahrens 	/*
1834fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1835fa9e4066Sahrens 	 * found.
1836fa9e4066Sahrens 	 */
1837fa9e4066Sahrens 	if (argc == 0 && first)
1838fa9e4066Sahrens 		(void) fprintf(stderr,
1839fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1840fa9e4066Sahrens 
1841ecd6cf80Smarks error:
1842ecd6cf80Smarks 	nvlist_free(props);
1843fa9e4066Sahrens 	nvlist_free(pools);
184499653d4eSeschrock 	free(searchdirs);
1845fa9e4066Sahrens 
1846fa9e4066Sahrens 	return (err ? 1 : 0);
1847fa9e4066Sahrens }
1848fa9e4066Sahrens 
1849fa9e4066Sahrens typedef struct iostat_cbdata {
1850fa9e4066Sahrens 	zpool_list_t *cb_list;
1851fa9e4066Sahrens 	int cb_verbose;
1852fa9e4066Sahrens 	int cb_iteration;
1853fa9e4066Sahrens 	int cb_namewidth;
1854fa9e4066Sahrens } iostat_cbdata_t;
1855fa9e4066Sahrens 
1856fa9e4066Sahrens static void
1857fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1858fa9e4066Sahrens {
1859fa9e4066Sahrens 	int i = 0;
1860fa9e4066Sahrens 
1861fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1862fa9e4066Sahrens 		(void) printf("-");
1863fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1864fa9e4066Sahrens }
1865fa9e4066Sahrens 
1866fa9e4066Sahrens static void
1867fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1868fa9e4066Sahrens {
1869fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1870fa9e4066Sahrens 	    cb->cb_namewidth, "");
1871fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1872fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1873fa9e4066Sahrens 	print_iostat_separator(cb);
1874fa9e4066Sahrens }
1875fa9e4066Sahrens 
1876fa9e4066Sahrens /*
1877fa9e4066Sahrens  * Display a single statistic.
1878fa9e4066Sahrens  */
1879990b4856Slling static void
1880fa9e4066Sahrens print_one_stat(uint64_t value)
1881fa9e4066Sahrens {
1882fa9e4066Sahrens 	char buf[64];
1883fa9e4066Sahrens 
1884fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1885fa9e4066Sahrens 	(void) printf("  %5s", buf);
1886fa9e4066Sahrens }
1887fa9e4066Sahrens 
1888fa9e4066Sahrens /*
1889fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1890fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1891fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1892fa9e4066Sahrens  */
1893fa9e4066Sahrens void
1894c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1895c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1896fa9e4066Sahrens {
1897fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1898fa9e4066Sahrens 	uint_t c, children;
1899fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1900fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1901fa9e4066Sahrens 	uint64_t tdelta;
1902fa9e4066Sahrens 	double scale;
1903afefbcddSeschrock 	char *vname;
1904fa9e4066Sahrens 
1905fa9e4066Sahrens 	if (oldnv != NULL) {
1906fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1907fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1908fa9e4066Sahrens 	} else {
1909fa9e4066Sahrens 		oldvs = &zerovs;
1910fa9e4066Sahrens 	}
1911fa9e4066Sahrens 
1912fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1913fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1914fa9e4066Sahrens 
1915fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1916fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1917fa9e4066Sahrens 	else
1918fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1919fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1920fa9e4066Sahrens 
1921fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1922fa9e4066Sahrens 
1923fa9e4066Sahrens 	if (tdelta == 0)
1924fa9e4066Sahrens 		scale = 1.0;
1925fa9e4066Sahrens 	else
1926fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1927fa9e4066Sahrens 
1928fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1929fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1930fa9e4066Sahrens 		(void) printf("      -      -");
1931fa9e4066Sahrens 	} else {
1932fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1933fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1934fa9e4066Sahrens 	}
1935fa9e4066Sahrens 
1936fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1937fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1938fa9e4066Sahrens 
1939fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1940fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1941fa9e4066Sahrens 
1942fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1943fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1944fa9e4066Sahrens 
1945fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1946fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1947fa9e4066Sahrens 
1948fa9e4066Sahrens 	(void) printf("\n");
1949fa9e4066Sahrens 
1950fa9e4066Sahrens 	if (!cb->cb_verbose)
1951fa9e4066Sahrens 		return;
1952fa9e4066Sahrens 
1953fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1954fa9e4066Sahrens 	    &newchild, &children) != 0)
1955fa9e4066Sahrens 		return;
1956fa9e4066Sahrens 
1957fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1958fa9e4066Sahrens 	    &oldchild, &c) != 0)
1959fa9e4066Sahrens 		return;
1960fa9e4066Sahrens 
1961afefbcddSeschrock 	for (c = 0; c < children; c++) {
196299653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1963c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1964afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1965afefbcddSeschrock 		free(vname);
1966afefbcddSeschrock 	}
1967fa94a07fSbrendan 
1968fa94a07fSbrendan 	/*
1969fa94a07fSbrendan 	 * Include level 2 ARC devices in iostat output
1970fa94a07fSbrendan 	 */
1971fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
1972fa94a07fSbrendan 	    &newchild, &children) != 0)
1973fa94a07fSbrendan 		return;
1974fa94a07fSbrendan 
1975fa94a07fSbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
1976fa94a07fSbrendan 	    &oldchild, &c) != 0)
1977fa94a07fSbrendan 		return;
1978fa94a07fSbrendan 
1979fa94a07fSbrendan 	if (children > 0) {
1980fa94a07fSbrendan 		(void) printf("%-*s      -      -      -      -      -      "
1981fa94a07fSbrendan 		    "-\n", cb->cb_namewidth, "cache");
1982fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1983fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1984fa94a07fSbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1985fa94a07fSbrendan 			    newchild[c], cb, depth + 2);
1986fa94a07fSbrendan 			free(vname);
1987fa94a07fSbrendan 		}
1988fa94a07fSbrendan 	}
1989fa9e4066Sahrens }
1990fa9e4066Sahrens 
1991088e9d47Seschrock static int
1992088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
1993088e9d47Seschrock {
1994088e9d47Seschrock 	iostat_cbdata_t *cb = data;
199594de1d4cSeschrock 	boolean_t missing;
1996088e9d47Seschrock 
1997088e9d47Seschrock 	/*
1998088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
1999088e9d47Seschrock 	 */
200094de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
200194de1d4cSeschrock 		return (-1);
200294de1d4cSeschrock 
200394de1d4cSeschrock 	if (missing)
2004088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
2005088e9d47Seschrock 
2006088e9d47Seschrock 	return (0);
2007088e9d47Seschrock }
2008088e9d47Seschrock 
2009fa9e4066Sahrens /*
2010fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
2011fa9e4066Sahrens  */
2012fa9e4066Sahrens int
2013fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
2014fa9e4066Sahrens {
2015fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
2016fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
2017fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
2018fa9e4066Sahrens 
2019088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
2020fa9e4066Sahrens 
2021088e9d47Seschrock 	if (cb->cb_iteration == 1)
2022fa9e4066Sahrens 		oldconfig = NULL;
2023fa9e4066Sahrens 
2024fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
2025fa9e4066Sahrens 	    &newnvroot) == 0);
2026fa9e4066Sahrens 
2027088e9d47Seschrock 	if (oldconfig == NULL)
2028fa9e4066Sahrens 		oldnvroot = NULL;
2029088e9d47Seschrock 	else
2030088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
2031088e9d47Seschrock 		    &oldnvroot) == 0);
2032fa9e4066Sahrens 
2033fa9e4066Sahrens 	/*
2034fa9e4066Sahrens 	 * Print out the statistics for the pool.
2035fa9e4066Sahrens 	 */
2036c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
2037fa9e4066Sahrens 
2038fa9e4066Sahrens 	if (cb->cb_verbose)
2039fa9e4066Sahrens 		print_iostat_separator(cb);
2040fa9e4066Sahrens 
2041fa9e4066Sahrens 	return (0);
2042fa9e4066Sahrens }
2043fa9e4066Sahrens 
2044fa9e4066Sahrens int
2045fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
2046fa9e4066Sahrens {
2047fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
2048fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2049fa9e4066Sahrens 
2050088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
2051fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2052fa9e4066Sahrens 		    &nvroot) == 0);
2053fa9e4066Sahrens 		if (!cb->cb_verbose)
2054fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
2055fa9e4066Sahrens 		else
2056c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
2057fa9e4066Sahrens 	}
2058fa9e4066Sahrens 
2059fa9e4066Sahrens 	/*
2060fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
2061fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
2062fa9e4066Sahrens 	 */
2063fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
2064fa9e4066Sahrens 		cb->cb_namewidth = 10;
2065fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
2066fa9e4066Sahrens 		cb->cb_namewidth = 38;
2067fa9e4066Sahrens 
2068fa9e4066Sahrens 	return (0);
2069fa9e4066Sahrens }
2070fa9e4066Sahrens 
2071fa9e4066Sahrens /*
2072fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
2073fa9e4066Sahrens  *
2074fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
2075fa9e4066Sahrens  *
2076fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
2077fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
2078fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
2079fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
2080fa9e4066Sahrens  * changes are all handled within libzfs.
2081fa9e4066Sahrens  */
2082fa9e4066Sahrens int
2083fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
2084fa9e4066Sahrens {
2085fa9e4066Sahrens 	int c;
2086fa9e4066Sahrens 	int ret;
2087fa9e4066Sahrens 	int npools;
2088fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
2089fa9e4066Sahrens 	zpool_list_t *list;
209099653d4eSeschrock 	boolean_t verbose = B_FALSE;
2091fa9e4066Sahrens 	iostat_cbdata_t cb;
2092fa9e4066Sahrens 
2093fa9e4066Sahrens 	/* check options */
2094fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
2095fa9e4066Sahrens 		switch (c) {
2096fa9e4066Sahrens 		case 'v':
209799653d4eSeschrock 			verbose = B_TRUE;
2098fa9e4066Sahrens 			break;
2099fa9e4066Sahrens 		case '?':
2100fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2101fa9e4066Sahrens 			    optopt);
210299653d4eSeschrock 			usage(B_FALSE);
2103fa9e4066Sahrens 		}
2104fa9e4066Sahrens 	}
2105fa9e4066Sahrens 
2106fa9e4066Sahrens 	argc -= optind;
2107fa9e4066Sahrens 	argv += optind;
2108fa9e4066Sahrens 
2109fa9e4066Sahrens 	/*
2110fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
2111fa9e4066Sahrens 	 */
2112fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2113fa9e4066Sahrens 		char *end;
2114fa9e4066Sahrens 
2115fa9e4066Sahrens 		errno = 0;
2116fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
2117fa9e4066Sahrens 
2118fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
2119fa9e4066Sahrens 			if (interval == 0) {
2120fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
2121fa9e4066Sahrens 				    "cannot be zero\n"));
212299653d4eSeschrock 				usage(B_FALSE);
2123fa9e4066Sahrens 			}
2124fa9e4066Sahrens 
2125fa9e4066Sahrens 			/*
2126fa9e4066Sahrens 			 * Ignore the last parameter
2127fa9e4066Sahrens 			 */
2128fa9e4066Sahrens 			argc--;
2129fa9e4066Sahrens 		} else {
2130fa9e4066Sahrens 			/*
2131fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
2132fa9e4066Sahrens 			 * user will get a more informative error message later
2133fa9e4066Sahrens 			 * on.
2134fa9e4066Sahrens 			 */
2135fa9e4066Sahrens 			interval = 0;
2136fa9e4066Sahrens 		}
2137fa9e4066Sahrens 	}
2138fa9e4066Sahrens 
2139fa9e4066Sahrens 	/*
2140fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
2141fa9e4066Sahrens 	 * and an integer.
2142fa9e4066Sahrens 	 */
2143fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2144fa9e4066Sahrens 		char *end;
2145fa9e4066Sahrens 
2146fa9e4066Sahrens 		errno = 0;
2147fa9e4066Sahrens 		count = interval;
2148fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
2149fa9e4066Sahrens 
2150fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
2151fa9e4066Sahrens 			if (interval == 0) {
2152fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
2153fa9e4066Sahrens 				    "cannot be zero\n"));
215499653d4eSeschrock 				usage(B_FALSE);
2155fa9e4066Sahrens 			}
2156fa9e4066Sahrens 
2157fa9e4066Sahrens 			/*
2158fa9e4066Sahrens 			 * Ignore the last parameter
2159fa9e4066Sahrens 			 */
2160fa9e4066Sahrens 			argc--;
2161fa9e4066Sahrens 		} else {
2162fa9e4066Sahrens 			interval = 0;
2163fa9e4066Sahrens 		}
2164fa9e4066Sahrens 	}
2165fa9e4066Sahrens 
2166fa9e4066Sahrens 	/*
2167fa9e4066Sahrens 	 * Construct the list of all interesting pools.
2168fa9e4066Sahrens 	 */
2169fa9e4066Sahrens 	ret = 0;
2170b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
2171fa9e4066Sahrens 		return (1);
2172fa9e4066Sahrens 
217399653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
217499653d4eSeschrock 		pool_list_free(list);
2175fa9e4066Sahrens 		return (1);
217699653d4eSeschrock 	}
2177fa9e4066Sahrens 
2178fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
217999653d4eSeschrock 		pool_list_free(list);
2180fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
2181fa9e4066Sahrens 		return (1);
2182fa9e4066Sahrens 	}
2183fa9e4066Sahrens 
2184fa9e4066Sahrens 	/*
2185fa9e4066Sahrens 	 * Enter the main iostat loop.
2186fa9e4066Sahrens 	 */
2187fa9e4066Sahrens 	cb.cb_list = list;
2188fa9e4066Sahrens 	cb.cb_verbose = verbose;
2189fa9e4066Sahrens 	cb.cb_iteration = 0;
2190fa9e4066Sahrens 	cb.cb_namewidth = 0;
2191fa9e4066Sahrens 
2192fa9e4066Sahrens 	for (;;) {
2193fa9e4066Sahrens 		pool_list_update(list);
2194fa9e4066Sahrens 
2195fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
2196fa9e4066Sahrens 			break;
2197fa9e4066Sahrens 
2198fa9e4066Sahrens 		/*
2199088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
2200088e9d47Seschrock 		 * before calculating the maximum name width, so that any
2201088e9d47Seschrock 		 * configuration changes are properly accounted for.
2202088e9d47Seschrock 		 */
220399653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
2204088e9d47Seschrock 
2205088e9d47Seschrock 		/*
2206fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
2207fa9e4066Sahrens 		 * for the pool / device name column across all pools.
2208fa9e4066Sahrens 		 */
2209fa9e4066Sahrens 		cb.cb_namewidth = 0;
221099653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2211fa9e4066Sahrens 
2212fa9e4066Sahrens 		/*
2213fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
2214fa9e4066Sahrens 		 */
2215fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
2216fa9e4066Sahrens 			print_iostat_header(&cb);
2217fa9e4066Sahrens 
221899653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2219fa9e4066Sahrens 
2220fa9e4066Sahrens 		/*
2221fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
2222fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
2223fa9e4066Sahrens 		 */
2224fa9e4066Sahrens 		if (npools > 1 && !verbose)
2225fa9e4066Sahrens 			print_iostat_separator(&cb);
2226fa9e4066Sahrens 
2227fa9e4066Sahrens 		if (verbose)
2228fa9e4066Sahrens 			(void) printf("\n");
2229fa9e4066Sahrens 
223039c23413Seschrock 		/*
223139c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
223239c23413Seschrock 		 * indefinitely.
223339c23413Seschrock 		 */
223439c23413Seschrock 		(void) fflush(stdout);
223539c23413Seschrock 
2236fa9e4066Sahrens 		if (interval == 0)
2237fa9e4066Sahrens 			break;
2238fa9e4066Sahrens 
2239fa9e4066Sahrens 		if (count != 0 && --count == 0)
2240fa9e4066Sahrens 			break;
2241fa9e4066Sahrens 
2242fa9e4066Sahrens 		(void) sleep(interval);
2243fa9e4066Sahrens 	}
2244fa9e4066Sahrens 
2245fa9e4066Sahrens 	pool_list_free(list);
2246fa9e4066Sahrens 
2247fa9e4066Sahrens 	return (ret);
2248fa9e4066Sahrens }
2249fa9e4066Sahrens 
2250fa9e4066Sahrens typedef struct list_cbdata {
225199653d4eSeschrock 	boolean_t	cb_scripted;
225299653d4eSeschrock 	boolean_t	cb_first;
2253990b4856Slling 	zprop_list_t	*cb_proplist;
2254fa9e4066Sahrens } list_cbdata_t;
2255fa9e4066Sahrens 
2256fa9e4066Sahrens /*
2257fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
2258fa9e4066Sahrens  */
2259990b4856Slling static void
2260990b4856Slling print_header(zprop_list_t *pl)
2261fa9e4066Sahrens {
2262990b4856Slling 	const char *header;
2263990b4856Slling 	boolean_t first = B_TRUE;
2264990b4856Slling 	boolean_t right_justify;
2265fa9e4066Sahrens 
2266990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2267990b4856Slling 		if (pl->pl_prop == ZPROP_INVAL)
2268990b4856Slling 			continue;
2269990b4856Slling 
2270990b4856Slling 		if (!first)
2271fa9e4066Sahrens 			(void) printf("  ");
2272fa9e4066Sahrens 		else
2273990b4856Slling 			first = B_FALSE;
2274fa9e4066Sahrens 
2275990b4856Slling 		header = zpool_prop_column_name(pl->pl_prop);
2276990b4856Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
2277990b4856Slling 
2278990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
2279990b4856Slling 			(void) printf("%s", header);
2280990b4856Slling 		else if (right_justify)
2281990b4856Slling 			(void) printf("%*s", pl->pl_width, header);
2282990b4856Slling 		else
2283990b4856Slling 			(void) printf("%-*s", pl->pl_width, header);
2284fa9e4066Sahrens 	}
2285fa9e4066Sahrens 
2286fa9e4066Sahrens 	(void) printf("\n");
2287fa9e4066Sahrens }
2288fa9e4066Sahrens 
2289990b4856Slling /*
2290990b4856Slling  * Given a pool and a list of properties, print out all the properties according
2291990b4856Slling  * to the described layout.
2292990b4856Slling  */
2293990b4856Slling static void
2294990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
2295990b4856Slling {
2296990b4856Slling 	boolean_t first = B_TRUE;
2297990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
2298990b4856Slling 	char *propstr;
2299990b4856Slling 	boolean_t right_justify;
2300990b4856Slling 	int width;
2301990b4856Slling 
2302990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2303990b4856Slling 		if (!first) {
2304990b4856Slling 			if (scripted)
2305990b4856Slling 				(void) printf("\t");
2306990b4856Slling 			else
2307990b4856Slling 				(void) printf("  ");
2308990b4856Slling 		} else {
2309990b4856Slling 			first = B_FALSE;
2310990b4856Slling 		}
2311990b4856Slling 
2312990b4856Slling 		right_justify = B_FALSE;
2313990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
2314990b4856Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
2315990b4856Slling 			    sizeof (property), NULL) != 0)
2316990b4856Slling 				propstr = "-";
2317990b4856Slling 			else
2318990b4856Slling 				propstr = property;
2319990b4856Slling 
2320990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2321990b4856Slling 		} else {
2322990b4856Slling 			propstr = "-";
2323990b4856Slling 		}
2324990b4856Slling 
2325990b4856Slling 		width = pl->pl_width;
2326990b4856Slling 
2327990b4856Slling 		/*
2328990b4856Slling 		 * If this is being called in scripted mode, or if this is the
2329990b4856Slling 		 * last column and it is left-justified, don't include a width
2330990b4856Slling 		 * format specifier.
2331990b4856Slling 		 */
2332990b4856Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
2333990b4856Slling 			(void) printf("%s", propstr);
2334990b4856Slling 		else if (right_justify)
2335990b4856Slling 			(void) printf("%*s", width, propstr);
2336990b4856Slling 		else
2337990b4856Slling 			(void) printf("%-*s", width, propstr);
2338990b4856Slling 	}
2339990b4856Slling 
2340990b4856Slling 	(void) printf("\n");
2341990b4856Slling }
2342990b4856Slling 
2343990b4856Slling /*
2344990b4856Slling  * Generic callback function to list a pool.
2345990b4856Slling  */
2346fa9e4066Sahrens int
2347fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2348fa9e4066Sahrens {
2349fa9e4066Sahrens 	list_cbdata_t *cbp = data;
2350fa9e4066Sahrens 
2351fa9e4066Sahrens 	if (cbp->cb_first) {
2352fa9e4066Sahrens 		if (!cbp->cb_scripted)
2353990b4856Slling 			print_header(cbp->cb_proplist);
235499653d4eSeschrock 		cbp->cb_first = B_FALSE;
2355fa9e4066Sahrens 	}
2356fa9e4066Sahrens 
2357990b4856Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2358fa9e4066Sahrens 
2359fa9e4066Sahrens 	return (0);
2360fa9e4066Sahrens }
2361fa9e4066Sahrens 
2362fa9e4066Sahrens /*
2363990b4856Slling  * zpool list [-H] [-o prop[,prop]*] [pool] ...
2364fa9e4066Sahrens  *
2365990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2366990b4856Slling  *		by a single tab.
2367990b4856Slling  *	-o	List of properties to display.  Defaults to
2368990b4856Slling  *		"name,size,used,available,capacity,health,altroot"
2369fa9e4066Sahrens  *
2370fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2371fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2372fa9e4066Sahrens  */
2373fa9e4066Sahrens int
2374fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2375fa9e4066Sahrens {
2376fa9e4066Sahrens 	int c;
2377fa9e4066Sahrens 	int ret;
2378fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2379990b4856Slling 	static char default_props[] =
2380990b4856Slling 	    "name,size,used,available,capacity,health,altroot";
2381990b4856Slling 	char *props = default_props;
2382fa9e4066Sahrens 
2383fa9e4066Sahrens 	/* check options */
2384fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2385fa9e4066Sahrens 		switch (c) {
2386fa9e4066Sahrens 		case 'H':
238799653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2388fa9e4066Sahrens 			break;
2389fa9e4066Sahrens 		case 'o':
2390990b4856Slling 			props = optarg;
2391fa9e4066Sahrens 			break;
2392fa9e4066Sahrens 		case ':':
2393fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2394fa9e4066Sahrens 			    "'%c' option\n"), optopt);
239599653d4eSeschrock 			usage(B_FALSE);
2396fa9e4066Sahrens 			break;
2397fa9e4066Sahrens 		case '?':
2398fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2399fa9e4066Sahrens 			    optopt);
240099653d4eSeschrock 			usage(B_FALSE);
2401fa9e4066Sahrens 		}
2402fa9e4066Sahrens 	}
2403fa9e4066Sahrens 
2404fa9e4066Sahrens 	argc -= optind;
2405fa9e4066Sahrens 	argv += optind;
2406fa9e4066Sahrens 
2407990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
240899653d4eSeschrock 		usage(B_FALSE);
2409fa9e4066Sahrens 
241099653d4eSeschrock 	cb.cb_first = B_TRUE;
2411fa9e4066Sahrens 
2412990b4856Slling 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2413990b4856Slling 	    list_callback, &cb);
2414990b4856Slling 
2415990b4856Slling 	zprop_free_list(cb.cb_proplist);
2416fa9e4066Sahrens 
2417fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2418fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2419fa9e4066Sahrens 		return (0);
2420fa9e4066Sahrens 	}
2421fa9e4066Sahrens 
2422fa9e4066Sahrens 	return (ret);
2423fa9e4066Sahrens }
2424fa9e4066Sahrens 
2425fa9e4066Sahrens static nvlist_t *
2426fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2427fa9e4066Sahrens {
2428fa9e4066Sahrens 	nvlist_t **child;
2429fa9e4066Sahrens 	uint_t c, children;
2430fa9e4066Sahrens 	nvlist_t *match;
2431fa9e4066Sahrens 	char *path;
2432fa9e4066Sahrens 
2433fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2434fa9e4066Sahrens 	    &child, &children) != 0) {
2435fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2436fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2437fa9e4066Sahrens 			name += 9;
2438fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2439fa9e4066Sahrens 			path += 9;
2440fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2441fa9e4066Sahrens 			return (nv);
2442fa9e4066Sahrens 		return (NULL);
2443fa9e4066Sahrens 	}
2444fa9e4066Sahrens 
2445fa9e4066Sahrens 	for (c = 0; c < children; c++)
2446fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2447fa9e4066Sahrens 			return (match);
2448fa9e4066Sahrens 
2449fa9e4066Sahrens 	return (NULL);
2450fa9e4066Sahrens }
2451fa9e4066Sahrens 
2452fa9e4066Sahrens static int
2453fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2454fa9e4066Sahrens {
245599653d4eSeschrock 	boolean_t force = B_FALSE;
2456fa9e4066Sahrens 	int c;
2457fa9e4066Sahrens 	nvlist_t *nvroot;
2458fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2459fa9e4066Sahrens 	zpool_handle_t *zhp;
246099653d4eSeschrock 	int ret;
2461fa9e4066Sahrens 
2462fa9e4066Sahrens 	/* check options */
2463fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2464fa9e4066Sahrens 		switch (c) {
2465fa9e4066Sahrens 		case 'f':
246699653d4eSeschrock 			force = B_TRUE;
2467fa9e4066Sahrens 			break;
2468fa9e4066Sahrens 		case '?':
2469fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2470fa9e4066Sahrens 			    optopt);
247199653d4eSeschrock 			usage(B_FALSE);
2472fa9e4066Sahrens 		}
2473fa9e4066Sahrens 	}
2474fa9e4066Sahrens 
2475fa9e4066Sahrens 	argc -= optind;
2476fa9e4066Sahrens 	argv += optind;
2477fa9e4066Sahrens 
2478fa9e4066Sahrens 	/* get pool name and check number of arguments */
2479fa9e4066Sahrens 	if (argc < 1) {
2480fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
248199653d4eSeschrock 		usage(B_FALSE);
2482fa9e4066Sahrens 	}
2483fa9e4066Sahrens 
2484fa9e4066Sahrens 	poolname = argv[0];
2485fa9e4066Sahrens 
2486fa9e4066Sahrens 	if (argc < 2) {
2487fa9e4066Sahrens 		(void) fprintf(stderr,
2488fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
248999653d4eSeschrock 		usage(B_FALSE);
2490fa9e4066Sahrens 	}
2491fa9e4066Sahrens 
2492fa9e4066Sahrens 	old_disk = argv[1];
2493fa9e4066Sahrens 
2494fa9e4066Sahrens 	if (argc < 3) {
2495fa9e4066Sahrens 		if (!replacing) {
2496fa9e4066Sahrens 			(void) fprintf(stderr,
2497fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
249899653d4eSeschrock 			usage(B_FALSE);
2499fa9e4066Sahrens 		}
2500fa9e4066Sahrens 		new_disk = old_disk;
2501fa9e4066Sahrens 		argc -= 1;
2502fa9e4066Sahrens 		argv += 1;
2503fa9e4066Sahrens 	} else {
2504fa9e4066Sahrens 		new_disk = argv[2];
2505fa9e4066Sahrens 		argc -= 2;
2506fa9e4066Sahrens 		argv += 2;
2507fa9e4066Sahrens 	}
2508fa9e4066Sahrens 
2509fa9e4066Sahrens 	if (argc > 1) {
2510fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
251199653d4eSeschrock 		usage(B_FALSE);
2512fa9e4066Sahrens 	}
2513fa9e4066Sahrens 
251499653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2515fa9e4066Sahrens 		return (1);
2516fa9e4066Sahrens 
25178488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2518fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2519fa9e4066Sahrens 		    poolname);
2520fa9e4066Sahrens 		zpool_close(zhp);
2521fa9e4066Sahrens 		return (1);
2522fa9e4066Sahrens 	}
2523fa9e4066Sahrens 
2524705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
2525705040edSEric Taylor 	    argc, argv);
2526fa9e4066Sahrens 	if (nvroot == NULL) {
2527fa9e4066Sahrens 		zpool_close(zhp);
2528fa9e4066Sahrens 		return (1);
2529fa9e4066Sahrens 	}
2530fa9e4066Sahrens 
253199653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
253299653d4eSeschrock 
253399653d4eSeschrock 	nvlist_free(nvroot);
253499653d4eSeschrock 	zpool_close(zhp);
253599653d4eSeschrock 
253699653d4eSeschrock 	return (ret);
2537fa9e4066Sahrens }
2538fa9e4066Sahrens 
2539fa9e4066Sahrens /*
2540fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2541fa9e4066Sahrens  *
2542fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2543fa9e4066Sahrens  *
2544fa9e4066Sahrens  * Replace <device> with <new_device>.
2545fa9e4066Sahrens  */
2546fa9e4066Sahrens /* ARGSUSED */
2547fa9e4066Sahrens int
2548fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2549fa9e4066Sahrens {
2550fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2551fa9e4066Sahrens }
2552fa9e4066Sahrens 
2553fa9e4066Sahrens /*
2554fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2555fa9e4066Sahrens  *
2556fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2557fa9e4066Sahrens  *
2558fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2559fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2560fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2561fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2562fa9e4066Sahrens  */
2563fa9e4066Sahrens int
2564fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2565fa9e4066Sahrens {
2566fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2567fa9e4066Sahrens }
2568fa9e4066Sahrens 
2569fa9e4066Sahrens /*
2570fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2571fa9e4066Sahrens  *
2572fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2573fa9e4066Sahrens  *		(not supported yet)
2574fa9e4066Sahrens  *
2575fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2576fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2577fa9e4066Sahrens  * has the only valid copy of some data.
2578fa9e4066Sahrens  */
2579fa9e4066Sahrens /* ARGSUSED */
2580fa9e4066Sahrens int
2581fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2582fa9e4066Sahrens {
2583fa9e4066Sahrens 	int c;
2584fa9e4066Sahrens 	char *poolname, *path;
2585fa9e4066Sahrens 	zpool_handle_t *zhp;
258699653d4eSeschrock 	int ret;
2587fa9e4066Sahrens 
2588fa9e4066Sahrens 	/* check options */
2589fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2590fa9e4066Sahrens 		switch (c) {
2591fa9e4066Sahrens 		case 'f':
2592fa9e4066Sahrens 		case '?':
2593fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2594fa9e4066Sahrens 			    optopt);
259599653d4eSeschrock 			usage(B_FALSE);
2596fa9e4066Sahrens 		}
2597fa9e4066Sahrens 	}
2598fa9e4066Sahrens 
2599fa9e4066Sahrens 	argc -= optind;
2600fa9e4066Sahrens 	argv += optind;
2601fa9e4066Sahrens 
2602fa9e4066Sahrens 	/* get pool name and check number of arguments */
2603fa9e4066Sahrens 	if (argc < 1) {
2604fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
260599653d4eSeschrock 		usage(B_FALSE);
2606fa9e4066Sahrens 	}
2607fa9e4066Sahrens 
2608fa9e4066Sahrens 	if (argc < 2) {
2609fa9e4066Sahrens 		(void) fprintf(stderr,
2610fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
261199653d4eSeschrock 		usage(B_FALSE);
2612fa9e4066Sahrens 	}
2613fa9e4066Sahrens 
2614fa9e4066Sahrens 	poolname = argv[0];
2615fa9e4066Sahrens 	path = argv[1];
2616fa9e4066Sahrens 
261799653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2618fa9e4066Sahrens 		return (1);
2619fa9e4066Sahrens 
262099653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
262199653d4eSeschrock 
262299653d4eSeschrock 	zpool_close(zhp);
262399653d4eSeschrock 
262499653d4eSeschrock 	return (ret);
2625fa9e4066Sahrens }
2626fa9e4066Sahrens 
2627fa9e4066Sahrens /*
2628441d80aaSlling  * zpool online <pool> <device> ...
2629fa9e4066Sahrens  */
2630fa9e4066Sahrens int
2631fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2632fa9e4066Sahrens {
2633fa9e4066Sahrens 	int c, i;
2634fa9e4066Sahrens 	char *poolname;
2635fa9e4066Sahrens 	zpool_handle_t *zhp;
2636fa9e4066Sahrens 	int ret = 0;
26373d7072f8Seschrock 	vdev_state_t newstate;
2638*573ca77eSGeorge Wilson 	int flags = 0;
2639fa9e4066Sahrens 
2640fa9e4066Sahrens 	/* check options */
2641*573ca77eSGeorge Wilson 	while ((c = getopt(argc, argv, "et")) != -1) {
2642fa9e4066Sahrens 		switch (c) {
2643*573ca77eSGeorge Wilson 		case 'e':
2644*573ca77eSGeorge Wilson 			flags |= ZFS_ONLINE_EXPAND;
2645*573ca77eSGeorge Wilson 			break;
2646fa9e4066Sahrens 		case 't':
2647fa9e4066Sahrens 		case '?':
2648fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2649fa9e4066Sahrens 			    optopt);
265099653d4eSeschrock 			usage(B_FALSE);
2651fa9e4066Sahrens 		}
2652fa9e4066Sahrens 	}
2653fa9e4066Sahrens 
2654fa9e4066Sahrens 	argc -= optind;
2655fa9e4066Sahrens 	argv += optind;
2656fa9e4066Sahrens 
2657fa9e4066Sahrens 	/* get pool name and check number of arguments */
2658fa9e4066Sahrens 	if (argc < 1) {
2659fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
266099653d4eSeschrock 		usage(B_FALSE);
2661fa9e4066Sahrens 	}
2662fa9e4066Sahrens 	if (argc < 2) {
2663fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
266499653d4eSeschrock 		usage(B_FALSE);
2665fa9e4066Sahrens 	}
2666fa9e4066Sahrens 
2667fa9e4066Sahrens 	poolname = argv[0];
2668fa9e4066Sahrens 
266999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2670fa9e4066Sahrens 		return (1);
2671fa9e4066Sahrens 
26723d7072f8Seschrock 	for (i = 1; i < argc; i++) {
2673*573ca77eSGeorge Wilson 		if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
26743d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
26753d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
26763d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
2677fa9e4066Sahrens 				    argv[i]);
26783d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
26793d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
26803d7072f8Seschrock 					    "clear' to restore a faulted "
26813d7072f8Seschrock 					    "device\n"));
2682fa9e4066Sahrens 				else
26833d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
26843d7072f8Seschrock 					    "replace' to replace devices "
26853d7072f8Seschrock 					    "that are no longer present\n"));
26863d7072f8Seschrock 			}
26873d7072f8Seschrock 		} else {
2688fa9e4066Sahrens 			ret = 1;
26893d7072f8Seschrock 		}
26903d7072f8Seschrock 	}
2691fa9e4066Sahrens 
269299653d4eSeschrock 	zpool_close(zhp);
269399653d4eSeschrock 
2694fa9e4066Sahrens 	return (ret);
2695fa9e4066Sahrens }
2696fa9e4066Sahrens 
2697fa9e4066Sahrens /*
2698441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2699fa9e4066Sahrens  *
2700fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2701fa9e4066Sahrens  *		so would appear to compromise pool availability.
2702fa9e4066Sahrens  *		(not supported yet)
2703fa9e4066Sahrens  *
2704fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2705fa9e4066Sahrens  *		state will not be persistent across reboots.
2706fa9e4066Sahrens  */
2707fa9e4066Sahrens /* ARGSUSED */
2708fa9e4066Sahrens int
2709fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2710fa9e4066Sahrens {
2711fa9e4066Sahrens 	int c, i;
2712fa9e4066Sahrens 	char *poolname;
2713fa9e4066Sahrens 	zpool_handle_t *zhp;
271499653d4eSeschrock 	int ret = 0;
271599653d4eSeschrock 	boolean_t istmp = B_FALSE;
2716fa9e4066Sahrens 
2717fa9e4066Sahrens 	/* check options */
2718fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2719fa9e4066Sahrens 		switch (c) {
2720fa9e4066Sahrens 		case 't':
272199653d4eSeschrock 			istmp = B_TRUE;
2722441d80aaSlling 			break;
2723441d80aaSlling 		case 'f':
2724fa9e4066Sahrens 		case '?':
2725fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2726fa9e4066Sahrens 			    optopt);
272799653d4eSeschrock 			usage(B_FALSE);
2728fa9e4066Sahrens 		}
2729fa9e4066Sahrens 	}
2730fa9e4066Sahrens 
2731fa9e4066Sahrens 	argc -= optind;
2732fa9e4066Sahrens 	argv += optind;
2733fa9e4066Sahrens 
2734fa9e4066Sahrens 	/* get pool name and check number of arguments */
2735fa9e4066Sahrens 	if (argc < 1) {
2736fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
273799653d4eSeschrock 		usage(B_FALSE);
2738fa9e4066Sahrens 	}
2739fa9e4066Sahrens 	if (argc < 2) {
2740fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
274199653d4eSeschrock 		usage(B_FALSE);
2742fa9e4066Sahrens 	}
2743fa9e4066Sahrens 
2744fa9e4066Sahrens 	poolname = argv[0];
2745fa9e4066Sahrens 
274699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2747fa9e4066Sahrens 		return (1);
2748fa9e4066Sahrens 
27493d7072f8Seschrock 	for (i = 1; i < argc; i++) {
27503d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2751fa9e4066Sahrens 			ret = 1;
27523d7072f8Seschrock 	}
2753fa9e4066Sahrens 
275499653d4eSeschrock 	zpool_close(zhp);
275599653d4eSeschrock 
2756fa9e4066Sahrens 	return (ret);
2757fa9e4066Sahrens }
2758fa9e4066Sahrens 
2759ea8dc4b6Seschrock /*
2760ea8dc4b6Seschrock  * zpool clear <pool> [device]
2761ea8dc4b6Seschrock  *
2762ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2763ea8dc4b6Seschrock  */
2764ea8dc4b6Seschrock int
2765ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2766ea8dc4b6Seschrock {
2767ea8dc4b6Seschrock 	int ret = 0;
2768ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2769ea8dc4b6Seschrock 	char *pool, *device;
2770ea8dc4b6Seschrock 
2771ea8dc4b6Seschrock 	if (argc < 2) {
2772ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
277399653d4eSeschrock 		usage(B_FALSE);
2774ea8dc4b6Seschrock 	}
2775ea8dc4b6Seschrock 
2776ea8dc4b6Seschrock 	if (argc > 3) {
2777ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
277899653d4eSeschrock 		usage(B_FALSE);
2779ea8dc4b6Seschrock 	}
2780ea8dc4b6Seschrock 
2781ea8dc4b6Seschrock 	pool = argv[1];
2782ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2783ea8dc4b6Seschrock 
2784b87f3af3Sperrin 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
2785ea8dc4b6Seschrock 		return (1);
2786ea8dc4b6Seschrock 
2787ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2788ea8dc4b6Seschrock 		ret = 1;
2789ea8dc4b6Seschrock 
2790ea8dc4b6Seschrock 	zpool_close(zhp);
2791ea8dc4b6Seschrock 
2792ea8dc4b6Seschrock 	return (ret);
2793ea8dc4b6Seschrock }
2794ea8dc4b6Seschrock 
2795fa9e4066Sahrens typedef struct scrub_cbdata {
2796fa9e4066Sahrens 	int	cb_type;
279706eeb2adSek110237 	int	cb_argc;
279806eeb2adSek110237 	char	**cb_argv;
2799fa9e4066Sahrens } scrub_cbdata_t;
2800fa9e4066Sahrens 
2801fa9e4066Sahrens int
2802fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2803fa9e4066Sahrens {
2804fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
280506eeb2adSek110237 	int err;
2806fa9e4066Sahrens 
2807ea8dc4b6Seschrock 	/*
2808ea8dc4b6Seschrock 	 * Ignore faulted pools.
2809ea8dc4b6Seschrock 	 */
2810ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2811ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2812ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2813ea8dc4b6Seschrock 		return (1);
2814ea8dc4b6Seschrock 	}
2815ea8dc4b6Seschrock 
281606eeb2adSek110237 	err = zpool_scrub(zhp, cb->cb_type);
281706eeb2adSek110237 
281806eeb2adSek110237 	return (err != 0);
2819fa9e4066Sahrens }
2820fa9e4066Sahrens 
2821fa9e4066Sahrens /*
2822fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2823fa9e4066Sahrens  *
2824fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2825fa9e4066Sahrens  */
2826fa9e4066Sahrens int
2827fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2828fa9e4066Sahrens {
2829fa9e4066Sahrens 	int c;
2830fa9e4066Sahrens 	scrub_cbdata_t cb;
2831fa9e4066Sahrens 
2832fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2833fa9e4066Sahrens 
2834fa9e4066Sahrens 	/* check options */
2835fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2836fa9e4066Sahrens 		switch (c) {
2837fa9e4066Sahrens 		case 's':
2838fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2839fa9e4066Sahrens 			break;
2840fa9e4066Sahrens 		case '?':
2841fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2842fa9e4066Sahrens 			    optopt);
284399653d4eSeschrock 			usage(B_FALSE);
2844fa9e4066Sahrens 		}
2845fa9e4066Sahrens 	}
2846fa9e4066Sahrens 
284706eeb2adSek110237 	cb.cb_argc = argc;
284806eeb2adSek110237 	cb.cb_argv = argv;
2849fa9e4066Sahrens 	argc -= optind;
2850fa9e4066Sahrens 	argv += optind;
2851fa9e4066Sahrens 
2852fa9e4066Sahrens 	if (argc < 1) {
2853fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
285499653d4eSeschrock 		usage(B_FALSE);
2855fa9e4066Sahrens 	}
2856fa9e4066Sahrens 
2857b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2858fa9e4066Sahrens }
2859fa9e4066Sahrens 
2860fa9e4066Sahrens typedef struct status_cbdata {
2861fa9e4066Sahrens 	int		cb_count;
2862e9dbad6fSeschrock 	boolean_t	cb_allpools;
286399653d4eSeschrock 	boolean_t	cb_verbose;
286499653d4eSeschrock 	boolean_t	cb_explain;
286599653d4eSeschrock 	boolean_t	cb_first;
2866fa9e4066Sahrens } status_cbdata_t;
2867fa9e4066Sahrens 
2868fa9e4066Sahrens /*
2869fa9e4066Sahrens  * Print out detailed scrub status.
2870fa9e4066Sahrens  */
2871fa9e4066Sahrens void
2872fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2873fa9e4066Sahrens {
2874fa9e4066Sahrens 	vdev_stat_t *vs;
2875fa9e4066Sahrens 	uint_t vsc;
2876fa9e4066Sahrens 	time_t start, end, now;
2877fa9e4066Sahrens 	double fraction_done;
287818ce54dfSek110237 	uint64_t examined, total, minutes_left, minutes_taken;
2879fa9e4066Sahrens 	char *scrub_type;
2880fa9e4066Sahrens 
2881fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2882fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2883fa9e4066Sahrens 
2884fa9e4066Sahrens 	/*
2885fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2886fa9e4066Sahrens 	 */
2887fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2888fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2889fa9e4066Sahrens 		return;
2890fa9e4066Sahrens 	}
2891fa9e4066Sahrens 
2892fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2893fa9e4066Sahrens 	    "resilver" : "scrub";
2894fa9e4066Sahrens 
2895fa9e4066Sahrens 	start = vs->vs_scrub_start;
2896fa9e4066Sahrens 	end = vs->vs_scrub_end;
2897fa9e4066Sahrens 	now = time(NULL);
2898fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2899fa9e4066Sahrens 	total = vs->vs_alloc;
2900fa9e4066Sahrens 
2901fa9e4066Sahrens 	if (end != 0) {
290218ce54dfSek110237 		minutes_taken = (uint64_t)((end - start) / 60);
290318ce54dfSek110237 
290418ce54dfSek110237 		(void) printf(gettext("%s %s after %lluh%um with %llu errors "
290518ce54dfSek110237 		    "on %s"),
2906fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
290718ce54dfSek110237 		    (u_longlong_t)(minutes_taken / 60),
290818ce54dfSek110237 		    (uint_t)(minutes_taken % 60),
2909fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2910fa9e4066Sahrens 		return;
2911fa9e4066Sahrens 	}
2912fa9e4066Sahrens 
2913fa9e4066Sahrens 	if (examined == 0)
2914fa9e4066Sahrens 		examined = 1;
2915fa9e4066Sahrens 	if (examined > total)
2916fa9e4066Sahrens 		total = examined;
2917fa9e4066Sahrens 
2918fa9e4066Sahrens 	fraction_done = (double)examined / total;
2919fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2920fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
292118ce54dfSek110237 	minutes_taken = (uint64_t)((now - start) / 60);
2922fa9e4066Sahrens 
292318ce54dfSek110237 	(void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, "
292418ce54dfSek110237 	    "%lluh%um to go\n"),
292518ce54dfSek110237 	    scrub_type, (u_longlong_t)(minutes_taken / 60),
292618ce54dfSek110237 	    (uint_t)(minutes_taken % 60), 100 * fraction_done,
2927fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2928fa9e4066Sahrens }
2929fa9e4066Sahrens 
2930ea8dc4b6Seschrock static void
2931ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
2932ea8dc4b6Seschrock {
293375519f38Sek110237 	nvlist_t *nverrlist = NULL;
293455434c77Sek110237 	nvpair_t *elem;
293555434c77Sek110237 	char *pathname;
293655434c77Sek110237 	size_t len = MAXPATHLEN * 2;
2937ea8dc4b6Seschrock 
293855434c77Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2939ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
2940ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
2941ea8dc4b6Seschrock 		return;
2942ea8dc4b6Seschrock 	}
2943ea8dc4b6Seschrock 
294455434c77Sek110237 	(void) printf("errors: Permanent errors have been "
294555434c77Sek110237 	    "detected in the following files:\n\n");
2946ea8dc4b6Seschrock 
294755434c77Sek110237 	pathname = safe_malloc(len);
294855434c77Sek110237 	elem = NULL;
294955434c77Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
295055434c77Sek110237 		nvlist_t *nv;
295155434c77Sek110237 		uint64_t dsobj, obj;
2952ea8dc4b6Seschrock 
295355434c77Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
295455434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
295555434c77Sek110237 		    &dsobj) == 0);
295655434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
295755434c77Sek110237 		    &obj) == 0);
295855434c77Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
295955434c77Sek110237 		(void) printf("%7s %s\n", "", pathname);
2960ea8dc4b6Seschrock 	}
296155434c77Sek110237 	free(pathname);
296255434c77Sek110237 	nvlist_free(nverrlist);
2963ea8dc4b6Seschrock }
2964ea8dc4b6Seschrock 
296599653d4eSeschrock static void
296699653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
296799653d4eSeschrock     int namewidth)
296899653d4eSeschrock {
296999653d4eSeschrock 	uint_t i;
297099653d4eSeschrock 	char *name;
297199653d4eSeschrock 
297299653d4eSeschrock 	if (nspares == 0)
297399653d4eSeschrock 		return;
297499653d4eSeschrock 
297599653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
297699653d4eSeschrock 
297799653d4eSeschrock 	for (i = 0; i < nspares; i++) {
297899653d4eSeschrock 		name = zpool_vdev_name(g_zfs, zhp, spares[i]);
297999653d4eSeschrock 		print_status_config(zhp, name, spares[i],
2980aa8cf21aSNeil Perrin 		    namewidth, 2, B_TRUE);
298199653d4eSeschrock 		free(name);
298299653d4eSeschrock 	}
298399653d4eSeschrock }
298499653d4eSeschrock 
2985fa94a07fSbrendan static void
2986fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
2987fa94a07fSbrendan     int namewidth)
2988fa94a07fSbrendan {
2989fa94a07fSbrendan 	uint_t i;
2990fa94a07fSbrendan 	char *name;
2991fa94a07fSbrendan 
2992fa94a07fSbrendan 	if (nl2cache == 0)
2993fa94a07fSbrendan 		return;
2994fa94a07fSbrendan 
2995fa94a07fSbrendan 	(void) printf(gettext("\tcache\n"));
2996fa94a07fSbrendan 
2997fa94a07fSbrendan 	for (i = 0; i < nl2cache; i++) {
2998fa94a07fSbrendan 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i]);
2999fa94a07fSbrendan 		print_status_config(zhp, name, l2cache[i],
3000aa8cf21aSNeil Perrin 		    namewidth, 2, B_FALSE);
3001aa8cf21aSNeil Perrin 		free(name);
3002aa8cf21aSNeil Perrin 	}
3003aa8cf21aSNeil Perrin }
3004aa8cf21aSNeil Perrin 
3005aa8cf21aSNeil Perrin /*
3006fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
3007fa9e4066Sahrens  *
3008fa9e4066Sahrens  *        pool: tank
3009fa9e4066Sahrens  *	status: DEGRADED
3010fa9e4066Sahrens  *	reason: One or more devices ...
3011fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
3012fa9e4066Sahrens  *	config:
3013fa9e4066Sahrens  *		mirror		DEGRADED
3014fa9e4066Sahrens  *                c1t0d0	OK
3015ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
3016fa9e4066Sahrens  *
3017fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
3018fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
3019fa9e4066Sahrens  */
3020fa9e4066Sahrens int
3021fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
3022fa9e4066Sahrens {
3023fa9e4066Sahrens 	status_cbdata_t *cbp = data;
3024fa9e4066Sahrens 	nvlist_t *config, *nvroot;
3025fa9e4066Sahrens 	char *msgid;
3026fa9e4066Sahrens 	int reason;
302746657f8dSmmusante 	const char *health;
302846657f8dSmmusante 	uint_t c;
302946657f8dSmmusante 	vdev_stat_t *vs;
3030fa9e4066Sahrens 
3031088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
3032fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
3033fa9e4066Sahrens 
3034fa9e4066Sahrens 	cbp->cb_count++;
3035fa9e4066Sahrens 
3036fa9e4066Sahrens 	/*
3037fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
3038fa9e4066Sahrens 	 * problems.
3039fa9e4066Sahrens 	 */
3040e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
3041e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
3042e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
3043e9dbad6fSeschrock 			    zpool_get_name(zhp));
3044e9dbad6fSeschrock 			if (cbp->cb_first)
3045e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
3046e9dbad6fSeschrock 		}
3047fa9e4066Sahrens 		return (0);
3048e9dbad6fSeschrock 	}
3049fa9e4066Sahrens 
3050fa9e4066Sahrens 	if (cbp->cb_first)
305199653d4eSeschrock 		cbp->cb_first = B_FALSE;
3052fa9e4066Sahrens 	else
3053fa9e4066Sahrens 		(void) printf("\n");
3054fa9e4066Sahrens 
305546657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
305646657f8dSmmusante 	    &nvroot) == 0);
305746657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
305846657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
3059990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3060fa9e4066Sahrens 
3061fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
3062fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
3063fa9e4066Sahrens 
3064fa9e4066Sahrens 	switch (reason) {
3065fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
3066fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3067fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
3068fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
3069fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3070fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3071fa9e4066Sahrens 		break;
3072fa9e4066Sahrens 
3073fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
3074fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3075fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
3076fa9e4066Sahrens 		    "pool to continue functioning.\n"));
3077fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3078fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3079fa9e4066Sahrens 		break;
3080fa9e4066Sahrens 
3081fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
3082fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3083fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
3084fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
3085fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
3086fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
3087fa9e4066Sahrens 		    "'zpool replace'.\n"));
3088fa9e4066Sahrens 		break;
3089fa9e4066Sahrens 
3090fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3091fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3092b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
3093fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
3094fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
3095fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
3096fa9e4066Sahrens 		    "from a backup source.\n"));
3097fa9e4066Sahrens 		break;
3098fa9e4066Sahrens 
3099fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
3100fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3101fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
3102fa9e4066Sahrens 		    "made to correct the error.  Applications are "
3103fa9e4066Sahrens 		    "unaffected.\n"));
3104fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
3105fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
3106ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
3107fa9e4066Sahrens 		    "replace'.\n"));
3108fa9e4066Sahrens 		break;
3109fa9e4066Sahrens 
3110fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
3111fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3112d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
3113fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
3114fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
3115fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
3116fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
3117fa9e4066Sahrens 		    "replace'.\n"));
3118fa9e4066Sahrens 		break;
3119fa9e4066Sahrens 
3120fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
3121fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
3122fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3123fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
3124fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3125fa9e4066Sahrens 		    "complete.\n"));
3126fa9e4066Sahrens 		break;
3127fa9e4066Sahrens 
3128ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3129ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3130ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3131ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3132ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3133ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3134ea8dc4b6Seschrock 		    "backup.\n"));
3135ea8dc4b6Seschrock 		break;
3136ea8dc4b6Seschrock 
3137ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3138ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3139ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3140ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
3141ea8dc4b6Seschrock 		    "from a backup source.\n"));
3142ea8dc4b6Seschrock 		break;
3143ea8dc4b6Seschrock 
3144eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3145eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3146eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3147eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3148eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3149eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3150eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3151eaca9bbdSeschrock 		break;
3152eaca9bbdSeschrock 
3153eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3154eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3155eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3156eaca9bbdSeschrock 		    "be accessed on this system.\n"));
3157eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
3158eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
3159eaca9bbdSeschrock 		    "backup.\n"));
3160eaca9bbdSeschrock 		break;
3161eaca9bbdSeschrock 
31623d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
31633d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
31643d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
31653d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
31663d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
31673d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
31683d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
31693d7072f8Seschrock 		break;
31703d7072f8Seschrock 
31713d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
31723d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
31733d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
31743d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
31753d7072f8Seschrock 		    "functioning.\n"));
31763d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
31773d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
31783d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
31793d7072f8Seschrock 		    "to be recovered.\n"));
31803d7072f8Seschrock 		break;
31813d7072f8Seschrock 
318232b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_WAIT:
318332b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
318432b87932Sek110237 		(void) printf(gettext("status: One or more devices are "
31858a79c1b5Sek110237 		    "faulted in response to IO failures.\n"));
318632b87932Sek110237 		(void) printf(gettext("action: Make sure the affected devices "
318732b87932Sek110237 		    "are connected, then run 'zpool clear'.\n"));
318832b87932Sek110237 		break;
318932b87932Sek110237 
3190b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
3191b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record "
3192b87f3af3Sperrin 		    "could not be read.\n"
3193b87f3af3Sperrin 		    "\tWaiting for adminstrator intervention to fix the "
3194b87f3af3Sperrin 		    "faulted pool.\n"));
3195b87f3af3Sperrin 		(void) printf(gettext("action: Either restore the affected "
3196b87f3af3Sperrin 		    "device(s) and run 'zpool online',\n"
3197b87f3af3Sperrin 		    "\tor ignore the intent log records by running "
3198b87f3af3Sperrin 		    "'zpool clear'.\n"));
3199b87f3af3Sperrin 		break;
3200b87f3af3Sperrin 
3201fa9e4066Sahrens 	default:
3202fa9e4066Sahrens 		/*
3203fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
3204fa9e4066Sahrens 		 */
3205fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
3206fa9e4066Sahrens 	}
3207fa9e4066Sahrens 
3208fa9e4066Sahrens 	if (msgid != NULL)
3209fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3210fa9e4066Sahrens 		    msgid);
3211fa9e4066Sahrens 
3212fa9e4066Sahrens 	if (config != NULL) {
3213fa9e4066Sahrens 		int namewidth;
3214ea8dc4b6Seschrock 		uint64_t nerr;
3215fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
3216fa94a07fSbrendan 		uint_t nspares, nl2cache;
3217fa9e4066Sahrens 
3218fa9e4066Sahrens 
3219fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
3220fa9e4066Sahrens 		print_scrub_status(nvroot);
3221fa9e4066Sahrens 
3222c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3223fa9e4066Sahrens 		if (namewidth < 10)
3224fa9e4066Sahrens 			namewidth = 10;
3225fa9e4066Sahrens 
3226fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
3227fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3228fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3229c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
3230aa8cf21aSNeil Perrin 		    namewidth, 0, B_FALSE);
323199653d4eSeschrock 
32324dea40f0SNeil Perrin 		if (num_logs(nvroot) > 0)
3233e6ca193dSGeorge Wilson 			print_logs(zhp, nvroot, namewidth, B_TRUE);
3234fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
3235fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
3236fa94a07fSbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
3237fa94a07fSbrendan 
323899653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
323999653d4eSeschrock 		    &spares, &nspares) == 0)
324099653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
3241ea8dc4b6Seschrock 
3242ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3243ea8dc4b6Seschrock 		    &nerr) == 0) {
324455434c77Sek110237 			nvlist_t *nverrlist = NULL;
324555434c77Sek110237 
3246ea8dc4b6Seschrock 			/*
3247ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3248ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3249ea8dc4b6Seschrock 			 * uniquifying the results.
3250ea8dc4b6Seschrock 			 */
325175519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
325255434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
325355434c77Sek110237 				nvpair_t *elem;
325455434c77Sek110237 
325555434c77Sek110237 				elem = NULL;
325655434c77Sek110237 				nerr = 0;
325755434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
325855434c77Sek110237 				    elem)) != NULL) {
325955434c77Sek110237 					nerr++;
326055434c77Sek110237 				}
326155434c77Sek110237 			}
326255434c77Sek110237 			nvlist_free(nverrlist);
3263ea8dc4b6Seschrock 
3264ea8dc4b6Seschrock 			(void) printf("\n");
326599653d4eSeschrock 
3266ea8dc4b6Seschrock 			if (nerr == 0)
3267ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3268ea8dc4b6Seschrock 				    "errors\n"));
3269ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3270e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
32715ad82045Snd150628 				    "errors, use '-v' for a list\n"),
32725ad82045Snd150628 				    (u_longlong_t)nerr);
3273ea8dc4b6Seschrock 			else
3274ea8dc4b6Seschrock 				print_error_log(zhp);
3275ea8dc4b6Seschrock 		}
3276fa9e4066Sahrens 	} else {
3277fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3278fa9e4066Sahrens 		    "determined.\n"));
3279fa9e4066Sahrens 	}
3280fa9e4066Sahrens 
3281fa9e4066Sahrens 	return (0);
3282fa9e4066Sahrens }
3283fa9e4066Sahrens 
3284fa9e4066Sahrens /*
3285fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3286fa9e4066Sahrens  *
3287fa9e4066Sahrens  *	-v	Display complete error logs
3288fa9e4066Sahrens  *	-x	Display only pools with potential problems
3289fa9e4066Sahrens  *
3290fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3291fa9e4066Sahrens  */
3292fa9e4066Sahrens int
3293fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3294fa9e4066Sahrens {
3295fa9e4066Sahrens 	int c;
3296fa9e4066Sahrens 	int ret;
3297fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3298fa9e4066Sahrens 
3299fa9e4066Sahrens 	/* check options */
3300fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3301fa9e4066Sahrens 		switch (c) {
3302fa9e4066Sahrens 		case 'v':
330399653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3304fa9e4066Sahrens 			break;
3305fa9e4066Sahrens 		case 'x':
330699653d4eSeschrock 			cb.cb_explain = B_TRUE;
3307fa9e4066Sahrens 			break;
3308fa9e4066Sahrens 		case '?':
3309fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3310fa9e4066Sahrens 			    optopt);
331199653d4eSeschrock 			usage(B_FALSE);
3312fa9e4066Sahrens 		}
3313fa9e4066Sahrens 	}
3314fa9e4066Sahrens 
3315fa9e4066Sahrens 	argc -= optind;
3316fa9e4066Sahrens 	argv += optind;
3317fa9e4066Sahrens 
331899653d4eSeschrock 	cb.cb_first = B_TRUE;
3319fa9e4066Sahrens 
3320e9dbad6fSeschrock 	if (argc == 0)
3321e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3322e9dbad6fSeschrock 
3323b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3324fa9e4066Sahrens 
3325fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3326fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3327e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3328fa9e4066Sahrens 		(void) printf(gettext("all pools are healthy\n"));
3329fa9e4066Sahrens 
3330fa9e4066Sahrens 	return (ret);
3331fa9e4066Sahrens }
3332fa9e4066Sahrens 
3333eaca9bbdSeschrock typedef struct upgrade_cbdata {
3334eaca9bbdSeschrock 	int	cb_all;
3335eaca9bbdSeschrock 	int	cb_first;
3336eaca9bbdSeschrock 	int	cb_newer;
333706eeb2adSek110237 	int	cb_argc;
3338990b4856Slling 	uint64_t cb_version;
333906eeb2adSek110237 	char	**cb_argv;
3340eaca9bbdSeschrock } upgrade_cbdata_t;
3341eaca9bbdSeschrock 
3342eaca9bbdSeschrock static int
3343eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3344eaca9bbdSeschrock {
3345eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3346eaca9bbdSeschrock 	nvlist_t *config;
3347eaca9bbdSeschrock 	uint64_t version;
3348eaca9bbdSeschrock 	int ret = 0;
3349eaca9bbdSeschrock 
3350eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3351eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3352eaca9bbdSeschrock 	    &version) == 0);
3353eaca9bbdSeschrock 
3354e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3355eaca9bbdSeschrock 		if (!cbp->cb_all) {
3356eaca9bbdSeschrock 			if (cbp->cb_first) {
3357eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3358eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3359eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3360eaca9bbdSeschrock 				    "longer be accessible by older software "
3361eaca9bbdSeschrock 				    "versions.\n\n"));
3362eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3363eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
336499653d4eSeschrock 				cbp->cb_first = B_FALSE;
3365eaca9bbdSeschrock 			}
3366eaca9bbdSeschrock 
33675ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3368eaca9bbdSeschrock 			    zpool_get_name(zhp));
3369eaca9bbdSeschrock 		} else {
337099653d4eSeschrock 			cbp->cb_first = B_FALSE;
3371990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
337206eeb2adSek110237 			if (!ret) {
3373eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3374990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
3375eaca9bbdSeschrock 			}
337606eeb2adSek110237 		}
3377e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3378eaca9bbdSeschrock 		assert(!cbp->cb_all);
3379eaca9bbdSeschrock 
3380eaca9bbdSeschrock 		if (cbp->cb_first) {
3381eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3382eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3383eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3384eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3385eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
338699653d4eSeschrock 			cbp->cb_first = B_FALSE;
3387eaca9bbdSeschrock 		}
3388eaca9bbdSeschrock 
33895ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3390eaca9bbdSeschrock 		    zpool_get_name(zhp));
3391eaca9bbdSeschrock 	}
3392eaca9bbdSeschrock 
3393eaca9bbdSeschrock 	zpool_close(zhp);
3394eaca9bbdSeschrock 	return (ret);
3395eaca9bbdSeschrock }
3396eaca9bbdSeschrock 
3397eaca9bbdSeschrock /* ARGSUSED */
3398eaca9bbdSeschrock static int
339906eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
3400eaca9bbdSeschrock {
3401990b4856Slling 	upgrade_cbdata_t *cbp = data;
3402990b4856Slling 	uint64_t cur_version;
3403eaca9bbdSeschrock 	int ret;
3404eaca9bbdSeschrock 
34058654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
34068654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
34078654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
34088654d025Sperrin 		    " to upgrade.\n"));
34098654d025Sperrin 		return (1);
34108654d025Sperrin 	}
3411990b4856Slling 
3412990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3413e6c728e1Sbrendan 	if (cur_version > cbp->cb_version) {
3414eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3415e6c728e1Sbrendan 		    "using more current version '%llu'.\n"),
3416e6c728e1Sbrendan 		    zpool_get_name(zhp), cur_version);
3417e6c728e1Sbrendan 		return (0);
3418e6c728e1Sbrendan 	}
3419e6c728e1Sbrendan 	if (cur_version == cbp->cb_version) {
3420e6c728e1Sbrendan 		(void) printf(gettext("Pool '%s' is already formatted "
3421e6c728e1Sbrendan 		    "using the current version.\n"), zpool_get_name(zhp));
3422eaca9bbdSeschrock 		return (0);
3423eaca9bbdSeschrock 	}
3424eaca9bbdSeschrock 
3425990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
342606eeb2adSek110237 
342706eeb2adSek110237 	if (!ret) {
342844cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
3429990b4856Slling 		    "from version %llu to version %llu\n\n"),
3430990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3431990b4856Slling 		    (u_longlong_t)cbp->cb_version);
343206eeb2adSek110237 	}
3433eaca9bbdSeschrock 
3434eaca9bbdSeschrock 	return (ret != 0);
3435eaca9bbdSeschrock }
3436eaca9bbdSeschrock 
3437eaca9bbdSeschrock /*
3438eaca9bbdSeschrock  * zpool upgrade
3439eaca9bbdSeschrock  * zpool upgrade -v
3440990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
3441eaca9bbdSeschrock  *
3442eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3443eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3444eaca9bbdSeschrock  * upgrade all pools.
3445eaca9bbdSeschrock  */
3446eaca9bbdSeschrock int
3447eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3448eaca9bbdSeschrock {
3449eaca9bbdSeschrock 	int c;
3450eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3451eaca9bbdSeschrock 	int ret = 0;
3452eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3453990b4856Slling 	char *end;
3454990b4856Slling 
3455eaca9bbdSeschrock 
3456eaca9bbdSeschrock 	/* check options */
3457478ed9adSEric Taylor 	while ((c = getopt(argc, argv, ":avV:")) != -1) {
3458eaca9bbdSeschrock 		switch (c) {
3459eaca9bbdSeschrock 		case 'a':
346099653d4eSeschrock 			cb.cb_all = B_TRUE;
3461eaca9bbdSeschrock 			break;
3462eaca9bbdSeschrock 		case 'v':
3463eaca9bbdSeschrock 			showversions = B_TRUE;
3464eaca9bbdSeschrock 			break;
3465990b4856Slling 		case 'V':
3466990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
3467351420b3Slling 			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
3468351420b3Slling 			    cb.cb_version < SPA_VERSION_1) {
3469990b4856Slling 				(void) fprintf(stderr,
3470990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
3471990b4856Slling 				usage(B_FALSE);
3472990b4856Slling 			}
3473990b4856Slling 			break;
3474478ed9adSEric Taylor 		case ':':
3475478ed9adSEric Taylor 			(void) fprintf(stderr, gettext("missing argument for "
3476478ed9adSEric Taylor 			    "'%c' option\n"), optopt);
3477478ed9adSEric Taylor 			usage(B_FALSE);
3478478ed9adSEric Taylor 			break;
3479eaca9bbdSeschrock 		case '?':
3480eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3481eaca9bbdSeschrock 			    optopt);
348299653d4eSeschrock 			usage(B_FALSE);
3483eaca9bbdSeschrock 		}
3484eaca9bbdSeschrock 	}
3485eaca9bbdSeschrock 
348606eeb2adSek110237 	cb.cb_argc = argc;
348706eeb2adSek110237 	cb.cb_argv = argv;
3488eaca9bbdSeschrock 	argc -= optind;
3489eaca9bbdSeschrock 	argv += optind;
3490eaca9bbdSeschrock 
3491351420b3Slling 	if (cb.cb_version == 0) {
3492351420b3Slling 		cb.cb_version = SPA_VERSION;
3493351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
3494351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
3495351420b3Slling 		    "incompatible with other arguments\n"));
3496351420b3Slling 		usage(B_FALSE);
3497351420b3Slling 	}
3498351420b3Slling 
3499eaca9bbdSeschrock 	if (showversions) {
3500eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3501eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3502eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
350399653d4eSeschrock 			usage(B_FALSE);
3504eaca9bbdSeschrock 		}
3505eaca9bbdSeschrock 	} else if (cb.cb_all) {
3506eaca9bbdSeschrock 		if (argc != 0) {
3507351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
3508351420b3Slling 			    "be used along with a pool name\n"));
350999653d4eSeschrock 			usage(B_FALSE);
3510eaca9bbdSeschrock 		}
3511eaca9bbdSeschrock 	}
3512eaca9bbdSeschrock 
3513e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3514e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
351599653d4eSeschrock 	cb.cb_first = B_TRUE;
3516eaca9bbdSeschrock 	if (showversions) {
3517eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3518d7d4af51Smmusante 		    "supported:\n\n"));
3519eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3520eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3521eaca9bbdSeschrock 		    "---------------\n");
352299653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
352344cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
352444cd46caSbillm 		    "(replicated metadata)\n"));
352599653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
352699653d4eSeschrock 		    "RAID-Z\n"));
3527d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
3528c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3529c9431fa1Sahl 		    "algorithm\n"));
3530990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
35318654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3532ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
3533a9799022Sck153898 		(void) printf(gettext(" 9   refquota and refreservation "
3534a9799022Sck153898 		    "properties\n"));
3535fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
3536088f3894Sahrens 		(void) printf(gettext(" 11  Improved scrub performance\n"));
3537bb0ade09Sahrens 		(void) printf(gettext(" 12  Snapshot properties\n"));
353874e7dc98SMatthew Ahrens 		(void) printf(gettext(" 13  snapused property\n"));
353914843421SMatthew Ahrens 		(void) printf(gettext(" 14  passthrough-x aclinherit\n"));
354014843421SMatthew Ahrens 		(void) printf(gettext(" 15  user/group space accounting\n"));
3541478ed9adSEric Taylor 		(void) printf(gettext(" 16  stmf property support\n"));
35428654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3543eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3544eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3545eaca9bbdSeschrock 		    "version/N\n\n");
3546eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3547eaca9bbdSeschrock 	} else if (argc == 0) {
3548eaca9bbdSeschrock 		int notfound;
3549eaca9bbdSeschrock 
355099653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3551eaca9bbdSeschrock 		notfound = cb.cb_first;
3552eaca9bbdSeschrock 
3553eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3554eaca9bbdSeschrock 			if (!cb.cb_first)
3555eaca9bbdSeschrock 				(void) printf("\n");
3556eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3557eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
355899653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3559eaca9bbdSeschrock 			if (!cb.cb_first) {
3560eaca9bbdSeschrock 				notfound = B_FALSE;
3561eaca9bbdSeschrock 				(void) printf("\n");
3562eaca9bbdSeschrock 			}
3563eaca9bbdSeschrock 		}
3564eaca9bbdSeschrock 
3565eaca9bbdSeschrock 		if (ret == 0) {
3566eaca9bbdSeschrock 			if (notfound)
3567eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3568eaca9bbdSeschrock 				    "using this version.\n"));
3569eaca9bbdSeschrock 			else if (!cb.cb_all)
3570eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3571eaca9bbdSeschrock 				    "for a list of available versions and "
3572eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3573eaca9bbdSeschrock 		}
3574eaca9bbdSeschrock 	} else {
3575b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3576b1b8ab34Slling 		    upgrade_one, &cb);
357706eeb2adSek110237 	}
357806eeb2adSek110237 
357906eeb2adSek110237 	return (ret);
358006eeb2adSek110237 }
358106eeb2adSek110237 
3582ecd6cf80Smarks typedef struct hist_cbdata {
3583ecd6cf80Smarks 	boolean_t first;
3584ecd6cf80Smarks 	int longfmt;
3585ecd6cf80Smarks 	int internal;
3586ecd6cf80Smarks } hist_cbdata_t;
3587ecd6cf80Smarks 
3588ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3589ecd6cf80Smarks 	"invalid event",
3590ecd6cf80Smarks 	"pool create",
3591ecd6cf80Smarks 	"vdev add",
3592ecd6cf80Smarks 	"pool remove",
3593ecd6cf80Smarks 	"pool destroy",
3594ecd6cf80Smarks 	"pool export",
3595ecd6cf80Smarks 	"pool import",
3596ecd6cf80Smarks 	"vdev attach",
3597ecd6cf80Smarks 	"vdev replace",
3598ecd6cf80Smarks 	"vdev detach",
3599ecd6cf80Smarks 	"vdev online",
3600ecd6cf80Smarks 	"vdev offline",
3601ecd6cf80Smarks 	"vdev upgrade",
3602ecd6cf80Smarks 	"pool clear",
3603ecd6cf80Smarks 	"pool scrub",
3604ecd6cf80Smarks 	"pool property set",
3605ecd6cf80Smarks 	"create",
3606ecd6cf80Smarks 	"clone",
3607ecd6cf80Smarks 	"destroy",
3608ecd6cf80Smarks 	"destroy_begin_sync",
3609ecd6cf80Smarks 	"inherit",
3610ecd6cf80Smarks 	"property set",
3611ecd6cf80Smarks 	"quota set",
3612ecd6cf80Smarks 	"permission update",
3613ecd6cf80Smarks 	"permission remove",
3614ecd6cf80Smarks 	"permission who remove",
3615ecd6cf80Smarks 	"promote",
3616ecd6cf80Smarks 	"receive",
3617ecd6cf80Smarks 	"rename",
3618ecd6cf80Smarks 	"reservation set",
3619ecd6cf80Smarks 	"replay_inc_sync",
3620ecd6cf80Smarks 	"replay_full_sync",
3621ecd6cf80Smarks 	"rollback",
3622ecd6cf80Smarks 	"snapshot",
3623e7437265Sahrens 	"filesystem version upgrade",
3624a9799022Sck153898 	"refquota set",
3625a9799022Sck153898 	"refreservation set",
3626088f3894Sahrens 	"pool scrub done",
3627ecd6cf80Smarks };
3628ecd6cf80Smarks 
362906eeb2adSek110237 /*
363006eeb2adSek110237  * Print out the command history for a specific pool.
363106eeb2adSek110237  */
363206eeb2adSek110237 static int
363306eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
363406eeb2adSek110237 {
363506eeb2adSek110237 	nvlist_t *nvhis;
363606eeb2adSek110237 	nvlist_t **records;
363706eeb2adSek110237 	uint_t numrecords;
363806eeb2adSek110237 	char *cmdstr;
3639ecd6cf80Smarks 	char *pathstr;
364006eeb2adSek110237 	uint64_t dst_time;
364106eeb2adSek110237 	time_t tsec;
364206eeb2adSek110237 	struct tm t;
364306eeb2adSek110237 	char tbuf[30];
364406eeb2adSek110237 	int ret, i;
3645ecd6cf80Smarks 	uint64_t who;
3646ecd6cf80Smarks 	struct passwd *pwd;
3647ecd6cf80Smarks 	char *hostname;
3648ecd6cf80Smarks 	char *zonename;
3649ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3650ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3651ecd6cf80Smarks 	uint64_t txg;
3652ecd6cf80Smarks 	uint64_t ievent;
365306eeb2adSek110237 
3654ecd6cf80Smarks 	cb->first = B_FALSE;
365506eeb2adSek110237 
365606eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
365706eeb2adSek110237 
365806eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
365906eeb2adSek110237 		return (ret);
366006eeb2adSek110237 
366106eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
366206eeb2adSek110237 	    &records, &numrecords) == 0);
366306eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
366406eeb2adSek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3665ecd6cf80Smarks 		    &dst_time) != 0)
3666ecd6cf80Smarks 			continue;
3667ecd6cf80Smarks 
3668ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3669ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3670ecd6cf80Smarks 		    &cmdstr) != 0) {
3671ecd6cf80Smarks 			if (cb->internal == 0)
3672ecd6cf80Smarks 				continue;
3673ecd6cf80Smarks 
3674ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3675ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3676ecd6cf80Smarks 				continue;
3677ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3678ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3679ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3680ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3681088f3894Sahrens 			if (ievent >= LOG_END)
3682ecd6cf80Smarks 				continue;
3683ecd6cf80Smarks 			(void) snprintf(internalstr,
3684ecd6cf80Smarks 			    sizeof (internalstr),
3685ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3686ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3687ecd6cf80Smarks 			    pathstr);
3688ecd6cf80Smarks 			cmdstr = internalstr;
3689ecd6cf80Smarks 		}
369006eeb2adSek110237 		tsec = dst_time;
369106eeb2adSek110237 		(void) localtime_r(&tsec, &t);
369206eeb2adSek110237 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3693ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3694ecd6cf80Smarks 
3695ecd6cf80Smarks 		if (!cb->longfmt) {
3696ecd6cf80Smarks 			(void) printf("\n");
3697ecd6cf80Smarks 			continue;
369806eeb2adSek110237 		}
3699ecd6cf80Smarks 		(void) printf(" [");
3700ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3701ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3702ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3703ecd6cf80Smarks 			if (pwd)
3704ecd6cf80Smarks 				(void) printf("user %s on",
3705ecd6cf80Smarks 				    pwd->pw_name);
3706ecd6cf80Smarks 			else
3707ecd6cf80Smarks 				(void) printf("user %d on",
3708ecd6cf80Smarks 				    (int)who);
3709ecd6cf80Smarks 		} else {
3710ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3711ecd6cf80Smarks 			continue;
3712ecd6cf80Smarks 		}
3713ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3714ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3715ecd6cf80Smarks 			(void) printf(" %s", hostname);
3716ecd6cf80Smarks 		}
3717ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3718ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3719ecd6cf80Smarks 			(void) printf(":%s", zonename);
3720ecd6cf80Smarks 		}
3721ecd6cf80Smarks 
3722ecd6cf80Smarks 		(void) printf("]");
3723ecd6cf80Smarks 		(void) printf("\n");
372406eeb2adSek110237 	}
372506eeb2adSek110237 	(void) printf("\n");
372606eeb2adSek110237 	nvlist_free(nvhis);
372706eeb2adSek110237 
372806eeb2adSek110237 	return (ret);
372906eeb2adSek110237 }
373006eeb2adSek110237 
373106eeb2adSek110237 /*
373206eeb2adSek110237  * zpool history <pool>
373306eeb2adSek110237  *
373406eeb2adSek110237  * Displays the history of commands that modified pools.
373506eeb2adSek110237  */
3736ecd6cf80Smarks 
3737ecd6cf80Smarks 
373806eeb2adSek110237 int
373906eeb2adSek110237 zpool_do_history(int argc, char **argv)
374006eeb2adSek110237 {
3741ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
374206eeb2adSek110237 	int ret;
3743ecd6cf80Smarks 	int c;
374406eeb2adSek110237 
3745ecd6cf80Smarks 	cbdata.first = B_TRUE;
3746ecd6cf80Smarks 	/* check options */
3747ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3748ecd6cf80Smarks 		switch (c) {
3749ecd6cf80Smarks 		case 'l':
3750ecd6cf80Smarks 			cbdata.longfmt = 1;
3751ecd6cf80Smarks 			break;
3752ecd6cf80Smarks 		case 'i':
3753ecd6cf80Smarks 			cbdata.internal = 1;
3754ecd6cf80Smarks 			break;
3755ecd6cf80Smarks 		case '?':
3756ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3757ecd6cf80Smarks 			    optopt);
3758ecd6cf80Smarks 			usage(B_FALSE);
3759ecd6cf80Smarks 		}
3760ecd6cf80Smarks 	}
376106eeb2adSek110237 	argc -= optind;
376206eeb2adSek110237 	argv += optind;
376306eeb2adSek110237 
3764b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3765ecd6cf80Smarks 	    &cbdata);
376606eeb2adSek110237 
3767ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
376806eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
376906eeb2adSek110237 		return (0);
3770eaca9bbdSeschrock 	}
3771eaca9bbdSeschrock 
3772eaca9bbdSeschrock 	return (ret);
3773eaca9bbdSeschrock }
3774eaca9bbdSeschrock 
3775b1b8ab34Slling static int
3776b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3777b1b8ab34Slling {
3778990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3779b1b8ab34Slling 	char value[MAXNAMELEN];
3780990b4856Slling 	zprop_source_t srctype;
3781990b4856Slling 	zprop_list_t *pl;
3782b1b8ab34Slling 
3783b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3784b1b8ab34Slling 
3785b1b8ab34Slling 		/*
3786990b4856Slling 		 * Skip the special fake placeholder. This will also skip
3787990b4856Slling 		 * over the name property when 'all' is specified.
3788b1b8ab34Slling 		 */
3789990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3790b1b8ab34Slling 		    pl == cbp->cb_proplist)
3791b1b8ab34Slling 			continue;
3792b1b8ab34Slling 
3793b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3794b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3795b1b8ab34Slling 			continue;
3796b1b8ab34Slling 
3797990b4856Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
3798b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3799b1b8ab34Slling 	}
3800b1b8ab34Slling 	return (0);
3801b1b8ab34Slling }
3802b1b8ab34Slling 
3803b1b8ab34Slling int
3804b1b8ab34Slling zpool_do_get(int argc, char **argv)
3805b1b8ab34Slling {
3806990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
3807990b4856Slling 	zprop_list_t fake_name = { 0 };
3808b1b8ab34Slling 	int ret;
3809b1b8ab34Slling 
3810b1b8ab34Slling 	if (argc < 3)
3811b1b8ab34Slling 		usage(B_FALSE);
3812b1b8ab34Slling 
3813b1b8ab34Slling 	cb.cb_first = B_TRUE;
3814990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
3815b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3816b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3817b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3818b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3819990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
3820b1b8ab34Slling 
3821990b4856Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3822990b4856Slling 	    ZFS_TYPE_POOL) != 0)
3823b1b8ab34Slling 		usage(B_FALSE);
3824b1b8ab34Slling 
3825b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3826990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
3827b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3828b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3829b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3830b1b8ab34Slling 	}
3831b1b8ab34Slling 
3832b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3833b1b8ab34Slling 	    get_callback, &cb);
3834b1b8ab34Slling 
3835b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3836990b4856Slling 		zprop_free_list(fake_name.pl_next);
3837b1b8ab34Slling 	else
3838990b4856Slling 		zprop_free_list(cb.cb_proplist);
3839b1b8ab34Slling 
3840b1b8ab34Slling 	return (ret);
3841b1b8ab34Slling }
3842b1b8ab34Slling 
3843b1b8ab34Slling typedef struct set_cbdata {
3844b1b8ab34Slling 	char *cb_propname;
3845b1b8ab34Slling 	char *cb_value;
3846b1b8ab34Slling 	boolean_t cb_any_successful;
3847b1b8ab34Slling } set_cbdata_t;
3848b1b8ab34Slling 
3849b1b8ab34Slling int
3850b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3851b1b8ab34Slling {
3852b1b8ab34Slling 	int error;
3853b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3854b1b8ab34Slling 
3855b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3856b1b8ab34Slling 
3857b1b8ab34Slling 	if (!error)
3858b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3859b1b8ab34Slling 
3860b1b8ab34Slling 	return (error);
3861b1b8ab34Slling }
3862b1b8ab34Slling 
3863b1b8ab34Slling int
3864b1b8ab34Slling zpool_do_set(int argc, char **argv)
3865b1b8ab34Slling {
3866b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3867b1b8ab34Slling 	int error;
3868b1b8ab34Slling 
3869b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3870b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3871b1b8ab34Slling 		    argv[1][1]);
3872b1b8ab34Slling 		usage(B_FALSE);
3873b1b8ab34Slling 	}
3874b1b8ab34Slling 
3875b1b8ab34Slling 	if (argc < 2) {
3876b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3877b1b8ab34Slling 		    "argument\n"));
3878b1b8ab34Slling 		usage(B_FALSE);
3879b1b8ab34Slling 	}
3880b1b8ab34Slling 
3881b1b8ab34Slling 	if (argc < 3) {
3882b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3883b1b8ab34Slling 		usage(B_FALSE);
3884b1b8ab34Slling 	}
3885b1b8ab34Slling 
3886b1b8ab34Slling 	if (argc > 3) {
3887b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3888b1b8ab34Slling 		usage(B_FALSE);
3889b1b8ab34Slling 	}
3890b1b8ab34Slling 
3891b1b8ab34Slling 	cb.cb_propname = argv[1];
3892b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3893b1b8ab34Slling 	if (cb.cb_value == NULL) {
3894b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3895b1b8ab34Slling 		    "property=value argument\n"));
3896b1b8ab34Slling 		usage(B_FALSE);
3897b1b8ab34Slling 	}
3898b1b8ab34Slling 
3899b1b8ab34Slling 	*(cb.cb_value) = '\0';
3900b1b8ab34Slling 	cb.cb_value++;
3901b1b8ab34Slling 
3902b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3903b1b8ab34Slling 	    set_callback, &cb);
3904b1b8ab34Slling 
3905b1b8ab34Slling 	return (error);
3906b1b8ab34Slling }
3907b1b8ab34Slling 
3908b1b8ab34Slling static int
3909b1b8ab34Slling find_command_idx(char *command, int *idx)
3910b1b8ab34Slling {
3911b1b8ab34Slling 	int i;
3912b1b8ab34Slling 
3913b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3914b1b8ab34Slling 		if (command_table[i].name == NULL)
3915b1b8ab34Slling 			continue;
3916b1b8ab34Slling 
3917b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3918b1b8ab34Slling 			*idx = i;
3919b1b8ab34Slling 			return (0);
3920b1b8ab34Slling 		}
3921b1b8ab34Slling 	}
3922b1b8ab34Slling 	return (1);
3923b1b8ab34Slling }
3924b1b8ab34Slling 
3925fa9e4066Sahrens int
3926fa9e4066Sahrens main(int argc, char **argv)
3927fa9e4066Sahrens {
3928fa9e4066Sahrens 	int ret;
3929fa9e4066Sahrens 	int i;
3930fa9e4066Sahrens 	char *cmdname;
3931fa9e4066Sahrens 
3932fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3933fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3934fa9e4066Sahrens 
393599653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
393699653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3937203a47d8Snd150628 		    "initialize ZFS library\n"));
393899653d4eSeschrock 		return (1);
393999653d4eSeschrock 	}
394099653d4eSeschrock 
394199653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
394299653d4eSeschrock 
3943fa9e4066Sahrens 	opterr = 0;
3944fa9e4066Sahrens 
3945fa9e4066Sahrens 	/*
3946fa9e4066Sahrens 	 * Make sure the user has specified some command.
3947fa9e4066Sahrens 	 */
3948fa9e4066Sahrens 	if (argc < 2) {
3949fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
395099653d4eSeschrock 		usage(B_FALSE);
3951fa9e4066Sahrens 	}
3952fa9e4066Sahrens 
3953fa9e4066Sahrens 	cmdname = argv[1];
3954fa9e4066Sahrens 
3955fa9e4066Sahrens 	/*
3956fa9e4066Sahrens 	 * Special case '-?'
3957fa9e4066Sahrens 	 */
3958fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
395999653d4eSeschrock 		usage(B_TRUE);
3960fa9e4066Sahrens 
39612a6b87f0Sek110237 	zpool_set_history_str("zpool", argc, argv, history_str);
39622a6b87f0Sek110237 	verify(zpool_stage_history(g_zfs, history_str) == 0);
39632a6b87f0Sek110237 
3964fa9e4066Sahrens 	/*
3965fa9e4066Sahrens 	 * Run the appropriate command.
3966fa9e4066Sahrens 	 */
3967b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
3968fa9e4066Sahrens 		current_command = &command_table[i];
3969fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
397091ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
397191ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
397291ebeef5Sahrens 		current_command = &command_table[i];
397391ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
397491ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
3975fa9e4066Sahrens 		/*
397691ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
397791ebeef5Sahrens 		 * it as such.
3978fa9e4066Sahrens 		 */
3979ea8dc4b6Seschrock 		char buf[16384];
3980ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
3981fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
3982fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
398391ebeef5Sahrens 	} else {
3984fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
3985fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
398699653d4eSeschrock 		usage(B_FALSE);
3987fa9e4066Sahrens 	}
3988fa9e4066Sahrens 
398999653d4eSeschrock 	libzfs_fini(g_zfs);
399099653d4eSeschrock 
3991fa9e4066Sahrens 	/*
3992fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3993fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
3994fa9e4066Sahrens 	 */
3995fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
3996fa9e4066Sahrens 		(void) printf("dumping core by request\n");
3997fa9e4066Sahrens 		abort();
3998fa9e4066Sahrens 	}
3999fa9e4066Sahrens 
4000fa9e4066Sahrens 	return (ret);
4001fa9e4066Sahrens }
4002