xref: /titanic_53/usr/src/cmd/zpool/zpool_main.c (revision 11022c7cf39f3b863e749f3866f6ddcb445c2d05)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5441d80aaSlling  * Common Development and Distribution License (the "License").
6441d80aaSlling  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
2199653d4eSeschrock 
22fa9e4066Sahrens /*
2318ce54dfSek110237  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28fa9e4066Sahrens 
29fa9e4066Sahrens #include <assert.h>
30fa9e4066Sahrens #include <ctype.h>
31fa9e4066Sahrens #include <dirent.h>
32fa9e4066Sahrens #include <errno.h>
33fa9e4066Sahrens #include <fcntl.h>
34fa9e4066Sahrens #include <libgen.h>
35fa9e4066Sahrens #include <libintl.h>
36fa9e4066Sahrens #include <libuutil.h>
37fa9e4066Sahrens #include <locale.h>
38fa9e4066Sahrens #include <stdio.h>
39fa9e4066Sahrens #include <stdlib.h>
40fa9e4066Sahrens #include <string.h>
41fa9e4066Sahrens #include <strings.h>
42fa9e4066Sahrens #include <unistd.h>
43fa9e4066Sahrens #include <priv.h>
44ecd6cf80Smarks #include <pwd.h>
45ecd6cf80Smarks #include <zone.h>
46b1b8ab34Slling #include <sys/fs/zfs.h>
47fa9e4066Sahrens 
48fa9e4066Sahrens #include <sys/stat.h>
49fa9e4066Sahrens 
50fa9e4066Sahrens #include <libzfs.h>
51fa9e4066Sahrens 
52fa9e4066Sahrens #include "zpool_util.h"
53fa9e4066Sahrens 
54fa9e4066Sahrens static int zpool_do_create(int, char **);
55fa9e4066Sahrens static int zpool_do_destroy(int, char **);
56fa9e4066Sahrens 
57fa9e4066Sahrens static int zpool_do_add(int, char **);
5899653d4eSeschrock static int zpool_do_remove(int, char **);
59fa9e4066Sahrens 
60fa9e4066Sahrens static int zpool_do_list(int, char **);
61fa9e4066Sahrens static int zpool_do_iostat(int, char **);
62fa9e4066Sahrens static int zpool_do_status(int, char **);
63fa9e4066Sahrens 
64fa9e4066Sahrens static int zpool_do_online(int, char **);
65fa9e4066Sahrens static int zpool_do_offline(int, char **);
66ea8dc4b6Seschrock static int zpool_do_clear(int, char **);
67fa9e4066Sahrens 
68fa9e4066Sahrens static int zpool_do_attach(int, char **);
69fa9e4066Sahrens static int zpool_do_detach(int, char **);
70fa9e4066Sahrens static int zpool_do_replace(int, char **);
71fa9e4066Sahrens 
72fa9e4066Sahrens static int zpool_do_scrub(int, char **);
73fa9e4066Sahrens 
74fa9e4066Sahrens static int zpool_do_import(int, char **);
75fa9e4066Sahrens static int zpool_do_export(int, char **);
76fa9e4066Sahrens 
77eaca9bbdSeschrock static int zpool_do_upgrade(int, char **);
78eaca9bbdSeschrock 
7906eeb2adSek110237 static int zpool_do_history(int, char **);
8006eeb2adSek110237 
81b1b8ab34Slling static int zpool_do_get(int, char **);
82b1b8ab34Slling static int zpool_do_set(int, char **);
83b1b8ab34Slling 
84fa9e4066Sahrens /*
85fa9e4066Sahrens  * These libumem hooks provide a reasonable set of defaults for the allocator's
86fa9e4066Sahrens  * debugging facilities.
87fa9e4066Sahrens  */
88fa9e4066Sahrens const char *
8999653d4eSeschrock _umem_debug_init(void)
90fa9e4066Sahrens {
91fa9e4066Sahrens 	return ("default,verbose"); /* $UMEM_DEBUG setting */
92fa9e4066Sahrens }
93fa9e4066Sahrens 
94fa9e4066Sahrens const char *
95fa9e4066Sahrens _umem_logging_init(void)
96fa9e4066Sahrens {
97fa9e4066Sahrens 	return ("fail,contents"); /* $UMEM_LOGGING setting */
98fa9e4066Sahrens }
99fa9e4066Sahrens 
10065cd9f28Seschrock typedef enum {
10165cd9f28Seschrock 	HELP_ADD,
10265cd9f28Seschrock 	HELP_ATTACH,
103ea8dc4b6Seschrock 	HELP_CLEAR,
10465cd9f28Seschrock 	HELP_CREATE,
10565cd9f28Seschrock 	HELP_DESTROY,
10665cd9f28Seschrock 	HELP_DETACH,
10765cd9f28Seschrock 	HELP_EXPORT,
10806eeb2adSek110237 	HELP_HISTORY,
10965cd9f28Seschrock 	HELP_IMPORT,
11065cd9f28Seschrock 	HELP_IOSTAT,
11165cd9f28Seschrock 	HELP_LIST,
11265cd9f28Seschrock 	HELP_OFFLINE,
11365cd9f28Seschrock 	HELP_ONLINE,
11465cd9f28Seschrock 	HELP_REPLACE,
11599653d4eSeschrock 	HELP_REMOVE,
11665cd9f28Seschrock 	HELP_SCRUB,
117eaca9bbdSeschrock 	HELP_STATUS,
118b1b8ab34Slling 	HELP_UPGRADE,
119b1b8ab34Slling 	HELP_GET,
120b1b8ab34Slling 	HELP_SET
12165cd9f28Seschrock } zpool_help_t;
12265cd9f28Seschrock 
12365cd9f28Seschrock 
124fa9e4066Sahrens typedef struct zpool_command {
125fa9e4066Sahrens 	const char	*name;
126fa9e4066Sahrens 	int		(*func)(int, char **);
12765cd9f28Seschrock 	zpool_help_t	usage;
128fa9e4066Sahrens } zpool_command_t;
129fa9e4066Sahrens 
130fa9e4066Sahrens /*
131fa9e4066Sahrens  * Master command table.  Each ZFS command has a name, associated function, and
132ea8dc4b6Seschrock  * usage message.  The usage messages need to be internationalized, so we have
133ea8dc4b6Seschrock  * to have a function to return the usage message based on a command index.
13465cd9f28Seschrock  *
13565cd9f28Seschrock  * These commands are organized according to how they are displayed in the usage
13665cd9f28Seschrock  * message.  An empty command (one with a NULL name) indicates an empty line in
13765cd9f28Seschrock  * the generic usage message.
138fa9e4066Sahrens  */
139fa9e4066Sahrens static zpool_command_t command_table[] = {
14065cd9f28Seschrock 	{ "create",	zpool_do_create,	HELP_CREATE		},
14165cd9f28Seschrock 	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
142fa9e4066Sahrens 	{ NULL },
14365cd9f28Seschrock 	{ "add",	zpool_do_add,		HELP_ADD		},
14499653d4eSeschrock 	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
145fa9e4066Sahrens 	{ NULL },
14665cd9f28Seschrock 	{ "list",	zpool_do_list,		HELP_LIST		},
14765cd9f28Seschrock 	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
14865cd9f28Seschrock 	{ "status",	zpool_do_status,	HELP_STATUS		},
149fa9e4066Sahrens 	{ NULL },
15065cd9f28Seschrock 	{ "online",	zpool_do_online,	HELP_ONLINE		},
15165cd9f28Seschrock 	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
152ea8dc4b6Seschrock 	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
153fa9e4066Sahrens 	{ NULL },
15465cd9f28Seschrock 	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
15565cd9f28Seschrock 	{ "detach",	zpool_do_detach,	HELP_DETACH		},
15665cd9f28Seschrock 	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
157fa9e4066Sahrens 	{ NULL },
15865cd9f28Seschrock 	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
159fa9e4066Sahrens 	{ NULL },
16065cd9f28Seschrock 	{ "import",	zpool_do_import,	HELP_IMPORT		},
16165cd9f28Seschrock 	{ "export",	zpool_do_export,	HELP_EXPORT		},
16206eeb2adSek110237 	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
16306eeb2adSek110237 	{ NULL },
164b1b8ab34Slling 	{ "history",	zpool_do_history,	HELP_HISTORY		},
165b1b8ab34Slling 	{ "get",	zpool_do_get,		HELP_GET		},
166b1b8ab34Slling 	{ "set",	zpool_do_set,		HELP_SET		},
167fa9e4066Sahrens };
168fa9e4066Sahrens 
169fa9e4066Sahrens #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
170fa9e4066Sahrens 
171fa9e4066Sahrens zpool_command_t *current_command;
1722a6b87f0Sek110237 static char history_str[HIS_MAX_RECORD_LEN];
173fa9e4066Sahrens 
17465cd9f28Seschrock static const char *
17565cd9f28Seschrock get_usage(zpool_help_t idx) {
17665cd9f28Seschrock 	switch (idx) {
17765cd9f28Seschrock 	case HELP_ADD:
17865cd9f28Seschrock 		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
17965cd9f28Seschrock 	case HELP_ATTACH:
18065cd9f28Seschrock 		return (gettext("\tattach [-f] <pool> <device> "
181e45ce728Sahrens 		    "<new-device>\n"));
182ea8dc4b6Seschrock 	case HELP_CLEAR:
183ea8dc4b6Seschrock 		return (gettext("\tclear <pool> [device]\n"));
18465cd9f28Seschrock 	case HELP_CREATE:
185990b4856Slling 		return (gettext("\tcreate [-fn] [-o property=value] ... \n"
186990b4856Slling 		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
18765cd9f28Seschrock 	case HELP_DESTROY:
18865cd9f28Seschrock 		return (gettext("\tdestroy [-f] <pool>\n"));
18965cd9f28Seschrock 	case HELP_DETACH:
19065cd9f28Seschrock 		return (gettext("\tdetach <pool> <device>\n"));
19165cd9f28Seschrock 	case HELP_EXPORT:
19265cd9f28Seschrock 		return (gettext("\texport [-f] <pool> ...\n"));
19306eeb2adSek110237 	case HELP_HISTORY:
194ecd6cf80Smarks 		return (gettext("\thistory [-il] [<pool>] ...\n"));
19565cd9f28Seschrock 	case HELP_IMPORT:
1964c58d714Sdarrenm 		return (gettext("\timport [-d dir] [-D]\n"
1972f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
1982f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n"
1992f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
2002f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] "
2012f8aaab3Seschrock 		    "<pool | id> [newpool]\n"));
20265cd9f28Seschrock 	case HELP_IOSTAT:
20365cd9f28Seschrock 		return (gettext("\tiostat [-v] [pool] ... [interval "
20465cd9f28Seschrock 		    "[count]]\n"));
20565cd9f28Seschrock 	case HELP_LIST:
206990b4856Slling 		return (gettext("\tlist [-H] [-o property[,...]] "
207990b4856Slling 		    "[pool] ...\n"));
20865cd9f28Seschrock 	case HELP_OFFLINE:
209441d80aaSlling 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
21065cd9f28Seschrock 	case HELP_ONLINE:
211441d80aaSlling 		return (gettext("\tonline <pool> <device> ...\n"));
21265cd9f28Seschrock 	case HELP_REPLACE:
21365cd9f28Seschrock 		return (gettext("\treplace [-f] <pool> <device> "
214e45ce728Sahrens 		    "[new-device]\n"));
21599653d4eSeschrock 	case HELP_REMOVE:
216fa94a07fSbrendan 		return (gettext("\tremove <pool> <device> ...\n"));
21765cd9f28Seschrock 	case HELP_SCRUB:
21865cd9f28Seschrock 		return (gettext("\tscrub [-s] <pool> ...\n"));
21965cd9f28Seschrock 	case HELP_STATUS:
22065cd9f28Seschrock 		return (gettext("\tstatus [-vx] [pool] ...\n"));
221eaca9bbdSeschrock 	case HELP_UPGRADE:
222eaca9bbdSeschrock 		return (gettext("\tupgrade\n"
223eaca9bbdSeschrock 		    "\tupgrade -v\n"
224990b4856Slling 		    "\tupgrade [-V version] <-a | pool ...>\n"));
225b1b8ab34Slling 	case HELP_GET:
226e45ce728Sahrens 		return (gettext("\tget <\"all\" | property[,...]> "
227b1b8ab34Slling 		    "<pool> ...\n"));
228b1b8ab34Slling 	case HELP_SET:
229b1b8ab34Slling 		return (gettext("\tset <property=value> <pool> \n"));
23065cd9f28Seschrock 	}
23165cd9f28Seschrock 
23265cd9f28Seschrock 	abort();
23365cd9f28Seschrock 	/* NOTREACHED */
23465cd9f28Seschrock }
23565cd9f28Seschrock 
236fa9e4066Sahrens 
237fa9e4066Sahrens /*
238b1b8ab34Slling  * Callback routine that will print out a pool property value.
239b1b8ab34Slling  */
240990b4856Slling static int
241990b4856Slling print_prop_cb(int prop, void *cb)
242b1b8ab34Slling {
243b1b8ab34Slling 	FILE *fp = cb;
244b1b8ab34Slling 
245b1b8ab34Slling 	(void) fprintf(fp, "\t%-13s  ", zpool_prop_to_name(prop));
246b1b8ab34Slling 
247990b4856Slling 	if (zpool_prop_readonly(prop))
248990b4856Slling 		(void) fprintf(fp, "  NO   ");
249990b4856Slling 	else
250990b4856Slling 		(void) fprintf(fp, " YES    ");
251990b4856Slling 
252b1b8ab34Slling 	if (zpool_prop_values(prop) == NULL)
253b1b8ab34Slling 		(void) fprintf(fp, "-\n");
254b1b8ab34Slling 	else
255b1b8ab34Slling 		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
256b1b8ab34Slling 
257990b4856Slling 	return (ZPROP_CONT);
258b1b8ab34Slling }
259b1b8ab34Slling 
260b1b8ab34Slling /*
261fa9e4066Sahrens  * Display usage message.  If we're inside a command, display only the usage for
262fa9e4066Sahrens  * that command.  Otherwise, iterate over the entire command table and display
263fa9e4066Sahrens  * a complete usage message.
264fa9e4066Sahrens  */
265fa9e4066Sahrens void
26699653d4eSeschrock usage(boolean_t requested)
267fa9e4066Sahrens {
268fa9e4066Sahrens 	FILE *fp = requested ? stdout : stderr;
269fa9e4066Sahrens 
270fa9e4066Sahrens 	if (current_command == NULL) {
271fa9e4066Sahrens 		int i;
272fa9e4066Sahrens 
273fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
274fa9e4066Sahrens 		(void) fprintf(fp,
275fa9e4066Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
276fa9e4066Sahrens 
277fa9e4066Sahrens 		for (i = 0; i < NCOMMAND; i++) {
278fa9e4066Sahrens 			if (command_table[i].name == NULL)
279fa9e4066Sahrens 				(void) fprintf(fp, "\n");
280fa9e4066Sahrens 			else
281fa9e4066Sahrens 				(void) fprintf(fp, "%s",
28265cd9f28Seschrock 				    get_usage(command_table[i].usage));
283fa9e4066Sahrens 		}
284fa9e4066Sahrens 	} else {
285fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
28665cd9f28Seschrock 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
287fa9e4066Sahrens 	}
288fa9e4066Sahrens 
289b1b8ab34Slling 	if (current_command != NULL &&
290b1b8ab34Slling 	    ((strcmp(current_command->name, "set") == 0) ||
291990b4856Slling 	    (strcmp(current_command->name, "get") == 0) ||
292990b4856Slling 	    (strcmp(current_command->name, "list") == 0))) {
293b1b8ab34Slling 
294b1b8ab34Slling 		(void) fprintf(fp,
295b1b8ab34Slling 		    gettext("\nthe following properties are supported:\n"));
296b1b8ab34Slling 
297990b4856Slling 		(void) fprintf(fp, "\n\t%-13s  %s  %s\n\n",
298990b4856Slling 		    "PROPERTY", "EDIT", "VALUES");
299b1b8ab34Slling 
300b1b8ab34Slling 		/* Iterate over all properties */
301990b4856Slling 		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
302990b4856Slling 		    ZFS_TYPE_POOL);
303b1b8ab34Slling 	}
304b1b8ab34Slling 
305e9dbad6fSeschrock 	/*
306e9dbad6fSeschrock 	 * See comments at end of main().
307e9dbad6fSeschrock 	 */
308e9dbad6fSeschrock 	if (getenv("ZFS_ABORT") != NULL) {
309e9dbad6fSeschrock 		(void) printf("dumping core by request\n");
310e9dbad6fSeschrock 		abort();
311e9dbad6fSeschrock 	}
312e9dbad6fSeschrock 
313fa9e4066Sahrens 	exit(requested ? 0 : 2);
314fa9e4066Sahrens }
315fa9e4066Sahrens 
316fa9e4066Sahrens void
3178654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
3188654d025Sperrin     boolean_t print_logs)
319fa9e4066Sahrens {
320fa9e4066Sahrens 	nvlist_t **child;
321fa9e4066Sahrens 	uint_t c, children;
322afefbcddSeschrock 	char *vname;
323fa9e4066Sahrens 
324fa9e4066Sahrens 	if (name != NULL)
325fa9e4066Sahrens 		(void) printf("\t%*s%s\n", indent, "", name);
326fa9e4066Sahrens 
327fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
328fa9e4066Sahrens 	    &child, &children) != 0)
329fa9e4066Sahrens 		return;
330fa9e4066Sahrens 
331afefbcddSeschrock 	for (c = 0; c < children; c++) {
3328654d025Sperrin 		uint64_t is_log = B_FALSE;
3338654d025Sperrin 
3348654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3358654d025Sperrin 		    &is_log);
3368654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
3378654d025Sperrin 			continue;
3388654d025Sperrin 
33999653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
3408654d025Sperrin 		print_vdev_tree(zhp, vname, child[c], indent + 2,
3418654d025Sperrin 		    B_FALSE);
342afefbcddSeschrock 		free(vname);
343afefbcddSeschrock 	}
344fa9e4066Sahrens }
345fa9e4066Sahrens 
346fa9e4066Sahrens /*
347990b4856Slling  * Add a property pair (name, string-value) into a property nvlist.
348990b4856Slling  */
349990b4856Slling static int
350990b4856Slling add_prop_list(const char *propname, char *propval, nvlist_t **props)
351990b4856Slling {
352990b4856Slling 	char *strval;
353990b4856Slling 	nvlist_t *proplist;
354990b4856Slling 	zpool_prop_t prop;
355990b4856Slling 
356990b4856Slling 	if (*props == NULL &&
357990b4856Slling 	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
358990b4856Slling 		(void) fprintf(stderr,
359990b4856Slling 		    gettext("internal error: out of memory\n"));
360990b4856Slling 		return (1);
361990b4856Slling 	}
362990b4856Slling 
363990b4856Slling 	proplist = *props;
364990b4856Slling 
365990b4856Slling 	if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
366990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' is "
367990b4856Slling 		    "not a valid pool property\n"), propname);
368990b4856Slling 		return (2);
369990b4856Slling 	}
370990b4856Slling 
371990b4856Slling 	/* Use normalized property name for nvlist operations */
372990b4856Slling 	if (nvlist_lookup_string(proplist, zpool_prop_to_name(prop),
3732f8aaab3Seschrock 	    &strval) == 0 && prop != ZPOOL_PROP_CACHEFILE) {
374990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' "
375990b4856Slling 		    "specified multiple times\n"), propname);
376990b4856Slling 		return (2);
377990b4856Slling 	}
378990b4856Slling 
379990b4856Slling 	if (nvlist_add_string(proplist, zpool_prop_to_name(prop),
380990b4856Slling 	    propval) != 0) {
381990b4856Slling 		(void) fprintf(stderr, gettext("internal "
382990b4856Slling 		    "error: out of memory\n"));
383990b4856Slling 		return (1);
384990b4856Slling 	}
385990b4856Slling 
386990b4856Slling 	return (0);
387990b4856Slling }
388990b4856Slling 
389990b4856Slling /*
390fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
391fa9e4066Sahrens  *
392fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
393fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
394fa9e4066Sahrens  *		they were to be added.
395fa9e4066Sahrens  *
396fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
397fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
398fa9e4066Sahrens  * libzfs.
399fa9e4066Sahrens  */
400fa9e4066Sahrens int
401fa9e4066Sahrens zpool_do_add(int argc, char **argv)
402fa9e4066Sahrens {
40399653d4eSeschrock 	boolean_t force = B_FALSE;
40499653d4eSeschrock 	boolean_t dryrun = B_FALSE;
405fa9e4066Sahrens 	int c;
406fa9e4066Sahrens 	nvlist_t *nvroot;
407fa9e4066Sahrens 	char *poolname;
408fa9e4066Sahrens 	int ret;
409fa9e4066Sahrens 	zpool_handle_t *zhp;
410fa9e4066Sahrens 	nvlist_t *config;
411fa9e4066Sahrens 
412fa9e4066Sahrens 	/* check options */
413fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
414fa9e4066Sahrens 		switch (c) {
415fa9e4066Sahrens 		case 'f':
41699653d4eSeschrock 			force = B_TRUE;
417fa9e4066Sahrens 			break;
418fa9e4066Sahrens 		case 'n':
41999653d4eSeschrock 			dryrun = B_TRUE;
420fa9e4066Sahrens 			break;
421fa9e4066Sahrens 		case '?':
422fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
423fa9e4066Sahrens 			    optopt);
42499653d4eSeschrock 			usage(B_FALSE);
425fa9e4066Sahrens 		}
426fa9e4066Sahrens 	}
427fa9e4066Sahrens 
428fa9e4066Sahrens 	argc -= optind;
429fa9e4066Sahrens 	argv += optind;
430fa9e4066Sahrens 
431fa9e4066Sahrens 	/* get pool name and check number of arguments */
432fa9e4066Sahrens 	if (argc < 1) {
433fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
43499653d4eSeschrock 		usage(B_FALSE);
435fa9e4066Sahrens 	}
436fa9e4066Sahrens 	if (argc < 2) {
437fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
43899653d4eSeschrock 		usage(B_FALSE);
439fa9e4066Sahrens 	}
440fa9e4066Sahrens 
441fa9e4066Sahrens 	poolname = argv[0];
442fa9e4066Sahrens 
443fa9e4066Sahrens 	argc--;
444fa9e4066Sahrens 	argv++;
445fa9e4066Sahrens 
44699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
447fa9e4066Sahrens 		return (1);
448fa9e4066Sahrens 
449088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
450fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
451fa9e4066Sahrens 		    poolname);
452fa9e4066Sahrens 		zpool_close(zhp);
453fa9e4066Sahrens 		return (1);
454fa9e4066Sahrens 	}
455fa9e4066Sahrens 
456fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
4578488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv);
458fa9e4066Sahrens 	if (nvroot == NULL) {
459fa9e4066Sahrens 		zpool_close(zhp);
460fa9e4066Sahrens 		return (1);
461fa9e4066Sahrens 	}
462fa9e4066Sahrens 
463fa9e4066Sahrens 	if (dryrun) {
464fa9e4066Sahrens 		nvlist_t *poolnvroot;
465fa9e4066Sahrens 
466fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
467fa9e4066Sahrens 		    &poolnvroot) == 0);
468fa9e4066Sahrens 
469fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
470fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
471fa9e4066Sahrens 
4728654d025Sperrin 		/* print original main pool and new tree */
4738654d025Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
4748654d025Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
4758654d025Sperrin 
4768654d025Sperrin 		/* Do the same for the logs */
4778654d025Sperrin 		if (num_logs(poolnvroot) > 0) {
4788654d025Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
4798654d025Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
4808654d025Sperrin 		} else if (num_logs(nvroot) > 0) {
4818654d025Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
4828654d025Sperrin 		}
483fa9e4066Sahrens 
484fa9e4066Sahrens 		ret = 0;
485fa9e4066Sahrens 	} else {
486fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
487fa9e4066Sahrens 	}
488fa9e4066Sahrens 
48999653d4eSeschrock 	nvlist_free(nvroot);
49099653d4eSeschrock 	zpool_close(zhp);
49199653d4eSeschrock 
49299653d4eSeschrock 	return (ret);
49399653d4eSeschrock }
49499653d4eSeschrock 
49599653d4eSeschrock /*
496fa94a07fSbrendan  * zpool remove <pool> <vdev> ...
49799653d4eSeschrock  *
49899653d4eSeschrock  * Removes the given vdev from the pool.  Currently, this only supports removing
499fa94a07fSbrendan  * spares and cache devices from the pool.  Eventually, we'll want to support
500fa94a07fSbrendan  * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs.
50199653d4eSeschrock  */
50299653d4eSeschrock int
50399653d4eSeschrock zpool_do_remove(int argc, char **argv)
50499653d4eSeschrock {
50599653d4eSeschrock 	char *poolname;
506fa94a07fSbrendan 	int i, ret = 0;
50799653d4eSeschrock 	zpool_handle_t *zhp;
50899653d4eSeschrock 
50999653d4eSeschrock 	argc--;
51099653d4eSeschrock 	argv++;
51199653d4eSeschrock 
51299653d4eSeschrock 	/* get pool name and check number of arguments */
51399653d4eSeschrock 	if (argc < 1) {
51499653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
51599653d4eSeschrock 		usage(B_FALSE);
51699653d4eSeschrock 	}
51799653d4eSeschrock 	if (argc < 2) {
51899653d4eSeschrock 		(void) fprintf(stderr, gettext("missing device\n"));
51999653d4eSeschrock 		usage(B_FALSE);
52099653d4eSeschrock 	}
52199653d4eSeschrock 
52299653d4eSeschrock 	poolname = argv[0];
52399653d4eSeschrock 
52499653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
52599653d4eSeschrock 		return (1);
52699653d4eSeschrock 
527fa94a07fSbrendan 	for (i = 1; i < argc; i++) {
528fa94a07fSbrendan 		if (zpool_vdev_remove(zhp, argv[i]) != 0)
529fa94a07fSbrendan 			ret = 1;
530fa94a07fSbrendan 	}
53199653d4eSeschrock 
532fa9e4066Sahrens 	return (ret);
533fa9e4066Sahrens }
534fa9e4066Sahrens 
535fa9e4066Sahrens /*
536990b4856Slling  * zpool create [-fn] [-o property=value] ... [-R root] [-m mountpoint]
537990b4856Slling  *		<pool> <dev> ...
538fa9e4066Sahrens  *
539fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
540fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
541fa9e4066Sahrens  *		were to be created.
542fa9e4066Sahrens  *      -R	Create a pool under an alternate root
543fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
544fa9e4066Sahrens  *      	'/<pool>'
545990b4856Slling  *	-o	Set property=value.
546fa9e4066Sahrens  *
547b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
548fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
549fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
550fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
551fa9e4066Sahrens  */
552fa9e4066Sahrens int
553fa9e4066Sahrens zpool_do_create(int argc, char **argv)
554fa9e4066Sahrens {
55599653d4eSeschrock 	boolean_t force = B_FALSE;
55699653d4eSeschrock 	boolean_t dryrun = B_FALSE;
557fa9e4066Sahrens 	int c;
558990b4856Slling 	nvlist_t *nvroot = NULL;
559fa9e4066Sahrens 	char *poolname;
560990b4856Slling 	int ret = 1;
561fa9e4066Sahrens 	char *altroot = NULL;
562fa9e4066Sahrens 	char *mountpoint = NULL;
56385dc7ea5Sdm120769 	nvlist_t **child;
56485dc7ea5Sdm120769 	uint_t children;
565990b4856Slling 	nvlist_t *props = NULL;
5662f8aaab3Seschrock 	char *propval;
567fa9e4066Sahrens 
568fa9e4066Sahrens 	/* check options */
569990b4856Slling 	while ((c = getopt(argc, argv, ":fnR:m:o:")) != -1) {
570fa9e4066Sahrens 		switch (c) {
571fa9e4066Sahrens 		case 'f':
57299653d4eSeschrock 			force = B_TRUE;
573fa9e4066Sahrens 			break;
574fa9e4066Sahrens 		case 'n':
57599653d4eSeschrock 			dryrun = B_TRUE;
576fa9e4066Sahrens 			break;
577fa9e4066Sahrens 		case 'R':
578fa9e4066Sahrens 			altroot = optarg;
579990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
580990b4856Slling 			    ZPOOL_PROP_ALTROOT), optarg, &props))
581990b4856Slling 				goto errout;
5822f8aaab3Seschrock 			if (nvlist_lookup_string(props,
5832f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
5842f8aaab3Seschrock 			    &propval) == 0)
5852f8aaab3Seschrock 				break;
586990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
5872f8aaab3Seschrock 			    ZPOOL_PROP_CACHEFILE), "none", &props))
588990b4856Slling 				goto errout;
589fa9e4066Sahrens 			break;
590fa9e4066Sahrens 		case 'm':
591fa9e4066Sahrens 			mountpoint = optarg;
592fa9e4066Sahrens 			break;
593990b4856Slling 		case 'o':
594990b4856Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
595990b4856Slling 				(void) fprintf(stderr, gettext("missing "
596990b4856Slling 				    "'=' for -o option\n"));
597990b4856Slling 				goto errout;
598990b4856Slling 			}
599990b4856Slling 			*propval = '\0';
600990b4856Slling 			propval++;
601990b4856Slling 
602990b4856Slling 			if (add_prop_list(optarg, propval, &props))
603990b4856Slling 				goto errout;
604990b4856Slling 			break;
605fa9e4066Sahrens 		case ':':
606fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
607fa9e4066Sahrens 			    "'%c' option\n"), optopt);
608990b4856Slling 			goto badusage;
609fa9e4066Sahrens 		case '?':
610fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
611fa9e4066Sahrens 			    optopt);
612990b4856Slling 			goto badusage;
613fa9e4066Sahrens 		}
614fa9e4066Sahrens 	}
615fa9e4066Sahrens 
616fa9e4066Sahrens 	argc -= optind;
617fa9e4066Sahrens 	argv += optind;
618fa9e4066Sahrens 
619fa9e4066Sahrens 	/* get pool name and check number of arguments */
620fa9e4066Sahrens 	if (argc < 1) {
621fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
622990b4856Slling 		goto badusage;
623fa9e4066Sahrens 	}
624fa9e4066Sahrens 	if (argc < 2) {
625fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
626990b4856Slling 		goto badusage;
627fa9e4066Sahrens 	}
628fa9e4066Sahrens 
629fa9e4066Sahrens 	poolname = argv[0];
630fa9e4066Sahrens 
631fa9e4066Sahrens 	/*
632fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
633fa9e4066Sahrens 	 * user to use 'zfs create' instead.
634fa9e4066Sahrens 	 */
635fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
636fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
637fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
638fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
639fa9e4066Sahrens 		    "create a dataset\n"));
640990b4856Slling 		goto errout;
641fa9e4066Sahrens 	}
642fa9e4066Sahrens 
643fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
64499653d4eSeschrock 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1,
64599653d4eSeschrock 	    argv + 1);
646fa9e4066Sahrens 	if (nvroot == NULL)
647fa9e4066Sahrens 		return (1);
648fa9e4066Sahrens 
64999653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
65085dc7ea5Sdm120769 	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
65185dc7ea5Sdm120769 	    &child, &children) == 0);
65285dc7ea5Sdm120769 	if (children == 0) {
65399653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
65499653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
65599653d4eSeschrock 		    "specified\n"));
656990b4856Slling 		goto errout;
65799653d4eSeschrock 	}
65899653d4eSeschrock 
65999653d4eSeschrock 
660fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
661fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
662e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
663990b4856Slling 		goto errout;
664fa9e4066Sahrens 	}
665fa9e4066Sahrens 
666fa9e4066Sahrens 	/*
667fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
668fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
669fa9e4066Sahrens 	 */
670fa9e4066Sahrens 	if (mountpoint == NULL ||
671fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
672fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
673fa9e4066Sahrens 		char buf[MAXPATHLEN];
674*11022c7cStimh 		DIR *dirp;
675fa9e4066Sahrens 
676fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
677fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
678fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
679fa9e4066Sahrens 			    "'none'\n"), mountpoint);
680990b4856Slling 			goto errout;
681fa9e4066Sahrens 		}
682fa9e4066Sahrens 
683fa9e4066Sahrens 		if (mountpoint == NULL) {
684fa9e4066Sahrens 			if (altroot != NULL)
685fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
686fa9e4066Sahrens 				    altroot, poolname);
687fa9e4066Sahrens 			else
688fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
689fa9e4066Sahrens 				    poolname);
690fa9e4066Sahrens 		} else {
691fa9e4066Sahrens 			if (altroot != NULL)
692fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
693fa9e4066Sahrens 				    altroot, mountpoint);
694fa9e4066Sahrens 			else
695fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
696fa9e4066Sahrens 				    mountpoint);
697fa9e4066Sahrens 		}
698fa9e4066Sahrens 
699*11022c7cStimh 		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
700*11022c7cStimh 			(void) fprintf(stderr, gettext("mountpoint '%s' : "
701*11022c7cStimh 			    "%s\n"), buf, strerror(errno));
702fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
703fa9e4066Sahrens 			    "option to provide a different default\n"));
704990b4856Slling 			goto errout;
705*11022c7cStimh 		} else if (dirp) {
706*11022c7cStimh 			int count = 0;
707*11022c7cStimh 
708*11022c7cStimh 			while (count < 3 && readdir(dirp) != NULL)
709*11022c7cStimh 				count++;
710*11022c7cStimh 			(void) closedir(dirp);
711*11022c7cStimh 
712*11022c7cStimh 			if (count > 2) {
713*11022c7cStimh 				(void) fprintf(stderr, gettext("mountpoint "
714*11022c7cStimh 				    "'%s' exists and is not empty\n"), buf);
715*11022c7cStimh 				(void) fprintf(stderr, gettext("use '-m' "
716*11022c7cStimh 				    "option to provide a "
717*11022c7cStimh 				    "different default\n"));
718*11022c7cStimh 				goto errout;
719*11022c7cStimh 			}
720fa9e4066Sahrens 		}
721fa9e4066Sahrens 	}
722fa9e4066Sahrens 
723fa9e4066Sahrens 	if (dryrun) {
724fa9e4066Sahrens 		/*
725fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
726fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
727fa9e4066Sahrens 		 * appropriate hierarchy.
728fa9e4066Sahrens 		 */
729fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
730fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
731fa9e4066Sahrens 
7328654d025Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7338654d025Sperrin 		if (num_logs(nvroot) > 0)
7348654d025Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
735fa9e4066Sahrens 
736fa9e4066Sahrens 		ret = 0;
737fa9e4066Sahrens 	} else {
738fa9e4066Sahrens 		/*
739fa9e4066Sahrens 		 * Hand off to libzfs.
740fa9e4066Sahrens 		 */
741990b4856Slling 		if (zpool_create(g_zfs, poolname, nvroot, props) == 0) {
74299653d4eSeschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
743fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
744fa9e4066Sahrens 			if (pool != NULL) {
745fa9e4066Sahrens 				if (mountpoint != NULL)
746fa9e4066Sahrens 					verify(zfs_prop_set(pool,
747e9dbad6fSeschrock 					    zfs_prop_to_name(
748e9dbad6fSeschrock 					    ZFS_PROP_MOUNTPOINT),
749fa9e4066Sahrens 					    mountpoint) == 0);
750fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
751da6c28aaSamw 					ret = zfs_shareall(pool);
752fa9e4066Sahrens 				zfs_close(pool);
753fa9e4066Sahrens 			}
75499653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
75599653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
75699653d4eSeschrock 			    "been omitted\n"));
757fa9e4066Sahrens 		}
758fa9e4066Sahrens 	}
759fa9e4066Sahrens 
760990b4856Slling errout:
761fa9e4066Sahrens 	nvlist_free(nvroot);
762990b4856Slling 	nvlist_free(props);
763fa9e4066Sahrens 	return (ret);
764990b4856Slling badusage:
765990b4856Slling 	nvlist_free(props);
766990b4856Slling 	usage(B_FALSE);
767990b4856Slling 	return (2);
768fa9e4066Sahrens }
769fa9e4066Sahrens 
770fa9e4066Sahrens /*
771fa9e4066Sahrens  * zpool destroy <pool>
772fa9e4066Sahrens  *
773fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
774fa9e4066Sahrens  *
775fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
776fa9e4066Sahrens  */
777fa9e4066Sahrens int
778fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
779fa9e4066Sahrens {
78099653d4eSeschrock 	boolean_t force = B_FALSE;
781fa9e4066Sahrens 	int c;
782fa9e4066Sahrens 	char *pool;
783fa9e4066Sahrens 	zpool_handle_t *zhp;
784fa9e4066Sahrens 	int ret;
785fa9e4066Sahrens 
786fa9e4066Sahrens 	/* check options */
787fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
788fa9e4066Sahrens 		switch (c) {
789fa9e4066Sahrens 		case 'f':
79099653d4eSeschrock 			force = B_TRUE;
791fa9e4066Sahrens 			break;
792fa9e4066Sahrens 		case '?':
793fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
794fa9e4066Sahrens 			    optopt);
79599653d4eSeschrock 			usage(B_FALSE);
796fa9e4066Sahrens 		}
797fa9e4066Sahrens 	}
798fa9e4066Sahrens 
799fa9e4066Sahrens 	argc -= optind;
800fa9e4066Sahrens 	argv += optind;
801fa9e4066Sahrens 
802fa9e4066Sahrens 	/* check arguments */
803fa9e4066Sahrens 	if (argc < 1) {
804fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
80599653d4eSeschrock 		usage(B_FALSE);
806fa9e4066Sahrens 	}
807fa9e4066Sahrens 	if (argc > 1) {
808fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
80999653d4eSeschrock 		usage(B_FALSE);
810fa9e4066Sahrens 	}
811fa9e4066Sahrens 
812fa9e4066Sahrens 	pool = argv[0];
813fa9e4066Sahrens 
81499653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
815fa9e4066Sahrens 		/*
816fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
817fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
818fa9e4066Sahrens 		 */
819fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
820fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
821fa9e4066Sahrens 			    "destroy a dataset\n"));
822fa9e4066Sahrens 		return (1);
823fa9e4066Sahrens 	}
824fa9e4066Sahrens 
825f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
826fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
827fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
828fa9e4066Sahrens 		return (1);
829fa9e4066Sahrens 	}
830fa9e4066Sahrens 
831fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
832fa9e4066Sahrens 
833fa9e4066Sahrens 	zpool_close(zhp);
834fa9e4066Sahrens 
835fa9e4066Sahrens 	return (ret);
836fa9e4066Sahrens }
837fa9e4066Sahrens 
838fa9e4066Sahrens /*
839fa9e4066Sahrens  * zpool export [-f] <pool> ...
840fa9e4066Sahrens  *
841fa9e4066Sahrens  *	-f	Forcefully unmount datasets
842fa9e4066Sahrens  *
843b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
844fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
845fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
846fa9e4066Sahrens  */
847fa9e4066Sahrens int
848fa9e4066Sahrens zpool_do_export(int argc, char **argv)
849fa9e4066Sahrens {
85099653d4eSeschrock 	boolean_t force = B_FALSE;
851fa9e4066Sahrens 	int c;
852fa9e4066Sahrens 	zpool_handle_t *zhp;
853fa9e4066Sahrens 	int ret;
854fa9e4066Sahrens 	int i;
855fa9e4066Sahrens 
856fa9e4066Sahrens 	/* check options */
857fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
858fa9e4066Sahrens 		switch (c) {
859fa9e4066Sahrens 		case 'f':
86099653d4eSeschrock 			force = B_TRUE;
861fa9e4066Sahrens 			break;
862fa9e4066Sahrens 		case '?':
863fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
864fa9e4066Sahrens 			    optopt);
86599653d4eSeschrock 			usage(B_FALSE);
866fa9e4066Sahrens 		}
867fa9e4066Sahrens 	}
868fa9e4066Sahrens 
869fa9e4066Sahrens 	argc -= optind;
870fa9e4066Sahrens 	argv += optind;
871fa9e4066Sahrens 
872fa9e4066Sahrens 	/* check arguments */
873fa9e4066Sahrens 	if (argc < 1) {
874fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
87599653d4eSeschrock 		usage(B_FALSE);
876fa9e4066Sahrens 	}
877fa9e4066Sahrens 
878fa9e4066Sahrens 	ret = 0;
879fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
88099653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
881fa9e4066Sahrens 			ret = 1;
882fa9e4066Sahrens 			continue;
883fa9e4066Sahrens 		}
884fa9e4066Sahrens 
885f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
886fa9e4066Sahrens 			ret = 1;
887fa9e4066Sahrens 			zpool_close(zhp);
888fa9e4066Sahrens 			continue;
889fa9e4066Sahrens 		}
890fa9e4066Sahrens 
891fa9e4066Sahrens 		if (zpool_export(zhp) != 0)
892fa9e4066Sahrens 			ret = 1;
893fa9e4066Sahrens 
894fa9e4066Sahrens 		zpool_close(zhp);
895fa9e4066Sahrens 	}
896fa9e4066Sahrens 
897fa9e4066Sahrens 	return (ret);
898fa9e4066Sahrens }
899fa9e4066Sahrens 
900fa9e4066Sahrens /*
901fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
902fa9e4066Sahrens  * name column.
903fa9e4066Sahrens  */
904fa9e4066Sahrens static int
905c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
906fa9e4066Sahrens {
90799653d4eSeschrock 	char *name = zpool_vdev_name(g_zfs, zhp, nv);
908fa9e4066Sahrens 	nvlist_t **child;
909fa9e4066Sahrens 	uint_t c, children;
910fa9e4066Sahrens 	int ret;
911fa9e4066Sahrens 
912fa9e4066Sahrens 	if (strlen(name) + depth > max)
913fa9e4066Sahrens 		max = strlen(name) + depth;
914fa9e4066Sahrens 
915afefbcddSeschrock 	free(name);
916afefbcddSeschrock 
91799653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
91899653d4eSeschrock 	    &child, &children) == 0) {
919fa9e4066Sahrens 		for (c = 0; c < children; c++)
92099653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
92199653d4eSeschrock 			    max)) > max)
922fa9e4066Sahrens 				max = ret;
92399653d4eSeschrock 	}
92499653d4eSeschrock 
925fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
926fa94a07fSbrendan 	    &child, &children) == 0) {
927fa94a07fSbrendan 		for (c = 0; c < children; c++)
928fa94a07fSbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
929fa94a07fSbrendan 			    max)) > max)
930fa94a07fSbrendan 				max = ret;
931fa94a07fSbrendan 	}
932fa94a07fSbrendan 
93399653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
93499653d4eSeschrock 	    &child, &children) == 0) {
93599653d4eSeschrock 		for (c = 0; c < children; c++)
93699653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
93799653d4eSeschrock 			    max)) > max)
93899653d4eSeschrock 				max = ret;
93999653d4eSeschrock 	}
94099653d4eSeschrock 
941fa9e4066Sahrens 
942fa9e4066Sahrens 	return (max);
943fa9e4066Sahrens }
944fa9e4066Sahrens 
945fa9e4066Sahrens 
946fa9e4066Sahrens /*
947fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
948fa9e4066Sahrens  * pool, printing out the name and status for each one.
949fa9e4066Sahrens  */
950fa9e4066Sahrens void
9518654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
9528654d025Sperrin     boolean_t print_logs)
953fa9e4066Sahrens {
954fa9e4066Sahrens 	nvlist_t **child;
955fa9e4066Sahrens 	uint_t c, children;
956fa9e4066Sahrens 	vdev_stat_t *vs;
957afefbcddSeschrock 	char *type, *vname;
958fa9e4066Sahrens 
959fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
960fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
961fa9e4066Sahrens 		return;
962fa9e4066Sahrens 
963fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
964fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
965fa9e4066Sahrens 
966fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
967990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
968fa9e4066Sahrens 
969fa9e4066Sahrens 	if (vs->vs_aux != 0) {
9703d7072f8Seschrock 		(void) printf("  ");
971fa9e4066Sahrens 
972fa9e4066Sahrens 		switch (vs->vs_aux) {
973fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
974fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
975fa9e4066Sahrens 			break;
976fa9e4066Sahrens 
977fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
978fa9e4066Sahrens 			(void) printf(gettext("missing device"));
979fa9e4066Sahrens 			break;
980fa9e4066Sahrens 
981fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
982fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
983fa9e4066Sahrens 			break;
984fa9e4066Sahrens 
985eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
986eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
987eaca9bbdSeschrock 			break;
988eaca9bbdSeschrock 
9893d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
9903d7072f8Seschrock 			(void) printf(gettext("too many errors"));
9913d7072f8Seschrock 			break;
9923d7072f8Seschrock 
993fa9e4066Sahrens 		default:
994fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
995fa9e4066Sahrens 			break;
996fa9e4066Sahrens 		}
997fa9e4066Sahrens 	}
998fa9e4066Sahrens 	(void) printf("\n");
999fa9e4066Sahrens 
1000fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1001fa9e4066Sahrens 	    &child, &children) != 0)
1002fa9e4066Sahrens 		return;
1003fa9e4066Sahrens 
1004afefbcddSeschrock 	for (c = 0; c < children; c++) {
10058654d025Sperrin 		uint64_t is_log = B_FALSE;
10068654d025Sperrin 
10078654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
10088654d025Sperrin 		    &is_log);
10098654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
10108654d025Sperrin 			continue;
10118654d025Sperrin 
101299653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1013afefbcddSeschrock 		print_import_config(vname, child[c],
10148654d025Sperrin 		    namewidth, depth + 2, B_FALSE);
1015afefbcddSeschrock 		free(vname);
1016afefbcddSeschrock 	}
101799653d4eSeschrock 
1018fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1019fa94a07fSbrendan 	    &child, &children) == 0) {
1020fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
1021fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1022fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1023fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1024fa94a07fSbrendan 			free(vname);
1025fa94a07fSbrendan 		}
1026fa94a07fSbrendan 	}
102799653d4eSeschrock 
1028fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1029fa94a07fSbrendan 	    &child, &children) == 0) {
103099653d4eSeschrock 		(void) printf(gettext("\tspares\n"));
103199653d4eSeschrock 		for (c = 0; c < children; c++) {
103299653d4eSeschrock 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
103399653d4eSeschrock 			(void) printf("\t  %s\n", vname);
103499653d4eSeschrock 			free(vname);
103599653d4eSeschrock 		}
1036fa9e4066Sahrens 	}
1037fa94a07fSbrendan }
1038fa9e4066Sahrens 
1039fa9e4066Sahrens /*
1040fa9e4066Sahrens  * Display the status for the given pool.
1041fa9e4066Sahrens  */
1042fa9e4066Sahrens static void
1043fa9e4066Sahrens show_import(nvlist_t *config)
1044fa9e4066Sahrens {
1045fa9e4066Sahrens 	uint64_t pool_state;
1046fa9e4066Sahrens 	vdev_stat_t *vs;
1047fa9e4066Sahrens 	char *name;
1048fa9e4066Sahrens 	uint64_t guid;
1049fa9e4066Sahrens 	char *msgid;
1050fa9e4066Sahrens 	nvlist_t *nvroot;
1051fa9e4066Sahrens 	int reason;
105246657f8dSmmusante 	const char *health;
1053fa9e4066Sahrens 	uint_t vsc;
1054fa9e4066Sahrens 	int namewidth;
1055fa9e4066Sahrens 
1056fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1057fa9e4066Sahrens 	    &name) == 0);
1058fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1059fa9e4066Sahrens 	    &guid) == 0);
1060fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1061fa9e4066Sahrens 	    &pool_state) == 0);
1062fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1063fa9e4066Sahrens 	    &nvroot) == 0);
1064fa9e4066Sahrens 
1065fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1066fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1067990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1068fa9e4066Sahrens 
1069fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1070fa9e4066Sahrens 
107146657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
107246657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
107346657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
10744c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
107546657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
10764c58d714Sdarrenm 	(void) printf("\n");
1077fa9e4066Sahrens 
1078fa9e4066Sahrens 	switch (reason) {
1079fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1080fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1081fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1082fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1083fa9e4066Sahrens 		    "from the system.\n"));
1084fa9e4066Sahrens 		break;
1085fa9e4066Sahrens 
1086fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1087fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1088fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1089fa9e4066Sahrens 		    "corrupted data.\n"));
1090fa9e4066Sahrens 		break;
1091fa9e4066Sahrens 
1092fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1093fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1094fa9e4066Sahrens 		break;
1095fa9e4066Sahrens 
1096441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1097441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1098441d80aaSlling 		    "are offlined.\n"));
1099441d80aaSlling 		break;
1100441d80aaSlling 
1101ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1102ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1103ea8dc4b6Seschrock 		    "corrupted.\n"));
1104ea8dc4b6Seschrock 		break;
1105ea8dc4b6Seschrock 
1106eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1107eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1108eaca9bbdSeschrock 		    "older on-disk version.\n"));
1109eaca9bbdSeschrock 		break;
1110eaca9bbdSeschrock 
1111eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1112eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1113eaca9bbdSeschrock 		    "incompatible version.\n"));
1114eaca9bbdSeschrock 		break;
111595173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
111695173954Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
111795173954Sek110237 		    "another system.\n"));
111895173954Sek110237 		break;
11193d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
11203d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
11213d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
11223d7072f8Seschrock 		    "faulted.\n"));
11233d7072f8Seschrock 		break;
11243d7072f8Seschrock 
1125fa9e4066Sahrens 	default:
1126fa9e4066Sahrens 		/*
1127fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1128fa9e4066Sahrens 		 */
1129fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1130fa9e4066Sahrens 	}
1131fa9e4066Sahrens 
1132fa9e4066Sahrens 	/*
1133fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1134fa9e4066Sahrens 	 */
113546657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1136eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1137eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1138eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1139eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1140eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
114195173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
114295173954Sek110237 			(void) printf(gettext("action: The pool can be "
114395173954Sek110237 			    "imported using its name or numeric "
114495173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1145fa9e4066Sahrens 		else
1146eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1147eaca9bbdSeschrock 			    "imported using its name or numeric "
1148eaca9bbdSeschrock 			    "identifier.\n"));
114946657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1150fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1151fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1152eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1153fa9e4066Sahrens 	} else {
1154eaca9bbdSeschrock 		switch (reason) {
1155eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1156eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1157eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1158eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1159eaca9bbdSeschrock 			    "backup.\n"));
1160eaca9bbdSeschrock 			break;
1161eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1162eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1163eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1164fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1165fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1166fa9e4066Sahrens 			    "again.\n"));
1167eaca9bbdSeschrock 			break;
1168eaca9bbdSeschrock 		default:
1169fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1170fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1171fa9e4066Sahrens 		}
1172eaca9bbdSeschrock 	}
1173eaca9bbdSeschrock 
117446657f8dSmmusante 	/*
117546657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
117646657f8dSmmusante 	 * is "corrupt data":
117746657f8dSmmusante 	 */
117846657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
117946657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
118046657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1181eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1182eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1183eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1184eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1185eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
118618ce54dfSek110237 			    "another system, but can be imported using\n\t"
1187eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1188eaca9bbdSeschrock 	}
1189fa9e4066Sahrens 
1190fa9e4066Sahrens 	if (msgid != NULL)
1191fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1192fa9e4066Sahrens 		    msgid);
1193fa9e4066Sahrens 
1194fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1195fa9e4066Sahrens 
1196c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1197fa9e4066Sahrens 	if (namewidth < 10)
1198fa9e4066Sahrens 		namewidth = 10;
11998654d025Sperrin 
12008654d025Sperrin 	print_import_config(name, nvroot, namewidth, 0, B_FALSE);
12018654d025Sperrin 	if (num_logs(nvroot) > 0) {
12028654d025Sperrin 		(void) printf(gettext("\tlogs\n"));
12038654d025Sperrin 		print_import_config(name, nvroot, namewidth, 0, B_TRUE);
12048654d025Sperrin 	}
1205fa9e4066Sahrens 
1206fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
120746657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1208fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
120946657f8dSmmusante 		    "configuration cannot be determined.\n"));
1210fa9e4066Sahrens 	}
1211fa9e4066Sahrens }
1212fa9e4066Sahrens 
1213fa9e4066Sahrens /*
1214fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1215990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1216990b4856Slling  * within the pool.
1217fa9e4066Sahrens  */
1218fa9e4066Sahrens static int
1219fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
1220990b4856Slling     int force, nvlist_t *props)
1221fa9e4066Sahrens {
1222fa9e4066Sahrens 	zpool_handle_t *zhp;
1223fa9e4066Sahrens 	char *name;
1224fa9e4066Sahrens 	uint64_t state;
1225eaca9bbdSeschrock 	uint64_t version;
1226ecd6cf80Smarks 	int error = 0;
1227fa9e4066Sahrens 
1228fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1229fa9e4066Sahrens 	    &name) == 0);
1230fa9e4066Sahrens 
1231fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1232fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1233eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1234eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1235e7437265Sahrens 	if (version > SPA_VERSION) {
1236eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1237eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1238eaca9bbdSeschrock 		return (1);
1239eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
124095173954Sek110237 		uint64_t hostid;
124195173954Sek110237 
124295173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
124395173954Sek110237 		    &hostid) == 0) {
124495173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
124595173954Sek110237 				char *hostname;
124695173954Sek110237 				uint64_t timestamp;
124795173954Sek110237 				time_t t;
124895173954Sek110237 
124995173954Sek110237 				verify(nvlist_lookup_string(config,
125095173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
125195173954Sek110237 				verify(nvlist_lookup_uint64(config,
125295173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
125395173954Sek110237 				t = timestamp;
125495173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
125595173954Sek110237 				    "'%s': pool may be in use from other "
125695173954Sek110237 				    "system, it was last accessed by %s "
125795173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
125895173954Sek110237 				    (unsigned long)hostid,
125995173954Sek110237 				    asctime(localtime(&t)));
126095173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
126195173954Sek110237 				    "import anyway\n"));
1262fa9e4066Sahrens 				return (1);
1263fa9e4066Sahrens 			}
126495173954Sek110237 		} else {
126595173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
126695173954Sek110237 			    "pool may be in use from other system\n"), name);
126795173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
126895173954Sek110237 			    "anyway\n"));
126995173954Sek110237 			return (1);
127095173954Sek110237 		}
127195173954Sek110237 	}
1272fa9e4066Sahrens 
1273990b4856Slling 	if (zpool_import_props(g_zfs, config, newname, props) != 0)
1274fa9e4066Sahrens 		return (1);
1275fa9e4066Sahrens 
1276fa9e4066Sahrens 	if (newname != NULL)
1277fa9e4066Sahrens 		name = (char *)newname;
1278fa9e4066Sahrens 
127999653d4eSeschrock 	verify((zhp = zpool_open(g_zfs, name)) != NULL);
1280fa9e4066Sahrens 
1281f3861e1aSahl 	if (zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1282fa9e4066Sahrens 		zpool_close(zhp);
1283fa9e4066Sahrens 		return (1);
1284fa9e4066Sahrens 	}
1285fa9e4066Sahrens 
1286fa9e4066Sahrens 	zpool_close(zhp);
1287ecd6cf80Smarks 	return (error);
1288fa9e4066Sahrens }
1289fa9e4066Sahrens 
1290fa9e4066Sahrens /*
12914c58d714Sdarrenm  * zpool import [-d dir] [-D]
12922f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
12932f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
12942f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
12952f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] <pool | id> [newpool]
12962f8aaab3Seschrock  *
12972f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
12982f8aaab3Seschrock  *		devices.
1299fa9e4066Sahrens  *
1300fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1301fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1302fa9e4066Sahrens  *
13034c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
13044c58d714Sdarrenm  *              specified destroyed pools.
13054c58d714Sdarrenm  *
1306fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1307fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1308fa9e4066Sahrens  *		is rebooted.
1309fa9e4066Sahrens  *
1310fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1311fa9e4066Sahrens  *
1312fa9e4066Sahrens  *       -a	Import all pools found.
1313fa9e4066Sahrens  *
1314990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1315ecd6cf80Smarks  *
1316fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1317fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1318fa9e4066Sahrens  */
1319fa9e4066Sahrens int
1320fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1321fa9e4066Sahrens {
1322fa9e4066Sahrens 	char **searchdirs = NULL;
1323fa9e4066Sahrens 	int nsearch = 0;
1324fa9e4066Sahrens 	int c;
1325fa9e4066Sahrens 	int err;
13262f8aaab3Seschrock 	nvlist_t *pools = NULL;
132799653d4eSeschrock 	boolean_t do_all = B_FALSE;
132899653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1329fa9e4066Sahrens 	char *mntopts = NULL;
133099653d4eSeschrock 	boolean_t do_force = B_FALSE;
1331fa9e4066Sahrens 	nvpair_t *elem;
1332fa9e4066Sahrens 	nvlist_t *config;
1333fa9e4066Sahrens 	uint64_t searchguid;
1334fa9e4066Sahrens 	char *searchname;
1335990b4856Slling 	char *propval;
1336fa9e4066Sahrens 	nvlist_t *found_config;
1337ecd6cf80Smarks 	nvlist_t *props = NULL;
133899653d4eSeschrock 	boolean_t first;
13394c58d714Sdarrenm 	uint64_t pool_state;
13402f8aaab3Seschrock 	char *cachefile = NULL;
1341fa9e4066Sahrens 
1342fa9e4066Sahrens 	/* check options */
13432f8aaab3Seschrock 	while ((c = getopt(argc, argv, ":afc:d:Do:p:R:")) != -1) {
1344fa9e4066Sahrens 		switch (c) {
1345fa9e4066Sahrens 		case 'a':
134699653d4eSeschrock 			do_all = B_TRUE;
1347fa9e4066Sahrens 			break;
13482f8aaab3Seschrock 		case 'c':
13492f8aaab3Seschrock 			cachefile = optarg;
13502f8aaab3Seschrock 			break;
1351fa9e4066Sahrens 		case 'd':
1352fa9e4066Sahrens 			if (searchdirs == NULL) {
1353fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1354fa9e4066Sahrens 			} else {
1355fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1356fa9e4066Sahrens 				    sizeof (char *));
1357fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1358fa9e4066Sahrens 				    sizeof (char *));
1359fa9e4066Sahrens 				free(searchdirs);
1360fa9e4066Sahrens 				searchdirs = tmp;
1361fa9e4066Sahrens 			}
1362fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1363fa9e4066Sahrens 			break;
13644c58d714Sdarrenm 		case 'D':
136599653d4eSeschrock 			do_destroyed = B_TRUE;
13664c58d714Sdarrenm 			break;
1367fa9e4066Sahrens 		case 'f':
136899653d4eSeschrock 			do_force = B_TRUE;
1369fa9e4066Sahrens 			break;
1370fa9e4066Sahrens 		case 'o':
1371990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1372990b4856Slling 				*propval = '\0';
1373990b4856Slling 				propval++;
1374990b4856Slling 				if (add_prop_list(optarg, propval, &props))
1375990b4856Slling 					goto error;
1376990b4856Slling 			} else {
1377fa9e4066Sahrens 				mntopts = optarg;
1378990b4856Slling 			}
1379fa9e4066Sahrens 			break;
1380fa9e4066Sahrens 		case 'R':
1381990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
1382990b4856Slling 			    ZPOOL_PROP_ALTROOT), optarg, &props))
1383990b4856Slling 				goto error;
13842f8aaab3Seschrock 			if (nvlist_lookup_string(props,
13852f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
13862f8aaab3Seschrock 			    &propval) == 0)
13872f8aaab3Seschrock 				break;
1388990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
13892f8aaab3Seschrock 			    ZPOOL_PROP_CACHEFILE), "none", &props))
1390990b4856Slling 				goto error;
1391fa9e4066Sahrens 			break;
1392fa9e4066Sahrens 		case ':':
1393fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1394fa9e4066Sahrens 			    "'%c' option\n"), optopt);
139599653d4eSeschrock 			usage(B_FALSE);
1396fa9e4066Sahrens 			break;
1397fa9e4066Sahrens 		case '?':
1398fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1399fa9e4066Sahrens 			    optopt);
140099653d4eSeschrock 			usage(B_FALSE);
1401fa9e4066Sahrens 		}
1402fa9e4066Sahrens 	}
1403fa9e4066Sahrens 
1404fa9e4066Sahrens 	argc -= optind;
1405fa9e4066Sahrens 	argv += optind;
1406fa9e4066Sahrens 
14072f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
14082f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
14092f8aaab3Seschrock 		usage(B_FALSE);
14102f8aaab3Seschrock 	}
14112f8aaab3Seschrock 
1412fa9e4066Sahrens 	if (searchdirs == NULL) {
1413fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1414fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1415fa9e4066Sahrens 		nsearch = 1;
1416fa9e4066Sahrens 	}
1417fa9e4066Sahrens 
1418fa9e4066Sahrens 	/* check argument count */
1419fa9e4066Sahrens 	if (do_all) {
1420fa9e4066Sahrens 		if (argc != 0) {
1421fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
142299653d4eSeschrock 			usage(B_FALSE);
1423fa9e4066Sahrens 		}
1424fa9e4066Sahrens 	} else {
1425fa9e4066Sahrens 		if (argc > 2) {
1426fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
142799653d4eSeschrock 			usage(B_FALSE);
1428fa9e4066Sahrens 		}
1429fa9e4066Sahrens 
1430fa9e4066Sahrens 		/*
1431fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1432fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1433fa9e4066Sahrens 		 * silently fail.
1434fa9e4066Sahrens 		 */
1435fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1436fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1437fa9e4066Sahrens 			    "discover pools: permission denied\n"));
143899653d4eSeschrock 			free(searchdirs);
1439fa9e4066Sahrens 			return (1);
1440fa9e4066Sahrens 		}
1441fa9e4066Sahrens 	}
1442fa9e4066Sahrens 
14432f8aaab3Seschrock 	if (cachefile)
14442f8aaab3Seschrock 		pools = zpool_find_import_cached(g_zfs, cachefile);
14452f8aaab3Seschrock 	else
14462f8aaab3Seschrock 		pools = zpool_find_import(g_zfs, nsearch, searchdirs);
14472f8aaab3Seschrock 
14482f8aaab3Seschrock 	if (pools == NULL) {
144999653d4eSeschrock 		free(searchdirs);
1450fa9e4066Sahrens 		return (1);
145199653d4eSeschrock 	}
1452fa9e4066Sahrens 
1453fa9e4066Sahrens 	/*
1454fa9e4066Sahrens 	 * We now have a list of all available pools in the given directories.
1455fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1456fa9e4066Sahrens 	 *
1457fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1458fa9e4066Sahrens 	 *		each one.
1459fa9e4066Sahrens 	 *
1460fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1461fa9e4066Sahrens 	 *
1462fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1463fa9e4066Sahrens 	 *		name and import that one.
14644c58d714Sdarrenm 	 *
14654c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1466fa9e4066Sahrens 	 */
1467fa9e4066Sahrens 	if (argc != 0) {
1468fa9e4066Sahrens 		char *endptr;
1469fa9e4066Sahrens 
1470fa9e4066Sahrens 		errno = 0;
1471fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1472fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1473fa9e4066Sahrens 			searchname = argv[0];
1474fa9e4066Sahrens 		else
1475fa9e4066Sahrens 			searchname = NULL;
1476fa9e4066Sahrens 		found_config = NULL;
1477fa9e4066Sahrens 	}
1478fa9e4066Sahrens 
1479fa9e4066Sahrens 	err = 0;
1480fa9e4066Sahrens 	elem = NULL;
148199653d4eSeschrock 	first = B_TRUE;
1482fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1483fa9e4066Sahrens 
1484fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1485fa9e4066Sahrens 
14864c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
14874c58d714Sdarrenm 		    &pool_state) == 0);
14884c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
14894c58d714Sdarrenm 			continue;
14904c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
14914c58d714Sdarrenm 			continue;
14924c58d714Sdarrenm 
1493fa9e4066Sahrens 		if (argc == 0) {
1494fa9e4066Sahrens 			if (first)
149599653d4eSeschrock 				first = B_FALSE;
14963bb79becSeschrock 			else if (!do_all)
1497fa9e4066Sahrens 				(void) printf("\n");
1498fa9e4066Sahrens 
1499fa9e4066Sahrens 			if (do_all)
1500fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1501990b4856Slling 				    do_force, props);
1502fa9e4066Sahrens 			else
1503fa9e4066Sahrens 				show_import(config);
1504fa9e4066Sahrens 		} else if (searchname != NULL) {
1505fa9e4066Sahrens 			char *name;
1506fa9e4066Sahrens 
1507fa9e4066Sahrens 			/*
1508fa9e4066Sahrens 			 * We are searching for a pool based on name.
1509fa9e4066Sahrens 			 */
1510fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1511fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1512fa9e4066Sahrens 
1513fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1514fa9e4066Sahrens 				if (found_config != NULL) {
1515fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1516fa9e4066Sahrens 					    "cannot import '%s': more than "
1517fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1518fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1519fa9e4066Sahrens 					    "import by numeric ID instead\n"));
152099653d4eSeschrock 					err = B_TRUE;
1521fa9e4066Sahrens 				}
1522fa9e4066Sahrens 				found_config = config;
1523fa9e4066Sahrens 			}
1524fa9e4066Sahrens 		} else {
1525fa9e4066Sahrens 			uint64_t guid;
1526fa9e4066Sahrens 
1527fa9e4066Sahrens 			/*
1528fa9e4066Sahrens 			 * Search for a pool by guid.
1529fa9e4066Sahrens 			 */
1530fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1531fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1532fa9e4066Sahrens 
1533fa9e4066Sahrens 			if (guid == searchguid)
1534fa9e4066Sahrens 				found_config = config;
1535fa9e4066Sahrens 		}
1536fa9e4066Sahrens 	}
1537fa9e4066Sahrens 
1538fa9e4066Sahrens 	/*
1539fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1540fa9e4066Sahrens 	 * pool, and then do the import.
1541fa9e4066Sahrens 	 */
1542fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1543fa9e4066Sahrens 		if (found_config == NULL) {
1544fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1545fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
154699653d4eSeschrock 			err = B_TRUE;
1547fa9e4066Sahrens 		} else {
1548fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1549990b4856Slling 			    argv[1], mntopts, do_force, props);
1550fa9e4066Sahrens 		}
1551fa9e4066Sahrens 	}
1552fa9e4066Sahrens 
1553fa9e4066Sahrens 	/*
1554fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1555fa9e4066Sahrens 	 * found.
1556fa9e4066Sahrens 	 */
1557fa9e4066Sahrens 	if (argc == 0 && first)
1558fa9e4066Sahrens 		(void) fprintf(stderr,
1559fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1560fa9e4066Sahrens 
1561ecd6cf80Smarks error:
1562ecd6cf80Smarks 	nvlist_free(props);
1563fa9e4066Sahrens 	nvlist_free(pools);
156499653d4eSeschrock 	free(searchdirs);
1565fa9e4066Sahrens 
1566fa9e4066Sahrens 	return (err ? 1 : 0);
1567fa9e4066Sahrens }
1568fa9e4066Sahrens 
1569fa9e4066Sahrens typedef struct iostat_cbdata {
1570fa9e4066Sahrens 	zpool_list_t *cb_list;
1571fa9e4066Sahrens 	int cb_verbose;
1572fa9e4066Sahrens 	int cb_iteration;
1573fa9e4066Sahrens 	int cb_namewidth;
1574fa9e4066Sahrens } iostat_cbdata_t;
1575fa9e4066Sahrens 
1576fa9e4066Sahrens static void
1577fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1578fa9e4066Sahrens {
1579fa9e4066Sahrens 	int i = 0;
1580fa9e4066Sahrens 
1581fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1582fa9e4066Sahrens 		(void) printf("-");
1583fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1584fa9e4066Sahrens }
1585fa9e4066Sahrens 
1586fa9e4066Sahrens static void
1587fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1588fa9e4066Sahrens {
1589fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1590fa9e4066Sahrens 	    cb->cb_namewidth, "");
1591fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1592fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1593fa9e4066Sahrens 	print_iostat_separator(cb);
1594fa9e4066Sahrens }
1595fa9e4066Sahrens 
1596fa9e4066Sahrens /*
1597fa9e4066Sahrens  * Display a single statistic.
1598fa9e4066Sahrens  */
1599990b4856Slling static void
1600fa9e4066Sahrens print_one_stat(uint64_t value)
1601fa9e4066Sahrens {
1602fa9e4066Sahrens 	char buf[64];
1603fa9e4066Sahrens 
1604fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1605fa9e4066Sahrens 	(void) printf("  %5s", buf);
1606fa9e4066Sahrens }
1607fa9e4066Sahrens 
1608fa9e4066Sahrens /*
1609fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1610fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1611fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1612fa9e4066Sahrens  */
1613fa9e4066Sahrens void
1614c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1615c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1616fa9e4066Sahrens {
1617fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1618fa9e4066Sahrens 	uint_t c, children;
1619fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1620fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1621fa9e4066Sahrens 	uint64_t tdelta;
1622fa9e4066Sahrens 	double scale;
1623afefbcddSeschrock 	char *vname;
1624fa9e4066Sahrens 
1625fa9e4066Sahrens 	if (oldnv != NULL) {
1626fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1627fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1628fa9e4066Sahrens 	} else {
1629fa9e4066Sahrens 		oldvs = &zerovs;
1630fa9e4066Sahrens 	}
1631fa9e4066Sahrens 
1632fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1633fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1634fa9e4066Sahrens 
1635fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1636fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1637fa9e4066Sahrens 	else
1638fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1639fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1640fa9e4066Sahrens 
1641fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1642fa9e4066Sahrens 
1643fa9e4066Sahrens 	if (tdelta == 0)
1644fa9e4066Sahrens 		scale = 1.0;
1645fa9e4066Sahrens 	else
1646fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1647fa9e4066Sahrens 
1648fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1649fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1650fa9e4066Sahrens 		(void) printf("      -      -");
1651fa9e4066Sahrens 	} else {
1652fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1653fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1654fa9e4066Sahrens 	}
1655fa9e4066Sahrens 
1656fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1657fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1658fa9e4066Sahrens 
1659fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1660fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1661fa9e4066Sahrens 
1662fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1663fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1664fa9e4066Sahrens 
1665fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1666fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1667fa9e4066Sahrens 
1668fa9e4066Sahrens 	(void) printf("\n");
1669fa9e4066Sahrens 
1670fa9e4066Sahrens 	if (!cb->cb_verbose)
1671fa9e4066Sahrens 		return;
1672fa9e4066Sahrens 
1673fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1674fa9e4066Sahrens 	    &newchild, &children) != 0)
1675fa9e4066Sahrens 		return;
1676fa9e4066Sahrens 
1677fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1678fa9e4066Sahrens 	    &oldchild, &c) != 0)
1679fa9e4066Sahrens 		return;
1680fa9e4066Sahrens 
1681afefbcddSeschrock 	for (c = 0; c < children; c++) {
168299653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1683c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1684afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1685afefbcddSeschrock 		free(vname);
1686afefbcddSeschrock 	}
1687fa94a07fSbrendan 
1688fa94a07fSbrendan 	/*
1689fa94a07fSbrendan 	 * Include level 2 ARC devices in iostat output
1690fa94a07fSbrendan 	 */
1691fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
1692fa94a07fSbrendan 	    &newchild, &children) != 0)
1693fa94a07fSbrendan 		return;
1694fa94a07fSbrendan 
1695fa94a07fSbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
1696fa94a07fSbrendan 	    &oldchild, &c) != 0)
1697fa94a07fSbrendan 		return;
1698fa94a07fSbrendan 
1699fa94a07fSbrendan 	if (children > 0) {
1700fa94a07fSbrendan 		(void) printf("%-*s      -      -      -      -      -      "
1701fa94a07fSbrendan 		    "-\n", cb->cb_namewidth, "cache");
1702fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1703fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1704fa94a07fSbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1705fa94a07fSbrendan 			    newchild[c], cb, depth + 2);
1706fa94a07fSbrendan 			free(vname);
1707fa94a07fSbrendan 		}
1708fa94a07fSbrendan 	}
1709fa9e4066Sahrens }
1710fa9e4066Sahrens 
1711088e9d47Seschrock static int
1712088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
1713088e9d47Seschrock {
1714088e9d47Seschrock 	iostat_cbdata_t *cb = data;
171594de1d4cSeschrock 	boolean_t missing;
1716088e9d47Seschrock 
1717088e9d47Seschrock 	/*
1718088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
1719088e9d47Seschrock 	 */
172094de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
172194de1d4cSeschrock 		return (-1);
172294de1d4cSeschrock 
172394de1d4cSeschrock 	if (missing)
1724088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
1725088e9d47Seschrock 
1726088e9d47Seschrock 	return (0);
1727088e9d47Seschrock }
1728088e9d47Seschrock 
1729fa9e4066Sahrens /*
1730fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
1731fa9e4066Sahrens  */
1732fa9e4066Sahrens int
1733fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
1734fa9e4066Sahrens {
1735fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1736fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
1737fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
1738fa9e4066Sahrens 
1739088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
1740fa9e4066Sahrens 
1741088e9d47Seschrock 	if (cb->cb_iteration == 1)
1742fa9e4066Sahrens 		oldconfig = NULL;
1743fa9e4066Sahrens 
1744fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1745fa9e4066Sahrens 	    &newnvroot) == 0);
1746fa9e4066Sahrens 
1747088e9d47Seschrock 	if (oldconfig == NULL)
1748fa9e4066Sahrens 		oldnvroot = NULL;
1749088e9d47Seschrock 	else
1750088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
1751088e9d47Seschrock 		    &oldnvroot) == 0);
1752fa9e4066Sahrens 
1753fa9e4066Sahrens 	/*
1754fa9e4066Sahrens 	 * Print out the statistics for the pool.
1755fa9e4066Sahrens 	 */
1756c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1757fa9e4066Sahrens 
1758fa9e4066Sahrens 	if (cb->cb_verbose)
1759fa9e4066Sahrens 		print_iostat_separator(cb);
1760fa9e4066Sahrens 
1761fa9e4066Sahrens 	return (0);
1762fa9e4066Sahrens }
1763fa9e4066Sahrens 
1764fa9e4066Sahrens int
1765fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
1766fa9e4066Sahrens {
1767fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1768fa9e4066Sahrens 	nvlist_t *config, *nvroot;
1769fa9e4066Sahrens 
1770088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
1771fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1772fa9e4066Sahrens 		    &nvroot) == 0);
1773fa9e4066Sahrens 		if (!cb->cb_verbose)
1774fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1775fa9e4066Sahrens 		else
1776c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
1777fa9e4066Sahrens 	}
1778fa9e4066Sahrens 
1779fa9e4066Sahrens 	/*
1780fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
1781fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
1782fa9e4066Sahrens 	 */
1783fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
1784fa9e4066Sahrens 		cb->cb_namewidth = 10;
1785fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
1786fa9e4066Sahrens 		cb->cb_namewidth = 38;
1787fa9e4066Sahrens 
1788fa9e4066Sahrens 	return (0);
1789fa9e4066Sahrens }
1790fa9e4066Sahrens 
1791fa9e4066Sahrens /*
1792fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
1793fa9e4066Sahrens  *
1794fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
1795fa9e4066Sahrens  *
1796fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
1797fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
1798fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1799fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
1800fa9e4066Sahrens  * changes are all handled within libzfs.
1801fa9e4066Sahrens  */
1802fa9e4066Sahrens int
1803fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
1804fa9e4066Sahrens {
1805fa9e4066Sahrens 	int c;
1806fa9e4066Sahrens 	int ret;
1807fa9e4066Sahrens 	int npools;
1808fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
1809fa9e4066Sahrens 	zpool_list_t *list;
181099653d4eSeschrock 	boolean_t verbose = B_FALSE;
1811fa9e4066Sahrens 	iostat_cbdata_t cb;
1812fa9e4066Sahrens 
1813fa9e4066Sahrens 	/* check options */
1814fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
1815fa9e4066Sahrens 		switch (c) {
1816fa9e4066Sahrens 		case 'v':
181799653d4eSeschrock 			verbose = B_TRUE;
1818fa9e4066Sahrens 			break;
1819fa9e4066Sahrens 		case '?':
1820fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1821fa9e4066Sahrens 			    optopt);
182299653d4eSeschrock 			usage(B_FALSE);
1823fa9e4066Sahrens 		}
1824fa9e4066Sahrens 	}
1825fa9e4066Sahrens 
1826fa9e4066Sahrens 	argc -= optind;
1827fa9e4066Sahrens 	argv += optind;
1828fa9e4066Sahrens 
1829fa9e4066Sahrens 	/*
1830fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
1831fa9e4066Sahrens 	 */
1832fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1833fa9e4066Sahrens 		char *end;
1834fa9e4066Sahrens 
1835fa9e4066Sahrens 		errno = 0;
1836fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1837fa9e4066Sahrens 
1838fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1839fa9e4066Sahrens 			if (interval == 0) {
1840fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1841fa9e4066Sahrens 				    "cannot be zero\n"));
184299653d4eSeschrock 				usage(B_FALSE);
1843fa9e4066Sahrens 			}
1844fa9e4066Sahrens 
1845fa9e4066Sahrens 			/*
1846fa9e4066Sahrens 			 * Ignore the last parameter
1847fa9e4066Sahrens 			 */
1848fa9e4066Sahrens 			argc--;
1849fa9e4066Sahrens 		} else {
1850fa9e4066Sahrens 			/*
1851fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
1852fa9e4066Sahrens 			 * user will get a more informative error message later
1853fa9e4066Sahrens 			 * on.
1854fa9e4066Sahrens 			 */
1855fa9e4066Sahrens 			interval = 0;
1856fa9e4066Sahrens 		}
1857fa9e4066Sahrens 	}
1858fa9e4066Sahrens 
1859fa9e4066Sahrens 	/*
1860fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
1861fa9e4066Sahrens 	 * and an integer.
1862fa9e4066Sahrens 	 */
1863fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1864fa9e4066Sahrens 		char *end;
1865fa9e4066Sahrens 
1866fa9e4066Sahrens 		errno = 0;
1867fa9e4066Sahrens 		count = interval;
1868fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1869fa9e4066Sahrens 
1870fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1871fa9e4066Sahrens 			if (interval == 0) {
1872fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1873fa9e4066Sahrens 				    "cannot be zero\n"));
187499653d4eSeschrock 				usage(B_FALSE);
1875fa9e4066Sahrens 			}
1876fa9e4066Sahrens 
1877fa9e4066Sahrens 			/*
1878fa9e4066Sahrens 			 * Ignore the last parameter
1879fa9e4066Sahrens 			 */
1880fa9e4066Sahrens 			argc--;
1881fa9e4066Sahrens 		} else {
1882fa9e4066Sahrens 			interval = 0;
1883fa9e4066Sahrens 		}
1884fa9e4066Sahrens 	}
1885fa9e4066Sahrens 
1886fa9e4066Sahrens 	/*
1887fa9e4066Sahrens 	 * Construct the list of all interesting pools.
1888fa9e4066Sahrens 	 */
1889fa9e4066Sahrens 	ret = 0;
1890b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
1891fa9e4066Sahrens 		return (1);
1892fa9e4066Sahrens 
189399653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
189499653d4eSeschrock 		pool_list_free(list);
1895fa9e4066Sahrens 		return (1);
189699653d4eSeschrock 	}
1897fa9e4066Sahrens 
1898fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
189999653d4eSeschrock 		pool_list_free(list);
1900fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
1901fa9e4066Sahrens 		return (1);
1902fa9e4066Sahrens 	}
1903fa9e4066Sahrens 
1904fa9e4066Sahrens 	/*
1905fa9e4066Sahrens 	 * Enter the main iostat loop.
1906fa9e4066Sahrens 	 */
1907fa9e4066Sahrens 	cb.cb_list = list;
1908fa9e4066Sahrens 	cb.cb_verbose = verbose;
1909fa9e4066Sahrens 	cb.cb_iteration = 0;
1910fa9e4066Sahrens 	cb.cb_namewidth = 0;
1911fa9e4066Sahrens 
1912fa9e4066Sahrens 	for (;;) {
1913fa9e4066Sahrens 		pool_list_update(list);
1914fa9e4066Sahrens 
1915fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
1916fa9e4066Sahrens 			break;
1917fa9e4066Sahrens 
1918fa9e4066Sahrens 		/*
1919088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
1920088e9d47Seschrock 		 * before calculating the maximum name width, so that any
1921088e9d47Seschrock 		 * configuration changes are properly accounted for.
1922088e9d47Seschrock 		 */
192399653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
1924088e9d47Seschrock 
1925088e9d47Seschrock 		/*
1926fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
1927fa9e4066Sahrens 		 * for the pool / device name column across all pools.
1928fa9e4066Sahrens 		 */
1929fa9e4066Sahrens 		cb.cb_namewidth = 0;
193099653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
1931fa9e4066Sahrens 
1932fa9e4066Sahrens 		/*
1933fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
1934fa9e4066Sahrens 		 */
1935fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
1936fa9e4066Sahrens 			print_iostat_header(&cb);
1937fa9e4066Sahrens 
193899653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
1939fa9e4066Sahrens 
1940fa9e4066Sahrens 		/*
1941fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
1942fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
1943fa9e4066Sahrens 		 */
1944fa9e4066Sahrens 		if (npools > 1 && !verbose)
1945fa9e4066Sahrens 			print_iostat_separator(&cb);
1946fa9e4066Sahrens 
1947fa9e4066Sahrens 		if (verbose)
1948fa9e4066Sahrens 			(void) printf("\n");
1949fa9e4066Sahrens 
195039c23413Seschrock 		/*
195139c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
195239c23413Seschrock 		 * indefinitely.
195339c23413Seschrock 		 */
195439c23413Seschrock 		(void) fflush(stdout);
195539c23413Seschrock 
1956fa9e4066Sahrens 		if (interval == 0)
1957fa9e4066Sahrens 			break;
1958fa9e4066Sahrens 
1959fa9e4066Sahrens 		if (count != 0 && --count == 0)
1960fa9e4066Sahrens 			break;
1961fa9e4066Sahrens 
1962fa9e4066Sahrens 		(void) sleep(interval);
1963fa9e4066Sahrens 	}
1964fa9e4066Sahrens 
1965fa9e4066Sahrens 	pool_list_free(list);
1966fa9e4066Sahrens 
1967fa9e4066Sahrens 	return (ret);
1968fa9e4066Sahrens }
1969fa9e4066Sahrens 
1970fa9e4066Sahrens typedef struct list_cbdata {
197199653d4eSeschrock 	boolean_t	cb_scripted;
197299653d4eSeschrock 	boolean_t	cb_first;
1973990b4856Slling 	zprop_list_t	*cb_proplist;
1974fa9e4066Sahrens } list_cbdata_t;
1975fa9e4066Sahrens 
1976fa9e4066Sahrens /*
1977fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
1978fa9e4066Sahrens  */
1979990b4856Slling static void
1980990b4856Slling print_header(zprop_list_t *pl)
1981fa9e4066Sahrens {
1982990b4856Slling 	const char *header;
1983990b4856Slling 	boolean_t first = B_TRUE;
1984990b4856Slling 	boolean_t right_justify;
1985fa9e4066Sahrens 
1986990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
1987990b4856Slling 		if (pl->pl_prop == ZPROP_INVAL)
1988990b4856Slling 			continue;
1989990b4856Slling 
1990990b4856Slling 		if (!first)
1991fa9e4066Sahrens 			(void) printf("  ");
1992fa9e4066Sahrens 		else
1993990b4856Slling 			first = B_FALSE;
1994fa9e4066Sahrens 
1995990b4856Slling 		header = zpool_prop_column_name(pl->pl_prop);
1996990b4856Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
1997990b4856Slling 
1998990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
1999990b4856Slling 			(void) printf("%s", header);
2000990b4856Slling 		else if (right_justify)
2001990b4856Slling 			(void) printf("%*s", pl->pl_width, header);
2002990b4856Slling 		else
2003990b4856Slling 			(void) printf("%-*s", pl->pl_width, header);
2004fa9e4066Sahrens 	}
2005fa9e4066Sahrens 
2006fa9e4066Sahrens 	(void) printf("\n");
2007fa9e4066Sahrens }
2008fa9e4066Sahrens 
2009990b4856Slling /*
2010990b4856Slling  * Given a pool and a list of properties, print out all the properties according
2011990b4856Slling  * to the described layout.
2012990b4856Slling  */
2013990b4856Slling static void
2014990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
2015990b4856Slling {
2016990b4856Slling 	boolean_t first = B_TRUE;
2017990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
2018990b4856Slling 	char *propstr;
2019990b4856Slling 	boolean_t right_justify;
2020990b4856Slling 	int width;
2021990b4856Slling 
2022990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2023990b4856Slling 		if (!first) {
2024990b4856Slling 			if (scripted)
2025990b4856Slling 				(void) printf("\t");
2026990b4856Slling 			else
2027990b4856Slling 				(void) printf("  ");
2028990b4856Slling 		} else {
2029990b4856Slling 			first = B_FALSE;
2030990b4856Slling 		}
2031990b4856Slling 
2032990b4856Slling 		right_justify = B_FALSE;
2033990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
2034990b4856Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
2035990b4856Slling 			    sizeof (property), NULL) != 0)
2036990b4856Slling 				propstr = "-";
2037990b4856Slling 			else
2038990b4856Slling 				propstr = property;
2039990b4856Slling 
2040990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2041990b4856Slling 		} else {
2042990b4856Slling 			propstr = "-";
2043990b4856Slling 		}
2044990b4856Slling 
2045990b4856Slling 		width = pl->pl_width;
2046990b4856Slling 
2047990b4856Slling 		/*
2048990b4856Slling 		 * If this is being called in scripted mode, or if this is the
2049990b4856Slling 		 * last column and it is left-justified, don't include a width
2050990b4856Slling 		 * format specifier.
2051990b4856Slling 		 */
2052990b4856Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
2053990b4856Slling 			(void) printf("%s", propstr);
2054990b4856Slling 		else if (right_justify)
2055990b4856Slling 			(void) printf("%*s", width, propstr);
2056990b4856Slling 		else
2057990b4856Slling 			(void) printf("%-*s", width, propstr);
2058990b4856Slling 	}
2059990b4856Slling 
2060990b4856Slling 	(void) printf("\n");
2061990b4856Slling }
2062990b4856Slling 
2063990b4856Slling /*
2064990b4856Slling  * Generic callback function to list a pool.
2065990b4856Slling  */
2066fa9e4066Sahrens int
2067fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2068fa9e4066Sahrens {
2069fa9e4066Sahrens 	list_cbdata_t *cbp = data;
2070fa9e4066Sahrens 
2071fa9e4066Sahrens 	if (cbp->cb_first) {
2072fa9e4066Sahrens 		if (!cbp->cb_scripted)
2073990b4856Slling 			print_header(cbp->cb_proplist);
207499653d4eSeschrock 		cbp->cb_first = B_FALSE;
2075fa9e4066Sahrens 	}
2076fa9e4066Sahrens 
2077990b4856Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2078fa9e4066Sahrens 
2079fa9e4066Sahrens 	return (0);
2080fa9e4066Sahrens }
2081fa9e4066Sahrens 
2082fa9e4066Sahrens /*
2083990b4856Slling  * zpool list [-H] [-o prop[,prop]*] [pool] ...
2084fa9e4066Sahrens  *
2085990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2086990b4856Slling  *		by a single tab.
2087990b4856Slling  *	-o	List of properties to display.  Defaults to
2088990b4856Slling  *		"name,size,used,available,capacity,health,altroot"
2089fa9e4066Sahrens  *
2090fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2091fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2092fa9e4066Sahrens  */
2093fa9e4066Sahrens int
2094fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2095fa9e4066Sahrens {
2096fa9e4066Sahrens 	int c;
2097fa9e4066Sahrens 	int ret;
2098fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2099990b4856Slling 	static char default_props[] =
2100990b4856Slling 	    "name,size,used,available,capacity,health,altroot";
2101990b4856Slling 	char *props = default_props;
2102fa9e4066Sahrens 
2103fa9e4066Sahrens 	/* check options */
2104fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2105fa9e4066Sahrens 		switch (c) {
2106fa9e4066Sahrens 		case 'H':
210799653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2108fa9e4066Sahrens 			break;
2109fa9e4066Sahrens 		case 'o':
2110990b4856Slling 			props = optarg;
2111fa9e4066Sahrens 			break;
2112fa9e4066Sahrens 		case ':':
2113fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2114fa9e4066Sahrens 			    "'%c' option\n"), optopt);
211599653d4eSeschrock 			usage(B_FALSE);
2116fa9e4066Sahrens 			break;
2117fa9e4066Sahrens 		case '?':
2118fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2119fa9e4066Sahrens 			    optopt);
212099653d4eSeschrock 			usage(B_FALSE);
2121fa9e4066Sahrens 		}
2122fa9e4066Sahrens 	}
2123fa9e4066Sahrens 
2124fa9e4066Sahrens 	argc -= optind;
2125fa9e4066Sahrens 	argv += optind;
2126fa9e4066Sahrens 
2127990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
212899653d4eSeschrock 		usage(B_FALSE);
2129fa9e4066Sahrens 
213099653d4eSeschrock 	cb.cb_first = B_TRUE;
2131fa9e4066Sahrens 
2132990b4856Slling 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2133990b4856Slling 	    list_callback, &cb);
2134990b4856Slling 
2135990b4856Slling 	zprop_free_list(cb.cb_proplist);
2136fa9e4066Sahrens 
2137fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2138fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2139fa9e4066Sahrens 		return (0);
2140fa9e4066Sahrens 	}
2141fa9e4066Sahrens 
2142fa9e4066Sahrens 	return (ret);
2143fa9e4066Sahrens }
2144fa9e4066Sahrens 
2145fa9e4066Sahrens static nvlist_t *
2146fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2147fa9e4066Sahrens {
2148fa9e4066Sahrens 	nvlist_t **child;
2149fa9e4066Sahrens 	uint_t c, children;
2150fa9e4066Sahrens 	nvlist_t *match;
2151fa9e4066Sahrens 	char *path;
2152fa9e4066Sahrens 
2153fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2154fa9e4066Sahrens 	    &child, &children) != 0) {
2155fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2156fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2157fa9e4066Sahrens 			name += 9;
2158fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2159fa9e4066Sahrens 			path += 9;
2160fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2161fa9e4066Sahrens 			return (nv);
2162fa9e4066Sahrens 		return (NULL);
2163fa9e4066Sahrens 	}
2164fa9e4066Sahrens 
2165fa9e4066Sahrens 	for (c = 0; c < children; c++)
2166fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2167fa9e4066Sahrens 			return (match);
2168fa9e4066Sahrens 
2169fa9e4066Sahrens 	return (NULL);
2170fa9e4066Sahrens }
2171fa9e4066Sahrens 
2172fa9e4066Sahrens static int
2173fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2174fa9e4066Sahrens {
217599653d4eSeschrock 	boolean_t force = B_FALSE;
2176fa9e4066Sahrens 	int c;
2177fa9e4066Sahrens 	nvlist_t *nvroot;
2178fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2179fa9e4066Sahrens 	zpool_handle_t *zhp;
218099653d4eSeschrock 	int ret;
2181fa9e4066Sahrens 
2182fa9e4066Sahrens 	/* check options */
2183fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2184fa9e4066Sahrens 		switch (c) {
2185fa9e4066Sahrens 		case 'f':
218699653d4eSeschrock 			force = B_TRUE;
2187fa9e4066Sahrens 			break;
2188fa9e4066Sahrens 		case '?':
2189fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2190fa9e4066Sahrens 			    optopt);
219199653d4eSeschrock 			usage(B_FALSE);
2192fa9e4066Sahrens 		}
2193fa9e4066Sahrens 	}
2194fa9e4066Sahrens 
2195fa9e4066Sahrens 	argc -= optind;
2196fa9e4066Sahrens 	argv += optind;
2197fa9e4066Sahrens 
2198fa9e4066Sahrens 	/* get pool name and check number of arguments */
2199fa9e4066Sahrens 	if (argc < 1) {
2200fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
220199653d4eSeschrock 		usage(B_FALSE);
2202fa9e4066Sahrens 	}
2203fa9e4066Sahrens 
2204fa9e4066Sahrens 	poolname = argv[0];
2205fa9e4066Sahrens 
2206fa9e4066Sahrens 	if (argc < 2) {
2207fa9e4066Sahrens 		(void) fprintf(stderr,
2208fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
220999653d4eSeschrock 		usage(B_FALSE);
2210fa9e4066Sahrens 	}
2211fa9e4066Sahrens 
2212fa9e4066Sahrens 	old_disk = argv[1];
2213fa9e4066Sahrens 
2214fa9e4066Sahrens 	if (argc < 3) {
2215fa9e4066Sahrens 		if (!replacing) {
2216fa9e4066Sahrens 			(void) fprintf(stderr,
2217fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
221899653d4eSeschrock 			usage(B_FALSE);
2219fa9e4066Sahrens 		}
2220fa9e4066Sahrens 		new_disk = old_disk;
2221fa9e4066Sahrens 		argc -= 1;
2222fa9e4066Sahrens 		argv += 1;
2223fa9e4066Sahrens 	} else {
2224fa9e4066Sahrens 		new_disk = argv[2];
2225fa9e4066Sahrens 		argc -= 2;
2226fa9e4066Sahrens 		argv += 2;
2227fa9e4066Sahrens 	}
2228fa9e4066Sahrens 
2229fa9e4066Sahrens 	if (argc > 1) {
2230fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
223199653d4eSeschrock 		usage(B_FALSE);
2232fa9e4066Sahrens 	}
2233fa9e4066Sahrens 
223499653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2235fa9e4066Sahrens 		return (1);
2236fa9e4066Sahrens 
22378488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2238fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2239fa9e4066Sahrens 		    poolname);
2240fa9e4066Sahrens 		zpool_close(zhp);
2241fa9e4066Sahrens 		return (1);
2242fa9e4066Sahrens 	}
2243fa9e4066Sahrens 
22448488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv);
2245fa9e4066Sahrens 	if (nvroot == NULL) {
2246fa9e4066Sahrens 		zpool_close(zhp);
2247fa9e4066Sahrens 		return (1);
2248fa9e4066Sahrens 	}
2249fa9e4066Sahrens 
225099653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
225199653d4eSeschrock 
225299653d4eSeschrock 	nvlist_free(nvroot);
225399653d4eSeschrock 	zpool_close(zhp);
225499653d4eSeschrock 
225599653d4eSeschrock 	return (ret);
2256fa9e4066Sahrens }
2257fa9e4066Sahrens 
2258fa9e4066Sahrens /*
2259fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2260fa9e4066Sahrens  *
2261fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2262fa9e4066Sahrens  *
2263fa9e4066Sahrens  * Replace <device> with <new_device>.
2264fa9e4066Sahrens  */
2265fa9e4066Sahrens /* ARGSUSED */
2266fa9e4066Sahrens int
2267fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2268fa9e4066Sahrens {
2269fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2270fa9e4066Sahrens }
2271fa9e4066Sahrens 
2272fa9e4066Sahrens /*
2273fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2274fa9e4066Sahrens  *
2275fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2276fa9e4066Sahrens  *
2277fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2278fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2279fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2280fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2281fa9e4066Sahrens  */
2282fa9e4066Sahrens int
2283fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2284fa9e4066Sahrens {
2285fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2286fa9e4066Sahrens }
2287fa9e4066Sahrens 
2288fa9e4066Sahrens /*
2289fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2290fa9e4066Sahrens  *
2291fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2292fa9e4066Sahrens  *		(not supported yet)
2293fa9e4066Sahrens  *
2294fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2295fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2296fa9e4066Sahrens  * has the only valid copy of some data.
2297fa9e4066Sahrens  */
2298fa9e4066Sahrens /* ARGSUSED */
2299fa9e4066Sahrens int
2300fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2301fa9e4066Sahrens {
2302fa9e4066Sahrens 	int c;
2303fa9e4066Sahrens 	char *poolname, *path;
2304fa9e4066Sahrens 	zpool_handle_t *zhp;
230599653d4eSeschrock 	int ret;
2306fa9e4066Sahrens 
2307fa9e4066Sahrens 	/* check options */
2308fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2309fa9e4066Sahrens 		switch (c) {
2310fa9e4066Sahrens 		case 'f':
2311fa9e4066Sahrens 		case '?':
2312fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2313fa9e4066Sahrens 			    optopt);
231499653d4eSeschrock 			usage(B_FALSE);
2315fa9e4066Sahrens 		}
2316fa9e4066Sahrens 	}
2317fa9e4066Sahrens 
2318fa9e4066Sahrens 	argc -= optind;
2319fa9e4066Sahrens 	argv += optind;
2320fa9e4066Sahrens 
2321fa9e4066Sahrens 	/* get pool name and check number of arguments */
2322fa9e4066Sahrens 	if (argc < 1) {
2323fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
232499653d4eSeschrock 		usage(B_FALSE);
2325fa9e4066Sahrens 	}
2326fa9e4066Sahrens 
2327fa9e4066Sahrens 	if (argc < 2) {
2328fa9e4066Sahrens 		(void) fprintf(stderr,
2329fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
233099653d4eSeschrock 		usage(B_FALSE);
2331fa9e4066Sahrens 	}
2332fa9e4066Sahrens 
2333fa9e4066Sahrens 	poolname = argv[0];
2334fa9e4066Sahrens 	path = argv[1];
2335fa9e4066Sahrens 
233699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2337fa9e4066Sahrens 		return (1);
2338fa9e4066Sahrens 
233999653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
234099653d4eSeschrock 
234199653d4eSeschrock 	zpool_close(zhp);
234299653d4eSeschrock 
234399653d4eSeschrock 	return (ret);
2344fa9e4066Sahrens }
2345fa9e4066Sahrens 
2346fa9e4066Sahrens /*
2347441d80aaSlling  * zpool online <pool> <device> ...
2348fa9e4066Sahrens  */
2349fa9e4066Sahrens int
2350fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2351fa9e4066Sahrens {
2352fa9e4066Sahrens 	int c, i;
2353fa9e4066Sahrens 	char *poolname;
2354fa9e4066Sahrens 	zpool_handle_t *zhp;
2355fa9e4066Sahrens 	int ret = 0;
23563d7072f8Seschrock 	vdev_state_t newstate;
2357fa9e4066Sahrens 
2358fa9e4066Sahrens 	/* check options */
2359fa9e4066Sahrens 	while ((c = getopt(argc, argv, "t")) != -1) {
2360fa9e4066Sahrens 		switch (c) {
2361fa9e4066Sahrens 		case 't':
2362fa9e4066Sahrens 		case '?':
2363fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2364fa9e4066Sahrens 			    optopt);
236599653d4eSeschrock 			usage(B_FALSE);
2366fa9e4066Sahrens 		}
2367fa9e4066Sahrens 	}
2368fa9e4066Sahrens 
2369fa9e4066Sahrens 	argc -= optind;
2370fa9e4066Sahrens 	argv += optind;
2371fa9e4066Sahrens 
2372fa9e4066Sahrens 	/* get pool name and check number of arguments */
2373fa9e4066Sahrens 	if (argc < 1) {
2374fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
237599653d4eSeschrock 		usage(B_FALSE);
2376fa9e4066Sahrens 	}
2377fa9e4066Sahrens 	if (argc < 2) {
2378fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
237999653d4eSeschrock 		usage(B_FALSE);
2380fa9e4066Sahrens 	}
2381fa9e4066Sahrens 
2382fa9e4066Sahrens 	poolname = argv[0];
2383fa9e4066Sahrens 
238499653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2385fa9e4066Sahrens 		return (1);
2386fa9e4066Sahrens 
23873d7072f8Seschrock 	for (i = 1; i < argc; i++) {
23883d7072f8Seschrock 		if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
23893d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
23903d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
23913d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
2392fa9e4066Sahrens 				    argv[i]);
23933d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
23943d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
23953d7072f8Seschrock 					    "clear' to restore a faulted "
23963d7072f8Seschrock 					    "device\n"));
2397fa9e4066Sahrens 				else
23983d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
23993d7072f8Seschrock 					    "replace' to replace devices "
24003d7072f8Seschrock 					    "that are no longer present\n"));
24013d7072f8Seschrock 			}
24023d7072f8Seschrock 		} else {
2403fa9e4066Sahrens 			ret = 1;
24043d7072f8Seschrock 		}
24053d7072f8Seschrock 	}
2406fa9e4066Sahrens 
240799653d4eSeschrock 	zpool_close(zhp);
240899653d4eSeschrock 
2409fa9e4066Sahrens 	return (ret);
2410fa9e4066Sahrens }
2411fa9e4066Sahrens 
2412fa9e4066Sahrens /*
2413441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2414fa9e4066Sahrens  *
2415fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2416fa9e4066Sahrens  *		so would appear to compromise pool availability.
2417fa9e4066Sahrens  *		(not supported yet)
2418fa9e4066Sahrens  *
2419fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2420fa9e4066Sahrens  *		state will not be persistent across reboots.
2421fa9e4066Sahrens  */
2422fa9e4066Sahrens /* ARGSUSED */
2423fa9e4066Sahrens int
2424fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2425fa9e4066Sahrens {
2426fa9e4066Sahrens 	int c, i;
2427fa9e4066Sahrens 	char *poolname;
2428fa9e4066Sahrens 	zpool_handle_t *zhp;
242999653d4eSeschrock 	int ret = 0;
243099653d4eSeschrock 	boolean_t istmp = B_FALSE;
2431fa9e4066Sahrens 
2432fa9e4066Sahrens 	/* check options */
2433fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2434fa9e4066Sahrens 		switch (c) {
2435fa9e4066Sahrens 		case 't':
243699653d4eSeschrock 			istmp = B_TRUE;
2437441d80aaSlling 			break;
2438441d80aaSlling 		case 'f':
2439fa9e4066Sahrens 		case '?':
2440fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2441fa9e4066Sahrens 			    optopt);
244299653d4eSeschrock 			usage(B_FALSE);
2443fa9e4066Sahrens 		}
2444fa9e4066Sahrens 	}
2445fa9e4066Sahrens 
2446fa9e4066Sahrens 	argc -= optind;
2447fa9e4066Sahrens 	argv += optind;
2448fa9e4066Sahrens 
2449fa9e4066Sahrens 	/* get pool name and check number of arguments */
2450fa9e4066Sahrens 	if (argc < 1) {
2451fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
245299653d4eSeschrock 		usage(B_FALSE);
2453fa9e4066Sahrens 	}
2454fa9e4066Sahrens 	if (argc < 2) {
2455fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
245699653d4eSeschrock 		usage(B_FALSE);
2457fa9e4066Sahrens 	}
2458fa9e4066Sahrens 
2459fa9e4066Sahrens 	poolname = argv[0];
2460fa9e4066Sahrens 
246199653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2462fa9e4066Sahrens 		return (1);
2463fa9e4066Sahrens 
24643d7072f8Seschrock 	for (i = 1; i < argc; i++) {
24653d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2466fa9e4066Sahrens 			ret = 1;
24673d7072f8Seschrock 	}
2468fa9e4066Sahrens 
246999653d4eSeschrock 	zpool_close(zhp);
247099653d4eSeschrock 
2471fa9e4066Sahrens 	return (ret);
2472fa9e4066Sahrens }
2473fa9e4066Sahrens 
2474ea8dc4b6Seschrock /*
2475ea8dc4b6Seschrock  * zpool clear <pool> [device]
2476ea8dc4b6Seschrock  *
2477ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2478ea8dc4b6Seschrock  */
2479ea8dc4b6Seschrock int
2480ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2481ea8dc4b6Seschrock {
2482ea8dc4b6Seschrock 	int ret = 0;
2483ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2484ea8dc4b6Seschrock 	char *pool, *device;
2485ea8dc4b6Seschrock 
2486ea8dc4b6Seschrock 	if (argc < 2) {
2487ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
248899653d4eSeschrock 		usage(B_FALSE);
2489ea8dc4b6Seschrock 	}
2490ea8dc4b6Seschrock 
2491ea8dc4b6Seschrock 	if (argc > 3) {
2492ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
249399653d4eSeschrock 		usage(B_FALSE);
2494ea8dc4b6Seschrock 	}
2495ea8dc4b6Seschrock 
2496ea8dc4b6Seschrock 	pool = argv[1];
2497ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2498ea8dc4b6Seschrock 
249999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, pool)) == NULL)
2500ea8dc4b6Seschrock 		return (1);
2501ea8dc4b6Seschrock 
2502ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2503ea8dc4b6Seschrock 		ret = 1;
2504ea8dc4b6Seschrock 
2505ea8dc4b6Seschrock 	zpool_close(zhp);
2506ea8dc4b6Seschrock 
2507ea8dc4b6Seschrock 	return (ret);
2508ea8dc4b6Seschrock }
2509ea8dc4b6Seschrock 
2510fa9e4066Sahrens typedef struct scrub_cbdata {
2511fa9e4066Sahrens 	int	cb_type;
251206eeb2adSek110237 	int	cb_argc;
251306eeb2adSek110237 	char	**cb_argv;
2514fa9e4066Sahrens } scrub_cbdata_t;
2515fa9e4066Sahrens 
2516fa9e4066Sahrens int
2517fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2518fa9e4066Sahrens {
2519fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
252006eeb2adSek110237 	int err;
2521fa9e4066Sahrens 
2522ea8dc4b6Seschrock 	/*
2523ea8dc4b6Seschrock 	 * Ignore faulted pools.
2524ea8dc4b6Seschrock 	 */
2525ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2526ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2527ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2528ea8dc4b6Seschrock 		return (1);
2529ea8dc4b6Seschrock 	}
2530ea8dc4b6Seschrock 
253106eeb2adSek110237 	err = zpool_scrub(zhp, cb->cb_type);
253206eeb2adSek110237 
253306eeb2adSek110237 	return (err != 0);
2534fa9e4066Sahrens }
2535fa9e4066Sahrens 
2536fa9e4066Sahrens /*
2537fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2538fa9e4066Sahrens  *
2539fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2540fa9e4066Sahrens  */
2541fa9e4066Sahrens int
2542fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2543fa9e4066Sahrens {
2544fa9e4066Sahrens 	int c;
2545fa9e4066Sahrens 	scrub_cbdata_t cb;
2546fa9e4066Sahrens 
2547fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2548fa9e4066Sahrens 
2549fa9e4066Sahrens 	/* check options */
2550fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2551fa9e4066Sahrens 		switch (c) {
2552fa9e4066Sahrens 		case 's':
2553fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2554fa9e4066Sahrens 			break;
2555fa9e4066Sahrens 		case '?':
2556fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2557fa9e4066Sahrens 			    optopt);
255899653d4eSeschrock 			usage(B_FALSE);
2559fa9e4066Sahrens 		}
2560fa9e4066Sahrens 	}
2561fa9e4066Sahrens 
256206eeb2adSek110237 	cb.cb_argc = argc;
256306eeb2adSek110237 	cb.cb_argv = argv;
2564fa9e4066Sahrens 	argc -= optind;
2565fa9e4066Sahrens 	argv += optind;
2566fa9e4066Sahrens 
2567fa9e4066Sahrens 	if (argc < 1) {
2568fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
256999653d4eSeschrock 		usage(B_FALSE);
2570fa9e4066Sahrens 	}
2571fa9e4066Sahrens 
2572b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2573fa9e4066Sahrens }
2574fa9e4066Sahrens 
2575fa9e4066Sahrens typedef struct status_cbdata {
2576fa9e4066Sahrens 	int		cb_count;
2577e9dbad6fSeschrock 	boolean_t	cb_allpools;
257899653d4eSeschrock 	boolean_t	cb_verbose;
257999653d4eSeschrock 	boolean_t	cb_explain;
258099653d4eSeschrock 	boolean_t	cb_first;
2581fa9e4066Sahrens } status_cbdata_t;
2582fa9e4066Sahrens 
2583fa9e4066Sahrens /*
2584fa9e4066Sahrens  * Print out detailed scrub status.
2585fa9e4066Sahrens  */
2586fa9e4066Sahrens void
2587fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2588fa9e4066Sahrens {
2589fa9e4066Sahrens 	vdev_stat_t *vs;
2590fa9e4066Sahrens 	uint_t vsc;
2591fa9e4066Sahrens 	time_t start, end, now;
2592fa9e4066Sahrens 	double fraction_done;
259318ce54dfSek110237 	uint64_t examined, total, minutes_left, minutes_taken;
2594fa9e4066Sahrens 	char *scrub_type;
2595fa9e4066Sahrens 
2596fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2597fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2598fa9e4066Sahrens 
2599fa9e4066Sahrens 	/*
2600fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2601fa9e4066Sahrens 	 */
2602fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2603fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2604fa9e4066Sahrens 		return;
2605fa9e4066Sahrens 	}
2606fa9e4066Sahrens 
2607fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2608fa9e4066Sahrens 	    "resilver" : "scrub";
2609fa9e4066Sahrens 
2610fa9e4066Sahrens 	start = vs->vs_scrub_start;
2611fa9e4066Sahrens 	end = vs->vs_scrub_end;
2612fa9e4066Sahrens 	now = time(NULL);
2613fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2614fa9e4066Sahrens 	total = vs->vs_alloc;
2615fa9e4066Sahrens 
2616fa9e4066Sahrens 	if (end != 0) {
261718ce54dfSek110237 		minutes_taken = (uint64_t)((end - start) / 60);
261818ce54dfSek110237 
261918ce54dfSek110237 		(void) printf(gettext("%s %s after %lluh%um with %llu errors "
262018ce54dfSek110237 		    "on %s"),
2621fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
262218ce54dfSek110237 		    (u_longlong_t)(minutes_taken / 60),
262318ce54dfSek110237 		    (uint_t)(minutes_taken % 60),
2624fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2625fa9e4066Sahrens 		return;
2626fa9e4066Sahrens 	}
2627fa9e4066Sahrens 
2628fa9e4066Sahrens 	if (examined == 0)
2629fa9e4066Sahrens 		examined = 1;
2630fa9e4066Sahrens 	if (examined > total)
2631fa9e4066Sahrens 		total = examined;
2632fa9e4066Sahrens 
2633fa9e4066Sahrens 	fraction_done = (double)examined / total;
2634fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2635fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
263618ce54dfSek110237 	minutes_taken = (uint64_t)((now - start) / 60);
2637fa9e4066Sahrens 
263818ce54dfSek110237 	(void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, "
263918ce54dfSek110237 	    "%lluh%um to go\n"),
264018ce54dfSek110237 	    scrub_type, (u_longlong_t)(minutes_taken / 60),
264118ce54dfSek110237 	    (uint_t)(minutes_taken % 60), 100 * fraction_done,
2642fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2643fa9e4066Sahrens }
2644fa9e4066Sahrens 
264599653d4eSeschrock typedef struct spare_cbdata {
264699653d4eSeschrock 	uint64_t	cb_guid;
264799653d4eSeschrock 	zpool_handle_t	*cb_zhp;
264899653d4eSeschrock } spare_cbdata_t;
264999653d4eSeschrock 
265099653d4eSeschrock static boolean_t
265199653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search)
265299653d4eSeschrock {
265399653d4eSeschrock 	uint64_t guid;
265499653d4eSeschrock 	nvlist_t **child;
265599653d4eSeschrock 	uint_t c, children;
265699653d4eSeschrock 
265799653d4eSeschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
265899653d4eSeschrock 	    search == guid)
265999653d4eSeschrock 		return (B_TRUE);
266099653d4eSeschrock 
266199653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
266299653d4eSeschrock 	    &child, &children) == 0) {
266399653d4eSeschrock 		for (c = 0; c < children; c++)
266499653d4eSeschrock 			if (find_vdev(child[c], search))
266599653d4eSeschrock 				return (B_TRUE);
266699653d4eSeschrock 	}
266799653d4eSeschrock 
266899653d4eSeschrock 	return (B_FALSE);
266999653d4eSeschrock }
267099653d4eSeschrock 
267199653d4eSeschrock static int
267299653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data)
267399653d4eSeschrock {
267499653d4eSeschrock 	spare_cbdata_t *cbp = data;
267599653d4eSeschrock 	nvlist_t *config, *nvroot;
267699653d4eSeschrock 
267799653d4eSeschrock 	config = zpool_get_config(zhp, NULL);
267899653d4eSeschrock 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
267999653d4eSeschrock 	    &nvroot) == 0);
268099653d4eSeschrock 
268199653d4eSeschrock 	if (find_vdev(nvroot, cbp->cb_guid)) {
268299653d4eSeschrock 		cbp->cb_zhp = zhp;
268399653d4eSeschrock 		return (1);
268499653d4eSeschrock 	}
268599653d4eSeschrock 
268699653d4eSeschrock 	zpool_close(zhp);
268799653d4eSeschrock 	return (0);
268899653d4eSeschrock }
268999653d4eSeschrock 
2690fa9e4066Sahrens /*
2691fa9e4066Sahrens  * Print out configuration state as requested by status_callback.
2692fa9e4066Sahrens  */
2693fa9e4066Sahrens void
2694c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
26958654d025Sperrin     int namewidth, int depth, boolean_t isspare, boolean_t print_logs)
2696fa9e4066Sahrens {
2697fa9e4066Sahrens 	nvlist_t **child;
2698fa9e4066Sahrens 	uint_t c, children;
2699fa9e4066Sahrens 	vdev_stat_t *vs;
2700ea8dc4b6Seschrock 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
2701afefbcddSeschrock 	char *vname;
2702ea8dc4b6Seschrock 	uint64_t notpresent;
270399653d4eSeschrock 	spare_cbdata_t cb;
2704990b4856Slling 	char *state;
2705fa9e4066Sahrens 
2706fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2707fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2708fa9e4066Sahrens 
2709fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2710fa9e4066Sahrens 	    &child, &children) != 0)
2711fa9e4066Sahrens 		children = 0;
2712fa9e4066Sahrens 
2713990b4856Slling 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
271499653d4eSeschrock 	if (isspare) {
271599653d4eSeschrock 		/*
271699653d4eSeschrock 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
271799653d4eSeschrock 		 * online drives.
271899653d4eSeschrock 		 */
271999653d4eSeschrock 		if (vs->vs_aux == VDEV_AUX_SPARED)
272099653d4eSeschrock 			state = "INUSE";
272199653d4eSeschrock 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
272299653d4eSeschrock 			state = "AVAIL";
272399653d4eSeschrock 	}
2724fa9e4066Sahrens 
272599653d4eSeschrock 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
272699653d4eSeschrock 	    name, state);
272799653d4eSeschrock 
272899653d4eSeschrock 	if (!isspare) {
2729fa9e4066Sahrens 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
2730fa9e4066Sahrens 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
2731fa9e4066Sahrens 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
2732fa9e4066Sahrens 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
273399653d4eSeschrock 	}
2734fa9e4066Sahrens 
2735ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2736ea8dc4b6Seschrock 	    &notpresent) == 0) {
2737ea8dc4b6Seschrock 		char *path;
2738ea8dc4b6Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
27390917b783Seschrock 		(void) printf("  was %s", path);
2740ea8dc4b6Seschrock 	} else if (vs->vs_aux != 0) {
2741fa9e4066Sahrens 		(void) printf("  ");
2742fa9e4066Sahrens 
2743fa9e4066Sahrens 		switch (vs->vs_aux) {
2744fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2745fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2746fa9e4066Sahrens 			break;
2747fa9e4066Sahrens 
2748fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2749fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2750fa9e4066Sahrens 			break;
2751fa9e4066Sahrens 
2752fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2753fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2754fa9e4066Sahrens 			break;
2755fa9e4066Sahrens 
2756eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
2757eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
2758eaca9bbdSeschrock 			break;
2759eaca9bbdSeschrock 
276099653d4eSeschrock 		case VDEV_AUX_SPARED:
276199653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
276299653d4eSeschrock 			    &cb.cb_guid) == 0);
276399653d4eSeschrock 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
276499653d4eSeschrock 				if (strcmp(zpool_get_name(cb.cb_zhp),
276599653d4eSeschrock 				    zpool_get_name(zhp)) == 0)
276699653d4eSeschrock 					(void) printf(gettext("currently in "
276799653d4eSeschrock 					    "use"));
276899653d4eSeschrock 				else
276999653d4eSeschrock 					(void) printf(gettext("in use by "
277099653d4eSeschrock 					    "pool '%s'"),
277199653d4eSeschrock 					    zpool_get_name(cb.cb_zhp));
277299653d4eSeschrock 				zpool_close(cb.cb_zhp);
277399653d4eSeschrock 			} else {
277499653d4eSeschrock 				(void) printf(gettext("currently in use"));
277599653d4eSeschrock 			}
277699653d4eSeschrock 			break;
277799653d4eSeschrock 
27783d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
27793d7072f8Seschrock 			(void) printf(gettext("too many errors"));
27803d7072f8Seschrock 			break;
27813d7072f8Seschrock 
2782fa9e4066Sahrens 		default:
2783fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2784fa9e4066Sahrens 			break;
2785fa9e4066Sahrens 		}
2786fa9e4066Sahrens 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2787fa9e4066Sahrens 		/*
2788fa9e4066Sahrens 		 * Report bytes resilvered/repaired on leaf devices.
2789fa9e4066Sahrens 		 */
2790fa9e4066Sahrens 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2791fa9e4066Sahrens 		(void) printf(gettext("  %s %s"), repaired,
2792fa9e4066Sahrens 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2793fa9e4066Sahrens 		    "resilvered" : "repaired");
2794fa9e4066Sahrens 	}
2795fa9e4066Sahrens 
2796fa9e4066Sahrens 	(void) printf("\n");
2797fa9e4066Sahrens 
2798afefbcddSeschrock 	for (c = 0; c < children; c++) {
27998654d025Sperrin 		uint64_t is_log = B_FALSE;
28008654d025Sperrin 
28018654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
28028654d025Sperrin 		    &is_log);
28038654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
28048654d025Sperrin 			continue;
280599653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
2806c67d9675Seschrock 		print_status_config(zhp, vname, child[c],
28078654d025Sperrin 		    namewidth, depth + 2, isspare, B_FALSE);
2808afefbcddSeschrock 		free(vname);
2809afefbcddSeschrock 	}
2810fa9e4066Sahrens }
2811fa9e4066Sahrens 
2812ea8dc4b6Seschrock static void
2813ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
2814ea8dc4b6Seschrock {
281575519f38Sek110237 	nvlist_t *nverrlist = NULL;
281655434c77Sek110237 	nvpair_t *elem;
281755434c77Sek110237 	char *pathname;
281855434c77Sek110237 	size_t len = MAXPATHLEN * 2;
2819ea8dc4b6Seschrock 
282055434c77Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2821ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
2822ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
2823ea8dc4b6Seschrock 		return;
2824ea8dc4b6Seschrock 	}
2825ea8dc4b6Seschrock 
282655434c77Sek110237 	(void) printf("errors: Permanent errors have been "
282755434c77Sek110237 	    "detected in the following files:\n\n");
2828ea8dc4b6Seschrock 
282955434c77Sek110237 	pathname = safe_malloc(len);
283055434c77Sek110237 	elem = NULL;
283155434c77Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
283255434c77Sek110237 		nvlist_t *nv;
283355434c77Sek110237 		uint64_t dsobj, obj;
2834ea8dc4b6Seschrock 
283555434c77Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
283655434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
283755434c77Sek110237 		    &dsobj) == 0);
283855434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
283955434c77Sek110237 		    &obj) == 0);
284055434c77Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
284155434c77Sek110237 		(void) printf("%7s %s\n", "", pathname);
2842ea8dc4b6Seschrock 	}
284355434c77Sek110237 	free(pathname);
284455434c77Sek110237 	nvlist_free(nverrlist);
2845ea8dc4b6Seschrock }
2846ea8dc4b6Seschrock 
284799653d4eSeschrock static void
284899653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
284999653d4eSeschrock     int namewidth)
285099653d4eSeschrock {
285199653d4eSeschrock 	uint_t i;
285299653d4eSeschrock 	char *name;
285399653d4eSeschrock 
285499653d4eSeschrock 	if (nspares == 0)
285599653d4eSeschrock 		return;
285699653d4eSeschrock 
285799653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
285899653d4eSeschrock 
285999653d4eSeschrock 	for (i = 0; i < nspares; i++) {
286099653d4eSeschrock 		name = zpool_vdev_name(g_zfs, zhp, spares[i]);
286199653d4eSeschrock 		print_status_config(zhp, name, spares[i],
28628654d025Sperrin 		    namewidth, 2, B_TRUE, B_FALSE);
286399653d4eSeschrock 		free(name);
286499653d4eSeschrock 	}
286599653d4eSeschrock }
286699653d4eSeschrock 
2867fa94a07fSbrendan static void
2868fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
2869fa94a07fSbrendan     int namewidth)
2870fa94a07fSbrendan {
2871fa94a07fSbrendan 	uint_t i;
2872fa94a07fSbrendan 	char *name;
2873fa94a07fSbrendan 
2874fa94a07fSbrendan 	if (nl2cache == 0)
2875fa94a07fSbrendan 		return;
2876fa94a07fSbrendan 
2877fa94a07fSbrendan 	(void) printf(gettext("\tcache\n"));
2878fa94a07fSbrendan 
2879fa94a07fSbrendan 	for (i = 0; i < nl2cache; i++) {
2880fa94a07fSbrendan 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i]);
2881fa94a07fSbrendan 		print_status_config(zhp, name, l2cache[i],
2882fa94a07fSbrendan 		    namewidth, 2, B_FALSE, B_FALSE);
2883fa94a07fSbrendan 		free(name);
2884fa94a07fSbrendan 	}
2885fa94a07fSbrendan }
2886fa94a07fSbrendan 
2887fa9e4066Sahrens /*
2888fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
2889fa9e4066Sahrens  *
2890fa9e4066Sahrens  *        pool: tank
2891fa9e4066Sahrens  *	status: DEGRADED
2892fa9e4066Sahrens  *	reason: One or more devices ...
2893fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
2894fa9e4066Sahrens  *	config:
2895fa9e4066Sahrens  *		mirror		DEGRADED
2896fa9e4066Sahrens  *                c1t0d0	OK
2897ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
2898fa9e4066Sahrens  *
2899fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
2900fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
2901fa9e4066Sahrens  */
2902fa9e4066Sahrens int
2903fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
2904fa9e4066Sahrens {
2905fa9e4066Sahrens 	status_cbdata_t *cbp = data;
2906fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2907fa9e4066Sahrens 	char *msgid;
2908fa9e4066Sahrens 	int reason;
290946657f8dSmmusante 	const char *health;
291046657f8dSmmusante 	uint_t c;
291146657f8dSmmusante 	vdev_stat_t *vs;
2912fa9e4066Sahrens 
2913088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
2914fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
2915fa9e4066Sahrens 
2916fa9e4066Sahrens 	cbp->cb_count++;
2917fa9e4066Sahrens 
2918fa9e4066Sahrens 	/*
2919fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
2920fa9e4066Sahrens 	 * problems.
2921fa9e4066Sahrens 	 */
2922e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
2923e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
2924e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
2925e9dbad6fSeschrock 			    zpool_get_name(zhp));
2926e9dbad6fSeschrock 			if (cbp->cb_first)
2927e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
2928e9dbad6fSeschrock 		}
2929fa9e4066Sahrens 		return (0);
2930e9dbad6fSeschrock 	}
2931fa9e4066Sahrens 
2932fa9e4066Sahrens 	if (cbp->cb_first)
293399653d4eSeschrock 		cbp->cb_first = B_FALSE;
2934fa9e4066Sahrens 	else
2935fa9e4066Sahrens 		(void) printf("\n");
2936fa9e4066Sahrens 
293746657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
293846657f8dSmmusante 	    &nvroot) == 0);
293946657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
294046657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
2941990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
2942fa9e4066Sahrens 
2943fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
2944fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
2945fa9e4066Sahrens 
2946fa9e4066Sahrens 	switch (reason) {
2947fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
2948fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2949fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
2950fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
2951fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2952fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2953fa9e4066Sahrens 		break;
2954fa9e4066Sahrens 
2955fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
2956fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2957fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
2958fa9e4066Sahrens 		    "pool to continue functioning.\n"));
2959fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2960fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2961fa9e4066Sahrens 		break;
2962fa9e4066Sahrens 
2963fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
2964fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2965fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
2966fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
2967fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
2968fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
2969fa9e4066Sahrens 		    "'zpool replace'.\n"));
2970fa9e4066Sahrens 		break;
2971fa9e4066Sahrens 
2972fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
2973fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2974b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
2975fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
2976fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
2977fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
2978fa9e4066Sahrens 		    "from a backup source.\n"));
2979fa9e4066Sahrens 		break;
2980fa9e4066Sahrens 
2981fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
2982fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
2983fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
2984fa9e4066Sahrens 		    "made to correct the error.  Applications are "
2985fa9e4066Sahrens 		    "unaffected.\n"));
2986fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
2987fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
2988ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
2989fa9e4066Sahrens 		    "replace'.\n"));
2990fa9e4066Sahrens 		break;
2991fa9e4066Sahrens 
2992fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
2993fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
2994d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
2995fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
2996fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
2997fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
2998fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
2999fa9e4066Sahrens 		    "replace'.\n"));
3000fa9e4066Sahrens 		break;
3001fa9e4066Sahrens 
3002fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
3003fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
3004fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3005fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
3006fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3007fa9e4066Sahrens 		    "complete.\n"));
3008fa9e4066Sahrens 		break;
3009fa9e4066Sahrens 
3010ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3011ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3012ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3013ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3014ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3015ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3016ea8dc4b6Seschrock 		    "backup.\n"));
3017ea8dc4b6Seschrock 		break;
3018ea8dc4b6Seschrock 
3019ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3020ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3021ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3022ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
3023ea8dc4b6Seschrock 		    "from a backup source.\n"));
3024ea8dc4b6Seschrock 		break;
3025ea8dc4b6Seschrock 
3026eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3027eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3028eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3029eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3030eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3031eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3032eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3033eaca9bbdSeschrock 		break;
3034eaca9bbdSeschrock 
3035eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3036eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3037eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3038eaca9bbdSeschrock 		    "be accessed on this system.\n"));
3039eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
3040eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
3041eaca9bbdSeschrock 		    "backup.\n"));
3042eaca9bbdSeschrock 		break;
3043eaca9bbdSeschrock 
30443d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
30453d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
30463d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
30473d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
30483d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
30493d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
30503d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
30513d7072f8Seschrock 		break;
30523d7072f8Seschrock 
30533d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
30543d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
30553d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
30563d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
30573d7072f8Seschrock 		    "functioning.\n"));
30583d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
30593d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
30603d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
30613d7072f8Seschrock 		    "to be recovered.\n"));
30623d7072f8Seschrock 		break;
30633d7072f8Seschrock 
3064fa9e4066Sahrens 	default:
3065fa9e4066Sahrens 		/*
3066fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
3067fa9e4066Sahrens 		 */
3068fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
3069fa9e4066Sahrens 	}
3070fa9e4066Sahrens 
3071fa9e4066Sahrens 	if (msgid != NULL)
3072fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3073fa9e4066Sahrens 		    msgid);
3074fa9e4066Sahrens 
3075fa9e4066Sahrens 	if (config != NULL) {
3076fa9e4066Sahrens 		int namewidth;
3077ea8dc4b6Seschrock 		uint64_t nerr;
3078fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
3079fa94a07fSbrendan 		uint_t nspares, nl2cache;
3080fa9e4066Sahrens 
3081fa9e4066Sahrens 
3082fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
3083fa9e4066Sahrens 		print_scrub_status(nvroot);
3084fa9e4066Sahrens 
3085c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3086fa9e4066Sahrens 		if (namewidth < 10)
3087fa9e4066Sahrens 			namewidth = 10;
3088fa9e4066Sahrens 
3089fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
3090fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3091fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3092c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
30938654d025Sperrin 		    namewidth, 0, B_FALSE, B_FALSE);
30948654d025Sperrin 		if (num_logs(nvroot) > 0)
30958654d025Sperrin 			print_status_config(zhp, "logs", nvroot, namewidth, 0,
30968654d025Sperrin 			    B_FALSE, B_TRUE);
309799653d4eSeschrock 
3098fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
3099fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
3100fa94a07fSbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
3101fa94a07fSbrendan 
310299653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
310399653d4eSeschrock 		    &spares, &nspares) == 0)
310499653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
3105ea8dc4b6Seschrock 
3106ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3107ea8dc4b6Seschrock 		    &nerr) == 0) {
310855434c77Sek110237 			nvlist_t *nverrlist = NULL;
310955434c77Sek110237 
3110ea8dc4b6Seschrock 			/*
3111ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3112ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3113ea8dc4b6Seschrock 			 * uniquifying the results.
3114ea8dc4b6Seschrock 			 */
311575519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
311655434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
311755434c77Sek110237 				nvpair_t *elem;
311855434c77Sek110237 
311955434c77Sek110237 				elem = NULL;
312055434c77Sek110237 				nerr = 0;
312155434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
312255434c77Sek110237 				    elem)) != NULL) {
312355434c77Sek110237 					nerr++;
312455434c77Sek110237 				}
312555434c77Sek110237 			}
312655434c77Sek110237 			nvlist_free(nverrlist);
3127ea8dc4b6Seschrock 
3128ea8dc4b6Seschrock 			(void) printf("\n");
312999653d4eSeschrock 
3130ea8dc4b6Seschrock 			if (nerr == 0)
3131ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3132ea8dc4b6Seschrock 				    "errors\n"));
3133ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3134e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
31355ad82045Snd150628 				    "errors, use '-v' for a list\n"),
31365ad82045Snd150628 				    (u_longlong_t)nerr);
3137ea8dc4b6Seschrock 			else
3138ea8dc4b6Seschrock 				print_error_log(zhp);
3139ea8dc4b6Seschrock 		}
3140fa9e4066Sahrens 	} else {
3141fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3142fa9e4066Sahrens 		    "determined.\n"));
3143fa9e4066Sahrens 	}
3144fa9e4066Sahrens 
3145fa9e4066Sahrens 	return (0);
3146fa9e4066Sahrens }
3147fa9e4066Sahrens 
3148fa9e4066Sahrens /*
3149fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3150fa9e4066Sahrens  *
3151fa9e4066Sahrens  *	-v	Display complete error logs
3152fa9e4066Sahrens  *	-x	Display only pools with potential problems
3153fa9e4066Sahrens  *
3154fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3155fa9e4066Sahrens  */
3156fa9e4066Sahrens int
3157fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3158fa9e4066Sahrens {
3159fa9e4066Sahrens 	int c;
3160fa9e4066Sahrens 	int ret;
3161fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3162fa9e4066Sahrens 
3163fa9e4066Sahrens 	/* check options */
3164fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3165fa9e4066Sahrens 		switch (c) {
3166fa9e4066Sahrens 		case 'v':
316799653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3168fa9e4066Sahrens 			break;
3169fa9e4066Sahrens 		case 'x':
317099653d4eSeschrock 			cb.cb_explain = B_TRUE;
3171fa9e4066Sahrens 			break;
3172fa9e4066Sahrens 		case '?':
3173fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3174fa9e4066Sahrens 			    optopt);
317599653d4eSeschrock 			usage(B_FALSE);
3176fa9e4066Sahrens 		}
3177fa9e4066Sahrens 	}
3178fa9e4066Sahrens 
3179fa9e4066Sahrens 	argc -= optind;
3180fa9e4066Sahrens 	argv += optind;
3181fa9e4066Sahrens 
318299653d4eSeschrock 	cb.cb_first = B_TRUE;
3183fa9e4066Sahrens 
3184e9dbad6fSeschrock 	if (argc == 0)
3185e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3186e9dbad6fSeschrock 
3187b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3188fa9e4066Sahrens 
3189fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3190fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3191e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3192fa9e4066Sahrens 		(void) printf(gettext("all pools are healthy\n"));
3193fa9e4066Sahrens 
3194fa9e4066Sahrens 	return (ret);
3195fa9e4066Sahrens }
3196fa9e4066Sahrens 
3197eaca9bbdSeschrock typedef struct upgrade_cbdata {
3198eaca9bbdSeschrock 	int	cb_all;
3199eaca9bbdSeschrock 	int	cb_first;
3200eaca9bbdSeschrock 	int	cb_newer;
320106eeb2adSek110237 	int	cb_argc;
3202990b4856Slling 	uint64_t cb_version;
320306eeb2adSek110237 	char	**cb_argv;
3204eaca9bbdSeschrock } upgrade_cbdata_t;
3205eaca9bbdSeschrock 
3206eaca9bbdSeschrock static int
3207eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3208eaca9bbdSeschrock {
3209eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3210eaca9bbdSeschrock 	nvlist_t *config;
3211eaca9bbdSeschrock 	uint64_t version;
3212eaca9bbdSeschrock 	int ret = 0;
3213eaca9bbdSeschrock 
3214eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3215eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3216eaca9bbdSeschrock 	    &version) == 0);
3217eaca9bbdSeschrock 
3218e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3219eaca9bbdSeschrock 		if (!cbp->cb_all) {
3220eaca9bbdSeschrock 			if (cbp->cb_first) {
3221eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3222eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3223eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3224eaca9bbdSeschrock 				    "longer be accessible by older software "
3225eaca9bbdSeschrock 				    "versions.\n\n"));
3226eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3227eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
322899653d4eSeschrock 				cbp->cb_first = B_FALSE;
3229eaca9bbdSeschrock 			}
3230eaca9bbdSeschrock 
32315ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3232eaca9bbdSeschrock 			    zpool_get_name(zhp));
3233eaca9bbdSeschrock 		} else {
323499653d4eSeschrock 			cbp->cb_first = B_FALSE;
3235990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
323606eeb2adSek110237 			if (!ret) {
3237eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3238990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
3239eaca9bbdSeschrock 			}
324006eeb2adSek110237 		}
3241e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3242eaca9bbdSeschrock 		assert(!cbp->cb_all);
3243eaca9bbdSeschrock 
3244eaca9bbdSeschrock 		if (cbp->cb_first) {
3245eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3246eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3247eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3248eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3249eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
325099653d4eSeschrock 			cbp->cb_first = B_FALSE;
3251eaca9bbdSeschrock 		}
3252eaca9bbdSeschrock 
32535ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3254eaca9bbdSeschrock 		    zpool_get_name(zhp));
3255eaca9bbdSeschrock 	}
3256eaca9bbdSeschrock 
3257eaca9bbdSeschrock 	zpool_close(zhp);
3258eaca9bbdSeschrock 	return (ret);
3259eaca9bbdSeschrock }
3260eaca9bbdSeschrock 
3261eaca9bbdSeschrock /* ARGSUSED */
3262eaca9bbdSeschrock static int
326306eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
3264eaca9bbdSeschrock {
3265990b4856Slling 	upgrade_cbdata_t *cbp = data;
3266990b4856Slling 	uint64_t cur_version;
3267eaca9bbdSeschrock 	int ret;
3268eaca9bbdSeschrock 
32698654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
32708654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
32718654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
32728654d025Sperrin 		    " to upgrade.\n"));
32738654d025Sperrin 		return (1);
32748654d025Sperrin 	}
3275990b4856Slling 
3276990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3277990b4856Slling 	if (cur_version >= cbp->cb_version) {
3278eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3279990b4856Slling 		    "using more current version '%d'.\n"), zpool_get_name(zhp),
3280990b4856Slling 		    cur_version);
3281eaca9bbdSeschrock 		return (0);
3282eaca9bbdSeschrock 	}
3283eaca9bbdSeschrock 
3284990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
328506eeb2adSek110237 
328606eeb2adSek110237 	if (!ret) {
328744cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
3288990b4856Slling 		    "from version %llu to version %llu\n\n"),
3289990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3290990b4856Slling 		    (u_longlong_t)cbp->cb_version);
329106eeb2adSek110237 	}
3292eaca9bbdSeschrock 
3293eaca9bbdSeschrock 	return (ret != 0);
3294eaca9bbdSeschrock }
3295eaca9bbdSeschrock 
3296eaca9bbdSeschrock /*
3297eaca9bbdSeschrock  * zpool upgrade
3298eaca9bbdSeschrock  * zpool upgrade -v
3299990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
3300eaca9bbdSeschrock  *
3301eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3302eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3303eaca9bbdSeschrock  * upgrade all pools.
3304eaca9bbdSeschrock  */
3305eaca9bbdSeschrock int
3306eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3307eaca9bbdSeschrock {
3308eaca9bbdSeschrock 	int c;
3309eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3310eaca9bbdSeschrock 	int ret = 0;
3311eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3312990b4856Slling 	char *end;
3313990b4856Slling 
3314eaca9bbdSeschrock 
3315eaca9bbdSeschrock 	/* check options */
3316990b4856Slling 	while ((c = getopt(argc, argv, "avV:")) != -1) {
3317eaca9bbdSeschrock 		switch (c) {
3318eaca9bbdSeschrock 		case 'a':
331999653d4eSeschrock 			cb.cb_all = B_TRUE;
3320eaca9bbdSeschrock 			break;
3321eaca9bbdSeschrock 		case 'v':
3322eaca9bbdSeschrock 			showversions = B_TRUE;
3323eaca9bbdSeschrock 			break;
3324990b4856Slling 		case 'V':
3325990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
3326351420b3Slling 			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
3327351420b3Slling 			    cb.cb_version < SPA_VERSION_1) {
3328990b4856Slling 				(void) fprintf(stderr,
3329990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
3330990b4856Slling 				usage(B_FALSE);
3331990b4856Slling 			}
3332990b4856Slling 			break;
3333eaca9bbdSeschrock 		case '?':
3334eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3335eaca9bbdSeschrock 			    optopt);
333699653d4eSeschrock 			usage(B_FALSE);
3337eaca9bbdSeschrock 		}
3338eaca9bbdSeschrock 	}
3339eaca9bbdSeschrock 
334006eeb2adSek110237 	cb.cb_argc = argc;
334106eeb2adSek110237 	cb.cb_argv = argv;
3342eaca9bbdSeschrock 	argc -= optind;
3343eaca9bbdSeschrock 	argv += optind;
3344eaca9bbdSeschrock 
3345351420b3Slling 	if (cb.cb_version == 0) {
3346351420b3Slling 		cb.cb_version = SPA_VERSION;
3347351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
3348351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
3349351420b3Slling 		    "incompatible with other arguments\n"));
3350351420b3Slling 		usage(B_FALSE);
3351351420b3Slling 	}
3352351420b3Slling 
3353eaca9bbdSeschrock 	if (showversions) {
3354eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3355eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3356eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
335799653d4eSeschrock 			usage(B_FALSE);
3358eaca9bbdSeschrock 		}
3359eaca9bbdSeschrock 	} else if (cb.cb_all) {
3360eaca9bbdSeschrock 		if (argc != 0) {
3361351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
3362351420b3Slling 			    "be used along with a pool name\n"));
336399653d4eSeschrock 			usage(B_FALSE);
3364eaca9bbdSeschrock 		}
3365eaca9bbdSeschrock 	}
3366eaca9bbdSeschrock 
3367e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3368e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
336999653d4eSeschrock 	cb.cb_first = B_TRUE;
3370eaca9bbdSeschrock 	if (showversions) {
3371eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3372d7d4af51Smmusante 		    "supported:\n\n"));
3373eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3374eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3375eaca9bbdSeschrock 		    "---------------\n");
337699653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
337744cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
337844cd46caSbillm 		    "(replicated metadata)\n"));
337999653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
338099653d4eSeschrock 		    "RAID-Z\n"));
3381d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
3382c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3383c9431fa1Sahl 		    "algorithm\n"));
3384990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
33858654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3386ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
3387a9799022Sck153898 		(void) printf(gettext(" 9   refquota and refreservation "
3388a9799022Sck153898 		    "properties\n"));
3389fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
33908654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3391eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3392eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3393eaca9bbdSeschrock 		    "version/N\n\n");
3394eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3395eaca9bbdSeschrock 	} else if (argc == 0) {
3396eaca9bbdSeschrock 		int notfound;
3397eaca9bbdSeschrock 
339899653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3399eaca9bbdSeschrock 		notfound = cb.cb_first;
3400eaca9bbdSeschrock 
3401eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3402eaca9bbdSeschrock 			if (!cb.cb_first)
3403eaca9bbdSeschrock 				(void) printf("\n");
3404eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3405eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
340699653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3407eaca9bbdSeschrock 			if (!cb.cb_first) {
3408eaca9bbdSeschrock 				notfound = B_FALSE;
3409eaca9bbdSeschrock 				(void) printf("\n");
3410eaca9bbdSeschrock 			}
3411eaca9bbdSeschrock 		}
3412eaca9bbdSeschrock 
3413eaca9bbdSeschrock 		if (ret == 0) {
3414eaca9bbdSeschrock 			if (notfound)
3415eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3416eaca9bbdSeschrock 				    "using this version.\n"));
3417eaca9bbdSeschrock 			else if (!cb.cb_all)
3418eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3419eaca9bbdSeschrock 				    "for a list of available versions and "
3420eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3421eaca9bbdSeschrock 		}
3422eaca9bbdSeschrock 	} else {
3423b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3424b1b8ab34Slling 		    upgrade_one, &cb);
342506eeb2adSek110237 	}
342606eeb2adSek110237 
342706eeb2adSek110237 	return (ret);
342806eeb2adSek110237 }
342906eeb2adSek110237 
3430ecd6cf80Smarks typedef struct hist_cbdata {
3431ecd6cf80Smarks 	boolean_t first;
3432ecd6cf80Smarks 	int longfmt;
3433ecd6cf80Smarks 	int internal;
3434ecd6cf80Smarks } hist_cbdata_t;
3435ecd6cf80Smarks 
3436ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3437ecd6cf80Smarks 	"invalid event",
3438ecd6cf80Smarks 	"pool create",
3439ecd6cf80Smarks 	"vdev add",
3440ecd6cf80Smarks 	"pool remove",
3441ecd6cf80Smarks 	"pool destroy",
3442ecd6cf80Smarks 	"pool export",
3443ecd6cf80Smarks 	"pool import",
3444ecd6cf80Smarks 	"vdev attach",
3445ecd6cf80Smarks 	"vdev replace",
3446ecd6cf80Smarks 	"vdev detach",
3447ecd6cf80Smarks 	"vdev online",
3448ecd6cf80Smarks 	"vdev offline",
3449ecd6cf80Smarks 	"vdev upgrade",
3450ecd6cf80Smarks 	"pool clear",
3451ecd6cf80Smarks 	"pool scrub",
3452ecd6cf80Smarks 	"pool property set",
3453ecd6cf80Smarks 	"create",
3454ecd6cf80Smarks 	"clone",
3455ecd6cf80Smarks 	"destroy",
3456ecd6cf80Smarks 	"destroy_begin_sync",
3457ecd6cf80Smarks 	"inherit",
3458ecd6cf80Smarks 	"property set",
3459ecd6cf80Smarks 	"quota set",
3460ecd6cf80Smarks 	"permission update",
3461ecd6cf80Smarks 	"permission remove",
3462ecd6cf80Smarks 	"permission who remove",
3463ecd6cf80Smarks 	"promote",
3464ecd6cf80Smarks 	"receive",
3465ecd6cf80Smarks 	"rename",
3466ecd6cf80Smarks 	"reservation set",
3467ecd6cf80Smarks 	"replay_inc_sync",
3468ecd6cf80Smarks 	"replay_full_sync",
3469ecd6cf80Smarks 	"rollback",
3470ecd6cf80Smarks 	"snapshot",
3471e7437265Sahrens 	"filesystem version upgrade",
3472a9799022Sck153898 	"refquota set",
3473a9799022Sck153898 	"refreservation set",
3474ecd6cf80Smarks };
3475ecd6cf80Smarks 
347606eeb2adSek110237 /*
347706eeb2adSek110237  * Print out the command history for a specific pool.
347806eeb2adSek110237  */
347906eeb2adSek110237 static int
348006eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
348106eeb2adSek110237 {
348206eeb2adSek110237 	nvlist_t *nvhis;
348306eeb2adSek110237 	nvlist_t **records;
348406eeb2adSek110237 	uint_t numrecords;
348506eeb2adSek110237 	char *cmdstr;
3486ecd6cf80Smarks 	char *pathstr;
348706eeb2adSek110237 	uint64_t dst_time;
348806eeb2adSek110237 	time_t tsec;
348906eeb2adSek110237 	struct tm t;
349006eeb2adSek110237 	char tbuf[30];
349106eeb2adSek110237 	int ret, i;
3492ecd6cf80Smarks 	uint64_t who;
3493ecd6cf80Smarks 	struct passwd *pwd;
3494ecd6cf80Smarks 	char *hostname;
3495ecd6cf80Smarks 	char *zonename;
3496ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3497ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3498ecd6cf80Smarks 	uint64_t txg;
3499ecd6cf80Smarks 	uint64_t ievent;
350006eeb2adSek110237 
3501ecd6cf80Smarks 	cb->first = B_FALSE;
350206eeb2adSek110237 
350306eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
350406eeb2adSek110237 
350506eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
350606eeb2adSek110237 		return (ret);
350706eeb2adSek110237 
350806eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
350906eeb2adSek110237 	    &records, &numrecords) == 0);
351006eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
351106eeb2adSek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3512ecd6cf80Smarks 		    &dst_time) != 0)
3513ecd6cf80Smarks 			continue;
3514ecd6cf80Smarks 
3515ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3516ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3517ecd6cf80Smarks 		    &cmdstr) != 0) {
3518ecd6cf80Smarks 			if (cb->internal == 0)
3519ecd6cf80Smarks 				continue;
3520ecd6cf80Smarks 
3521ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3522ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3523ecd6cf80Smarks 				continue;
3524ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3525ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3526ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3527ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3528ecd6cf80Smarks 			if (ievent > LOG_END)
3529ecd6cf80Smarks 				continue;
3530ecd6cf80Smarks 			(void) snprintf(internalstr,
3531ecd6cf80Smarks 			    sizeof (internalstr),
3532ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3533ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3534ecd6cf80Smarks 			    pathstr);
3535ecd6cf80Smarks 			cmdstr = internalstr;
3536ecd6cf80Smarks 		}
353706eeb2adSek110237 		tsec = dst_time;
353806eeb2adSek110237 		(void) localtime_r(&tsec, &t);
353906eeb2adSek110237 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3540ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3541ecd6cf80Smarks 
3542ecd6cf80Smarks 		if (!cb->longfmt) {
3543ecd6cf80Smarks 			(void) printf("\n");
3544ecd6cf80Smarks 			continue;
354506eeb2adSek110237 		}
3546ecd6cf80Smarks 		(void) printf(" [");
3547ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3548ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3549ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3550ecd6cf80Smarks 			if (pwd)
3551ecd6cf80Smarks 				(void) printf("user %s on",
3552ecd6cf80Smarks 				    pwd->pw_name);
3553ecd6cf80Smarks 			else
3554ecd6cf80Smarks 				(void) printf("user %d on",
3555ecd6cf80Smarks 				    (int)who);
3556ecd6cf80Smarks 		} else {
3557ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3558ecd6cf80Smarks 			continue;
3559ecd6cf80Smarks 		}
3560ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3561ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3562ecd6cf80Smarks 			(void) printf(" %s", hostname);
3563ecd6cf80Smarks 		}
3564ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3565ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3566ecd6cf80Smarks 			(void) printf(":%s", zonename);
3567ecd6cf80Smarks 		}
3568ecd6cf80Smarks 
3569ecd6cf80Smarks 		(void) printf("]");
3570ecd6cf80Smarks 		(void) printf("\n");
357106eeb2adSek110237 	}
357206eeb2adSek110237 	(void) printf("\n");
357306eeb2adSek110237 	nvlist_free(nvhis);
357406eeb2adSek110237 
357506eeb2adSek110237 	return (ret);
357606eeb2adSek110237 }
357706eeb2adSek110237 
357806eeb2adSek110237 /*
357906eeb2adSek110237  * zpool history <pool>
358006eeb2adSek110237  *
358106eeb2adSek110237  * Displays the history of commands that modified pools.
358206eeb2adSek110237  */
3583ecd6cf80Smarks 
3584ecd6cf80Smarks 
358506eeb2adSek110237 int
358606eeb2adSek110237 zpool_do_history(int argc, char **argv)
358706eeb2adSek110237 {
3588ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
358906eeb2adSek110237 	int ret;
3590ecd6cf80Smarks 	int c;
359106eeb2adSek110237 
3592ecd6cf80Smarks 	cbdata.first = B_TRUE;
3593ecd6cf80Smarks 	/* check options */
3594ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3595ecd6cf80Smarks 		switch (c) {
3596ecd6cf80Smarks 		case 'l':
3597ecd6cf80Smarks 			cbdata.longfmt = 1;
3598ecd6cf80Smarks 			break;
3599ecd6cf80Smarks 		case 'i':
3600ecd6cf80Smarks 			cbdata.internal = 1;
3601ecd6cf80Smarks 			break;
3602ecd6cf80Smarks 		case '?':
3603ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3604ecd6cf80Smarks 			    optopt);
3605ecd6cf80Smarks 			usage(B_FALSE);
3606ecd6cf80Smarks 		}
3607ecd6cf80Smarks 	}
360806eeb2adSek110237 	argc -= optind;
360906eeb2adSek110237 	argv += optind;
361006eeb2adSek110237 
3611b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3612ecd6cf80Smarks 	    &cbdata);
361306eeb2adSek110237 
3614ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
361506eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
361606eeb2adSek110237 		return (0);
3617eaca9bbdSeschrock 	}
3618eaca9bbdSeschrock 
3619eaca9bbdSeschrock 	return (ret);
3620eaca9bbdSeschrock }
3621eaca9bbdSeschrock 
3622b1b8ab34Slling static int
3623b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3624b1b8ab34Slling {
3625990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3626b1b8ab34Slling 	char value[MAXNAMELEN];
3627990b4856Slling 	zprop_source_t srctype;
3628990b4856Slling 	zprop_list_t *pl;
3629b1b8ab34Slling 
3630b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3631b1b8ab34Slling 
3632b1b8ab34Slling 		/*
3633990b4856Slling 		 * Skip the special fake placeholder. This will also skip
3634990b4856Slling 		 * over the name property when 'all' is specified.
3635b1b8ab34Slling 		 */
3636990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3637b1b8ab34Slling 		    pl == cbp->cb_proplist)
3638b1b8ab34Slling 			continue;
3639b1b8ab34Slling 
3640b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3641b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3642b1b8ab34Slling 			continue;
3643b1b8ab34Slling 
3644990b4856Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
3645b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3646b1b8ab34Slling 	}
3647b1b8ab34Slling 	return (0);
3648b1b8ab34Slling }
3649b1b8ab34Slling 
3650b1b8ab34Slling int
3651b1b8ab34Slling zpool_do_get(int argc, char **argv)
3652b1b8ab34Slling {
3653990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
3654990b4856Slling 	zprop_list_t fake_name = { 0 };
3655b1b8ab34Slling 	int ret;
3656b1b8ab34Slling 
3657b1b8ab34Slling 	if (argc < 3)
3658b1b8ab34Slling 		usage(B_FALSE);
3659b1b8ab34Slling 
3660b1b8ab34Slling 	cb.cb_first = B_TRUE;
3661990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
3662b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3663b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3664b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3665b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3666990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
3667b1b8ab34Slling 
3668990b4856Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3669990b4856Slling 	    ZFS_TYPE_POOL) != 0)
3670b1b8ab34Slling 		usage(B_FALSE);
3671b1b8ab34Slling 
3672b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3673990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
3674b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3675b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3676b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3677b1b8ab34Slling 	}
3678b1b8ab34Slling 
3679b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3680b1b8ab34Slling 	    get_callback, &cb);
3681b1b8ab34Slling 
3682b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3683990b4856Slling 		zprop_free_list(fake_name.pl_next);
3684b1b8ab34Slling 	else
3685990b4856Slling 		zprop_free_list(cb.cb_proplist);
3686b1b8ab34Slling 
3687b1b8ab34Slling 	return (ret);
3688b1b8ab34Slling }
3689b1b8ab34Slling 
3690b1b8ab34Slling typedef struct set_cbdata {
3691b1b8ab34Slling 	char *cb_propname;
3692b1b8ab34Slling 	char *cb_value;
3693b1b8ab34Slling 	boolean_t cb_any_successful;
3694b1b8ab34Slling } set_cbdata_t;
3695b1b8ab34Slling 
3696b1b8ab34Slling int
3697b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3698b1b8ab34Slling {
3699b1b8ab34Slling 	int error;
3700b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3701b1b8ab34Slling 
3702b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3703b1b8ab34Slling 
3704b1b8ab34Slling 	if (!error)
3705b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3706b1b8ab34Slling 
3707b1b8ab34Slling 	return (error);
3708b1b8ab34Slling }
3709b1b8ab34Slling 
3710b1b8ab34Slling int
3711b1b8ab34Slling zpool_do_set(int argc, char **argv)
3712b1b8ab34Slling {
3713b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3714b1b8ab34Slling 	int error;
3715b1b8ab34Slling 
3716b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3717b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3718b1b8ab34Slling 		    argv[1][1]);
3719b1b8ab34Slling 		usage(B_FALSE);
3720b1b8ab34Slling 	}
3721b1b8ab34Slling 
3722b1b8ab34Slling 	if (argc < 2) {
3723b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3724b1b8ab34Slling 		    "argument\n"));
3725b1b8ab34Slling 		usage(B_FALSE);
3726b1b8ab34Slling 	}
3727b1b8ab34Slling 
3728b1b8ab34Slling 	if (argc < 3) {
3729b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3730b1b8ab34Slling 		usage(B_FALSE);
3731b1b8ab34Slling 	}
3732b1b8ab34Slling 
3733b1b8ab34Slling 	if (argc > 3) {
3734b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3735b1b8ab34Slling 		usage(B_FALSE);
3736b1b8ab34Slling 	}
3737b1b8ab34Slling 
3738b1b8ab34Slling 	cb.cb_propname = argv[1];
3739b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3740b1b8ab34Slling 	if (cb.cb_value == NULL) {
3741b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3742b1b8ab34Slling 		    "property=value argument\n"));
3743b1b8ab34Slling 		usage(B_FALSE);
3744b1b8ab34Slling 	}
3745b1b8ab34Slling 
3746b1b8ab34Slling 	*(cb.cb_value) = '\0';
3747b1b8ab34Slling 	cb.cb_value++;
3748b1b8ab34Slling 
3749b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3750b1b8ab34Slling 	    set_callback, &cb);
3751b1b8ab34Slling 
3752b1b8ab34Slling 	return (error);
3753b1b8ab34Slling }
3754b1b8ab34Slling 
3755b1b8ab34Slling static int
3756b1b8ab34Slling find_command_idx(char *command, int *idx)
3757b1b8ab34Slling {
3758b1b8ab34Slling 	int i;
3759b1b8ab34Slling 
3760b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3761b1b8ab34Slling 		if (command_table[i].name == NULL)
3762b1b8ab34Slling 			continue;
3763b1b8ab34Slling 
3764b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3765b1b8ab34Slling 			*idx = i;
3766b1b8ab34Slling 			return (0);
3767b1b8ab34Slling 		}
3768b1b8ab34Slling 	}
3769b1b8ab34Slling 	return (1);
3770b1b8ab34Slling }
3771b1b8ab34Slling 
3772fa9e4066Sahrens int
3773fa9e4066Sahrens main(int argc, char **argv)
3774fa9e4066Sahrens {
3775fa9e4066Sahrens 	int ret;
3776fa9e4066Sahrens 	int i;
3777fa9e4066Sahrens 	char *cmdname;
3778fa9e4066Sahrens 
3779fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3780fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3781fa9e4066Sahrens 
378299653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
378399653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3784203a47d8Snd150628 		    "initialize ZFS library\n"));
378599653d4eSeschrock 		return (1);
378699653d4eSeschrock 	}
378799653d4eSeschrock 
378899653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
378999653d4eSeschrock 
3790fa9e4066Sahrens 	opterr = 0;
3791fa9e4066Sahrens 
3792fa9e4066Sahrens 	/*
3793fa9e4066Sahrens 	 * Make sure the user has specified some command.
3794fa9e4066Sahrens 	 */
3795fa9e4066Sahrens 	if (argc < 2) {
3796fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
379799653d4eSeschrock 		usage(B_FALSE);
3798fa9e4066Sahrens 	}
3799fa9e4066Sahrens 
3800fa9e4066Sahrens 	cmdname = argv[1];
3801fa9e4066Sahrens 
3802fa9e4066Sahrens 	/*
3803fa9e4066Sahrens 	 * Special case '-?'
3804fa9e4066Sahrens 	 */
3805fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
380699653d4eSeschrock 		usage(B_TRUE);
3807fa9e4066Sahrens 
38082a6b87f0Sek110237 	zpool_set_history_str("zpool", argc, argv, history_str);
38092a6b87f0Sek110237 	verify(zpool_stage_history(g_zfs, history_str) == 0);
38102a6b87f0Sek110237 
3811fa9e4066Sahrens 	/*
3812fa9e4066Sahrens 	 * Run the appropriate command.
3813fa9e4066Sahrens 	 */
3814b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
3815fa9e4066Sahrens 		current_command = &command_table[i];
3816fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
381791ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
381891ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
381991ebeef5Sahrens 		current_command = &command_table[i];
382091ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
382191ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
3822fa9e4066Sahrens 		/*
382391ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
382491ebeef5Sahrens 		 * it as such.
3825fa9e4066Sahrens 		 */
3826ea8dc4b6Seschrock 		char buf[16384];
3827ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
3828fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
3829fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
383091ebeef5Sahrens 	} else {
3831fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
3832fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
383399653d4eSeschrock 		usage(B_FALSE);
3834fa9e4066Sahrens 	}
3835fa9e4066Sahrens 
383699653d4eSeschrock 	libzfs_fini(g_zfs);
383799653d4eSeschrock 
3838fa9e4066Sahrens 	/*
3839fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3840fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
3841fa9e4066Sahrens 	 */
3842fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
3843fa9e4066Sahrens 		(void) printf("dumping core by request\n");
3844fa9e4066Sahrens 		abort();
3845fa9e4066Sahrens 	}
3846fa9e4066Sahrens 
3847fa9e4066Sahrens 	return (ret);
3848fa9e4066Sahrens }
3849