xref: /titanic_53/usr/src/cmd/zpool/zpool_main.c (revision aa8cf21aa2aaa2df3db469354ccc0c47f8cdaab9)
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 {
3790a48a24eStimh 		if ((fprop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
3800a48a24eStimh 			(void) fprintf(stderr, gettext("property '%s' is "
3810a48a24eStimh 			    "not a valid file system property\n"), propname);
3820a48a24eStimh 			return (2);
3830a48a24eStimh 		}
3840a48a24eStimh 		normnm = zfs_prop_to_name(fprop);
3850a48a24eStimh 	}
386990b4856Slling 
3870a48a24eStimh 	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
3880a48a24eStimh 	    prop != ZPOOL_PROP_CACHEFILE) {
389990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' "
390990b4856Slling 		    "specified multiple times\n"), propname);
391990b4856Slling 		return (2);
392990b4856Slling 	}
393990b4856Slling 
3940a48a24eStimh 	if (nvlist_add_string(proplist, normnm, propval) != 0) {
395990b4856Slling 		(void) fprintf(stderr, gettext("internal "
396990b4856Slling 		    "error: out of memory\n"));
397990b4856Slling 		return (1);
398990b4856Slling 	}
399990b4856Slling 
400990b4856Slling 	return (0);
401990b4856Slling }
402990b4856Slling 
403990b4856Slling /*
404fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
405fa9e4066Sahrens  *
406fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
407fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
408fa9e4066Sahrens  *		they were to be added.
409fa9e4066Sahrens  *
410fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
411fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
412fa9e4066Sahrens  * libzfs.
413fa9e4066Sahrens  */
414fa9e4066Sahrens int
415fa9e4066Sahrens zpool_do_add(int argc, char **argv)
416fa9e4066Sahrens {
41799653d4eSeschrock 	boolean_t force = B_FALSE;
41899653d4eSeschrock 	boolean_t dryrun = B_FALSE;
419fa9e4066Sahrens 	int c;
420fa9e4066Sahrens 	nvlist_t *nvroot;
421fa9e4066Sahrens 	char *poolname;
422fa9e4066Sahrens 	int ret;
423fa9e4066Sahrens 	zpool_handle_t *zhp;
424fa9e4066Sahrens 	nvlist_t *config;
425fa9e4066Sahrens 
426fa9e4066Sahrens 	/* check options */
427fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
428fa9e4066Sahrens 		switch (c) {
429fa9e4066Sahrens 		case 'f':
43099653d4eSeschrock 			force = B_TRUE;
431fa9e4066Sahrens 			break;
432fa9e4066Sahrens 		case 'n':
43399653d4eSeschrock 			dryrun = B_TRUE;
434fa9e4066Sahrens 			break;
435fa9e4066Sahrens 		case '?':
436fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
437fa9e4066Sahrens 			    optopt);
43899653d4eSeschrock 			usage(B_FALSE);
439fa9e4066Sahrens 		}
440fa9e4066Sahrens 	}
441fa9e4066Sahrens 
442fa9e4066Sahrens 	argc -= optind;
443fa9e4066Sahrens 	argv += optind;
444fa9e4066Sahrens 
445fa9e4066Sahrens 	/* get pool name and check number of arguments */
446fa9e4066Sahrens 	if (argc < 1) {
447fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
44899653d4eSeschrock 		usage(B_FALSE);
449fa9e4066Sahrens 	}
450fa9e4066Sahrens 	if (argc < 2) {
451fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
45299653d4eSeschrock 		usage(B_FALSE);
453fa9e4066Sahrens 	}
454fa9e4066Sahrens 
455fa9e4066Sahrens 	poolname = argv[0];
456fa9e4066Sahrens 
457fa9e4066Sahrens 	argc--;
458fa9e4066Sahrens 	argv++;
459fa9e4066Sahrens 
46099653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
461fa9e4066Sahrens 		return (1);
462fa9e4066Sahrens 
463088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
464fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
465fa9e4066Sahrens 		    poolname);
466fa9e4066Sahrens 		zpool_close(zhp);
467fa9e4066Sahrens 		return (1);
468fa9e4066Sahrens 	}
469fa9e4066Sahrens 
470fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
471705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
472705040edSEric Taylor 	    argc, argv);
473fa9e4066Sahrens 	if (nvroot == NULL) {
474fa9e4066Sahrens 		zpool_close(zhp);
475fa9e4066Sahrens 		return (1);
476fa9e4066Sahrens 	}
477fa9e4066Sahrens 
478fa9e4066Sahrens 	if (dryrun) {
479fa9e4066Sahrens 		nvlist_t *poolnvroot;
480fa9e4066Sahrens 
481fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
482fa9e4066Sahrens 		    &poolnvroot) == 0);
483fa9e4066Sahrens 
484fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
485fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
486fa9e4066Sahrens 
4878654d025Sperrin 		/* print original main pool and new tree */
4888654d025Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
4898654d025Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
4908654d025Sperrin 
4918654d025Sperrin 		/* Do the same for the logs */
4928654d025Sperrin 		if (num_logs(poolnvroot) > 0) {
4938654d025Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
4948654d025Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
4958654d025Sperrin 		} else if (num_logs(nvroot) > 0) {
4968654d025Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
4978654d025Sperrin 		}
498fa9e4066Sahrens 
499fa9e4066Sahrens 		ret = 0;
500fa9e4066Sahrens 	} else {
501fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
502fa9e4066Sahrens 	}
503fa9e4066Sahrens 
50499653d4eSeschrock 	nvlist_free(nvroot);
50599653d4eSeschrock 	zpool_close(zhp);
50699653d4eSeschrock 
50799653d4eSeschrock 	return (ret);
50899653d4eSeschrock }
50999653d4eSeschrock 
51099653d4eSeschrock /*
511fa94a07fSbrendan  * zpool remove <pool> <vdev> ...
51299653d4eSeschrock  *
51399653d4eSeschrock  * Removes the given vdev from the pool.  Currently, this only supports removing
514fa94a07fSbrendan  * spares and cache devices from the pool.  Eventually, we'll want to support
515fa94a07fSbrendan  * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs.
51699653d4eSeschrock  */
51799653d4eSeschrock int
51899653d4eSeschrock zpool_do_remove(int argc, char **argv)
51999653d4eSeschrock {
52099653d4eSeschrock 	char *poolname;
521fa94a07fSbrendan 	int i, ret = 0;
52299653d4eSeschrock 	zpool_handle_t *zhp;
52399653d4eSeschrock 
52499653d4eSeschrock 	argc--;
52599653d4eSeschrock 	argv++;
52699653d4eSeschrock 
52799653d4eSeschrock 	/* get pool name and check number of arguments */
52899653d4eSeschrock 	if (argc < 1) {
52999653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
53099653d4eSeschrock 		usage(B_FALSE);
53199653d4eSeschrock 	}
53299653d4eSeschrock 	if (argc < 2) {
53399653d4eSeschrock 		(void) fprintf(stderr, gettext("missing device\n"));
53499653d4eSeschrock 		usage(B_FALSE);
53599653d4eSeschrock 	}
53699653d4eSeschrock 
53799653d4eSeschrock 	poolname = argv[0];
53899653d4eSeschrock 
53999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
54099653d4eSeschrock 		return (1);
54199653d4eSeschrock 
542fa94a07fSbrendan 	for (i = 1; i < argc; i++) {
543fa94a07fSbrendan 		if (zpool_vdev_remove(zhp, argv[i]) != 0)
544fa94a07fSbrendan 			ret = 1;
545fa94a07fSbrendan 	}
54699653d4eSeschrock 
547fa9e4066Sahrens 	return (ret);
548fa9e4066Sahrens }
549fa9e4066Sahrens 
550fa9e4066Sahrens /*
5510a48a24eStimh  * zpool create [-fn] [-o property=value] ...
5520a48a24eStimh  *		[-O file-system-property=value] ...
5530a48a24eStimh  *		[-R root] [-m mountpoint] <pool> <dev> ...
554fa9e4066Sahrens  *
555fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
556fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
557fa9e4066Sahrens  *		were to be created.
558fa9e4066Sahrens  *      -R	Create a pool under an alternate root
559fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
560fa9e4066Sahrens  *      	'/<pool>'
561990b4856Slling  *	-o	Set property=value.
5620a48a24eStimh  *	-O	Set fsproperty=value in the pool's root file system
563fa9e4066Sahrens  *
564b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
565fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
566fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
567fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
568fa9e4066Sahrens  */
569fa9e4066Sahrens int
570fa9e4066Sahrens zpool_do_create(int argc, char **argv)
571fa9e4066Sahrens {
57299653d4eSeschrock 	boolean_t force = B_FALSE;
57399653d4eSeschrock 	boolean_t dryrun = B_FALSE;
574fa9e4066Sahrens 	int c;
575990b4856Slling 	nvlist_t *nvroot = NULL;
576fa9e4066Sahrens 	char *poolname;
577990b4856Slling 	int ret = 1;
578fa9e4066Sahrens 	char *altroot = NULL;
579fa9e4066Sahrens 	char *mountpoint = NULL;
5800a48a24eStimh 	nvlist_t *fsprops = NULL;
581990b4856Slling 	nvlist_t *props = NULL;
5822f8aaab3Seschrock 	char *propval;
583fa9e4066Sahrens 
584fa9e4066Sahrens 	/* check options */
5850a48a24eStimh 	while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) {
586fa9e4066Sahrens 		switch (c) {
587fa9e4066Sahrens 		case 'f':
58899653d4eSeschrock 			force = B_TRUE;
589fa9e4066Sahrens 			break;
590fa9e4066Sahrens 		case 'n':
59199653d4eSeschrock 			dryrun = B_TRUE;
592fa9e4066Sahrens 			break;
593fa9e4066Sahrens 		case 'R':
594fa9e4066Sahrens 			altroot = optarg;
595990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
5960a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
597990b4856Slling 				goto errout;
5982f8aaab3Seschrock 			if (nvlist_lookup_string(props,
5992f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
6002f8aaab3Seschrock 			    &propval) == 0)
6012f8aaab3Seschrock 				break;
602990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
6030a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
604990b4856Slling 				goto errout;
605fa9e4066Sahrens 			break;
606fa9e4066Sahrens 		case 'm':
607fa9e4066Sahrens 			mountpoint = optarg;
608fa9e4066Sahrens 			break;
609990b4856Slling 		case 'o':
610990b4856Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
611990b4856Slling 				(void) fprintf(stderr, gettext("missing "
612990b4856Slling 				    "'=' for -o option\n"));
613990b4856Slling 				goto errout;
614990b4856Slling 			}
615990b4856Slling 			*propval = '\0';
616990b4856Slling 			propval++;
617990b4856Slling 
6180a48a24eStimh 			if (add_prop_list(optarg, propval, &props, B_TRUE))
6190a48a24eStimh 				goto errout;
6200a48a24eStimh 			break;
6210a48a24eStimh 		case 'O':
6220a48a24eStimh 			if ((propval = strchr(optarg, '=')) == NULL) {
6230a48a24eStimh 				(void) fprintf(stderr, gettext("missing "
6240a48a24eStimh 				    "'=' for -O option\n"));
6250a48a24eStimh 				goto errout;
6260a48a24eStimh 			}
6270a48a24eStimh 			*propval = '\0';
6280a48a24eStimh 			propval++;
6290a48a24eStimh 
6300a48a24eStimh 			if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
631990b4856Slling 				goto errout;
632990b4856Slling 			break;
633fa9e4066Sahrens 		case ':':
634fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
635fa9e4066Sahrens 			    "'%c' option\n"), optopt);
636990b4856Slling 			goto badusage;
637fa9e4066Sahrens 		case '?':
638fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
639fa9e4066Sahrens 			    optopt);
640990b4856Slling 			goto badusage;
641fa9e4066Sahrens 		}
642fa9e4066Sahrens 	}
643fa9e4066Sahrens 
644fa9e4066Sahrens 	argc -= optind;
645fa9e4066Sahrens 	argv += optind;
646fa9e4066Sahrens 
647fa9e4066Sahrens 	/* get pool name and check number of arguments */
648fa9e4066Sahrens 	if (argc < 1) {
649fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
650990b4856Slling 		goto badusage;
651fa9e4066Sahrens 	}
652fa9e4066Sahrens 	if (argc < 2) {
653fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
654990b4856Slling 		goto badusage;
655fa9e4066Sahrens 	}
656fa9e4066Sahrens 
657fa9e4066Sahrens 	poolname = argv[0];
658fa9e4066Sahrens 
659fa9e4066Sahrens 	/*
660fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
661fa9e4066Sahrens 	 * user to use 'zfs create' instead.
662fa9e4066Sahrens 	 */
663fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
664fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
665fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
666fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
667fa9e4066Sahrens 		    "create a dataset\n"));
668990b4856Slling 		goto errout;
669fa9e4066Sahrens 	}
670fa9e4066Sahrens 
671fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
672705040edSEric Taylor 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
673705040edSEric Taylor 	    argc - 1, argv + 1);
674fa9e4066Sahrens 	if (nvroot == NULL)
6750a48a24eStimh 		goto errout;
676fa9e4066Sahrens 
67799653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
678b7b97454Sperrin 	if (!zfs_allocatable_devs(nvroot)) {
67999653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
68099653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
68199653d4eSeschrock 		    "specified\n"));
682990b4856Slling 		goto errout;
68399653d4eSeschrock 	}
68499653d4eSeschrock 
68599653d4eSeschrock 
686fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
687fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
688e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
689990b4856Slling 		goto errout;
690fa9e4066Sahrens 	}
691fa9e4066Sahrens 
692fa9e4066Sahrens 	/*
693fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
694fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
695fa9e4066Sahrens 	 */
696fa9e4066Sahrens 	if (mountpoint == NULL ||
697fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
698fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
699fa9e4066Sahrens 		char buf[MAXPATHLEN];
70011022c7cStimh 		DIR *dirp;
701fa9e4066Sahrens 
702fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
703fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
704fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
705fa9e4066Sahrens 			    "'none'\n"), mountpoint);
706990b4856Slling 			goto errout;
707fa9e4066Sahrens 		}
708fa9e4066Sahrens 
709fa9e4066Sahrens 		if (mountpoint == NULL) {
710fa9e4066Sahrens 			if (altroot != NULL)
711fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
712fa9e4066Sahrens 				    altroot, poolname);
713fa9e4066Sahrens 			else
714fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
715fa9e4066Sahrens 				    poolname);
716fa9e4066Sahrens 		} else {
717fa9e4066Sahrens 			if (altroot != NULL)
718fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
719fa9e4066Sahrens 				    altroot, mountpoint);
720fa9e4066Sahrens 			else
721fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
722fa9e4066Sahrens 				    mountpoint);
723fa9e4066Sahrens 		}
724fa9e4066Sahrens 
72511022c7cStimh 		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
72611022c7cStimh 			(void) fprintf(stderr, gettext("mountpoint '%s' : "
72711022c7cStimh 			    "%s\n"), buf, strerror(errno));
728fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
729fa9e4066Sahrens 			    "option to provide a different default\n"));
730990b4856Slling 			goto errout;
73111022c7cStimh 		} else if (dirp) {
73211022c7cStimh 			int count = 0;
73311022c7cStimh 
73411022c7cStimh 			while (count < 3 && readdir(dirp) != NULL)
73511022c7cStimh 				count++;
73611022c7cStimh 			(void) closedir(dirp);
73711022c7cStimh 
73811022c7cStimh 			if (count > 2) {
73911022c7cStimh 				(void) fprintf(stderr, gettext("mountpoint "
74011022c7cStimh 				    "'%s' exists and is not empty\n"), buf);
74111022c7cStimh 				(void) fprintf(stderr, gettext("use '-m' "
74211022c7cStimh 				    "option to provide a "
74311022c7cStimh 				    "different default\n"));
74411022c7cStimh 				goto errout;
74511022c7cStimh 			}
746fa9e4066Sahrens 		}
747fa9e4066Sahrens 	}
748fa9e4066Sahrens 
749fa9e4066Sahrens 	if (dryrun) {
750fa9e4066Sahrens 		/*
751fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
752fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
753fa9e4066Sahrens 		 * appropriate hierarchy.
754fa9e4066Sahrens 		 */
755fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
756fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
757fa9e4066Sahrens 
7588654d025Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7598654d025Sperrin 		if (num_logs(nvroot) > 0)
7608654d025Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
761fa9e4066Sahrens 
762fa9e4066Sahrens 		ret = 0;
763fa9e4066Sahrens 	} else {
764fa9e4066Sahrens 		/*
765fa9e4066Sahrens 		 * Hand off to libzfs.
766fa9e4066Sahrens 		 */
7670a48a24eStimh 		if (zpool_create(g_zfs, poolname,
7680a48a24eStimh 		    nvroot, props, fsprops) == 0) {
76999653d4eSeschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
770fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
771fa9e4066Sahrens 			if (pool != NULL) {
772fa9e4066Sahrens 				if (mountpoint != NULL)
773fa9e4066Sahrens 					verify(zfs_prop_set(pool,
774e9dbad6fSeschrock 					    zfs_prop_to_name(
775e9dbad6fSeschrock 					    ZFS_PROP_MOUNTPOINT),
776fa9e4066Sahrens 					    mountpoint) == 0);
777fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
778da6c28aaSamw 					ret = zfs_shareall(pool);
779fa9e4066Sahrens 				zfs_close(pool);
780fa9e4066Sahrens 			}
78199653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
78299653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
78399653d4eSeschrock 			    "been omitted\n"));
784fa9e4066Sahrens 		}
785fa9e4066Sahrens 	}
786fa9e4066Sahrens 
787990b4856Slling errout:
788fa9e4066Sahrens 	nvlist_free(nvroot);
7890a48a24eStimh 	nvlist_free(fsprops);
790990b4856Slling 	nvlist_free(props);
791fa9e4066Sahrens 	return (ret);
792990b4856Slling badusage:
7930a48a24eStimh 	nvlist_free(fsprops);
794990b4856Slling 	nvlist_free(props);
795990b4856Slling 	usage(B_FALSE);
796990b4856Slling 	return (2);
797fa9e4066Sahrens }
798fa9e4066Sahrens 
799fa9e4066Sahrens /*
800fa9e4066Sahrens  * zpool destroy <pool>
801fa9e4066Sahrens  *
802fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
803fa9e4066Sahrens  *
804fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
805fa9e4066Sahrens  */
806fa9e4066Sahrens int
807fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
808fa9e4066Sahrens {
80999653d4eSeschrock 	boolean_t force = B_FALSE;
810fa9e4066Sahrens 	int c;
811fa9e4066Sahrens 	char *pool;
812fa9e4066Sahrens 	zpool_handle_t *zhp;
813fa9e4066Sahrens 	int ret;
814fa9e4066Sahrens 
815fa9e4066Sahrens 	/* check options */
816fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
817fa9e4066Sahrens 		switch (c) {
818fa9e4066Sahrens 		case 'f':
81999653d4eSeschrock 			force = B_TRUE;
820fa9e4066Sahrens 			break;
821fa9e4066Sahrens 		case '?':
822fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
823fa9e4066Sahrens 			    optopt);
82499653d4eSeschrock 			usage(B_FALSE);
825fa9e4066Sahrens 		}
826fa9e4066Sahrens 	}
827fa9e4066Sahrens 
828fa9e4066Sahrens 	argc -= optind;
829fa9e4066Sahrens 	argv += optind;
830fa9e4066Sahrens 
831fa9e4066Sahrens 	/* check arguments */
832fa9e4066Sahrens 	if (argc < 1) {
833fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
83499653d4eSeschrock 		usage(B_FALSE);
835fa9e4066Sahrens 	}
836fa9e4066Sahrens 	if (argc > 1) {
837fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
83899653d4eSeschrock 		usage(B_FALSE);
839fa9e4066Sahrens 	}
840fa9e4066Sahrens 
841fa9e4066Sahrens 	pool = argv[0];
842fa9e4066Sahrens 
84399653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
844fa9e4066Sahrens 		/*
845fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
846fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
847fa9e4066Sahrens 		 */
848fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
849fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
850fa9e4066Sahrens 			    "destroy a dataset\n"));
851fa9e4066Sahrens 		return (1);
852fa9e4066Sahrens 	}
853fa9e4066Sahrens 
854f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
855fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
856fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
857fa9e4066Sahrens 		return (1);
858fa9e4066Sahrens 	}
859fa9e4066Sahrens 
860fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
861fa9e4066Sahrens 
862fa9e4066Sahrens 	zpool_close(zhp);
863fa9e4066Sahrens 
864fa9e4066Sahrens 	return (ret);
865fa9e4066Sahrens }
866fa9e4066Sahrens 
867fa9e4066Sahrens /*
868fa9e4066Sahrens  * zpool export [-f] <pool> ...
869fa9e4066Sahrens  *
870fa9e4066Sahrens  *	-f	Forcefully unmount datasets
871fa9e4066Sahrens  *
872b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
873fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
874fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
875fa9e4066Sahrens  */
876fa9e4066Sahrens int
877fa9e4066Sahrens zpool_do_export(int argc, char **argv)
878fa9e4066Sahrens {
87999653d4eSeschrock 	boolean_t force = B_FALSE;
880394ab0cbSGeorge Wilson 	boolean_t hardforce = B_FALSE;
881fa9e4066Sahrens 	int c;
882fa9e4066Sahrens 	zpool_handle_t *zhp;
883fa9e4066Sahrens 	int ret;
884fa9e4066Sahrens 	int i;
885fa9e4066Sahrens 
886fa9e4066Sahrens 	/* check options */
887394ab0cbSGeorge Wilson 	while ((c = getopt(argc, argv, "fF")) != -1) {
888fa9e4066Sahrens 		switch (c) {
889fa9e4066Sahrens 		case 'f':
89099653d4eSeschrock 			force = B_TRUE;
891fa9e4066Sahrens 			break;
892394ab0cbSGeorge Wilson 		case 'F':
893394ab0cbSGeorge Wilson 			hardforce = B_TRUE;
894394ab0cbSGeorge Wilson 			break;
895fa9e4066Sahrens 		case '?':
896fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
897fa9e4066Sahrens 			    optopt);
89899653d4eSeschrock 			usage(B_FALSE);
899fa9e4066Sahrens 		}
900fa9e4066Sahrens 	}
901fa9e4066Sahrens 
902fa9e4066Sahrens 	argc -= optind;
903fa9e4066Sahrens 	argv += optind;
904fa9e4066Sahrens 
905fa9e4066Sahrens 	/* check arguments */
906fa9e4066Sahrens 	if (argc < 1) {
907fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
90899653d4eSeschrock 		usage(B_FALSE);
909fa9e4066Sahrens 	}
910fa9e4066Sahrens 
911fa9e4066Sahrens 	ret = 0;
912fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
91399653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
914fa9e4066Sahrens 			ret = 1;
915fa9e4066Sahrens 			continue;
916fa9e4066Sahrens 		}
917fa9e4066Sahrens 
918f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
919fa9e4066Sahrens 			ret = 1;
920fa9e4066Sahrens 			zpool_close(zhp);
921fa9e4066Sahrens 			continue;
922fa9e4066Sahrens 		}
923fa9e4066Sahrens 
924394ab0cbSGeorge Wilson 		if (hardforce) {
925394ab0cbSGeorge Wilson 			if (zpool_export_force(zhp) != 0)
926fa9e4066Sahrens 				ret = 1;
927394ab0cbSGeorge Wilson 		} else if (zpool_export(zhp, force) != 0) {
928394ab0cbSGeorge Wilson 			ret = 1;
929394ab0cbSGeorge Wilson 		}
930fa9e4066Sahrens 
931fa9e4066Sahrens 		zpool_close(zhp);
932fa9e4066Sahrens 	}
933fa9e4066Sahrens 
934fa9e4066Sahrens 	return (ret);
935fa9e4066Sahrens }
936fa9e4066Sahrens 
937fa9e4066Sahrens /*
938fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
939fa9e4066Sahrens  * name column.
940fa9e4066Sahrens  */
941fa9e4066Sahrens static int
942c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
943fa9e4066Sahrens {
94499653d4eSeschrock 	char *name = zpool_vdev_name(g_zfs, zhp, nv);
945fa9e4066Sahrens 	nvlist_t **child;
946fa9e4066Sahrens 	uint_t c, children;
947fa9e4066Sahrens 	int ret;
948fa9e4066Sahrens 
949fa9e4066Sahrens 	if (strlen(name) + depth > max)
950fa9e4066Sahrens 		max = strlen(name) + depth;
951fa9e4066Sahrens 
952afefbcddSeschrock 	free(name);
953afefbcddSeschrock 
95499653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
95599653d4eSeschrock 	    &child, &children) == 0) {
956fa9e4066Sahrens 		for (c = 0; c < children; c++)
95799653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
95899653d4eSeschrock 			    max)) > max)
959fa9e4066Sahrens 				max = ret;
96099653d4eSeschrock 	}
96199653d4eSeschrock 
962fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
963fa94a07fSbrendan 	    &child, &children) == 0) {
964fa94a07fSbrendan 		for (c = 0; c < children; c++)
965fa94a07fSbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
966fa94a07fSbrendan 			    max)) > max)
967fa94a07fSbrendan 				max = ret;
968fa94a07fSbrendan 	}
969fa94a07fSbrendan 
97099653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
97199653d4eSeschrock 	    &child, &children) == 0) {
97299653d4eSeschrock 		for (c = 0; c < children; c++)
97399653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
97499653d4eSeschrock 			    max)) > max)
97599653d4eSeschrock 				max = ret;
97699653d4eSeschrock 	}
97799653d4eSeschrock 
978fa9e4066Sahrens 
979fa9e4066Sahrens 	return (max);
980fa9e4066Sahrens }
981fa9e4066Sahrens 
982fa9e4066Sahrens 
983fa9e4066Sahrens /*
984fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
985fa9e4066Sahrens  * pool, printing out the name and status for each one.
986fa9e4066Sahrens  */
987fa9e4066Sahrens void
9888654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
9898654d025Sperrin     boolean_t print_logs)
990fa9e4066Sahrens {
991fa9e4066Sahrens 	nvlist_t **child;
992fa9e4066Sahrens 	uint_t c, children;
993fa9e4066Sahrens 	vdev_stat_t *vs;
994afefbcddSeschrock 	char *type, *vname;
995fa9e4066Sahrens 
996fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
997fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
998fa9e4066Sahrens 		return;
999fa9e4066Sahrens 
1000fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
1001fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
1002fa9e4066Sahrens 
1003fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
1004990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1005fa9e4066Sahrens 
1006fa9e4066Sahrens 	if (vs->vs_aux != 0) {
10073d7072f8Seschrock 		(void) printf("  ");
1008fa9e4066Sahrens 
1009fa9e4066Sahrens 		switch (vs->vs_aux) {
1010fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
1011fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
1012fa9e4066Sahrens 			break;
1013fa9e4066Sahrens 
1014fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
1015fa9e4066Sahrens 			(void) printf(gettext("missing device"));
1016fa9e4066Sahrens 			break;
1017fa9e4066Sahrens 
1018fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
1019fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
1020fa9e4066Sahrens 			break;
1021fa9e4066Sahrens 
1022eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
1023eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
1024eaca9bbdSeschrock 			break;
1025eaca9bbdSeschrock 
10263d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
10273d7072f8Seschrock 			(void) printf(gettext("too many errors"));
10283d7072f8Seschrock 			break;
10293d7072f8Seschrock 
1030fa9e4066Sahrens 		default:
1031fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
1032fa9e4066Sahrens 			break;
1033fa9e4066Sahrens 		}
1034fa9e4066Sahrens 	}
1035fa9e4066Sahrens 	(void) printf("\n");
1036fa9e4066Sahrens 
1037fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1038fa9e4066Sahrens 	    &child, &children) != 0)
1039fa9e4066Sahrens 		return;
1040fa9e4066Sahrens 
1041afefbcddSeschrock 	for (c = 0; c < children; c++) {
10428654d025Sperrin 		uint64_t is_log = B_FALSE;
10438654d025Sperrin 
10448654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
10458654d025Sperrin 		    &is_log);
10468654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
10478654d025Sperrin 			continue;
10488654d025Sperrin 
104999653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1050afefbcddSeschrock 		print_import_config(vname, child[c],
10518654d025Sperrin 		    namewidth, depth + 2, B_FALSE);
1052afefbcddSeschrock 		free(vname);
1053afefbcddSeschrock 	}
105499653d4eSeschrock 
1055fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1056fa94a07fSbrendan 	    &child, &children) == 0) {
1057fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
1058fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1059fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1060fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1061fa94a07fSbrendan 			free(vname);
1062fa94a07fSbrendan 		}
1063fa94a07fSbrendan 	}
106499653d4eSeschrock 
1065fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1066fa94a07fSbrendan 	    &child, &children) == 0) {
106799653d4eSeschrock 		(void) printf(gettext("\tspares\n"));
106899653d4eSeschrock 		for (c = 0; c < children; c++) {
106999653d4eSeschrock 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
107099653d4eSeschrock 			(void) printf("\t  %s\n", vname);
107199653d4eSeschrock 			free(vname);
107299653d4eSeschrock 		}
1073fa9e4066Sahrens 	}
1074fa94a07fSbrendan }
1075fa9e4066Sahrens 
1076fa9e4066Sahrens /*
1077fa9e4066Sahrens  * Display the status for the given pool.
1078fa9e4066Sahrens  */
1079fa9e4066Sahrens static void
1080fa9e4066Sahrens show_import(nvlist_t *config)
1081fa9e4066Sahrens {
1082fa9e4066Sahrens 	uint64_t pool_state;
1083fa9e4066Sahrens 	vdev_stat_t *vs;
1084fa9e4066Sahrens 	char *name;
1085fa9e4066Sahrens 	uint64_t guid;
1086fa9e4066Sahrens 	char *msgid;
1087fa9e4066Sahrens 	nvlist_t *nvroot;
1088fa9e4066Sahrens 	int reason;
108946657f8dSmmusante 	const char *health;
1090fa9e4066Sahrens 	uint_t vsc;
1091fa9e4066Sahrens 	int namewidth;
1092fa9e4066Sahrens 
1093fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1094fa9e4066Sahrens 	    &name) == 0);
1095fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1096fa9e4066Sahrens 	    &guid) == 0);
1097fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1098fa9e4066Sahrens 	    &pool_state) == 0);
1099fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1100fa9e4066Sahrens 	    &nvroot) == 0);
1101fa9e4066Sahrens 
1102fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1103fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1104990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1105fa9e4066Sahrens 
1106fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1107fa9e4066Sahrens 
110846657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
110946657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
111046657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
11114c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
111246657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
11134c58d714Sdarrenm 	(void) printf("\n");
1114fa9e4066Sahrens 
1115fa9e4066Sahrens 	switch (reason) {
1116fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1117fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1118fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1119fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1120fa9e4066Sahrens 		    "from the system.\n"));
1121fa9e4066Sahrens 		break;
1122fa9e4066Sahrens 
1123fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1124fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1125fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1126fa9e4066Sahrens 		    "corrupted data.\n"));
1127fa9e4066Sahrens 		break;
1128fa9e4066Sahrens 
1129fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1130fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1131fa9e4066Sahrens 		break;
1132fa9e4066Sahrens 
1133441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1134441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1135441d80aaSlling 		    "are offlined.\n"));
1136441d80aaSlling 		break;
1137441d80aaSlling 
1138ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1139ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1140ea8dc4b6Seschrock 		    "corrupted.\n"));
1141ea8dc4b6Seschrock 		break;
1142ea8dc4b6Seschrock 
1143eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1144eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1145eaca9bbdSeschrock 		    "older on-disk version.\n"));
1146eaca9bbdSeschrock 		break;
1147eaca9bbdSeschrock 
1148eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1149eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1150eaca9bbdSeschrock 		    "incompatible version.\n"));
1151eaca9bbdSeschrock 		break;
1152b87f3af3Sperrin 
115395173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
115495173954Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
115595173954Sek110237 		    "another system.\n"));
115695173954Sek110237 		break;
1157b87f3af3Sperrin 
11583d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
11593d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
11603d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
11613d7072f8Seschrock 		    "faulted.\n"));
11623d7072f8Seschrock 		break;
11633d7072f8Seschrock 
1164b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
1165b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record cannot be "
1166b87f3af3Sperrin 		    "read.\n"));
1167b87f3af3Sperrin 		break;
1168b87f3af3Sperrin 
1169fa9e4066Sahrens 	default:
1170fa9e4066Sahrens 		/*
1171fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1172fa9e4066Sahrens 		 */
1173fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1174fa9e4066Sahrens 	}
1175fa9e4066Sahrens 
1176fa9e4066Sahrens 	/*
1177fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1178fa9e4066Sahrens 	 */
117946657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1180eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1181eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1182eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1183eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1184eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
118595173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
118695173954Sek110237 			(void) printf(gettext("action: The pool can be "
118795173954Sek110237 			    "imported using its name or numeric "
118895173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1189fa9e4066Sahrens 		else
1190eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1191eaca9bbdSeschrock 			    "imported using its name or numeric "
1192eaca9bbdSeschrock 			    "identifier.\n"));
119346657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1194fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1195fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1196eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1197fa9e4066Sahrens 	} else {
1198eaca9bbdSeschrock 		switch (reason) {
1199eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1200eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1201eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1202eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1203eaca9bbdSeschrock 			    "backup.\n"));
1204eaca9bbdSeschrock 			break;
1205eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1206eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1207eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1208fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1209fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1210fa9e4066Sahrens 			    "again.\n"));
1211eaca9bbdSeschrock 			break;
1212eaca9bbdSeschrock 		default:
1213fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1214fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1215fa9e4066Sahrens 		}
1216eaca9bbdSeschrock 	}
1217eaca9bbdSeschrock 
121846657f8dSmmusante 	/*
121946657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
122046657f8dSmmusante 	 * is "corrupt data":
122146657f8dSmmusante 	 */
122246657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
122346657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
122446657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1225eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1226eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1227eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1228eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1229eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
123018ce54dfSek110237 			    "another system, but can be imported using\n\t"
1231eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1232eaca9bbdSeschrock 	}
1233fa9e4066Sahrens 
1234fa9e4066Sahrens 	if (msgid != NULL)
1235fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1236fa9e4066Sahrens 		    msgid);
1237fa9e4066Sahrens 
1238fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1239fa9e4066Sahrens 
1240c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1241fa9e4066Sahrens 	if (namewidth < 10)
1242fa9e4066Sahrens 		namewidth = 10;
12438654d025Sperrin 
12448654d025Sperrin 	print_import_config(name, nvroot, namewidth, 0, B_FALSE);
12458654d025Sperrin 	if (num_logs(nvroot) > 0) {
12468654d025Sperrin 		(void) printf(gettext("\tlogs\n"));
12478654d025Sperrin 		print_import_config(name, nvroot, namewidth, 0, B_TRUE);
12488654d025Sperrin 	}
1249fa9e4066Sahrens 
1250fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
125146657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1252fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
125346657f8dSmmusante 		    "configuration cannot be determined.\n"));
1254fa9e4066Sahrens 	}
1255fa9e4066Sahrens }
1256fa9e4066Sahrens 
1257fa9e4066Sahrens /*
1258fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1259990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1260990b4856Slling  * within the pool.
1261fa9e4066Sahrens  */
1262fa9e4066Sahrens static int
1263fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
1264c5904d13Seschrock     int force, nvlist_t *props, boolean_t allowfaulted)
1265fa9e4066Sahrens {
1266fa9e4066Sahrens 	zpool_handle_t *zhp;
1267fa9e4066Sahrens 	char *name;
1268fa9e4066Sahrens 	uint64_t state;
1269eaca9bbdSeschrock 	uint64_t version;
1270ecd6cf80Smarks 	int error = 0;
1271fa9e4066Sahrens 
1272fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1273fa9e4066Sahrens 	    &name) == 0);
1274fa9e4066Sahrens 
1275fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1276fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1277eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1278eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1279e7437265Sahrens 	if (version > SPA_VERSION) {
1280eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1281eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1282eaca9bbdSeschrock 		return (1);
1283eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
128495173954Sek110237 		uint64_t hostid;
128595173954Sek110237 
128695173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
128795173954Sek110237 		    &hostid) == 0) {
128895173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
128995173954Sek110237 				char *hostname;
129095173954Sek110237 				uint64_t timestamp;
129195173954Sek110237 				time_t t;
129295173954Sek110237 
129395173954Sek110237 				verify(nvlist_lookup_string(config,
129495173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
129595173954Sek110237 				verify(nvlist_lookup_uint64(config,
129695173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
129795173954Sek110237 				t = timestamp;
129895173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
129995173954Sek110237 				    "'%s': pool may be in use from other "
130095173954Sek110237 				    "system, it was last accessed by %s "
130195173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
130295173954Sek110237 				    (unsigned long)hostid,
130395173954Sek110237 				    asctime(localtime(&t)));
130495173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
130595173954Sek110237 				    "import anyway\n"));
1306fa9e4066Sahrens 				return (1);
1307fa9e4066Sahrens 			}
130895173954Sek110237 		} else {
130995173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
131095173954Sek110237 			    "pool may be in use from other system\n"), name);
131195173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
131295173954Sek110237 			    "anyway\n"));
131395173954Sek110237 			return (1);
131495173954Sek110237 		}
131595173954Sek110237 	}
1316fa9e4066Sahrens 
1317c5904d13Seschrock 	if (zpool_import_props(g_zfs, config, newname, props,
1318c5904d13Seschrock 	    allowfaulted) != 0)
1319fa9e4066Sahrens 		return (1);
1320fa9e4066Sahrens 
1321fa9e4066Sahrens 	if (newname != NULL)
1322fa9e4066Sahrens 		name = (char *)newname;
1323fa9e4066Sahrens 
1324c5904d13Seschrock 	verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL);
1325fa9e4066Sahrens 
1326379c004dSEric Schrock 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
1327379c004dSEric Schrock 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1328fa9e4066Sahrens 		zpool_close(zhp);
1329fa9e4066Sahrens 		return (1);
1330fa9e4066Sahrens 	}
1331fa9e4066Sahrens 
1332fa9e4066Sahrens 	zpool_close(zhp);
1333ecd6cf80Smarks 	return (error);
1334fa9e4066Sahrens }
1335fa9e4066Sahrens 
1336fa9e4066Sahrens /*
13374c58d714Sdarrenm  * zpool import [-d dir] [-D]
13382f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
13392f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
13402f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
13412f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] <pool | id> [newpool]
13422f8aaab3Seschrock  *
13432f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
13442f8aaab3Seschrock  *		devices.
1345fa9e4066Sahrens  *
1346fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1347fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1348fa9e4066Sahrens  *
13494c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
13504c58d714Sdarrenm  *              specified destroyed pools.
13514c58d714Sdarrenm  *
1352fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1353fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1354fa9e4066Sahrens  *		is rebooted.
1355fa9e4066Sahrens  *
1356fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1357fa9e4066Sahrens  *
1358c5904d13Seschrock  *       -F	Import even in the presence of faulted vdevs.  This is an
1359c5904d13Seschrock  *       	intentionally undocumented option for testing purposes, and
1360c5904d13Seschrock  *       	treats the pool configuration as complete, leaving any bad
1361c5904d13Seschrock  *		vdevs in the FAULTED state.
1362c5904d13Seschrock  *
1363fa9e4066Sahrens  *       -a	Import all pools found.
1364fa9e4066Sahrens  *
1365990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1366ecd6cf80Smarks  *
1367fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1368fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1369fa9e4066Sahrens  */
1370fa9e4066Sahrens int
1371fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1372fa9e4066Sahrens {
1373fa9e4066Sahrens 	char **searchdirs = NULL;
1374fa9e4066Sahrens 	int nsearch = 0;
1375fa9e4066Sahrens 	int c;
1376fa9e4066Sahrens 	int err;
13772f8aaab3Seschrock 	nvlist_t *pools = NULL;
137899653d4eSeschrock 	boolean_t do_all = B_FALSE;
137999653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1380fa9e4066Sahrens 	char *mntopts = NULL;
138199653d4eSeschrock 	boolean_t do_force = B_FALSE;
1382fa9e4066Sahrens 	nvpair_t *elem;
1383fa9e4066Sahrens 	nvlist_t *config;
138424e697d4Sck153898 	uint64_t searchguid = 0;
138524e697d4Sck153898 	char *searchname = NULL;
1386990b4856Slling 	char *propval;
1387fa9e4066Sahrens 	nvlist_t *found_config;
1388ecd6cf80Smarks 	nvlist_t *props = NULL;
138999653d4eSeschrock 	boolean_t first;
1390c5904d13Seschrock 	boolean_t allow_faulted = B_FALSE;
13914c58d714Sdarrenm 	uint64_t pool_state;
13922f8aaab3Seschrock 	char *cachefile = NULL;
1393fa9e4066Sahrens 
1394fa9e4066Sahrens 	/* check options */
1395c5904d13Seschrock 	while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) {
1396fa9e4066Sahrens 		switch (c) {
1397fa9e4066Sahrens 		case 'a':
139899653d4eSeschrock 			do_all = B_TRUE;
1399fa9e4066Sahrens 			break;
14002f8aaab3Seschrock 		case 'c':
14012f8aaab3Seschrock 			cachefile = optarg;
14022f8aaab3Seschrock 			break;
1403fa9e4066Sahrens 		case 'd':
1404fa9e4066Sahrens 			if (searchdirs == NULL) {
1405fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1406fa9e4066Sahrens 			} else {
1407fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1408fa9e4066Sahrens 				    sizeof (char *));
1409fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1410fa9e4066Sahrens 				    sizeof (char *));
1411fa9e4066Sahrens 				free(searchdirs);
1412fa9e4066Sahrens 				searchdirs = tmp;
1413fa9e4066Sahrens 			}
1414fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1415fa9e4066Sahrens 			break;
14164c58d714Sdarrenm 		case 'D':
141799653d4eSeschrock 			do_destroyed = B_TRUE;
14184c58d714Sdarrenm 			break;
1419fa9e4066Sahrens 		case 'f':
142099653d4eSeschrock 			do_force = B_TRUE;
1421fa9e4066Sahrens 			break;
1422c5904d13Seschrock 		case 'F':
1423c5904d13Seschrock 			allow_faulted = B_TRUE;
1424c5904d13Seschrock 			break;
1425fa9e4066Sahrens 		case 'o':
1426990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1427990b4856Slling 				*propval = '\0';
1428990b4856Slling 				propval++;
14290a48a24eStimh 				if (add_prop_list(optarg, propval,
14300a48a24eStimh 				    &props, B_TRUE))
1431990b4856Slling 					goto error;
1432990b4856Slling 			} else {
1433fa9e4066Sahrens 				mntopts = optarg;
1434990b4856Slling 			}
1435fa9e4066Sahrens 			break;
1436fa9e4066Sahrens 		case 'R':
1437990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
14380a48a24eStimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1439990b4856Slling 				goto error;
14402f8aaab3Seschrock 			if (nvlist_lookup_string(props,
14412f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
14422f8aaab3Seschrock 			    &propval) == 0)
14432f8aaab3Seschrock 				break;
1444990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
14450a48a24eStimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1446990b4856Slling 				goto error;
1447fa9e4066Sahrens 			break;
1448fa9e4066Sahrens 		case ':':
1449fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1450fa9e4066Sahrens 			    "'%c' option\n"), optopt);
145199653d4eSeschrock 			usage(B_FALSE);
1452fa9e4066Sahrens 			break;
1453fa9e4066Sahrens 		case '?':
1454fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1455fa9e4066Sahrens 			    optopt);
145699653d4eSeschrock 			usage(B_FALSE);
1457fa9e4066Sahrens 		}
1458fa9e4066Sahrens 	}
1459fa9e4066Sahrens 
1460fa9e4066Sahrens 	argc -= optind;
1461fa9e4066Sahrens 	argv += optind;
1462fa9e4066Sahrens 
14632f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
14642f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
14652f8aaab3Seschrock 		usage(B_FALSE);
14662f8aaab3Seschrock 	}
14672f8aaab3Seschrock 
1468fa9e4066Sahrens 	if (searchdirs == NULL) {
1469fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1470fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1471fa9e4066Sahrens 		nsearch = 1;
1472fa9e4066Sahrens 	}
1473fa9e4066Sahrens 
1474fa9e4066Sahrens 	/* check argument count */
1475fa9e4066Sahrens 	if (do_all) {
1476fa9e4066Sahrens 		if (argc != 0) {
1477fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
147899653d4eSeschrock 			usage(B_FALSE);
1479fa9e4066Sahrens 		}
1480fa9e4066Sahrens 	} else {
1481fa9e4066Sahrens 		if (argc > 2) {
1482fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
148399653d4eSeschrock 			usage(B_FALSE);
1484fa9e4066Sahrens 		}
1485fa9e4066Sahrens 
1486fa9e4066Sahrens 		/*
1487fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1488fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1489fa9e4066Sahrens 		 * silently fail.
1490fa9e4066Sahrens 		 */
1491fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1492fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1493fa9e4066Sahrens 			    "discover pools: permission denied\n"));
149499653d4eSeschrock 			free(searchdirs);
1495fa9e4066Sahrens 			return (1);
1496fa9e4066Sahrens 		}
1497fa9e4066Sahrens 	}
1498fa9e4066Sahrens 
1499fa9e4066Sahrens 	/*
1500fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1501fa9e4066Sahrens 	 *
1502fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1503fa9e4066Sahrens 	 *		each one.
1504fa9e4066Sahrens 	 *
1505fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1506fa9e4066Sahrens 	 *
1507fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1508fa9e4066Sahrens 	 *		name and import that one.
15094c58d714Sdarrenm 	 *
15104c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1511fa9e4066Sahrens 	 */
1512fa9e4066Sahrens 	if (argc != 0) {
1513fa9e4066Sahrens 		char *endptr;
1514fa9e4066Sahrens 
1515fa9e4066Sahrens 		errno = 0;
1516fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1517fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1518fa9e4066Sahrens 			searchname = argv[0];
1519fa9e4066Sahrens 		found_config = NULL;
1520fa9e4066Sahrens 	}
1521fa9e4066Sahrens 
152224e697d4Sck153898 	if (cachefile) {
1523e829d913Sck153898 		pools = zpool_find_import_cached(g_zfs, cachefile, searchname,
1524e829d913Sck153898 		    searchguid);
152524e697d4Sck153898 	} else if (searchname != NULL) {
152624e697d4Sck153898 		pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs,
152724e697d4Sck153898 		    searchname);
152824e697d4Sck153898 	} else {
152924e697d4Sck153898 		/*
153024e697d4Sck153898 		 * It's OK to search by guid even if searchguid is 0.
153124e697d4Sck153898 		 */
153224e697d4Sck153898 		pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs,
153324e697d4Sck153898 		    searchguid);
153424e697d4Sck153898 	}
153524e697d4Sck153898 
153624e697d4Sck153898 	if (pools == NULL) {
153724e697d4Sck153898 		if (argc != 0) {
153824e697d4Sck153898 			(void) fprintf(stderr, gettext("cannot import '%s': "
153924e697d4Sck153898 			    "no such pool available\n"), argv[0]);
154024e697d4Sck153898 		}
154124e697d4Sck153898 		free(searchdirs);
154224e697d4Sck153898 		return (1);
154324e697d4Sck153898 	}
154424e697d4Sck153898 
154524e697d4Sck153898 	/*
154624e697d4Sck153898 	 * At this point we have a list of import candidate configs. Even if
154724e697d4Sck153898 	 * we were searching by pool name or guid, we still need to
154824e697d4Sck153898 	 * post-process the list to deal with pool state and possible
154924e697d4Sck153898 	 * duplicate names.
155024e697d4Sck153898 	 */
1551fa9e4066Sahrens 	err = 0;
1552fa9e4066Sahrens 	elem = NULL;
155399653d4eSeschrock 	first = B_TRUE;
1554fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1555fa9e4066Sahrens 
1556fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1557fa9e4066Sahrens 
15584c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
15594c58d714Sdarrenm 		    &pool_state) == 0);
15604c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
15614c58d714Sdarrenm 			continue;
15624c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
15634c58d714Sdarrenm 			continue;
15644c58d714Sdarrenm 
1565fa9e4066Sahrens 		if (argc == 0) {
1566fa9e4066Sahrens 			if (first)
156799653d4eSeschrock 				first = B_FALSE;
15683bb79becSeschrock 			else if (!do_all)
1569fa9e4066Sahrens 				(void) printf("\n");
1570fa9e4066Sahrens 
1571fa9e4066Sahrens 			if (do_all)
1572fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1573c5904d13Seschrock 				    do_force, props, allow_faulted);
1574fa9e4066Sahrens 			else
1575fa9e4066Sahrens 				show_import(config);
1576fa9e4066Sahrens 		} else if (searchname != NULL) {
1577fa9e4066Sahrens 			char *name;
1578fa9e4066Sahrens 
1579fa9e4066Sahrens 			/*
1580fa9e4066Sahrens 			 * We are searching for a pool based on name.
1581fa9e4066Sahrens 			 */
1582fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1583fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1584fa9e4066Sahrens 
1585fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1586fa9e4066Sahrens 				if (found_config != NULL) {
1587fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1588fa9e4066Sahrens 					    "cannot import '%s': more than "
1589fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1590fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1591fa9e4066Sahrens 					    "import by numeric ID instead\n"));
159299653d4eSeschrock 					err = B_TRUE;
1593fa9e4066Sahrens 				}
1594fa9e4066Sahrens 				found_config = config;
1595fa9e4066Sahrens 			}
1596fa9e4066Sahrens 		} else {
1597fa9e4066Sahrens 			uint64_t guid;
1598fa9e4066Sahrens 
1599fa9e4066Sahrens 			/*
1600fa9e4066Sahrens 			 * Search for a pool by guid.
1601fa9e4066Sahrens 			 */
1602fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1603fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1604fa9e4066Sahrens 
1605fa9e4066Sahrens 			if (guid == searchguid)
1606fa9e4066Sahrens 				found_config = config;
1607fa9e4066Sahrens 		}
1608fa9e4066Sahrens 	}
1609fa9e4066Sahrens 
1610fa9e4066Sahrens 	/*
1611fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1612fa9e4066Sahrens 	 * pool, and then do the import.
1613fa9e4066Sahrens 	 */
1614fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1615fa9e4066Sahrens 		if (found_config == NULL) {
1616fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1617fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
161899653d4eSeschrock 			err = B_TRUE;
1619fa9e4066Sahrens 		} else {
1620fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1621c5904d13Seschrock 			    argv[1], mntopts, do_force, props, allow_faulted);
1622fa9e4066Sahrens 		}
1623fa9e4066Sahrens 	}
1624fa9e4066Sahrens 
1625fa9e4066Sahrens 	/*
1626fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1627fa9e4066Sahrens 	 * found.
1628fa9e4066Sahrens 	 */
1629fa9e4066Sahrens 	if (argc == 0 && first)
1630fa9e4066Sahrens 		(void) fprintf(stderr,
1631fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1632fa9e4066Sahrens 
1633ecd6cf80Smarks error:
1634ecd6cf80Smarks 	nvlist_free(props);
1635fa9e4066Sahrens 	nvlist_free(pools);
163699653d4eSeschrock 	free(searchdirs);
1637fa9e4066Sahrens 
1638fa9e4066Sahrens 	return (err ? 1 : 0);
1639fa9e4066Sahrens }
1640fa9e4066Sahrens 
1641fa9e4066Sahrens typedef struct iostat_cbdata {
1642fa9e4066Sahrens 	zpool_list_t *cb_list;
1643fa9e4066Sahrens 	int cb_verbose;
1644fa9e4066Sahrens 	int cb_iteration;
1645fa9e4066Sahrens 	int cb_namewidth;
1646fa9e4066Sahrens } iostat_cbdata_t;
1647fa9e4066Sahrens 
1648fa9e4066Sahrens static void
1649fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1650fa9e4066Sahrens {
1651fa9e4066Sahrens 	int i = 0;
1652fa9e4066Sahrens 
1653fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1654fa9e4066Sahrens 		(void) printf("-");
1655fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1656fa9e4066Sahrens }
1657fa9e4066Sahrens 
1658fa9e4066Sahrens static void
1659fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1660fa9e4066Sahrens {
1661fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1662fa9e4066Sahrens 	    cb->cb_namewidth, "");
1663fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1664fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1665fa9e4066Sahrens 	print_iostat_separator(cb);
1666fa9e4066Sahrens }
1667fa9e4066Sahrens 
1668fa9e4066Sahrens /*
1669fa9e4066Sahrens  * Display a single statistic.
1670fa9e4066Sahrens  */
1671990b4856Slling static void
1672fa9e4066Sahrens print_one_stat(uint64_t value)
1673fa9e4066Sahrens {
1674fa9e4066Sahrens 	char buf[64];
1675fa9e4066Sahrens 
1676fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1677fa9e4066Sahrens 	(void) printf("  %5s", buf);
1678fa9e4066Sahrens }
1679fa9e4066Sahrens 
1680fa9e4066Sahrens /*
1681fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1682fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1683fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1684fa9e4066Sahrens  */
1685fa9e4066Sahrens void
1686c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1687c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1688fa9e4066Sahrens {
1689fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1690fa9e4066Sahrens 	uint_t c, children;
1691fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1692fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1693fa9e4066Sahrens 	uint64_t tdelta;
1694fa9e4066Sahrens 	double scale;
1695afefbcddSeschrock 	char *vname;
1696fa9e4066Sahrens 
1697fa9e4066Sahrens 	if (oldnv != NULL) {
1698fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1699fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1700fa9e4066Sahrens 	} else {
1701fa9e4066Sahrens 		oldvs = &zerovs;
1702fa9e4066Sahrens 	}
1703fa9e4066Sahrens 
1704fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1705fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1706fa9e4066Sahrens 
1707fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1708fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1709fa9e4066Sahrens 	else
1710fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1711fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1712fa9e4066Sahrens 
1713fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1714fa9e4066Sahrens 
1715fa9e4066Sahrens 	if (tdelta == 0)
1716fa9e4066Sahrens 		scale = 1.0;
1717fa9e4066Sahrens 	else
1718fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1719fa9e4066Sahrens 
1720fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1721fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1722fa9e4066Sahrens 		(void) printf("      -      -");
1723fa9e4066Sahrens 	} else {
1724fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1725fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1726fa9e4066Sahrens 	}
1727fa9e4066Sahrens 
1728fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1729fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1730fa9e4066Sahrens 
1731fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1732fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1733fa9e4066Sahrens 
1734fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1735fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1736fa9e4066Sahrens 
1737fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1738fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1739fa9e4066Sahrens 
1740fa9e4066Sahrens 	(void) printf("\n");
1741fa9e4066Sahrens 
1742fa9e4066Sahrens 	if (!cb->cb_verbose)
1743fa9e4066Sahrens 		return;
1744fa9e4066Sahrens 
1745fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1746fa9e4066Sahrens 	    &newchild, &children) != 0)
1747fa9e4066Sahrens 		return;
1748fa9e4066Sahrens 
1749fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1750fa9e4066Sahrens 	    &oldchild, &c) != 0)
1751fa9e4066Sahrens 		return;
1752fa9e4066Sahrens 
1753afefbcddSeschrock 	for (c = 0; c < children; c++) {
175499653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1755c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1756afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1757afefbcddSeschrock 		free(vname);
1758afefbcddSeschrock 	}
1759fa94a07fSbrendan 
1760fa94a07fSbrendan 	/*
1761fa94a07fSbrendan 	 * Include level 2 ARC devices in iostat output
1762fa94a07fSbrendan 	 */
1763fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
1764fa94a07fSbrendan 	    &newchild, &children) != 0)
1765fa94a07fSbrendan 		return;
1766fa94a07fSbrendan 
1767fa94a07fSbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
1768fa94a07fSbrendan 	    &oldchild, &c) != 0)
1769fa94a07fSbrendan 		return;
1770fa94a07fSbrendan 
1771fa94a07fSbrendan 	if (children > 0) {
1772fa94a07fSbrendan 		(void) printf("%-*s      -      -      -      -      -      "
1773fa94a07fSbrendan 		    "-\n", cb->cb_namewidth, "cache");
1774fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1775fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1776fa94a07fSbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1777fa94a07fSbrendan 			    newchild[c], cb, depth + 2);
1778fa94a07fSbrendan 			free(vname);
1779fa94a07fSbrendan 		}
1780fa94a07fSbrendan 	}
1781fa9e4066Sahrens }
1782fa9e4066Sahrens 
1783088e9d47Seschrock static int
1784088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
1785088e9d47Seschrock {
1786088e9d47Seschrock 	iostat_cbdata_t *cb = data;
178794de1d4cSeschrock 	boolean_t missing;
1788088e9d47Seschrock 
1789088e9d47Seschrock 	/*
1790088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
1791088e9d47Seschrock 	 */
179294de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
179394de1d4cSeschrock 		return (-1);
179494de1d4cSeschrock 
179594de1d4cSeschrock 	if (missing)
1796088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
1797088e9d47Seschrock 
1798088e9d47Seschrock 	return (0);
1799088e9d47Seschrock }
1800088e9d47Seschrock 
1801fa9e4066Sahrens /*
1802fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
1803fa9e4066Sahrens  */
1804fa9e4066Sahrens int
1805fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
1806fa9e4066Sahrens {
1807fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1808fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
1809fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
1810fa9e4066Sahrens 
1811088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
1812fa9e4066Sahrens 
1813088e9d47Seschrock 	if (cb->cb_iteration == 1)
1814fa9e4066Sahrens 		oldconfig = NULL;
1815fa9e4066Sahrens 
1816fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1817fa9e4066Sahrens 	    &newnvroot) == 0);
1818fa9e4066Sahrens 
1819088e9d47Seschrock 	if (oldconfig == NULL)
1820fa9e4066Sahrens 		oldnvroot = NULL;
1821088e9d47Seschrock 	else
1822088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
1823088e9d47Seschrock 		    &oldnvroot) == 0);
1824fa9e4066Sahrens 
1825fa9e4066Sahrens 	/*
1826fa9e4066Sahrens 	 * Print out the statistics for the pool.
1827fa9e4066Sahrens 	 */
1828c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1829fa9e4066Sahrens 
1830fa9e4066Sahrens 	if (cb->cb_verbose)
1831fa9e4066Sahrens 		print_iostat_separator(cb);
1832fa9e4066Sahrens 
1833fa9e4066Sahrens 	return (0);
1834fa9e4066Sahrens }
1835fa9e4066Sahrens 
1836fa9e4066Sahrens int
1837fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
1838fa9e4066Sahrens {
1839fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1840fa9e4066Sahrens 	nvlist_t *config, *nvroot;
1841fa9e4066Sahrens 
1842088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
1843fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1844fa9e4066Sahrens 		    &nvroot) == 0);
1845fa9e4066Sahrens 		if (!cb->cb_verbose)
1846fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1847fa9e4066Sahrens 		else
1848c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
1849fa9e4066Sahrens 	}
1850fa9e4066Sahrens 
1851fa9e4066Sahrens 	/*
1852fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
1853fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
1854fa9e4066Sahrens 	 */
1855fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
1856fa9e4066Sahrens 		cb->cb_namewidth = 10;
1857fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
1858fa9e4066Sahrens 		cb->cb_namewidth = 38;
1859fa9e4066Sahrens 
1860fa9e4066Sahrens 	return (0);
1861fa9e4066Sahrens }
1862fa9e4066Sahrens 
1863fa9e4066Sahrens /*
1864fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
1865fa9e4066Sahrens  *
1866fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
1867fa9e4066Sahrens  *
1868fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
1869fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
1870fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1871fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
1872fa9e4066Sahrens  * changes are all handled within libzfs.
1873fa9e4066Sahrens  */
1874fa9e4066Sahrens int
1875fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
1876fa9e4066Sahrens {
1877fa9e4066Sahrens 	int c;
1878fa9e4066Sahrens 	int ret;
1879fa9e4066Sahrens 	int npools;
1880fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
1881fa9e4066Sahrens 	zpool_list_t *list;
188299653d4eSeschrock 	boolean_t verbose = B_FALSE;
1883fa9e4066Sahrens 	iostat_cbdata_t cb;
1884fa9e4066Sahrens 
1885fa9e4066Sahrens 	/* check options */
1886fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
1887fa9e4066Sahrens 		switch (c) {
1888fa9e4066Sahrens 		case 'v':
188999653d4eSeschrock 			verbose = B_TRUE;
1890fa9e4066Sahrens 			break;
1891fa9e4066Sahrens 		case '?':
1892fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1893fa9e4066Sahrens 			    optopt);
189499653d4eSeschrock 			usage(B_FALSE);
1895fa9e4066Sahrens 		}
1896fa9e4066Sahrens 	}
1897fa9e4066Sahrens 
1898fa9e4066Sahrens 	argc -= optind;
1899fa9e4066Sahrens 	argv += optind;
1900fa9e4066Sahrens 
1901fa9e4066Sahrens 	/*
1902fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
1903fa9e4066Sahrens 	 */
1904fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1905fa9e4066Sahrens 		char *end;
1906fa9e4066Sahrens 
1907fa9e4066Sahrens 		errno = 0;
1908fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1909fa9e4066Sahrens 
1910fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1911fa9e4066Sahrens 			if (interval == 0) {
1912fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1913fa9e4066Sahrens 				    "cannot be zero\n"));
191499653d4eSeschrock 				usage(B_FALSE);
1915fa9e4066Sahrens 			}
1916fa9e4066Sahrens 
1917fa9e4066Sahrens 			/*
1918fa9e4066Sahrens 			 * Ignore the last parameter
1919fa9e4066Sahrens 			 */
1920fa9e4066Sahrens 			argc--;
1921fa9e4066Sahrens 		} else {
1922fa9e4066Sahrens 			/*
1923fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
1924fa9e4066Sahrens 			 * user will get a more informative error message later
1925fa9e4066Sahrens 			 * on.
1926fa9e4066Sahrens 			 */
1927fa9e4066Sahrens 			interval = 0;
1928fa9e4066Sahrens 		}
1929fa9e4066Sahrens 	}
1930fa9e4066Sahrens 
1931fa9e4066Sahrens 	/*
1932fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
1933fa9e4066Sahrens 	 * and an integer.
1934fa9e4066Sahrens 	 */
1935fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1936fa9e4066Sahrens 		char *end;
1937fa9e4066Sahrens 
1938fa9e4066Sahrens 		errno = 0;
1939fa9e4066Sahrens 		count = interval;
1940fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1941fa9e4066Sahrens 
1942fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1943fa9e4066Sahrens 			if (interval == 0) {
1944fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1945fa9e4066Sahrens 				    "cannot be zero\n"));
194699653d4eSeschrock 				usage(B_FALSE);
1947fa9e4066Sahrens 			}
1948fa9e4066Sahrens 
1949fa9e4066Sahrens 			/*
1950fa9e4066Sahrens 			 * Ignore the last parameter
1951fa9e4066Sahrens 			 */
1952fa9e4066Sahrens 			argc--;
1953fa9e4066Sahrens 		} else {
1954fa9e4066Sahrens 			interval = 0;
1955fa9e4066Sahrens 		}
1956fa9e4066Sahrens 	}
1957fa9e4066Sahrens 
1958fa9e4066Sahrens 	/*
1959fa9e4066Sahrens 	 * Construct the list of all interesting pools.
1960fa9e4066Sahrens 	 */
1961fa9e4066Sahrens 	ret = 0;
1962b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
1963fa9e4066Sahrens 		return (1);
1964fa9e4066Sahrens 
196599653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
196699653d4eSeschrock 		pool_list_free(list);
1967fa9e4066Sahrens 		return (1);
196899653d4eSeschrock 	}
1969fa9e4066Sahrens 
1970fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
197199653d4eSeschrock 		pool_list_free(list);
1972fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
1973fa9e4066Sahrens 		return (1);
1974fa9e4066Sahrens 	}
1975fa9e4066Sahrens 
1976fa9e4066Sahrens 	/*
1977fa9e4066Sahrens 	 * Enter the main iostat loop.
1978fa9e4066Sahrens 	 */
1979fa9e4066Sahrens 	cb.cb_list = list;
1980fa9e4066Sahrens 	cb.cb_verbose = verbose;
1981fa9e4066Sahrens 	cb.cb_iteration = 0;
1982fa9e4066Sahrens 	cb.cb_namewidth = 0;
1983fa9e4066Sahrens 
1984fa9e4066Sahrens 	for (;;) {
1985fa9e4066Sahrens 		pool_list_update(list);
1986fa9e4066Sahrens 
1987fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
1988fa9e4066Sahrens 			break;
1989fa9e4066Sahrens 
1990fa9e4066Sahrens 		/*
1991088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
1992088e9d47Seschrock 		 * before calculating the maximum name width, so that any
1993088e9d47Seschrock 		 * configuration changes are properly accounted for.
1994088e9d47Seschrock 		 */
199599653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
1996088e9d47Seschrock 
1997088e9d47Seschrock 		/*
1998fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
1999fa9e4066Sahrens 		 * for the pool / device name column across all pools.
2000fa9e4066Sahrens 		 */
2001fa9e4066Sahrens 		cb.cb_namewidth = 0;
200299653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2003fa9e4066Sahrens 
2004fa9e4066Sahrens 		/*
2005fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
2006fa9e4066Sahrens 		 */
2007fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
2008fa9e4066Sahrens 			print_iostat_header(&cb);
2009fa9e4066Sahrens 
201099653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2011fa9e4066Sahrens 
2012fa9e4066Sahrens 		/*
2013fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
2014fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
2015fa9e4066Sahrens 		 */
2016fa9e4066Sahrens 		if (npools > 1 && !verbose)
2017fa9e4066Sahrens 			print_iostat_separator(&cb);
2018fa9e4066Sahrens 
2019fa9e4066Sahrens 		if (verbose)
2020fa9e4066Sahrens 			(void) printf("\n");
2021fa9e4066Sahrens 
202239c23413Seschrock 		/*
202339c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
202439c23413Seschrock 		 * indefinitely.
202539c23413Seschrock 		 */
202639c23413Seschrock 		(void) fflush(stdout);
202739c23413Seschrock 
2028fa9e4066Sahrens 		if (interval == 0)
2029fa9e4066Sahrens 			break;
2030fa9e4066Sahrens 
2031fa9e4066Sahrens 		if (count != 0 && --count == 0)
2032fa9e4066Sahrens 			break;
2033fa9e4066Sahrens 
2034fa9e4066Sahrens 		(void) sleep(interval);
2035fa9e4066Sahrens 	}
2036fa9e4066Sahrens 
2037fa9e4066Sahrens 	pool_list_free(list);
2038fa9e4066Sahrens 
2039fa9e4066Sahrens 	return (ret);
2040fa9e4066Sahrens }
2041fa9e4066Sahrens 
2042fa9e4066Sahrens typedef struct list_cbdata {
204399653d4eSeschrock 	boolean_t	cb_scripted;
204499653d4eSeschrock 	boolean_t	cb_first;
2045990b4856Slling 	zprop_list_t	*cb_proplist;
2046fa9e4066Sahrens } list_cbdata_t;
2047fa9e4066Sahrens 
2048fa9e4066Sahrens /*
2049fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
2050fa9e4066Sahrens  */
2051990b4856Slling static void
2052990b4856Slling print_header(zprop_list_t *pl)
2053fa9e4066Sahrens {
2054990b4856Slling 	const char *header;
2055990b4856Slling 	boolean_t first = B_TRUE;
2056990b4856Slling 	boolean_t right_justify;
2057fa9e4066Sahrens 
2058990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2059990b4856Slling 		if (pl->pl_prop == ZPROP_INVAL)
2060990b4856Slling 			continue;
2061990b4856Slling 
2062990b4856Slling 		if (!first)
2063fa9e4066Sahrens 			(void) printf("  ");
2064fa9e4066Sahrens 		else
2065990b4856Slling 			first = B_FALSE;
2066fa9e4066Sahrens 
2067990b4856Slling 		header = zpool_prop_column_name(pl->pl_prop);
2068990b4856Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
2069990b4856Slling 
2070990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
2071990b4856Slling 			(void) printf("%s", header);
2072990b4856Slling 		else if (right_justify)
2073990b4856Slling 			(void) printf("%*s", pl->pl_width, header);
2074990b4856Slling 		else
2075990b4856Slling 			(void) printf("%-*s", pl->pl_width, header);
2076fa9e4066Sahrens 	}
2077fa9e4066Sahrens 
2078fa9e4066Sahrens 	(void) printf("\n");
2079fa9e4066Sahrens }
2080fa9e4066Sahrens 
2081990b4856Slling /*
2082990b4856Slling  * Given a pool and a list of properties, print out all the properties according
2083990b4856Slling  * to the described layout.
2084990b4856Slling  */
2085990b4856Slling static void
2086990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
2087990b4856Slling {
2088990b4856Slling 	boolean_t first = B_TRUE;
2089990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
2090990b4856Slling 	char *propstr;
2091990b4856Slling 	boolean_t right_justify;
2092990b4856Slling 	int width;
2093990b4856Slling 
2094990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2095990b4856Slling 		if (!first) {
2096990b4856Slling 			if (scripted)
2097990b4856Slling 				(void) printf("\t");
2098990b4856Slling 			else
2099990b4856Slling 				(void) printf("  ");
2100990b4856Slling 		} else {
2101990b4856Slling 			first = B_FALSE;
2102990b4856Slling 		}
2103990b4856Slling 
2104990b4856Slling 		right_justify = B_FALSE;
2105990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
2106990b4856Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
2107990b4856Slling 			    sizeof (property), NULL) != 0)
2108990b4856Slling 				propstr = "-";
2109990b4856Slling 			else
2110990b4856Slling 				propstr = property;
2111990b4856Slling 
2112990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2113990b4856Slling 		} else {
2114990b4856Slling 			propstr = "-";
2115990b4856Slling 		}
2116990b4856Slling 
2117990b4856Slling 		width = pl->pl_width;
2118990b4856Slling 
2119990b4856Slling 		/*
2120990b4856Slling 		 * If this is being called in scripted mode, or if this is the
2121990b4856Slling 		 * last column and it is left-justified, don't include a width
2122990b4856Slling 		 * format specifier.
2123990b4856Slling 		 */
2124990b4856Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
2125990b4856Slling 			(void) printf("%s", propstr);
2126990b4856Slling 		else if (right_justify)
2127990b4856Slling 			(void) printf("%*s", width, propstr);
2128990b4856Slling 		else
2129990b4856Slling 			(void) printf("%-*s", width, propstr);
2130990b4856Slling 	}
2131990b4856Slling 
2132990b4856Slling 	(void) printf("\n");
2133990b4856Slling }
2134990b4856Slling 
2135990b4856Slling /*
2136990b4856Slling  * Generic callback function to list a pool.
2137990b4856Slling  */
2138fa9e4066Sahrens int
2139fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2140fa9e4066Sahrens {
2141fa9e4066Sahrens 	list_cbdata_t *cbp = data;
2142fa9e4066Sahrens 
2143fa9e4066Sahrens 	if (cbp->cb_first) {
2144fa9e4066Sahrens 		if (!cbp->cb_scripted)
2145990b4856Slling 			print_header(cbp->cb_proplist);
214699653d4eSeschrock 		cbp->cb_first = B_FALSE;
2147fa9e4066Sahrens 	}
2148fa9e4066Sahrens 
2149990b4856Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2150fa9e4066Sahrens 
2151fa9e4066Sahrens 	return (0);
2152fa9e4066Sahrens }
2153fa9e4066Sahrens 
2154fa9e4066Sahrens /*
2155990b4856Slling  * zpool list [-H] [-o prop[,prop]*] [pool] ...
2156fa9e4066Sahrens  *
2157990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2158990b4856Slling  *		by a single tab.
2159990b4856Slling  *	-o	List of properties to display.  Defaults to
2160990b4856Slling  *		"name,size,used,available,capacity,health,altroot"
2161fa9e4066Sahrens  *
2162fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2163fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2164fa9e4066Sahrens  */
2165fa9e4066Sahrens int
2166fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2167fa9e4066Sahrens {
2168fa9e4066Sahrens 	int c;
2169fa9e4066Sahrens 	int ret;
2170fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2171990b4856Slling 	static char default_props[] =
2172990b4856Slling 	    "name,size,used,available,capacity,health,altroot";
2173990b4856Slling 	char *props = default_props;
2174fa9e4066Sahrens 
2175fa9e4066Sahrens 	/* check options */
2176fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2177fa9e4066Sahrens 		switch (c) {
2178fa9e4066Sahrens 		case 'H':
217999653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2180fa9e4066Sahrens 			break;
2181fa9e4066Sahrens 		case 'o':
2182990b4856Slling 			props = optarg;
2183fa9e4066Sahrens 			break;
2184fa9e4066Sahrens 		case ':':
2185fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2186fa9e4066Sahrens 			    "'%c' option\n"), optopt);
218799653d4eSeschrock 			usage(B_FALSE);
2188fa9e4066Sahrens 			break;
2189fa9e4066Sahrens 		case '?':
2190fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2191fa9e4066Sahrens 			    optopt);
219299653d4eSeschrock 			usage(B_FALSE);
2193fa9e4066Sahrens 		}
2194fa9e4066Sahrens 	}
2195fa9e4066Sahrens 
2196fa9e4066Sahrens 	argc -= optind;
2197fa9e4066Sahrens 	argv += optind;
2198fa9e4066Sahrens 
2199990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
220099653d4eSeschrock 		usage(B_FALSE);
2201fa9e4066Sahrens 
220299653d4eSeschrock 	cb.cb_first = B_TRUE;
2203fa9e4066Sahrens 
2204990b4856Slling 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2205990b4856Slling 	    list_callback, &cb);
2206990b4856Slling 
2207990b4856Slling 	zprop_free_list(cb.cb_proplist);
2208fa9e4066Sahrens 
2209fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2210fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2211fa9e4066Sahrens 		return (0);
2212fa9e4066Sahrens 	}
2213fa9e4066Sahrens 
2214fa9e4066Sahrens 	return (ret);
2215fa9e4066Sahrens }
2216fa9e4066Sahrens 
2217fa9e4066Sahrens static nvlist_t *
2218fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2219fa9e4066Sahrens {
2220fa9e4066Sahrens 	nvlist_t **child;
2221fa9e4066Sahrens 	uint_t c, children;
2222fa9e4066Sahrens 	nvlist_t *match;
2223fa9e4066Sahrens 	char *path;
2224fa9e4066Sahrens 
2225fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2226fa9e4066Sahrens 	    &child, &children) != 0) {
2227fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2228fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2229fa9e4066Sahrens 			name += 9;
2230fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2231fa9e4066Sahrens 			path += 9;
2232fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2233fa9e4066Sahrens 			return (nv);
2234fa9e4066Sahrens 		return (NULL);
2235fa9e4066Sahrens 	}
2236fa9e4066Sahrens 
2237fa9e4066Sahrens 	for (c = 0; c < children; c++)
2238fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2239fa9e4066Sahrens 			return (match);
2240fa9e4066Sahrens 
2241fa9e4066Sahrens 	return (NULL);
2242fa9e4066Sahrens }
2243fa9e4066Sahrens 
2244fa9e4066Sahrens static int
2245fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2246fa9e4066Sahrens {
224799653d4eSeschrock 	boolean_t force = B_FALSE;
2248fa9e4066Sahrens 	int c;
2249fa9e4066Sahrens 	nvlist_t *nvroot;
2250fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2251fa9e4066Sahrens 	zpool_handle_t *zhp;
225299653d4eSeschrock 	int ret;
2253fa9e4066Sahrens 
2254fa9e4066Sahrens 	/* check options */
2255fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2256fa9e4066Sahrens 		switch (c) {
2257fa9e4066Sahrens 		case 'f':
225899653d4eSeschrock 			force = B_TRUE;
2259fa9e4066Sahrens 			break;
2260fa9e4066Sahrens 		case '?':
2261fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2262fa9e4066Sahrens 			    optopt);
226399653d4eSeschrock 			usage(B_FALSE);
2264fa9e4066Sahrens 		}
2265fa9e4066Sahrens 	}
2266fa9e4066Sahrens 
2267fa9e4066Sahrens 	argc -= optind;
2268fa9e4066Sahrens 	argv += optind;
2269fa9e4066Sahrens 
2270fa9e4066Sahrens 	/* get pool name and check number of arguments */
2271fa9e4066Sahrens 	if (argc < 1) {
2272fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
227399653d4eSeschrock 		usage(B_FALSE);
2274fa9e4066Sahrens 	}
2275fa9e4066Sahrens 
2276fa9e4066Sahrens 	poolname = argv[0];
2277fa9e4066Sahrens 
2278fa9e4066Sahrens 	if (argc < 2) {
2279fa9e4066Sahrens 		(void) fprintf(stderr,
2280fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
228199653d4eSeschrock 		usage(B_FALSE);
2282fa9e4066Sahrens 	}
2283fa9e4066Sahrens 
2284fa9e4066Sahrens 	old_disk = argv[1];
2285fa9e4066Sahrens 
2286fa9e4066Sahrens 	if (argc < 3) {
2287fa9e4066Sahrens 		if (!replacing) {
2288fa9e4066Sahrens 			(void) fprintf(stderr,
2289fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
229099653d4eSeschrock 			usage(B_FALSE);
2291fa9e4066Sahrens 		}
2292fa9e4066Sahrens 		new_disk = old_disk;
2293fa9e4066Sahrens 		argc -= 1;
2294fa9e4066Sahrens 		argv += 1;
2295fa9e4066Sahrens 	} else {
2296fa9e4066Sahrens 		new_disk = argv[2];
2297fa9e4066Sahrens 		argc -= 2;
2298fa9e4066Sahrens 		argv += 2;
2299fa9e4066Sahrens 	}
2300fa9e4066Sahrens 
2301fa9e4066Sahrens 	if (argc > 1) {
2302fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
230399653d4eSeschrock 		usage(B_FALSE);
2304fa9e4066Sahrens 	}
2305fa9e4066Sahrens 
230699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2307fa9e4066Sahrens 		return (1);
2308fa9e4066Sahrens 
23098488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2310fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2311fa9e4066Sahrens 		    poolname);
2312fa9e4066Sahrens 		zpool_close(zhp);
2313fa9e4066Sahrens 		return (1);
2314fa9e4066Sahrens 	}
2315fa9e4066Sahrens 
2316705040edSEric Taylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
2317705040edSEric Taylor 	    argc, argv);
2318fa9e4066Sahrens 	if (nvroot == NULL) {
2319fa9e4066Sahrens 		zpool_close(zhp);
2320fa9e4066Sahrens 		return (1);
2321fa9e4066Sahrens 	}
2322fa9e4066Sahrens 
232399653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
232499653d4eSeschrock 
232599653d4eSeschrock 	nvlist_free(nvroot);
232699653d4eSeschrock 	zpool_close(zhp);
232799653d4eSeschrock 
232899653d4eSeschrock 	return (ret);
2329fa9e4066Sahrens }
2330fa9e4066Sahrens 
2331fa9e4066Sahrens /*
2332fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2333fa9e4066Sahrens  *
2334fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2335fa9e4066Sahrens  *
2336fa9e4066Sahrens  * Replace <device> with <new_device>.
2337fa9e4066Sahrens  */
2338fa9e4066Sahrens /* ARGSUSED */
2339fa9e4066Sahrens int
2340fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2341fa9e4066Sahrens {
2342fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2343fa9e4066Sahrens }
2344fa9e4066Sahrens 
2345fa9e4066Sahrens /*
2346fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2347fa9e4066Sahrens  *
2348fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2349fa9e4066Sahrens  *
2350fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2351fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2352fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2353fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2354fa9e4066Sahrens  */
2355fa9e4066Sahrens int
2356fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2357fa9e4066Sahrens {
2358fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2359fa9e4066Sahrens }
2360fa9e4066Sahrens 
2361fa9e4066Sahrens /*
2362fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2363fa9e4066Sahrens  *
2364fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2365fa9e4066Sahrens  *		(not supported yet)
2366fa9e4066Sahrens  *
2367fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2368fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2369fa9e4066Sahrens  * has the only valid copy of some data.
2370fa9e4066Sahrens  */
2371fa9e4066Sahrens /* ARGSUSED */
2372fa9e4066Sahrens int
2373fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2374fa9e4066Sahrens {
2375fa9e4066Sahrens 	int c;
2376fa9e4066Sahrens 	char *poolname, *path;
2377fa9e4066Sahrens 	zpool_handle_t *zhp;
237899653d4eSeschrock 	int ret;
2379fa9e4066Sahrens 
2380fa9e4066Sahrens 	/* check options */
2381fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2382fa9e4066Sahrens 		switch (c) {
2383fa9e4066Sahrens 		case 'f':
2384fa9e4066Sahrens 		case '?':
2385fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2386fa9e4066Sahrens 			    optopt);
238799653d4eSeschrock 			usage(B_FALSE);
2388fa9e4066Sahrens 		}
2389fa9e4066Sahrens 	}
2390fa9e4066Sahrens 
2391fa9e4066Sahrens 	argc -= optind;
2392fa9e4066Sahrens 	argv += optind;
2393fa9e4066Sahrens 
2394fa9e4066Sahrens 	/* get pool name and check number of arguments */
2395fa9e4066Sahrens 	if (argc < 1) {
2396fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
239799653d4eSeschrock 		usage(B_FALSE);
2398fa9e4066Sahrens 	}
2399fa9e4066Sahrens 
2400fa9e4066Sahrens 	if (argc < 2) {
2401fa9e4066Sahrens 		(void) fprintf(stderr,
2402fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
240399653d4eSeschrock 		usage(B_FALSE);
2404fa9e4066Sahrens 	}
2405fa9e4066Sahrens 
2406fa9e4066Sahrens 	poolname = argv[0];
2407fa9e4066Sahrens 	path = argv[1];
2408fa9e4066Sahrens 
240999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2410fa9e4066Sahrens 		return (1);
2411fa9e4066Sahrens 
241299653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
241399653d4eSeschrock 
241499653d4eSeschrock 	zpool_close(zhp);
241599653d4eSeschrock 
241699653d4eSeschrock 	return (ret);
2417fa9e4066Sahrens }
2418fa9e4066Sahrens 
2419fa9e4066Sahrens /*
2420441d80aaSlling  * zpool online <pool> <device> ...
2421fa9e4066Sahrens  */
2422fa9e4066Sahrens int
2423fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2424fa9e4066Sahrens {
2425fa9e4066Sahrens 	int c, i;
2426fa9e4066Sahrens 	char *poolname;
2427fa9e4066Sahrens 	zpool_handle_t *zhp;
2428fa9e4066Sahrens 	int ret = 0;
24293d7072f8Seschrock 	vdev_state_t newstate;
2430fa9e4066Sahrens 
2431fa9e4066Sahrens 	/* check options */
2432fa9e4066Sahrens 	while ((c = getopt(argc, argv, "t")) != -1) {
2433fa9e4066Sahrens 		switch (c) {
2434fa9e4066Sahrens 		case 't':
2435fa9e4066Sahrens 		case '?':
2436fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2437fa9e4066Sahrens 			    optopt);
243899653d4eSeschrock 			usage(B_FALSE);
2439fa9e4066Sahrens 		}
2440fa9e4066Sahrens 	}
2441fa9e4066Sahrens 
2442fa9e4066Sahrens 	argc -= optind;
2443fa9e4066Sahrens 	argv += optind;
2444fa9e4066Sahrens 
2445fa9e4066Sahrens 	/* get pool name and check number of arguments */
2446fa9e4066Sahrens 	if (argc < 1) {
2447fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
244899653d4eSeschrock 		usage(B_FALSE);
2449fa9e4066Sahrens 	}
2450fa9e4066Sahrens 	if (argc < 2) {
2451fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
245299653d4eSeschrock 		usage(B_FALSE);
2453fa9e4066Sahrens 	}
2454fa9e4066Sahrens 
2455fa9e4066Sahrens 	poolname = argv[0];
2456fa9e4066Sahrens 
245799653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2458fa9e4066Sahrens 		return (1);
2459fa9e4066Sahrens 
24603d7072f8Seschrock 	for (i = 1; i < argc; i++) {
24613d7072f8Seschrock 		if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
24623d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
24633d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
24643d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
2465fa9e4066Sahrens 				    argv[i]);
24663d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
24673d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24683d7072f8Seschrock 					    "clear' to restore a faulted "
24693d7072f8Seschrock 					    "device\n"));
2470fa9e4066Sahrens 				else
24713d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24723d7072f8Seschrock 					    "replace' to replace devices "
24733d7072f8Seschrock 					    "that are no longer present\n"));
24743d7072f8Seschrock 			}
24753d7072f8Seschrock 		} else {
2476fa9e4066Sahrens 			ret = 1;
24773d7072f8Seschrock 		}
24783d7072f8Seschrock 	}
2479fa9e4066Sahrens 
248099653d4eSeschrock 	zpool_close(zhp);
248199653d4eSeschrock 
2482fa9e4066Sahrens 	return (ret);
2483fa9e4066Sahrens }
2484fa9e4066Sahrens 
2485fa9e4066Sahrens /*
2486441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2487fa9e4066Sahrens  *
2488fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2489fa9e4066Sahrens  *		so would appear to compromise pool availability.
2490fa9e4066Sahrens  *		(not supported yet)
2491fa9e4066Sahrens  *
2492fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2493fa9e4066Sahrens  *		state will not be persistent across reboots.
2494fa9e4066Sahrens  */
2495fa9e4066Sahrens /* ARGSUSED */
2496fa9e4066Sahrens int
2497fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2498fa9e4066Sahrens {
2499fa9e4066Sahrens 	int c, i;
2500fa9e4066Sahrens 	char *poolname;
2501fa9e4066Sahrens 	zpool_handle_t *zhp;
250299653d4eSeschrock 	int ret = 0;
250399653d4eSeschrock 	boolean_t istmp = B_FALSE;
2504fa9e4066Sahrens 
2505fa9e4066Sahrens 	/* check options */
2506fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2507fa9e4066Sahrens 		switch (c) {
2508fa9e4066Sahrens 		case 't':
250999653d4eSeschrock 			istmp = B_TRUE;
2510441d80aaSlling 			break;
2511441d80aaSlling 		case 'f':
2512fa9e4066Sahrens 		case '?':
2513fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2514fa9e4066Sahrens 			    optopt);
251599653d4eSeschrock 			usage(B_FALSE);
2516fa9e4066Sahrens 		}
2517fa9e4066Sahrens 	}
2518fa9e4066Sahrens 
2519fa9e4066Sahrens 	argc -= optind;
2520fa9e4066Sahrens 	argv += optind;
2521fa9e4066Sahrens 
2522fa9e4066Sahrens 	/* get pool name and check number of arguments */
2523fa9e4066Sahrens 	if (argc < 1) {
2524fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
252599653d4eSeschrock 		usage(B_FALSE);
2526fa9e4066Sahrens 	}
2527fa9e4066Sahrens 	if (argc < 2) {
2528fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
252999653d4eSeschrock 		usage(B_FALSE);
2530fa9e4066Sahrens 	}
2531fa9e4066Sahrens 
2532fa9e4066Sahrens 	poolname = argv[0];
2533fa9e4066Sahrens 
253499653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2535fa9e4066Sahrens 		return (1);
2536fa9e4066Sahrens 
25373d7072f8Seschrock 	for (i = 1; i < argc; i++) {
25383d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2539fa9e4066Sahrens 			ret = 1;
25403d7072f8Seschrock 	}
2541fa9e4066Sahrens 
254299653d4eSeschrock 	zpool_close(zhp);
254399653d4eSeschrock 
2544fa9e4066Sahrens 	return (ret);
2545fa9e4066Sahrens }
2546fa9e4066Sahrens 
2547ea8dc4b6Seschrock /*
2548ea8dc4b6Seschrock  * zpool clear <pool> [device]
2549ea8dc4b6Seschrock  *
2550ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2551ea8dc4b6Seschrock  */
2552ea8dc4b6Seschrock int
2553ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2554ea8dc4b6Seschrock {
2555ea8dc4b6Seschrock 	int ret = 0;
2556ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2557ea8dc4b6Seschrock 	char *pool, *device;
2558ea8dc4b6Seschrock 
2559ea8dc4b6Seschrock 	if (argc < 2) {
2560ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
256199653d4eSeschrock 		usage(B_FALSE);
2562ea8dc4b6Seschrock 	}
2563ea8dc4b6Seschrock 
2564ea8dc4b6Seschrock 	if (argc > 3) {
2565ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
256699653d4eSeschrock 		usage(B_FALSE);
2567ea8dc4b6Seschrock 	}
2568ea8dc4b6Seschrock 
2569ea8dc4b6Seschrock 	pool = argv[1];
2570ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2571ea8dc4b6Seschrock 
2572b87f3af3Sperrin 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
2573ea8dc4b6Seschrock 		return (1);
2574ea8dc4b6Seschrock 
2575ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2576ea8dc4b6Seschrock 		ret = 1;
2577ea8dc4b6Seschrock 
2578ea8dc4b6Seschrock 	zpool_close(zhp);
2579ea8dc4b6Seschrock 
2580ea8dc4b6Seschrock 	return (ret);
2581ea8dc4b6Seschrock }
2582ea8dc4b6Seschrock 
2583fa9e4066Sahrens typedef struct scrub_cbdata {
2584fa9e4066Sahrens 	int	cb_type;
258506eeb2adSek110237 	int	cb_argc;
258606eeb2adSek110237 	char	**cb_argv;
2587fa9e4066Sahrens } scrub_cbdata_t;
2588fa9e4066Sahrens 
2589fa9e4066Sahrens int
2590fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2591fa9e4066Sahrens {
2592fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
259306eeb2adSek110237 	int err;
2594fa9e4066Sahrens 
2595ea8dc4b6Seschrock 	/*
2596ea8dc4b6Seschrock 	 * Ignore faulted pools.
2597ea8dc4b6Seschrock 	 */
2598ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2599ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2600ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2601ea8dc4b6Seschrock 		return (1);
2602ea8dc4b6Seschrock 	}
2603ea8dc4b6Seschrock 
260406eeb2adSek110237 	err = zpool_scrub(zhp, cb->cb_type);
260506eeb2adSek110237 
260606eeb2adSek110237 	return (err != 0);
2607fa9e4066Sahrens }
2608fa9e4066Sahrens 
2609fa9e4066Sahrens /*
2610fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2611fa9e4066Sahrens  *
2612fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2613fa9e4066Sahrens  */
2614fa9e4066Sahrens int
2615fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2616fa9e4066Sahrens {
2617fa9e4066Sahrens 	int c;
2618fa9e4066Sahrens 	scrub_cbdata_t cb;
2619fa9e4066Sahrens 
2620fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2621fa9e4066Sahrens 
2622fa9e4066Sahrens 	/* check options */
2623fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2624fa9e4066Sahrens 		switch (c) {
2625fa9e4066Sahrens 		case 's':
2626fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2627fa9e4066Sahrens 			break;
2628fa9e4066Sahrens 		case '?':
2629fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2630fa9e4066Sahrens 			    optopt);
263199653d4eSeschrock 			usage(B_FALSE);
2632fa9e4066Sahrens 		}
2633fa9e4066Sahrens 	}
2634fa9e4066Sahrens 
263506eeb2adSek110237 	cb.cb_argc = argc;
263606eeb2adSek110237 	cb.cb_argv = argv;
2637fa9e4066Sahrens 	argc -= optind;
2638fa9e4066Sahrens 	argv += optind;
2639fa9e4066Sahrens 
2640fa9e4066Sahrens 	if (argc < 1) {
2641fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
264299653d4eSeschrock 		usage(B_FALSE);
2643fa9e4066Sahrens 	}
2644fa9e4066Sahrens 
2645b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2646fa9e4066Sahrens }
2647fa9e4066Sahrens 
2648fa9e4066Sahrens typedef struct status_cbdata {
2649fa9e4066Sahrens 	int		cb_count;
2650e9dbad6fSeschrock 	boolean_t	cb_allpools;
265199653d4eSeschrock 	boolean_t	cb_verbose;
265299653d4eSeschrock 	boolean_t	cb_explain;
265399653d4eSeschrock 	boolean_t	cb_first;
2654fa9e4066Sahrens } status_cbdata_t;
2655fa9e4066Sahrens 
2656fa9e4066Sahrens /*
2657fa9e4066Sahrens  * Print out detailed scrub status.
2658fa9e4066Sahrens  */
2659fa9e4066Sahrens void
2660fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2661fa9e4066Sahrens {
2662fa9e4066Sahrens 	vdev_stat_t *vs;
2663fa9e4066Sahrens 	uint_t vsc;
2664fa9e4066Sahrens 	time_t start, end, now;
2665fa9e4066Sahrens 	double fraction_done;
266618ce54dfSek110237 	uint64_t examined, total, minutes_left, minutes_taken;
2667fa9e4066Sahrens 	char *scrub_type;
2668fa9e4066Sahrens 
2669fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2670fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2671fa9e4066Sahrens 
2672fa9e4066Sahrens 	/*
2673fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2674fa9e4066Sahrens 	 */
2675fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2676fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2677fa9e4066Sahrens 		return;
2678fa9e4066Sahrens 	}
2679fa9e4066Sahrens 
2680fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2681fa9e4066Sahrens 	    "resilver" : "scrub";
2682fa9e4066Sahrens 
2683fa9e4066Sahrens 	start = vs->vs_scrub_start;
2684fa9e4066Sahrens 	end = vs->vs_scrub_end;
2685fa9e4066Sahrens 	now = time(NULL);
2686fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2687fa9e4066Sahrens 	total = vs->vs_alloc;
2688fa9e4066Sahrens 
2689fa9e4066Sahrens 	if (end != 0) {
269018ce54dfSek110237 		minutes_taken = (uint64_t)((end - start) / 60);
269118ce54dfSek110237 
269218ce54dfSek110237 		(void) printf(gettext("%s %s after %lluh%um with %llu errors "
269318ce54dfSek110237 		    "on %s"),
2694fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
269518ce54dfSek110237 		    (u_longlong_t)(minutes_taken / 60),
269618ce54dfSek110237 		    (uint_t)(minutes_taken % 60),
2697fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2698fa9e4066Sahrens 		return;
2699fa9e4066Sahrens 	}
2700fa9e4066Sahrens 
2701fa9e4066Sahrens 	if (examined == 0)
2702fa9e4066Sahrens 		examined = 1;
2703fa9e4066Sahrens 	if (examined > total)
2704fa9e4066Sahrens 		total = examined;
2705fa9e4066Sahrens 
2706fa9e4066Sahrens 	fraction_done = (double)examined / total;
2707fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2708fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
270918ce54dfSek110237 	minutes_taken = (uint64_t)((now - start) / 60);
2710fa9e4066Sahrens 
271118ce54dfSek110237 	(void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, "
271218ce54dfSek110237 	    "%lluh%um to go\n"),
271318ce54dfSek110237 	    scrub_type, (u_longlong_t)(minutes_taken / 60),
271418ce54dfSek110237 	    (uint_t)(minutes_taken % 60), 100 * fraction_done,
2715fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2716fa9e4066Sahrens }
2717fa9e4066Sahrens 
271899653d4eSeschrock typedef struct spare_cbdata {
271999653d4eSeschrock 	uint64_t	cb_guid;
272099653d4eSeschrock 	zpool_handle_t	*cb_zhp;
272199653d4eSeschrock } spare_cbdata_t;
272299653d4eSeschrock 
272399653d4eSeschrock static boolean_t
272499653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search)
272599653d4eSeschrock {
272699653d4eSeschrock 	uint64_t guid;
272799653d4eSeschrock 	nvlist_t **child;
272899653d4eSeschrock 	uint_t c, children;
272999653d4eSeschrock 
273099653d4eSeschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
273199653d4eSeschrock 	    search == guid)
273299653d4eSeschrock 		return (B_TRUE);
273399653d4eSeschrock 
273499653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
273599653d4eSeschrock 	    &child, &children) == 0) {
273699653d4eSeschrock 		for (c = 0; c < children; c++)
273799653d4eSeschrock 			if (find_vdev(child[c], search))
273899653d4eSeschrock 				return (B_TRUE);
273999653d4eSeschrock 	}
274099653d4eSeschrock 
274199653d4eSeschrock 	return (B_FALSE);
274299653d4eSeschrock }
274399653d4eSeschrock 
274499653d4eSeschrock static int
274599653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data)
274699653d4eSeschrock {
274799653d4eSeschrock 	spare_cbdata_t *cbp = data;
274899653d4eSeschrock 	nvlist_t *config, *nvroot;
274999653d4eSeschrock 
275099653d4eSeschrock 	config = zpool_get_config(zhp, NULL);
275199653d4eSeschrock 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
275299653d4eSeschrock 	    &nvroot) == 0);
275399653d4eSeschrock 
275499653d4eSeschrock 	if (find_vdev(nvroot, cbp->cb_guid)) {
275599653d4eSeschrock 		cbp->cb_zhp = zhp;
275699653d4eSeschrock 		return (1);
275799653d4eSeschrock 	}
275899653d4eSeschrock 
275999653d4eSeschrock 	zpool_close(zhp);
276099653d4eSeschrock 	return (0);
276199653d4eSeschrock }
276299653d4eSeschrock 
2763fa9e4066Sahrens /*
2764fa9e4066Sahrens  * Print out configuration state as requested by status_callback.
2765fa9e4066Sahrens  */
2766fa9e4066Sahrens void
2767c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
2768*aa8cf21aSNeil Perrin     int namewidth, int depth, boolean_t isspare)
2769fa9e4066Sahrens {
2770fa9e4066Sahrens 	nvlist_t **child;
2771fa9e4066Sahrens 	uint_t c, children;
2772fa9e4066Sahrens 	vdev_stat_t *vs;
2773ea8dc4b6Seschrock 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
2774afefbcddSeschrock 	char *vname;
2775ea8dc4b6Seschrock 	uint64_t notpresent;
277699653d4eSeschrock 	spare_cbdata_t cb;
2777990b4856Slling 	char *state;
2778fa9e4066Sahrens 
2779fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2780fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2781fa9e4066Sahrens 
2782fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2783fa9e4066Sahrens 	    &child, &children) != 0)
2784fa9e4066Sahrens 		children = 0;
2785fa9e4066Sahrens 
2786990b4856Slling 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
278799653d4eSeschrock 	if (isspare) {
278899653d4eSeschrock 		/*
278999653d4eSeschrock 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
279099653d4eSeschrock 		 * online drives.
279199653d4eSeschrock 		 */
279299653d4eSeschrock 		if (vs->vs_aux == VDEV_AUX_SPARED)
279399653d4eSeschrock 			state = "INUSE";
279499653d4eSeschrock 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
279599653d4eSeschrock 			state = "AVAIL";
279699653d4eSeschrock 	}
2797fa9e4066Sahrens 
279899653d4eSeschrock 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
279999653d4eSeschrock 	    name, state);
280099653d4eSeschrock 
280199653d4eSeschrock 	if (!isspare) {
2802fa9e4066Sahrens 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
2803fa9e4066Sahrens 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
2804fa9e4066Sahrens 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
2805fa9e4066Sahrens 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
280699653d4eSeschrock 	}
2807fa9e4066Sahrens 
2808ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2809ea8dc4b6Seschrock 	    &notpresent) == 0) {
2810ea8dc4b6Seschrock 		char *path;
2811ea8dc4b6Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
28120917b783Seschrock 		(void) printf("  was %s", path);
2813ea8dc4b6Seschrock 	} else if (vs->vs_aux != 0) {
2814fa9e4066Sahrens 		(void) printf("  ");
2815fa9e4066Sahrens 
2816fa9e4066Sahrens 		switch (vs->vs_aux) {
2817fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2818fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2819fa9e4066Sahrens 			break;
2820fa9e4066Sahrens 
2821fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2822fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2823fa9e4066Sahrens 			break;
2824fa9e4066Sahrens 
2825fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2826fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2827fa9e4066Sahrens 			break;
2828fa9e4066Sahrens 
2829eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
2830eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
2831eaca9bbdSeschrock 			break;
2832eaca9bbdSeschrock 
283399653d4eSeschrock 		case VDEV_AUX_SPARED:
283499653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
283599653d4eSeschrock 			    &cb.cb_guid) == 0);
283699653d4eSeschrock 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
283799653d4eSeschrock 				if (strcmp(zpool_get_name(cb.cb_zhp),
283899653d4eSeschrock 				    zpool_get_name(zhp)) == 0)
283999653d4eSeschrock 					(void) printf(gettext("currently in "
284099653d4eSeschrock 					    "use"));
284199653d4eSeschrock 				else
284299653d4eSeschrock 					(void) printf(gettext("in use by "
284399653d4eSeschrock 					    "pool '%s'"),
284499653d4eSeschrock 					    zpool_get_name(cb.cb_zhp));
284599653d4eSeschrock 				zpool_close(cb.cb_zhp);
284699653d4eSeschrock 			} else {
284799653d4eSeschrock 				(void) printf(gettext("currently in use"));
284899653d4eSeschrock 			}
284999653d4eSeschrock 			break;
285099653d4eSeschrock 
28513d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
28523d7072f8Seschrock 			(void) printf(gettext("too many errors"));
28533d7072f8Seschrock 			break;
28543d7072f8Seschrock 
285532b87932Sek110237 		case VDEV_AUX_IO_FAILURE:
285632b87932Sek110237 			(void) printf(gettext("experienced I/O failures"));
285732b87932Sek110237 			break;
285832b87932Sek110237 
2859b87f3af3Sperrin 		case VDEV_AUX_BAD_LOG:
2860b87f3af3Sperrin 			(void) printf(gettext("bad intent log"));
2861b87f3af3Sperrin 			break;
2862b87f3af3Sperrin 
2863fa9e4066Sahrens 		default:
2864fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2865fa9e4066Sahrens 			break;
2866fa9e4066Sahrens 		}
2867fa9e4066Sahrens 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2868fa9e4066Sahrens 		/*
2869fa9e4066Sahrens 		 * Report bytes resilvered/repaired on leaf devices.
2870fa9e4066Sahrens 		 */
2871fa9e4066Sahrens 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2872fa9e4066Sahrens 		(void) printf(gettext("  %s %s"), repaired,
2873fa9e4066Sahrens 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2874fa9e4066Sahrens 		    "resilvered" : "repaired");
2875fa9e4066Sahrens 	}
2876fa9e4066Sahrens 
2877fa9e4066Sahrens 	(void) printf("\n");
2878fa9e4066Sahrens 
2879afefbcddSeschrock 	for (c = 0; c < children; c++) {
28808654d025Sperrin 		uint64_t is_log = B_FALSE;
28818654d025Sperrin 
2882*aa8cf21aSNeil Perrin 		/* Don't print logs here */
28838654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
28848654d025Sperrin 		    &is_log);
2885*aa8cf21aSNeil Perrin 		if (is_log)
28868654d025Sperrin 			continue;
288799653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
2888c67d9675Seschrock 		print_status_config(zhp, vname, child[c],
2889*aa8cf21aSNeil Perrin 		    namewidth, depth + 2, isspare);
2890afefbcddSeschrock 		free(vname);
2891afefbcddSeschrock 	}
2892fa9e4066Sahrens }
2893fa9e4066Sahrens 
2894ea8dc4b6Seschrock static void
2895ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
2896ea8dc4b6Seschrock {
289775519f38Sek110237 	nvlist_t *nverrlist = NULL;
289855434c77Sek110237 	nvpair_t *elem;
289955434c77Sek110237 	char *pathname;
290055434c77Sek110237 	size_t len = MAXPATHLEN * 2;
2901ea8dc4b6Seschrock 
290255434c77Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2903ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
2904ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
2905ea8dc4b6Seschrock 		return;
2906ea8dc4b6Seschrock 	}
2907ea8dc4b6Seschrock 
290855434c77Sek110237 	(void) printf("errors: Permanent errors have been "
290955434c77Sek110237 	    "detected in the following files:\n\n");
2910ea8dc4b6Seschrock 
291155434c77Sek110237 	pathname = safe_malloc(len);
291255434c77Sek110237 	elem = NULL;
291355434c77Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
291455434c77Sek110237 		nvlist_t *nv;
291555434c77Sek110237 		uint64_t dsobj, obj;
2916ea8dc4b6Seschrock 
291755434c77Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
291855434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
291955434c77Sek110237 		    &dsobj) == 0);
292055434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
292155434c77Sek110237 		    &obj) == 0);
292255434c77Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
292355434c77Sek110237 		(void) printf("%7s %s\n", "", pathname);
2924ea8dc4b6Seschrock 	}
292555434c77Sek110237 	free(pathname);
292655434c77Sek110237 	nvlist_free(nverrlist);
2927ea8dc4b6Seschrock }
2928ea8dc4b6Seschrock 
292999653d4eSeschrock static void
293099653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
293199653d4eSeschrock     int namewidth)
293299653d4eSeschrock {
293399653d4eSeschrock 	uint_t i;
293499653d4eSeschrock 	char *name;
293599653d4eSeschrock 
293699653d4eSeschrock 	if (nspares == 0)
293799653d4eSeschrock 		return;
293899653d4eSeschrock 
293999653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
294099653d4eSeschrock 
294199653d4eSeschrock 	for (i = 0; i < nspares; i++) {
294299653d4eSeschrock 		name = zpool_vdev_name(g_zfs, zhp, spares[i]);
294399653d4eSeschrock 		print_status_config(zhp, name, spares[i],
2944*aa8cf21aSNeil Perrin 		    namewidth, 2, B_TRUE);
294599653d4eSeschrock 		free(name);
294699653d4eSeschrock 	}
294799653d4eSeschrock }
294899653d4eSeschrock 
2949fa94a07fSbrendan static void
2950fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
2951fa94a07fSbrendan     int namewidth)
2952fa94a07fSbrendan {
2953fa94a07fSbrendan 	uint_t i;
2954fa94a07fSbrendan 	char *name;
2955fa94a07fSbrendan 
2956fa94a07fSbrendan 	if (nl2cache == 0)
2957fa94a07fSbrendan 		return;
2958fa94a07fSbrendan 
2959fa94a07fSbrendan 	(void) printf(gettext("\tcache\n"));
2960fa94a07fSbrendan 
2961fa94a07fSbrendan 	for (i = 0; i < nl2cache; i++) {
2962fa94a07fSbrendan 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i]);
2963fa94a07fSbrendan 		print_status_config(zhp, name, l2cache[i],
2964*aa8cf21aSNeil Perrin 		    namewidth, 2, B_FALSE);
2965*aa8cf21aSNeil Perrin 		free(name);
2966*aa8cf21aSNeil Perrin 	}
2967*aa8cf21aSNeil Perrin }
2968*aa8cf21aSNeil Perrin 
2969*aa8cf21aSNeil Perrin /*
2970*aa8cf21aSNeil Perrin  * Print log vdevs.
2971*aa8cf21aSNeil Perrin  * Logs are recorded as top level vdevs in the main pool child array but with
2972*aa8cf21aSNeil Perrin  * "is_log" set to 1. We use print_status_config() to print the top level logs
2973*aa8cf21aSNeil Perrin  * then any log children (eg mirrored slogs) are printed recursively - which
2974*aa8cf21aSNeil Perrin  * works because only the top level vdev is marked "is_log"
2975*aa8cf21aSNeil Perrin  */
2976*aa8cf21aSNeil Perrin static void
2977*aa8cf21aSNeil Perrin print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth)
2978*aa8cf21aSNeil Perrin {
2979*aa8cf21aSNeil Perrin 	uint_t c, children;
2980*aa8cf21aSNeil Perrin 	nvlist_t **child;
2981*aa8cf21aSNeil Perrin 
2982*aa8cf21aSNeil Perrin 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
2983*aa8cf21aSNeil Perrin 	    &children) != 0)
2984*aa8cf21aSNeil Perrin 		return;
2985*aa8cf21aSNeil Perrin 
2986*aa8cf21aSNeil Perrin 	(void) printf(gettext("\tlogs\n"));
2987*aa8cf21aSNeil Perrin 
2988*aa8cf21aSNeil Perrin 	for (c = 0; c < children; c++) {
2989*aa8cf21aSNeil Perrin 		uint64_t is_log = B_FALSE;
2990*aa8cf21aSNeil Perrin 		char *name;
2991*aa8cf21aSNeil Perrin 
2992*aa8cf21aSNeil Perrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
2993*aa8cf21aSNeil Perrin 		    &is_log);
2994*aa8cf21aSNeil Perrin 		if (!is_log)
2995*aa8cf21aSNeil Perrin 			continue;
2996*aa8cf21aSNeil Perrin 		name = zpool_vdev_name(g_zfs, zhp, child[c]);
2997*aa8cf21aSNeil Perrin 		print_status_config(zhp, name, child[c], namewidth, 2, B_FALSE);
2998fa94a07fSbrendan 		free(name);
2999fa94a07fSbrendan 	}
3000fa94a07fSbrendan }
3001fa94a07fSbrendan 
3002fa9e4066Sahrens /*
3003fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
3004fa9e4066Sahrens  *
3005fa9e4066Sahrens  *        pool: tank
3006fa9e4066Sahrens  *	status: DEGRADED
3007fa9e4066Sahrens  *	reason: One or more devices ...
3008fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
3009fa9e4066Sahrens  *	config:
3010fa9e4066Sahrens  *		mirror		DEGRADED
3011fa9e4066Sahrens  *                c1t0d0	OK
3012ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
3013fa9e4066Sahrens  *
3014fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
3015fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
3016fa9e4066Sahrens  */
3017fa9e4066Sahrens int
3018fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
3019fa9e4066Sahrens {
3020fa9e4066Sahrens 	status_cbdata_t *cbp = data;
3021fa9e4066Sahrens 	nvlist_t *config, *nvroot;
3022fa9e4066Sahrens 	char *msgid;
3023fa9e4066Sahrens 	int reason;
302446657f8dSmmusante 	const char *health;
302546657f8dSmmusante 	uint_t c;
302646657f8dSmmusante 	vdev_stat_t *vs;
3027fa9e4066Sahrens 
3028088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
3029fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
3030fa9e4066Sahrens 
3031fa9e4066Sahrens 	cbp->cb_count++;
3032fa9e4066Sahrens 
3033fa9e4066Sahrens 	/*
3034fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
3035fa9e4066Sahrens 	 * problems.
3036fa9e4066Sahrens 	 */
3037e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
3038e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
3039e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
3040e9dbad6fSeschrock 			    zpool_get_name(zhp));
3041e9dbad6fSeschrock 			if (cbp->cb_first)
3042e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
3043e9dbad6fSeschrock 		}
3044fa9e4066Sahrens 		return (0);
3045e9dbad6fSeschrock 	}
3046fa9e4066Sahrens 
3047fa9e4066Sahrens 	if (cbp->cb_first)
304899653d4eSeschrock 		cbp->cb_first = B_FALSE;
3049fa9e4066Sahrens 	else
3050fa9e4066Sahrens 		(void) printf("\n");
3051fa9e4066Sahrens 
305246657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
305346657f8dSmmusante 	    &nvroot) == 0);
305446657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
305546657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
3056990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3057fa9e4066Sahrens 
3058fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
3059fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
3060fa9e4066Sahrens 
3061fa9e4066Sahrens 	switch (reason) {
3062fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
3063fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3064fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
3065fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
3066fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3067fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3068fa9e4066Sahrens 		break;
3069fa9e4066Sahrens 
3070fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
3071fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3072fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
3073fa9e4066Sahrens 		    "pool to continue functioning.\n"));
3074fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3075fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
3076fa9e4066Sahrens 		break;
3077fa9e4066Sahrens 
3078fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
3079fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3080fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
3081fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
3082fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
3083fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
3084fa9e4066Sahrens 		    "'zpool replace'.\n"));
3085fa9e4066Sahrens 		break;
3086fa9e4066Sahrens 
3087fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3088fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3089b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
3090fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
3091fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
3092fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
3093fa9e4066Sahrens 		    "from a backup source.\n"));
3094fa9e4066Sahrens 		break;
3095fa9e4066Sahrens 
3096fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
3097fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3098fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
3099fa9e4066Sahrens 		    "made to correct the error.  Applications are "
3100fa9e4066Sahrens 		    "unaffected.\n"));
3101fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
3102fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
3103ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
3104fa9e4066Sahrens 		    "replace'.\n"));
3105fa9e4066Sahrens 		break;
3106fa9e4066Sahrens 
3107fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
3108fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3109d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
3110fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
3111fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
3112fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
3113fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
3114fa9e4066Sahrens 		    "replace'.\n"));
3115fa9e4066Sahrens 		break;
3116fa9e4066Sahrens 
3117fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
3118fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
3119fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3120fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
3121fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3122fa9e4066Sahrens 		    "complete.\n"));
3123fa9e4066Sahrens 		break;
3124fa9e4066Sahrens 
3125ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3126ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3127ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3128ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3129ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3130ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3131ea8dc4b6Seschrock 		    "backup.\n"));
3132ea8dc4b6Seschrock 		break;
3133ea8dc4b6Seschrock 
3134ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3135ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3136ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3137ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
3138ea8dc4b6Seschrock 		    "from a backup source.\n"));
3139ea8dc4b6Seschrock 		break;
3140ea8dc4b6Seschrock 
3141eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3142eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3143eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3144eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3145eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3146eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3147eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3148eaca9bbdSeschrock 		break;
3149eaca9bbdSeschrock 
3150eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3151eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3152eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3153eaca9bbdSeschrock 		    "be accessed on this system.\n"));
3154eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
3155eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
3156eaca9bbdSeschrock 		    "backup.\n"));
3157eaca9bbdSeschrock 		break;
3158eaca9bbdSeschrock 
31593d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
31603d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
31613d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
31623d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
31633d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
31643d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
31653d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
31663d7072f8Seschrock 		break;
31673d7072f8Seschrock 
31683d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
31693d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
31703d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
31713d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
31723d7072f8Seschrock 		    "functioning.\n"));
31733d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
31743d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
31753d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
31763d7072f8Seschrock 		    "to be recovered.\n"));
31773d7072f8Seschrock 		break;
31783d7072f8Seschrock 
317932b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_WAIT:
318032b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
318132b87932Sek110237 		(void) printf(gettext("status: One or more devices are "
31828a79c1b5Sek110237 		    "faulted in response to IO failures.\n"));
318332b87932Sek110237 		(void) printf(gettext("action: Make sure the affected devices "
318432b87932Sek110237 		    "are connected, then run 'zpool clear'.\n"));
318532b87932Sek110237 		break;
318632b87932Sek110237 
3187b87f3af3Sperrin 	case ZPOOL_STATUS_BAD_LOG:
3188b87f3af3Sperrin 		(void) printf(gettext("status: An intent log record "
3189b87f3af3Sperrin 		    "could not be read.\n"
3190b87f3af3Sperrin 		    "\tWaiting for adminstrator intervention to fix the "
3191b87f3af3Sperrin 		    "faulted pool.\n"));
3192b87f3af3Sperrin 		(void) printf(gettext("action: Either restore the affected "
3193b87f3af3Sperrin 		    "device(s) and run 'zpool online',\n"
3194b87f3af3Sperrin 		    "\tor ignore the intent log records by running "
3195b87f3af3Sperrin 		    "'zpool clear'.\n"));
3196b87f3af3Sperrin 		break;
3197b87f3af3Sperrin 
3198fa9e4066Sahrens 	default:
3199fa9e4066Sahrens 		/*
3200fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
3201fa9e4066Sahrens 		 */
3202fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
3203fa9e4066Sahrens 	}
3204fa9e4066Sahrens 
3205fa9e4066Sahrens 	if (msgid != NULL)
3206fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3207fa9e4066Sahrens 		    msgid);
3208fa9e4066Sahrens 
3209fa9e4066Sahrens 	if (config != NULL) {
3210fa9e4066Sahrens 		int namewidth;
3211ea8dc4b6Seschrock 		uint64_t nerr;
3212fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
3213fa94a07fSbrendan 		uint_t nspares, nl2cache;
3214fa9e4066Sahrens 
3215fa9e4066Sahrens 
3216fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
3217fa9e4066Sahrens 		print_scrub_status(nvroot);
3218fa9e4066Sahrens 
3219c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3220fa9e4066Sahrens 		if (namewidth < 10)
3221fa9e4066Sahrens 			namewidth = 10;
3222fa9e4066Sahrens 
3223fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
3224fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3225fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3226c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
3227*aa8cf21aSNeil Perrin 		    namewidth, 0, B_FALSE);
322899653d4eSeschrock 
3229*aa8cf21aSNeil Perrin 		print_logs(zhp, nvroot, namewidth);
3230fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
3231fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
3232fa94a07fSbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
3233fa94a07fSbrendan 
323499653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
323599653d4eSeschrock 		    &spares, &nspares) == 0)
323699653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
3237ea8dc4b6Seschrock 
3238ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3239ea8dc4b6Seschrock 		    &nerr) == 0) {
324055434c77Sek110237 			nvlist_t *nverrlist = NULL;
324155434c77Sek110237 
3242ea8dc4b6Seschrock 			/*
3243ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3244ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3245ea8dc4b6Seschrock 			 * uniquifying the results.
3246ea8dc4b6Seschrock 			 */
324775519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
324855434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
324955434c77Sek110237 				nvpair_t *elem;
325055434c77Sek110237 
325155434c77Sek110237 				elem = NULL;
325255434c77Sek110237 				nerr = 0;
325355434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
325455434c77Sek110237 				    elem)) != NULL) {
325555434c77Sek110237 					nerr++;
325655434c77Sek110237 				}
325755434c77Sek110237 			}
325855434c77Sek110237 			nvlist_free(nverrlist);
3259ea8dc4b6Seschrock 
3260ea8dc4b6Seschrock 			(void) printf("\n");
326199653d4eSeschrock 
3262ea8dc4b6Seschrock 			if (nerr == 0)
3263ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3264ea8dc4b6Seschrock 				    "errors\n"));
3265ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3266e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
32675ad82045Snd150628 				    "errors, use '-v' for a list\n"),
32685ad82045Snd150628 				    (u_longlong_t)nerr);
3269ea8dc4b6Seschrock 			else
3270ea8dc4b6Seschrock 				print_error_log(zhp);
3271ea8dc4b6Seschrock 		}
3272fa9e4066Sahrens 	} else {
3273fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3274fa9e4066Sahrens 		    "determined.\n"));
3275fa9e4066Sahrens 	}
3276fa9e4066Sahrens 
3277fa9e4066Sahrens 	return (0);
3278fa9e4066Sahrens }
3279fa9e4066Sahrens 
3280fa9e4066Sahrens /*
3281fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3282fa9e4066Sahrens  *
3283fa9e4066Sahrens  *	-v	Display complete error logs
3284fa9e4066Sahrens  *	-x	Display only pools with potential problems
3285fa9e4066Sahrens  *
3286fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3287fa9e4066Sahrens  */
3288fa9e4066Sahrens int
3289fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3290fa9e4066Sahrens {
3291fa9e4066Sahrens 	int c;
3292fa9e4066Sahrens 	int ret;
3293fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3294fa9e4066Sahrens 
3295fa9e4066Sahrens 	/* check options */
3296fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3297fa9e4066Sahrens 		switch (c) {
3298fa9e4066Sahrens 		case 'v':
329999653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3300fa9e4066Sahrens 			break;
3301fa9e4066Sahrens 		case 'x':
330299653d4eSeschrock 			cb.cb_explain = B_TRUE;
3303fa9e4066Sahrens 			break;
3304fa9e4066Sahrens 		case '?':
3305fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3306fa9e4066Sahrens 			    optopt);
330799653d4eSeschrock 			usage(B_FALSE);
3308fa9e4066Sahrens 		}
3309fa9e4066Sahrens 	}
3310fa9e4066Sahrens 
3311fa9e4066Sahrens 	argc -= optind;
3312fa9e4066Sahrens 	argv += optind;
3313fa9e4066Sahrens 
331499653d4eSeschrock 	cb.cb_first = B_TRUE;
3315fa9e4066Sahrens 
3316e9dbad6fSeschrock 	if (argc == 0)
3317e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3318e9dbad6fSeschrock 
3319b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3320fa9e4066Sahrens 
3321fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3322fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3323e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3324fa9e4066Sahrens 		(void) printf(gettext("all pools are healthy\n"));
3325fa9e4066Sahrens 
3326fa9e4066Sahrens 	return (ret);
3327fa9e4066Sahrens }
3328fa9e4066Sahrens 
3329eaca9bbdSeschrock typedef struct upgrade_cbdata {
3330eaca9bbdSeschrock 	int	cb_all;
3331eaca9bbdSeschrock 	int	cb_first;
3332eaca9bbdSeschrock 	int	cb_newer;
333306eeb2adSek110237 	int	cb_argc;
3334990b4856Slling 	uint64_t cb_version;
333506eeb2adSek110237 	char	**cb_argv;
3336eaca9bbdSeschrock } upgrade_cbdata_t;
3337eaca9bbdSeschrock 
3338eaca9bbdSeschrock static int
3339eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3340eaca9bbdSeschrock {
3341eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3342eaca9bbdSeschrock 	nvlist_t *config;
3343eaca9bbdSeschrock 	uint64_t version;
3344eaca9bbdSeschrock 	int ret = 0;
3345eaca9bbdSeschrock 
3346eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3347eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3348eaca9bbdSeschrock 	    &version) == 0);
3349eaca9bbdSeschrock 
3350e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3351eaca9bbdSeschrock 		if (!cbp->cb_all) {
3352eaca9bbdSeschrock 			if (cbp->cb_first) {
3353eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3354eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3355eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3356eaca9bbdSeschrock 				    "longer be accessible by older software "
3357eaca9bbdSeschrock 				    "versions.\n\n"));
3358eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3359eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
336099653d4eSeschrock 				cbp->cb_first = B_FALSE;
3361eaca9bbdSeschrock 			}
3362eaca9bbdSeschrock 
33635ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3364eaca9bbdSeschrock 			    zpool_get_name(zhp));
3365eaca9bbdSeschrock 		} else {
336699653d4eSeschrock 			cbp->cb_first = B_FALSE;
3367990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
336806eeb2adSek110237 			if (!ret) {
3369eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3370990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
3371eaca9bbdSeschrock 			}
337206eeb2adSek110237 		}
3373e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3374eaca9bbdSeschrock 		assert(!cbp->cb_all);
3375eaca9bbdSeschrock 
3376eaca9bbdSeschrock 		if (cbp->cb_first) {
3377eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3378eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3379eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3380eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3381eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
338299653d4eSeschrock 			cbp->cb_first = B_FALSE;
3383eaca9bbdSeschrock 		}
3384eaca9bbdSeschrock 
33855ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3386eaca9bbdSeschrock 		    zpool_get_name(zhp));
3387eaca9bbdSeschrock 	}
3388eaca9bbdSeschrock 
3389eaca9bbdSeschrock 	zpool_close(zhp);
3390eaca9bbdSeschrock 	return (ret);
3391eaca9bbdSeschrock }
3392eaca9bbdSeschrock 
3393eaca9bbdSeschrock /* ARGSUSED */
3394eaca9bbdSeschrock static int
339506eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
3396eaca9bbdSeschrock {
3397990b4856Slling 	upgrade_cbdata_t *cbp = data;
3398990b4856Slling 	uint64_t cur_version;
3399eaca9bbdSeschrock 	int ret;
3400eaca9bbdSeschrock 
34018654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
34028654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
34038654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
34048654d025Sperrin 		    " to upgrade.\n"));
34058654d025Sperrin 		return (1);
34068654d025Sperrin 	}
3407990b4856Slling 
3408990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3409e6c728e1Sbrendan 	if (cur_version > cbp->cb_version) {
3410eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3411e6c728e1Sbrendan 		    "using more current version '%llu'.\n"),
3412e6c728e1Sbrendan 		    zpool_get_name(zhp), cur_version);
3413e6c728e1Sbrendan 		return (0);
3414e6c728e1Sbrendan 	}
3415e6c728e1Sbrendan 	if (cur_version == cbp->cb_version) {
3416e6c728e1Sbrendan 		(void) printf(gettext("Pool '%s' is already formatted "
3417e6c728e1Sbrendan 		    "using the current version.\n"), zpool_get_name(zhp));
3418eaca9bbdSeschrock 		return (0);
3419eaca9bbdSeschrock 	}
3420eaca9bbdSeschrock 
3421990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
342206eeb2adSek110237 
342306eeb2adSek110237 	if (!ret) {
342444cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
3425990b4856Slling 		    "from version %llu to version %llu\n\n"),
3426990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3427990b4856Slling 		    (u_longlong_t)cbp->cb_version);
342806eeb2adSek110237 	}
3429eaca9bbdSeschrock 
3430eaca9bbdSeschrock 	return (ret != 0);
3431eaca9bbdSeschrock }
3432eaca9bbdSeschrock 
3433eaca9bbdSeschrock /*
3434eaca9bbdSeschrock  * zpool upgrade
3435eaca9bbdSeschrock  * zpool upgrade -v
3436990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
3437eaca9bbdSeschrock  *
3438eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3439eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3440eaca9bbdSeschrock  * upgrade all pools.
3441eaca9bbdSeschrock  */
3442eaca9bbdSeschrock int
3443eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3444eaca9bbdSeschrock {
3445eaca9bbdSeschrock 	int c;
3446eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3447eaca9bbdSeschrock 	int ret = 0;
3448eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3449990b4856Slling 	char *end;
3450990b4856Slling 
3451eaca9bbdSeschrock 
3452eaca9bbdSeschrock 	/* check options */
3453990b4856Slling 	while ((c = getopt(argc, argv, "avV:")) != -1) {
3454eaca9bbdSeschrock 		switch (c) {
3455eaca9bbdSeschrock 		case 'a':
345699653d4eSeschrock 			cb.cb_all = B_TRUE;
3457eaca9bbdSeschrock 			break;
3458eaca9bbdSeschrock 		case 'v':
3459eaca9bbdSeschrock 			showversions = B_TRUE;
3460eaca9bbdSeschrock 			break;
3461990b4856Slling 		case 'V':
3462990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
3463351420b3Slling 			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
3464351420b3Slling 			    cb.cb_version < SPA_VERSION_1) {
3465990b4856Slling 				(void) fprintf(stderr,
3466990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
3467990b4856Slling 				usage(B_FALSE);
3468990b4856Slling 			}
3469990b4856Slling 			break;
3470eaca9bbdSeschrock 		case '?':
3471eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3472eaca9bbdSeschrock 			    optopt);
347399653d4eSeschrock 			usage(B_FALSE);
3474eaca9bbdSeschrock 		}
3475eaca9bbdSeschrock 	}
3476eaca9bbdSeschrock 
347706eeb2adSek110237 	cb.cb_argc = argc;
347806eeb2adSek110237 	cb.cb_argv = argv;
3479eaca9bbdSeschrock 	argc -= optind;
3480eaca9bbdSeschrock 	argv += optind;
3481eaca9bbdSeschrock 
3482351420b3Slling 	if (cb.cb_version == 0) {
3483351420b3Slling 		cb.cb_version = SPA_VERSION;
3484351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
3485351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
3486351420b3Slling 		    "incompatible with other arguments\n"));
3487351420b3Slling 		usage(B_FALSE);
3488351420b3Slling 	}
3489351420b3Slling 
3490eaca9bbdSeschrock 	if (showversions) {
3491eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3492eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3493eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
349499653d4eSeschrock 			usage(B_FALSE);
3495eaca9bbdSeschrock 		}
3496eaca9bbdSeschrock 	} else if (cb.cb_all) {
3497eaca9bbdSeschrock 		if (argc != 0) {
3498351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
3499351420b3Slling 			    "be used along with a pool name\n"));
350099653d4eSeschrock 			usage(B_FALSE);
3501eaca9bbdSeschrock 		}
3502eaca9bbdSeschrock 	}
3503eaca9bbdSeschrock 
3504e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3505e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
350699653d4eSeschrock 	cb.cb_first = B_TRUE;
3507eaca9bbdSeschrock 	if (showversions) {
3508eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3509d7d4af51Smmusante 		    "supported:\n\n"));
3510eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3511eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3512eaca9bbdSeschrock 		    "---------------\n");
351399653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
351444cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
351544cd46caSbillm 		    "(replicated metadata)\n"));
351699653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
351799653d4eSeschrock 		    "RAID-Z\n"));
3518d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
3519c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3520c9431fa1Sahl 		    "algorithm\n"));
3521990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
35228654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3523ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
3524a9799022Sck153898 		(void) printf(gettext(" 9   refquota and refreservation "
3525a9799022Sck153898 		    "properties\n"));
3526fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
3527088f3894Sahrens 		(void) printf(gettext(" 11  Improved scrub performance\n"));
3528bb0ade09Sahrens 		(void) printf(gettext(" 12  Snapshot properties\n"));
352974e7dc98SMatthew Ahrens 		(void) printf(gettext(" 13  snapused property\n"));
3530d0f3f37eSMark Shellenbaum 		(void) printf(gettext(" 14  passthrough-x aclinherit "
3531d0f3f37eSMark Shellenbaum 		    "support\n"));
35328654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3533eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3534eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3535eaca9bbdSeschrock 		    "version/N\n\n");
3536eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3537eaca9bbdSeschrock 	} else if (argc == 0) {
3538eaca9bbdSeschrock 		int notfound;
3539eaca9bbdSeschrock 
354099653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3541eaca9bbdSeschrock 		notfound = cb.cb_first;
3542eaca9bbdSeschrock 
3543eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3544eaca9bbdSeschrock 			if (!cb.cb_first)
3545eaca9bbdSeschrock 				(void) printf("\n");
3546eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3547eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
354899653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3549eaca9bbdSeschrock 			if (!cb.cb_first) {
3550eaca9bbdSeschrock 				notfound = B_FALSE;
3551eaca9bbdSeschrock 				(void) printf("\n");
3552eaca9bbdSeschrock 			}
3553eaca9bbdSeschrock 		}
3554eaca9bbdSeschrock 
3555eaca9bbdSeschrock 		if (ret == 0) {
3556eaca9bbdSeschrock 			if (notfound)
3557eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3558eaca9bbdSeschrock 				    "using this version.\n"));
3559eaca9bbdSeschrock 			else if (!cb.cb_all)
3560eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3561eaca9bbdSeschrock 				    "for a list of available versions and "
3562eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3563eaca9bbdSeschrock 		}
3564eaca9bbdSeschrock 	} else {
3565b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3566b1b8ab34Slling 		    upgrade_one, &cb);
356706eeb2adSek110237 	}
356806eeb2adSek110237 
356906eeb2adSek110237 	return (ret);
357006eeb2adSek110237 }
357106eeb2adSek110237 
3572ecd6cf80Smarks typedef struct hist_cbdata {
3573ecd6cf80Smarks 	boolean_t first;
3574ecd6cf80Smarks 	int longfmt;
3575ecd6cf80Smarks 	int internal;
3576ecd6cf80Smarks } hist_cbdata_t;
3577ecd6cf80Smarks 
3578ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3579ecd6cf80Smarks 	"invalid event",
3580ecd6cf80Smarks 	"pool create",
3581ecd6cf80Smarks 	"vdev add",
3582ecd6cf80Smarks 	"pool remove",
3583ecd6cf80Smarks 	"pool destroy",
3584ecd6cf80Smarks 	"pool export",
3585ecd6cf80Smarks 	"pool import",
3586ecd6cf80Smarks 	"vdev attach",
3587ecd6cf80Smarks 	"vdev replace",
3588ecd6cf80Smarks 	"vdev detach",
3589ecd6cf80Smarks 	"vdev online",
3590ecd6cf80Smarks 	"vdev offline",
3591ecd6cf80Smarks 	"vdev upgrade",
3592ecd6cf80Smarks 	"pool clear",
3593ecd6cf80Smarks 	"pool scrub",
3594ecd6cf80Smarks 	"pool property set",
3595ecd6cf80Smarks 	"create",
3596ecd6cf80Smarks 	"clone",
3597ecd6cf80Smarks 	"destroy",
3598ecd6cf80Smarks 	"destroy_begin_sync",
3599ecd6cf80Smarks 	"inherit",
3600ecd6cf80Smarks 	"property set",
3601ecd6cf80Smarks 	"quota set",
3602ecd6cf80Smarks 	"permission update",
3603ecd6cf80Smarks 	"permission remove",
3604ecd6cf80Smarks 	"permission who remove",
3605ecd6cf80Smarks 	"promote",
3606ecd6cf80Smarks 	"receive",
3607ecd6cf80Smarks 	"rename",
3608ecd6cf80Smarks 	"reservation set",
3609ecd6cf80Smarks 	"replay_inc_sync",
3610ecd6cf80Smarks 	"replay_full_sync",
3611ecd6cf80Smarks 	"rollback",
3612ecd6cf80Smarks 	"snapshot",
3613e7437265Sahrens 	"filesystem version upgrade",
3614a9799022Sck153898 	"refquota set",
3615a9799022Sck153898 	"refreservation set",
3616088f3894Sahrens 	"pool scrub done",
3617ecd6cf80Smarks };
3618ecd6cf80Smarks 
361906eeb2adSek110237 /*
362006eeb2adSek110237  * Print out the command history for a specific pool.
362106eeb2adSek110237  */
362206eeb2adSek110237 static int
362306eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
362406eeb2adSek110237 {
362506eeb2adSek110237 	nvlist_t *nvhis;
362606eeb2adSek110237 	nvlist_t **records;
362706eeb2adSek110237 	uint_t numrecords;
362806eeb2adSek110237 	char *cmdstr;
3629ecd6cf80Smarks 	char *pathstr;
363006eeb2adSek110237 	uint64_t dst_time;
363106eeb2adSek110237 	time_t tsec;
363206eeb2adSek110237 	struct tm t;
363306eeb2adSek110237 	char tbuf[30];
363406eeb2adSek110237 	int ret, i;
3635ecd6cf80Smarks 	uint64_t who;
3636ecd6cf80Smarks 	struct passwd *pwd;
3637ecd6cf80Smarks 	char *hostname;
3638ecd6cf80Smarks 	char *zonename;
3639ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3640ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3641ecd6cf80Smarks 	uint64_t txg;
3642ecd6cf80Smarks 	uint64_t ievent;
364306eeb2adSek110237 
3644ecd6cf80Smarks 	cb->first = B_FALSE;
364506eeb2adSek110237 
364606eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
364706eeb2adSek110237 
364806eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
364906eeb2adSek110237 		return (ret);
365006eeb2adSek110237 
365106eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
365206eeb2adSek110237 	    &records, &numrecords) == 0);
365306eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
365406eeb2adSek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3655ecd6cf80Smarks 		    &dst_time) != 0)
3656ecd6cf80Smarks 			continue;
3657ecd6cf80Smarks 
3658ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3659ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3660ecd6cf80Smarks 		    &cmdstr) != 0) {
3661ecd6cf80Smarks 			if (cb->internal == 0)
3662ecd6cf80Smarks 				continue;
3663ecd6cf80Smarks 
3664ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3665ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3666ecd6cf80Smarks 				continue;
3667ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3668ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3669ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3670ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3671088f3894Sahrens 			if (ievent >= LOG_END)
3672ecd6cf80Smarks 				continue;
3673ecd6cf80Smarks 			(void) snprintf(internalstr,
3674ecd6cf80Smarks 			    sizeof (internalstr),
3675ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3676ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3677ecd6cf80Smarks 			    pathstr);
3678ecd6cf80Smarks 			cmdstr = internalstr;
3679ecd6cf80Smarks 		}
368006eeb2adSek110237 		tsec = dst_time;
368106eeb2adSek110237 		(void) localtime_r(&tsec, &t);
368206eeb2adSek110237 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3683ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3684ecd6cf80Smarks 
3685ecd6cf80Smarks 		if (!cb->longfmt) {
3686ecd6cf80Smarks 			(void) printf("\n");
3687ecd6cf80Smarks 			continue;
368806eeb2adSek110237 		}
3689ecd6cf80Smarks 		(void) printf(" [");
3690ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3691ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3692ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3693ecd6cf80Smarks 			if (pwd)
3694ecd6cf80Smarks 				(void) printf("user %s on",
3695ecd6cf80Smarks 				    pwd->pw_name);
3696ecd6cf80Smarks 			else
3697ecd6cf80Smarks 				(void) printf("user %d on",
3698ecd6cf80Smarks 				    (int)who);
3699ecd6cf80Smarks 		} else {
3700ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3701ecd6cf80Smarks 			continue;
3702ecd6cf80Smarks 		}
3703ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3704ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3705ecd6cf80Smarks 			(void) printf(" %s", hostname);
3706ecd6cf80Smarks 		}
3707ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3708ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3709ecd6cf80Smarks 			(void) printf(":%s", zonename);
3710ecd6cf80Smarks 		}
3711ecd6cf80Smarks 
3712ecd6cf80Smarks 		(void) printf("]");
3713ecd6cf80Smarks 		(void) printf("\n");
371406eeb2adSek110237 	}
371506eeb2adSek110237 	(void) printf("\n");
371606eeb2adSek110237 	nvlist_free(nvhis);
371706eeb2adSek110237 
371806eeb2adSek110237 	return (ret);
371906eeb2adSek110237 }
372006eeb2adSek110237 
372106eeb2adSek110237 /*
372206eeb2adSek110237  * zpool history <pool>
372306eeb2adSek110237  *
372406eeb2adSek110237  * Displays the history of commands that modified pools.
372506eeb2adSek110237  */
3726ecd6cf80Smarks 
3727ecd6cf80Smarks 
372806eeb2adSek110237 int
372906eeb2adSek110237 zpool_do_history(int argc, char **argv)
373006eeb2adSek110237 {
3731ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
373206eeb2adSek110237 	int ret;
3733ecd6cf80Smarks 	int c;
373406eeb2adSek110237 
3735ecd6cf80Smarks 	cbdata.first = B_TRUE;
3736ecd6cf80Smarks 	/* check options */
3737ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3738ecd6cf80Smarks 		switch (c) {
3739ecd6cf80Smarks 		case 'l':
3740ecd6cf80Smarks 			cbdata.longfmt = 1;
3741ecd6cf80Smarks 			break;
3742ecd6cf80Smarks 		case 'i':
3743ecd6cf80Smarks 			cbdata.internal = 1;
3744ecd6cf80Smarks 			break;
3745ecd6cf80Smarks 		case '?':
3746ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3747ecd6cf80Smarks 			    optopt);
3748ecd6cf80Smarks 			usage(B_FALSE);
3749ecd6cf80Smarks 		}
3750ecd6cf80Smarks 	}
375106eeb2adSek110237 	argc -= optind;
375206eeb2adSek110237 	argv += optind;
375306eeb2adSek110237 
3754b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3755ecd6cf80Smarks 	    &cbdata);
375606eeb2adSek110237 
3757ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
375806eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
375906eeb2adSek110237 		return (0);
3760eaca9bbdSeschrock 	}
3761eaca9bbdSeschrock 
3762eaca9bbdSeschrock 	return (ret);
3763eaca9bbdSeschrock }
3764eaca9bbdSeschrock 
3765b1b8ab34Slling static int
3766b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3767b1b8ab34Slling {
3768990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3769b1b8ab34Slling 	char value[MAXNAMELEN];
3770990b4856Slling 	zprop_source_t srctype;
3771990b4856Slling 	zprop_list_t *pl;
3772b1b8ab34Slling 
3773b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3774b1b8ab34Slling 
3775b1b8ab34Slling 		/*
3776990b4856Slling 		 * Skip the special fake placeholder. This will also skip
3777990b4856Slling 		 * over the name property when 'all' is specified.
3778b1b8ab34Slling 		 */
3779990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3780b1b8ab34Slling 		    pl == cbp->cb_proplist)
3781b1b8ab34Slling 			continue;
3782b1b8ab34Slling 
3783b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3784b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3785b1b8ab34Slling 			continue;
3786b1b8ab34Slling 
3787990b4856Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
3788b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3789b1b8ab34Slling 	}
3790b1b8ab34Slling 	return (0);
3791b1b8ab34Slling }
3792b1b8ab34Slling 
3793b1b8ab34Slling int
3794b1b8ab34Slling zpool_do_get(int argc, char **argv)
3795b1b8ab34Slling {
3796990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
3797990b4856Slling 	zprop_list_t fake_name = { 0 };
3798b1b8ab34Slling 	int ret;
3799b1b8ab34Slling 
3800b1b8ab34Slling 	if (argc < 3)
3801b1b8ab34Slling 		usage(B_FALSE);
3802b1b8ab34Slling 
3803b1b8ab34Slling 	cb.cb_first = B_TRUE;
3804990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
3805b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3806b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3807b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3808b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3809990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
3810b1b8ab34Slling 
3811990b4856Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3812990b4856Slling 	    ZFS_TYPE_POOL) != 0)
3813b1b8ab34Slling 		usage(B_FALSE);
3814b1b8ab34Slling 
3815b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3816990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
3817b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3818b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3819b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3820b1b8ab34Slling 	}
3821b1b8ab34Slling 
3822b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3823b1b8ab34Slling 	    get_callback, &cb);
3824b1b8ab34Slling 
3825b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3826990b4856Slling 		zprop_free_list(fake_name.pl_next);
3827b1b8ab34Slling 	else
3828990b4856Slling 		zprop_free_list(cb.cb_proplist);
3829b1b8ab34Slling 
3830b1b8ab34Slling 	return (ret);
3831b1b8ab34Slling }
3832b1b8ab34Slling 
3833b1b8ab34Slling typedef struct set_cbdata {
3834b1b8ab34Slling 	char *cb_propname;
3835b1b8ab34Slling 	char *cb_value;
3836b1b8ab34Slling 	boolean_t cb_any_successful;
3837b1b8ab34Slling } set_cbdata_t;
3838b1b8ab34Slling 
3839b1b8ab34Slling int
3840b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3841b1b8ab34Slling {
3842b1b8ab34Slling 	int error;
3843b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3844b1b8ab34Slling 
3845b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3846b1b8ab34Slling 
3847b1b8ab34Slling 	if (!error)
3848b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3849b1b8ab34Slling 
3850b1b8ab34Slling 	return (error);
3851b1b8ab34Slling }
3852b1b8ab34Slling 
3853b1b8ab34Slling int
3854b1b8ab34Slling zpool_do_set(int argc, char **argv)
3855b1b8ab34Slling {
3856b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3857b1b8ab34Slling 	int error;
3858b1b8ab34Slling 
3859b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3860b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3861b1b8ab34Slling 		    argv[1][1]);
3862b1b8ab34Slling 		usage(B_FALSE);
3863b1b8ab34Slling 	}
3864b1b8ab34Slling 
3865b1b8ab34Slling 	if (argc < 2) {
3866b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3867b1b8ab34Slling 		    "argument\n"));
3868b1b8ab34Slling 		usage(B_FALSE);
3869b1b8ab34Slling 	}
3870b1b8ab34Slling 
3871b1b8ab34Slling 	if (argc < 3) {
3872b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3873b1b8ab34Slling 		usage(B_FALSE);
3874b1b8ab34Slling 	}
3875b1b8ab34Slling 
3876b1b8ab34Slling 	if (argc > 3) {
3877b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3878b1b8ab34Slling 		usage(B_FALSE);
3879b1b8ab34Slling 	}
3880b1b8ab34Slling 
3881b1b8ab34Slling 	cb.cb_propname = argv[1];
3882b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3883b1b8ab34Slling 	if (cb.cb_value == NULL) {
3884b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3885b1b8ab34Slling 		    "property=value argument\n"));
3886b1b8ab34Slling 		usage(B_FALSE);
3887b1b8ab34Slling 	}
3888b1b8ab34Slling 
3889b1b8ab34Slling 	*(cb.cb_value) = '\0';
3890b1b8ab34Slling 	cb.cb_value++;
3891b1b8ab34Slling 
3892b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3893b1b8ab34Slling 	    set_callback, &cb);
3894b1b8ab34Slling 
3895b1b8ab34Slling 	return (error);
3896b1b8ab34Slling }
3897b1b8ab34Slling 
3898b1b8ab34Slling static int
3899b1b8ab34Slling find_command_idx(char *command, int *idx)
3900b1b8ab34Slling {
3901b1b8ab34Slling 	int i;
3902b1b8ab34Slling 
3903b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3904b1b8ab34Slling 		if (command_table[i].name == NULL)
3905b1b8ab34Slling 			continue;
3906b1b8ab34Slling 
3907b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3908b1b8ab34Slling 			*idx = i;
3909b1b8ab34Slling 			return (0);
3910b1b8ab34Slling 		}
3911b1b8ab34Slling 	}
3912b1b8ab34Slling 	return (1);
3913b1b8ab34Slling }
3914b1b8ab34Slling 
3915fa9e4066Sahrens int
3916fa9e4066Sahrens main(int argc, char **argv)
3917fa9e4066Sahrens {
3918fa9e4066Sahrens 	int ret;
3919fa9e4066Sahrens 	int i;
3920fa9e4066Sahrens 	char *cmdname;
3921fa9e4066Sahrens 
3922fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3923fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3924fa9e4066Sahrens 
392599653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
392699653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3927203a47d8Snd150628 		    "initialize ZFS library\n"));
392899653d4eSeschrock 		return (1);
392999653d4eSeschrock 	}
393099653d4eSeschrock 
393199653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
393299653d4eSeschrock 
3933fa9e4066Sahrens 	opterr = 0;
3934fa9e4066Sahrens 
3935fa9e4066Sahrens 	/*
3936fa9e4066Sahrens 	 * Make sure the user has specified some command.
3937fa9e4066Sahrens 	 */
3938fa9e4066Sahrens 	if (argc < 2) {
3939fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
394099653d4eSeschrock 		usage(B_FALSE);
3941fa9e4066Sahrens 	}
3942fa9e4066Sahrens 
3943fa9e4066Sahrens 	cmdname = argv[1];
3944fa9e4066Sahrens 
3945fa9e4066Sahrens 	/*
3946fa9e4066Sahrens 	 * Special case '-?'
3947fa9e4066Sahrens 	 */
3948fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
394999653d4eSeschrock 		usage(B_TRUE);
3950fa9e4066Sahrens 
39512a6b87f0Sek110237 	zpool_set_history_str("zpool", argc, argv, history_str);
39522a6b87f0Sek110237 	verify(zpool_stage_history(g_zfs, history_str) == 0);
39532a6b87f0Sek110237 
3954fa9e4066Sahrens 	/*
3955fa9e4066Sahrens 	 * Run the appropriate command.
3956fa9e4066Sahrens 	 */
3957b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
3958fa9e4066Sahrens 		current_command = &command_table[i];
3959fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
396091ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
396191ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
396291ebeef5Sahrens 		current_command = &command_table[i];
396391ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
396491ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
3965fa9e4066Sahrens 		/*
396691ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
396791ebeef5Sahrens 		 * it as such.
3968fa9e4066Sahrens 		 */
3969ea8dc4b6Seschrock 		char buf[16384];
3970ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
3971fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
3972fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
397391ebeef5Sahrens 	} else {
3974fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
3975fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
397699653d4eSeschrock 		usage(B_FALSE);
3977fa9e4066Sahrens 	}
3978fa9e4066Sahrens 
397999653d4eSeschrock 	libzfs_fini(g_zfs);
398099653d4eSeschrock 
3981fa9e4066Sahrens 	/*
3982fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3983fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
3984fa9e4066Sahrens 	 */
3985fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
3986fa9e4066Sahrens 		(void) printf("dumping core by request\n");
3987fa9e4066Sahrens 		abort();
3988fa9e4066Sahrens 	}
3989fa9e4066Sahrens 
3990fa9e4066Sahrens 	return (ret);
3991fa9e4066Sahrens }
3992