xref: /titanic_53/usr/src/cmd/zpool/zpool_main.c (revision e45ce728996d8e573eecb27f555fb86aaff0cafd)
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 /*
2339c23413Seschrock  * Copyright 2007 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;
172fa9e4066Sahrens 
17365cd9f28Seschrock static const char *
17465cd9f28Seschrock get_usage(zpool_help_t idx) {
17565cd9f28Seschrock 	switch (idx) {
17665cd9f28Seschrock 	case HELP_ADD:
17765cd9f28Seschrock 		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
17865cd9f28Seschrock 	case HELP_ATTACH:
17965cd9f28Seschrock 		return (gettext("\tattach [-f] <pool> <device> "
180*e45ce728Sahrens 		    "<new-device>\n"));
181ea8dc4b6Seschrock 	case HELP_CLEAR:
182ea8dc4b6Seschrock 		return (gettext("\tclear <pool> [device]\n"));
18365cd9f28Seschrock 	case HELP_CREATE:
18465cd9f28Seschrock 		return (gettext("\tcreate  [-fn] [-R root] [-m mountpoint] "
18565cd9f28Seschrock 		    "<pool> <vdev> ...\n"));
18665cd9f28Seschrock 	case HELP_DESTROY:
18765cd9f28Seschrock 		return (gettext("\tdestroy [-f] <pool>\n"));
18865cd9f28Seschrock 	case HELP_DETACH:
18965cd9f28Seschrock 		return (gettext("\tdetach <pool> <device>\n"));
19065cd9f28Seschrock 	case HELP_EXPORT:
19165cd9f28Seschrock 		return (gettext("\texport [-f] <pool> ...\n"));
19206eeb2adSek110237 	case HELP_HISTORY:
193ecd6cf80Smarks 		return (gettext("\thistory [-il] [<pool>] ...\n"));
19465cd9f28Seschrock 	case HELP_IMPORT:
1954c58d714Sdarrenm 		return (gettext("\timport [-d dir] [-D]\n"
196ecd6cf80Smarks 		    "\timport [-p property=value] [-d dir] [-D] [-f] "
197ecd6cf80Smarks 		    "[-o opts] [-R root] -a\n"
198ecd6cf80Smarks 		    "\timport [-p property=value] [-d dir] [-D] [-f] \n"
199ecd6cf80Smarks 		    "\t    [-o opts] [-R root ] <pool | id> [newpool]\n"));
20065cd9f28Seschrock 	case HELP_IOSTAT:
20165cd9f28Seschrock 		return (gettext("\tiostat [-v] [pool] ... [interval "
20265cd9f28Seschrock 		    "[count]]\n"));
20365cd9f28Seschrock 	case HELP_LIST:
204*e45ce728Sahrens 		return (gettext("\tlist [-H] [-o field[,...]] [pool] ...\n"));
20565cd9f28Seschrock 	case HELP_OFFLINE:
206441d80aaSlling 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
20765cd9f28Seschrock 	case HELP_ONLINE:
208441d80aaSlling 		return (gettext("\tonline <pool> <device> ...\n"));
20965cd9f28Seschrock 	case HELP_REPLACE:
21065cd9f28Seschrock 		return (gettext("\treplace [-f] <pool> <device> "
211*e45ce728Sahrens 		    "[new-device]\n"));
21299653d4eSeschrock 	case HELP_REMOVE:
21399653d4eSeschrock 		return (gettext("\tremove <pool> <device>\n"));
21465cd9f28Seschrock 	case HELP_SCRUB:
21565cd9f28Seschrock 		return (gettext("\tscrub [-s] <pool> ...\n"));
21665cd9f28Seschrock 	case HELP_STATUS:
21765cd9f28Seschrock 		return (gettext("\tstatus [-vx] [pool] ...\n"));
218eaca9bbdSeschrock 	case HELP_UPGRADE:
219eaca9bbdSeschrock 		return (gettext("\tupgrade\n"
220eaca9bbdSeschrock 		    "\tupgrade -v\n"
221eaca9bbdSeschrock 		    "\tupgrade <-a | pool>\n"));
222b1b8ab34Slling 	case HELP_GET:
223*e45ce728Sahrens 		return (gettext("\tget <\"all\" | property[,...]> "
224b1b8ab34Slling 		    "<pool> ...\n"));
225b1b8ab34Slling 	case HELP_SET:
226b1b8ab34Slling 		return (gettext("\tset <property=value> <pool> \n"));
22765cd9f28Seschrock 	}
22865cd9f28Seschrock 
22965cd9f28Seschrock 	abort();
23065cd9f28Seschrock 	/* NOTREACHED */
23165cd9f28Seschrock }
23265cd9f28Seschrock 
233fa9e4066Sahrens /*
234fa9e4066Sahrens  * Fields available for 'zpool list'.
235fa9e4066Sahrens  */
236fa9e4066Sahrens typedef enum {
237fa9e4066Sahrens 	ZPOOL_FIELD_NAME,
238fa9e4066Sahrens 	ZPOOL_FIELD_SIZE,
239fa9e4066Sahrens 	ZPOOL_FIELD_USED,
240fa9e4066Sahrens 	ZPOOL_FIELD_AVAILABLE,
241fa9e4066Sahrens 	ZPOOL_FIELD_CAPACITY,
242fa9e4066Sahrens 	ZPOOL_FIELD_HEALTH,
243fa9e4066Sahrens 	ZPOOL_FIELD_ROOT
244fa9e4066Sahrens } zpool_field_t;
245fa9e4066Sahrens 
246fa9e4066Sahrens #define	MAX_FIELDS	10
247fa9e4066Sahrens 
248fa9e4066Sahrens typedef struct column_def {
249fa9e4066Sahrens 	const char	*cd_title;
250fa9e4066Sahrens 	size_t		cd_width;
251fa9e4066Sahrens 	enum {
252fa9e4066Sahrens 		left_justify,
253fa9e4066Sahrens 		right_justify
254fa9e4066Sahrens 	}		cd_justify;
255fa9e4066Sahrens } column_def_t;
256fa9e4066Sahrens 
257fa9e4066Sahrens static column_def_t column_table[] = {
258fa9e4066Sahrens 	{ "NAME",	20,	left_justify	},
259fa9e4066Sahrens 	{ "SIZE",	6,	right_justify	},
260fa9e4066Sahrens 	{ "USED",	6,	right_justify	},
261fa9e4066Sahrens 	{ "AVAIL",	6,	right_justify	},
262fa9e4066Sahrens 	{ "CAP",	5,	right_justify	},
263fa9e4066Sahrens 	{ "HEALTH",	9,	left_justify	},
264fa9e4066Sahrens 	{ "ALTROOT",	15,	left_justify	}
265fa9e4066Sahrens };
266fa9e4066Sahrens 
267fa9e4066Sahrens static char *column_subopts[] = {
268fa9e4066Sahrens 	"name",
269fa9e4066Sahrens 	"size",
270fa9e4066Sahrens 	"used",
271fa9e4066Sahrens 	"available",
272fa9e4066Sahrens 	"capacity",
273fa9e4066Sahrens 	"health",
274fa9e4066Sahrens 	"root",
275fa9e4066Sahrens 	NULL
276fa9e4066Sahrens };
277fa9e4066Sahrens 
278fa9e4066Sahrens /*
279b1b8ab34Slling  * Callback routine that will print out a pool property value.
280b1b8ab34Slling  */
281b1b8ab34Slling static zpool_prop_t
282b1b8ab34Slling print_prop_cb(zpool_prop_t prop, void *cb)
283b1b8ab34Slling {
284b1b8ab34Slling 	FILE *fp = cb;
285b1b8ab34Slling 
286b1b8ab34Slling 	(void) fprintf(fp, "\t%-13s  ", zpool_prop_to_name(prop));
287b1b8ab34Slling 
288b1b8ab34Slling 	if (zpool_prop_values(prop) == NULL)
289b1b8ab34Slling 		(void) fprintf(fp, "-\n");
290b1b8ab34Slling 	else
291b1b8ab34Slling 		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
292b1b8ab34Slling 
293b1b8ab34Slling 	return (ZFS_PROP_CONT);
294b1b8ab34Slling }
295b1b8ab34Slling 
296b1b8ab34Slling /*
297fa9e4066Sahrens  * Display usage message.  If we're inside a command, display only the usage for
298fa9e4066Sahrens  * that command.  Otherwise, iterate over the entire command table and display
299fa9e4066Sahrens  * a complete usage message.
300fa9e4066Sahrens  */
301fa9e4066Sahrens void
30299653d4eSeschrock usage(boolean_t requested)
303fa9e4066Sahrens {
304fa9e4066Sahrens 	int i;
305fa9e4066Sahrens 	FILE *fp = requested ? stdout : stderr;
306fa9e4066Sahrens 
307fa9e4066Sahrens 	if (current_command == NULL) {
308fa9e4066Sahrens 		int i;
309fa9e4066Sahrens 
310fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
311fa9e4066Sahrens 		(void) fprintf(fp,
312fa9e4066Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
313fa9e4066Sahrens 
314fa9e4066Sahrens 		for (i = 0; i < NCOMMAND; i++) {
315fa9e4066Sahrens 			if (command_table[i].name == NULL)
316fa9e4066Sahrens 				(void) fprintf(fp, "\n");
317fa9e4066Sahrens 			else
318fa9e4066Sahrens 				(void) fprintf(fp, "%s",
31965cd9f28Seschrock 				    get_usage(command_table[i].usage));
320fa9e4066Sahrens 		}
321fa9e4066Sahrens 	} else {
322fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
32365cd9f28Seschrock 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
324fa9e4066Sahrens 
325fa9e4066Sahrens 		if (strcmp(current_command->name, "list") == 0) {
326fa9e4066Sahrens 			(void) fprintf(fp, gettext("\nwhere 'field' is one "
327fa9e4066Sahrens 			    "of the following:\n\n"));
328fa9e4066Sahrens 
329fa9e4066Sahrens 			for (i = 0; column_subopts[i] != NULL; i++)
330fa9e4066Sahrens 				(void) fprintf(fp, "\t%s\n", column_subopts[i]);
331fa9e4066Sahrens 		}
332fa9e4066Sahrens 	}
333fa9e4066Sahrens 
334b1b8ab34Slling 	if (current_command != NULL &&
335b1b8ab34Slling 	    ((strcmp(current_command->name, "set") == 0) ||
336b1b8ab34Slling 	    (strcmp(current_command->name, "get") == 0))) {
337b1b8ab34Slling 
338b1b8ab34Slling 		(void) fprintf(fp,
339b1b8ab34Slling 		    gettext("\nthe following properties are supported:\n"));
340b1b8ab34Slling 
341b1b8ab34Slling 		(void) fprintf(fp, "\n\t%-13s  %s\n\n",
342b1b8ab34Slling 		    "PROPERTY", "VALUES");
343b1b8ab34Slling 
344b1b8ab34Slling 		/* Iterate over all properties */
34591ebeef5Sahrens 		(void) zpool_prop_iter(print_prop_cb, fp);
346b1b8ab34Slling 	}
347b1b8ab34Slling 
348e9dbad6fSeschrock 	/*
349e9dbad6fSeschrock 	 * See comments at end of main().
350e9dbad6fSeschrock 	 */
351e9dbad6fSeschrock 	if (getenv("ZFS_ABORT") != NULL) {
352e9dbad6fSeschrock 		(void) printf("dumping core by request\n");
353e9dbad6fSeschrock 		abort();
354e9dbad6fSeschrock 	}
355e9dbad6fSeschrock 
356fa9e4066Sahrens 	exit(requested ? 0 : 2);
357fa9e4066Sahrens }
358fa9e4066Sahrens 
359fa9e4066Sahrens const char *
36046657f8dSmmusante state_to_health(int vs_state)
36146657f8dSmmusante {
36246657f8dSmmusante 	switch (vs_state) {
36346657f8dSmmusante 	case VDEV_STATE_CLOSED:
36446657f8dSmmusante 	case VDEV_STATE_CANT_OPEN:
36546657f8dSmmusante 	case VDEV_STATE_OFFLINE:
36646657f8dSmmusante 		return (dgettext(TEXT_DOMAIN, "FAULTED"));
36746657f8dSmmusante 	case VDEV_STATE_DEGRADED:
36846657f8dSmmusante 		return (dgettext(TEXT_DOMAIN, "DEGRADED"));
36946657f8dSmmusante 	case VDEV_STATE_HEALTHY:
37046657f8dSmmusante 		return (dgettext(TEXT_DOMAIN, "ONLINE"));
37146657f8dSmmusante 	}
37246657f8dSmmusante 
37346657f8dSmmusante 	return (dgettext(TEXT_DOMAIN, "UNKNOWN"));
37446657f8dSmmusante }
37546657f8dSmmusante 
37646657f8dSmmusante const char *
377ea8dc4b6Seschrock state_to_name(vdev_stat_t *vs)
378fa9e4066Sahrens {
379ea8dc4b6Seschrock 	switch (vs->vs_state) {
380fa9e4066Sahrens 	case VDEV_STATE_CLOSED:
381fa9e4066Sahrens 	case VDEV_STATE_CANT_OPEN:
382ea8dc4b6Seschrock 		if (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)
383fa9e4066Sahrens 			return (gettext("FAULTED"));
384ea8dc4b6Seschrock 		else
385ea8dc4b6Seschrock 			return (gettext("UNAVAIL"));
386fa9e4066Sahrens 	case VDEV_STATE_OFFLINE:
387fa9e4066Sahrens 		return (gettext("OFFLINE"));
3883d7072f8Seschrock 	case VDEV_STATE_REMOVED:
3893d7072f8Seschrock 		return (gettext("REMOVED"));
3903d7072f8Seschrock 	case VDEV_STATE_FAULTED:
3913d7072f8Seschrock 		return (gettext("FAULTED"));
392fa9e4066Sahrens 	case VDEV_STATE_DEGRADED:
393fa9e4066Sahrens 		return (gettext("DEGRADED"));
394fa9e4066Sahrens 	case VDEV_STATE_HEALTHY:
395fa9e4066Sahrens 		return (gettext("ONLINE"));
396fa9e4066Sahrens 	}
397fa9e4066Sahrens 
398fa9e4066Sahrens 	return (gettext("UNKNOWN"));
399fa9e4066Sahrens }
400fa9e4066Sahrens 
401fa9e4066Sahrens void
4028654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
4038654d025Sperrin     boolean_t print_logs)
404fa9e4066Sahrens {
405fa9e4066Sahrens 	nvlist_t **child;
406fa9e4066Sahrens 	uint_t c, children;
407afefbcddSeschrock 	char *vname;
408fa9e4066Sahrens 
409fa9e4066Sahrens 	if (name != NULL)
410fa9e4066Sahrens 		(void) printf("\t%*s%s\n", indent, "", name);
411fa9e4066Sahrens 
412fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
413fa9e4066Sahrens 	    &child, &children) != 0)
414fa9e4066Sahrens 		return;
415fa9e4066Sahrens 
416afefbcddSeschrock 	for (c = 0; c < children; c++) {
4178654d025Sperrin 		uint64_t is_log = B_FALSE;
4188654d025Sperrin 
4198654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
4208654d025Sperrin 		    &is_log);
4218654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
4228654d025Sperrin 			continue;
4238654d025Sperrin 
42499653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
4258654d025Sperrin 		print_vdev_tree(zhp, vname, child[c], indent + 2,
4268654d025Sperrin 		    B_FALSE);
427afefbcddSeschrock 		free(vname);
428afefbcddSeschrock 	}
429fa9e4066Sahrens }
430fa9e4066Sahrens 
431fa9e4066Sahrens /*
432fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
433fa9e4066Sahrens  *
434fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
435fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
436fa9e4066Sahrens  *		they were to be added.
437fa9e4066Sahrens  *
438fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
439fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
440fa9e4066Sahrens  * libzfs.
441fa9e4066Sahrens  */
442fa9e4066Sahrens int
443fa9e4066Sahrens zpool_do_add(int argc, char **argv)
444fa9e4066Sahrens {
44599653d4eSeschrock 	boolean_t force = B_FALSE;
44699653d4eSeschrock 	boolean_t dryrun = B_FALSE;
447fa9e4066Sahrens 	int c;
448fa9e4066Sahrens 	nvlist_t *nvroot;
449fa9e4066Sahrens 	char *poolname;
450fa9e4066Sahrens 	int ret;
451fa9e4066Sahrens 	zpool_handle_t *zhp;
452fa9e4066Sahrens 	nvlist_t *config;
453fa9e4066Sahrens 
454fa9e4066Sahrens 	/* check options */
455fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
456fa9e4066Sahrens 		switch (c) {
457fa9e4066Sahrens 		case 'f':
45899653d4eSeschrock 			force = B_TRUE;
459fa9e4066Sahrens 			break;
460fa9e4066Sahrens 		case 'n':
46199653d4eSeschrock 			dryrun = B_TRUE;
462fa9e4066Sahrens 			break;
463fa9e4066Sahrens 		case '?':
464fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
465fa9e4066Sahrens 			    optopt);
46699653d4eSeschrock 			usage(B_FALSE);
467fa9e4066Sahrens 		}
468fa9e4066Sahrens 	}
469fa9e4066Sahrens 
470fa9e4066Sahrens 	argc -= optind;
471fa9e4066Sahrens 	argv += optind;
472fa9e4066Sahrens 
473fa9e4066Sahrens 	/* get pool name and check number of arguments */
474fa9e4066Sahrens 	if (argc < 1) {
475fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
47699653d4eSeschrock 		usage(B_FALSE);
477fa9e4066Sahrens 	}
478fa9e4066Sahrens 	if (argc < 2) {
479fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
48099653d4eSeschrock 		usage(B_FALSE);
481fa9e4066Sahrens 	}
482fa9e4066Sahrens 
483fa9e4066Sahrens 	poolname = argv[0];
484fa9e4066Sahrens 
485fa9e4066Sahrens 	argc--;
486fa9e4066Sahrens 	argv++;
487fa9e4066Sahrens 
48899653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
489fa9e4066Sahrens 		return (1);
490fa9e4066Sahrens 
491088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
492fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
493fa9e4066Sahrens 		    poolname);
494fa9e4066Sahrens 		zpool_close(zhp);
495fa9e4066Sahrens 		return (1);
496fa9e4066Sahrens 	}
497fa9e4066Sahrens 
498fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
4998488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv);
500fa9e4066Sahrens 	if (nvroot == NULL) {
501fa9e4066Sahrens 		zpool_close(zhp);
502fa9e4066Sahrens 		return (1);
503fa9e4066Sahrens 	}
504fa9e4066Sahrens 
505fa9e4066Sahrens 	if (dryrun) {
506fa9e4066Sahrens 		nvlist_t *poolnvroot;
507fa9e4066Sahrens 
508fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
509fa9e4066Sahrens 		    &poolnvroot) == 0);
510fa9e4066Sahrens 
511fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
512fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
513fa9e4066Sahrens 
5148654d025Sperrin 		/* print original main pool and new tree */
5158654d025Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
5168654d025Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
5178654d025Sperrin 
5188654d025Sperrin 		/* Do the same for the logs */
5198654d025Sperrin 		if (num_logs(poolnvroot) > 0) {
5208654d025Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
5218654d025Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
5228654d025Sperrin 		} else if (num_logs(nvroot) > 0) {
5238654d025Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
5248654d025Sperrin 		}
525fa9e4066Sahrens 
526fa9e4066Sahrens 		ret = 0;
527fa9e4066Sahrens 	} else {
528fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
529fa9e4066Sahrens 	}
530fa9e4066Sahrens 
53199653d4eSeschrock 	nvlist_free(nvroot);
53299653d4eSeschrock 	zpool_close(zhp);
53399653d4eSeschrock 
53499653d4eSeschrock 	return (ret);
53599653d4eSeschrock }
53699653d4eSeschrock 
53799653d4eSeschrock /*
53899653d4eSeschrock  * zpool remove <pool> <vdev>
53999653d4eSeschrock  *
54099653d4eSeschrock  * Removes the given vdev from the pool.  Currently, this only supports removing
54199653d4eSeschrock  * spares from the pool.  Eventually, we'll want to support removing leaf vdevs
54299653d4eSeschrock  * (as an alias for 'detach') as well as toplevel vdevs.
54399653d4eSeschrock  */
54499653d4eSeschrock int
54599653d4eSeschrock zpool_do_remove(int argc, char **argv)
54699653d4eSeschrock {
54799653d4eSeschrock 	char *poolname;
54899653d4eSeschrock 	int ret;
54999653d4eSeschrock 	zpool_handle_t *zhp;
55099653d4eSeschrock 
55199653d4eSeschrock 	argc--;
55299653d4eSeschrock 	argv++;
55399653d4eSeschrock 
55499653d4eSeschrock 	/* get pool name and check number of arguments */
55599653d4eSeschrock 	if (argc < 1) {
55699653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
55799653d4eSeschrock 		usage(B_FALSE);
55899653d4eSeschrock 	}
55999653d4eSeschrock 	if (argc < 2) {
56099653d4eSeschrock 		(void) fprintf(stderr, gettext("missing device\n"));
56199653d4eSeschrock 		usage(B_FALSE);
56299653d4eSeschrock 	}
56399653d4eSeschrock 
56499653d4eSeschrock 	poolname = argv[0];
56599653d4eSeschrock 
56699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
56799653d4eSeschrock 		return (1);
56899653d4eSeschrock 
56999653d4eSeschrock 	ret = (zpool_vdev_remove(zhp, argv[1]) != 0);
57099653d4eSeschrock 
571fa9e4066Sahrens 	return (ret);
572fa9e4066Sahrens }
573fa9e4066Sahrens 
574fa9e4066Sahrens /*
575fa9e4066Sahrens  * zpool create [-fn] [-R root] [-m mountpoint] <pool> <dev> ...
576fa9e4066Sahrens  *
577fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
578fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
579fa9e4066Sahrens  *		were to be created.
580fa9e4066Sahrens  *      -R	Create a pool under an alternate root
581fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
582fa9e4066Sahrens  *      	'/<pool>'
583fa9e4066Sahrens  *
584b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
585fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
586fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
587fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
588fa9e4066Sahrens  */
589fa9e4066Sahrens int
590fa9e4066Sahrens zpool_do_create(int argc, char **argv)
591fa9e4066Sahrens {
59299653d4eSeschrock 	boolean_t force = B_FALSE;
59399653d4eSeschrock 	boolean_t dryrun = B_FALSE;
594fa9e4066Sahrens 	int c;
595fa9e4066Sahrens 	nvlist_t *nvroot;
596fa9e4066Sahrens 	char *poolname;
597fa9e4066Sahrens 	int ret;
598fa9e4066Sahrens 	char *altroot = NULL;
599fa9e4066Sahrens 	char *mountpoint = NULL;
60099653d4eSeschrock 	nvlist_t **child;
60199653d4eSeschrock 	uint_t children;
602fa9e4066Sahrens 
603fa9e4066Sahrens 	/* check options */
604fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":fnR:m:")) != -1) {
605fa9e4066Sahrens 		switch (c) {
606fa9e4066Sahrens 		case 'f':
60799653d4eSeschrock 			force = B_TRUE;
608fa9e4066Sahrens 			break;
609fa9e4066Sahrens 		case 'n':
61099653d4eSeschrock 			dryrun = B_TRUE;
611fa9e4066Sahrens 			break;
612fa9e4066Sahrens 		case 'R':
613fa9e4066Sahrens 			altroot = optarg;
614fa9e4066Sahrens 			break;
615fa9e4066Sahrens 		case 'm':
616fa9e4066Sahrens 			mountpoint = optarg;
617fa9e4066Sahrens 			break;
618fa9e4066Sahrens 		case ':':
619fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
620fa9e4066Sahrens 			    "'%c' option\n"), optopt);
62199653d4eSeschrock 			usage(B_FALSE);
622fa9e4066Sahrens 			break;
623fa9e4066Sahrens 		case '?':
624fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
625fa9e4066Sahrens 			    optopt);
62699653d4eSeschrock 			usage(B_FALSE);
627fa9e4066Sahrens 		}
628fa9e4066Sahrens 	}
629fa9e4066Sahrens 
630fa9e4066Sahrens 	argc -= optind;
631fa9e4066Sahrens 	argv += optind;
632fa9e4066Sahrens 
633fa9e4066Sahrens 	/* get pool name and check number of arguments */
634fa9e4066Sahrens 	if (argc < 1) {
635fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
63699653d4eSeschrock 		usage(B_FALSE);
637fa9e4066Sahrens 	}
638fa9e4066Sahrens 	if (argc < 2) {
639fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
64099653d4eSeschrock 		usage(B_FALSE);
641fa9e4066Sahrens 	}
642fa9e4066Sahrens 
643fa9e4066Sahrens 	poolname = argv[0];
644fa9e4066Sahrens 
645fa9e4066Sahrens 	/*
646fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
647fa9e4066Sahrens 	 * user to use 'zfs create' instead.
648fa9e4066Sahrens 	 */
649fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
650fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
651fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
652fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
653fa9e4066Sahrens 		    "create a dataset\n"));
654fa9e4066Sahrens 		return (1);
655fa9e4066Sahrens 	}
656fa9e4066Sahrens 
657fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
65899653d4eSeschrock 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1,
65999653d4eSeschrock 	    argv + 1);
660fa9e4066Sahrens 	if (nvroot == NULL)
661fa9e4066Sahrens 		return (1);
662fa9e4066Sahrens 
66399653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
66499653d4eSeschrock 	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
66599653d4eSeschrock 	    &child, &children) == 0);
66699653d4eSeschrock 	if (children == 0) {
66799653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
66899653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
66999653d4eSeschrock 		    "specified\n"));
67099653d4eSeschrock 		return (1);
67199653d4eSeschrock 	}
67299653d4eSeschrock 
67399653d4eSeschrock 
674fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
675fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
676e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
67799653d4eSeschrock 		nvlist_free(nvroot);
678fa9e4066Sahrens 		return (1);
679fa9e4066Sahrens 	}
680fa9e4066Sahrens 
681fa9e4066Sahrens 	/*
682fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
683fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
684fa9e4066Sahrens 	 */
685fa9e4066Sahrens 	if (mountpoint == NULL ||
686fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
687fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
688fa9e4066Sahrens 		char buf[MAXPATHLEN];
689fa9e4066Sahrens 		struct stat64 statbuf;
690fa9e4066Sahrens 
691fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
692fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
693fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
694fa9e4066Sahrens 			    "'none'\n"), mountpoint);
69599653d4eSeschrock 			nvlist_free(nvroot);
696fa9e4066Sahrens 			return (1);
697fa9e4066Sahrens 		}
698fa9e4066Sahrens 
699fa9e4066Sahrens 		if (mountpoint == NULL) {
700fa9e4066Sahrens 			if (altroot != NULL)
701fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
702fa9e4066Sahrens 				    altroot, poolname);
703fa9e4066Sahrens 			else
704fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
705fa9e4066Sahrens 				    poolname);
706fa9e4066Sahrens 		} else {
707fa9e4066Sahrens 			if (altroot != NULL)
708fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
709fa9e4066Sahrens 				    altroot, mountpoint);
710fa9e4066Sahrens 			else
711fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
712fa9e4066Sahrens 				    mountpoint);
713fa9e4066Sahrens 		}
714fa9e4066Sahrens 
715fa9e4066Sahrens 		if (stat64(buf, &statbuf) == 0 &&
716fa9e4066Sahrens 		    statbuf.st_nlink != 2) {
717fa9e4066Sahrens 			if (mountpoint == NULL)
718fa9e4066Sahrens 				(void) fprintf(stderr, gettext("default "
719fa9e4066Sahrens 				    "mountpoint '%s' exists and is not "
720fa9e4066Sahrens 				    "empty\n"), buf);
721fa9e4066Sahrens 			else
722fa9e4066Sahrens 				(void) fprintf(stderr, gettext("mountpoint "
723fa9e4066Sahrens 				    "'%s' exists and is not empty\n"), buf);
724fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
725fa9e4066Sahrens 			    "option to provide a different default\n"));
72699653d4eSeschrock 			nvlist_free(nvroot);
727fa9e4066Sahrens 			return (1);
728fa9e4066Sahrens 		}
729fa9e4066Sahrens 	}
730fa9e4066Sahrens 
731fa9e4066Sahrens 
732fa9e4066Sahrens 	if (dryrun) {
733fa9e4066Sahrens 		/*
734fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
735fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
736fa9e4066Sahrens 		 * appropriate hierarchy.
737fa9e4066Sahrens 		 */
738fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
739fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
740fa9e4066Sahrens 
7418654d025Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7428654d025Sperrin 		if (num_logs(nvroot) > 0)
7438654d025Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
744fa9e4066Sahrens 
745fa9e4066Sahrens 		ret = 0;
746fa9e4066Sahrens 	} else {
747fa9e4066Sahrens 		ret = 1;
748fa9e4066Sahrens 		/*
749fa9e4066Sahrens 		 * Hand off to libzfs.
750fa9e4066Sahrens 		 */
75199653d4eSeschrock 		if (zpool_create(g_zfs, poolname, nvroot, altroot) == 0) {
75299653d4eSeschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
753fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
754fa9e4066Sahrens 			if (pool != NULL) {
755fa9e4066Sahrens 				if (mountpoint != NULL)
756fa9e4066Sahrens 					verify(zfs_prop_set(pool,
757e9dbad6fSeschrock 					    zfs_prop_to_name(
758e9dbad6fSeschrock 					    ZFS_PROP_MOUNTPOINT),
759fa9e4066Sahrens 					    mountpoint) == 0);
760fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
761f3861e1aSahl 					ret = zfs_share_nfs(pool);
762fa9e4066Sahrens 				zfs_close(pool);
763fa9e4066Sahrens 			}
76499653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
76599653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
76699653d4eSeschrock 			    "been omitted\n"));
767fa9e4066Sahrens 		}
768fa9e4066Sahrens 	}
769fa9e4066Sahrens 
770fa9e4066Sahrens 	nvlist_free(nvroot);
771fa9e4066Sahrens 
772fa9e4066Sahrens 	return (ret);
773fa9e4066Sahrens }
774fa9e4066Sahrens 
775fa9e4066Sahrens /*
776fa9e4066Sahrens  * zpool destroy <pool>
777fa9e4066Sahrens  *
778fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
779fa9e4066Sahrens  *
780fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
781fa9e4066Sahrens  */
782fa9e4066Sahrens int
783fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
784fa9e4066Sahrens {
78599653d4eSeschrock 	boolean_t force = B_FALSE;
786fa9e4066Sahrens 	int c;
787fa9e4066Sahrens 	char *pool;
788fa9e4066Sahrens 	zpool_handle_t *zhp;
789fa9e4066Sahrens 	int ret;
790fa9e4066Sahrens 
791fa9e4066Sahrens 	/* check options */
792fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
793fa9e4066Sahrens 		switch (c) {
794fa9e4066Sahrens 		case 'f':
79599653d4eSeschrock 			force = B_TRUE;
796fa9e4066Sahrens 			break;
797fa9e4066Sahrens 		case '?':
798fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
799fa9e4066Sahrens 			    optopt);
80099653d4eSeschrock 			usage(B_FALSE);
801fa9e4066Sahrens 		}
802fa9e4066Sahrens 	}
803fa9e4066Sahrens 
804fa9e4066Sahrens 	argc -= optind;
805fa9e4066Sahrens 	argv += optind;
806fa9e4066Sahrens 
807fa9e4066Sahrens 	/* check arguments */
808fa9e4066Sahrens 	if (argc < 1) {
809fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
81099653d4eSeschrock 		usage(B_FALSE);
811fa9e4066Sahrens 	}
812fa9e4066Sahrens 	if (argc > 1) {
813fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
81499653d4eSeschrock 		usage(B_FALSE);
815fa9e4066Sahrens 	}
816fa9e4066Sahrens 
817fa9e4066Sahrens 	pool = argv[0];
818fa9e4066Sahrens 
81999653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
820fa9e4066Sahrens 		/*
821fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
822fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
823fa9e4066Sahrens 		 */
824fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
825fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
826fa9e4066Sahrens 			    "destroy a dataset\n"));
827fa9e4066Sahrens 		return (1);
828fa9e4066Sahrens 	}
829fa9e4066Sahrens 
830f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
831fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
832fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
833fa9e4066Sahrens 		return (1);
834fa9e4066Sahrens 	}
835fa9e4066Sahrens 
836fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
837fa9e4066Sahrens 
838fa9e4066Sahrens 	zpool_close(zhp);
839fa9e4066Sahrens 
840fa9e4066Sahrens 	return (ret);
841fa9e4066Sahrens }
842fa9e4066Sahrens 
843fa9e4066Sahrens /*
844fa9e4066Sahrens  * zpool export [-f] <pool> ...
845fa9e4066Sahrens  *
846fa9e4066Sahrens  *	-f	Forcefully unmount datasets
847fa9e4066Sahrens  *
848b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
849fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
850fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
851fa9e4066Sahrens  */
852fa9e4066Sahrens int
853fa9e4066Sahrens zpool_do_export(int argc, char **argv)
854fa9e4066Sahrens {
85599653d4eSeschrock 	boolean_t force = B_FALSE;
856fa9e4066Sahrens 	int c;
857fa9e4066Sahrens 	zpool_handle_t *zhp;
858fa9e4066Sahrens 	int ret;
859fa9e4066Sahrens 	int i;
860fa9e4066Sahrens 
861fa9e4066Sahrens 	/* check options */
862fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
863fa9e4066Sahrens 		switch (c) {
864fa9e4066Sahrens 		case 'f':
86599653d4eSeschrock 			force = B_TRUE;
866fa9e4066Sahrens 			break;
867fa9e4066Sahrens 		case '?':
868fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
869fa9e4066Sahrens 			    optopt);
87099653d4eSeschrock 			usage(B_FALSE);
871fa9e4066Sahrens 		}
872fa9e4066Sahrens 	}
873fa9e4066Sahrens 
874fa9e4066Sahrens 	argc -= optind;
875fa9e4066Sahrens 	argv += optind;
876fa9e4066Sahrens 
877fa9e4066Sahrens 	/* check arguments */
878fa9e4066Sahrens 	if (argc < 1) {
879fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
88099653d4eSeschrock 		usage(B_FALSE);
881fa9e4066Sahrens 	}
882fa9e4066Sahrens 
883fa9e4066Sahrens 	ret = 0;
884fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
88599653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
886fa9e4066Sahrens 			ret = 1;
887fa9e4066Sahrens 			continue;
888fa9e4066Sahrens 		}
889fa9e4066Sahrens 
890f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
891fa9e4066Sahrens 			ret = 1;
892fa9e4066Sahrens 			zpool_close(zhp);
893fa9e4066Sahrens 			continue;
894fa9e4066Sahrens 		}
895fa9e4066Sahrens 
896fa9e4066Sahrens 		if (zpool_export(zhp) != 0)
897fa9e4066Sahrens 			ret = 1;
898fa9e4066Sahrens 
899fa9e4066Sahrens 		zpool_close(zhp);
900fa9e4066Sahrens 	}
901fa9e4066Sahrens 
902fa9e4066Sahrens 	return (ret);
903fa9e4066Sahrens }
904fa9e4066Sahrens 
905fa9e4066Sahrens /*
906fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
907fa9e4066Sahrens  * name column.
908fa9e4066Sahrens  */
909fa9e4066Sahrens static int
910c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
911fa9e4066Sahrens {
91299653d4eSeschrock 	char *name = zpool_vdev_name(g_zfs, zhp, nv);
913fa9e4066Sahrens 	nvlist_t **child;
914fa9e4066Sahrens 	uint_t c, children;
915fa9e4066Sahrens 	int ret;
916fa9e4066Sahrens 
917fa9e4066Sahrens 	if (strlen(name) + depth > max)
918fa9e4066Sahrens 		max = strlen(name) + depth;
919fa9e4066Sahrens 
920afefbcddSeschrock 	free(name);
921afefbcddSeschrock 
92299653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
92399653d4eSeschrock 	    &child, &children) == 0) {
924fa9e4066Sahrens 		for (c = 0; c < children; c++)
92599653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
92699653d4eSeschrock 			    max)) > max)
927fa9e4066Sahrens 				max = ret;
92899653d4eSeschrock 	}
92999653d4eSeschrock 
93099653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
93199653d4eSeschrock 	    &child, &children) == 0) {
93299653d4eSeschrock 		for (c = 0; c < children; c++)
93399653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
93499653d4eSeschrock 			    max)) > max)
93599653d4eSeschrock 				max = ret;
93699653d4eSeschrock 	}
93799653d4eSeschrock 
938fa9e4066Sahrens 
939fa9e4066Sahrens 	return (max);
940fa9e4066Sahrens }
941fa9e4066Sahrens 
942fa9e4066Sahrens 
943fa9e4066Sahrens /*
944fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
945fa9e4066Sahrens  * pool, printing out the name and status for each one.
946fa9e4066Sahrens  */
947fa9e4066Sahrens void
9488654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
9498654d025Sperrin     boolean_t print_logs)
950fa9e4066Sahrens {
951fa9e4066Sahrens 	nvlist_t **child;
952fa9e4066Sahrens 	uint_t c, children;
953fa9e4066Sahrens 	vdev_stat_t *vs;
954afefbcddSeschrock 	char *type, *vname;
955fa9e4066Sahrens 
956fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
957fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
958fa9e4066Sahrens 		return;
959fa9e4066Sahrens 
960fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
961fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
962fa9e4066Sahrens 
963fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
9643d7072f8Seschrock 	(void) printf("  %s", state_to_name(vs));
965fa9e4066Sahrens 
966fa9e4066Sahrens 	if (vs->vs_aux != 0) {
9673d7072f8Seschrock 		(void) printf("  ");
968fa9e4066Sahrens 
969fa9e4066Sahrens 		switch (vs->vs_aux) {
970fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
971fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
972fa9e4066Sahrens 			break;
973fa9e4066Sahrens 
974fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
975fa9e4066Sahrens 			(void) printf(gettext("missing device"));
976fa9e4066Sahrens 			break;
977fa9e4066Sahrens 
978fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
979fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
980fa9e4066Sahrens 			break;
981fa9e4066Sahrens 
982eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
983eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
984eaca9bbdSeschrock 			break;
985eaca9bbdSeschrock 
9863d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
9873d7072f8Seschrock 			(void) printf(gettext("too many errors"));
9883d7072f8Seschrock 			break;
9893d7072f8Seschrock 
990fa9e4066Sahrens 		default:
991fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
992fa9e4066Sahrens 			break;
993fa9e4066Sahrens 		}
994fa9e4066Sahrens 	}
995fa9e4066Sahrens 	(void) printf("\n");
996fa9e4066Sahrens 
997fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
998fa9e4066Sahrens 	    &child, &children) != 0)
999fa9e4066Sahrens 		return;
1000fa9e4066Sahrens 
1001afefbcddSeschrock 	for (c = 0; c < children; c++) {
10028654d025Sperrin 		uint64_t is_log = B_FALSE;
10038654d025Sperrin 
10048654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
10058654d025Sperrin 		    &is_log);
10068654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
10078654d025Sperrin 			continue;
10088654d025Sperrin 
100999653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1010afefbcddSeschrock 		print_import_config(vname, child[c],
10118654d025Sperrin 		    namewidth, depth + 2, B_FALSE);
1012afefbcddSeschrock 		free(vname);
1013afefbcddSeschrock 	}
101499653d4eSeschrock 
101599653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
101699653d4eSeschrock 	    &child, &children) != 0)
101799653d4eSeschrock 		return;
101899653d4eSeschrock 
101999653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
102099653d4eSeschrock 	for (c = 0; c < children; c++) {
102199653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
102299653d4eSeschrock 		(void) printf("\t  %s\n", vname);
102399653d4eSeschrock 		free(vname);
102499653d4eSeschrock 	}
1025fa9e4066Sahrens }
1026fa9e4066Sahrens 
1027fa9e4066Sahrens /*
1028fa9e4066Sahrens  * Display the status for the given pool.
1029fa9e4066Sahrens  */
1030fa9e4066Sahrens static void
1031fa9e4066Sahrens show_import(nvlist_t *config)
1032fa9e4066Sahrens {
1033fa9e4066Sahrens 	uint64_t pool_state;
1034fa9e4066Sahrens 	vdev_stat_t *vs;
1035fa9e4066Sahrens 	char *name;
1036fa9e4066Sahrens 	uint64_t guid;
1037fa9e4066Sahrens 	char *msgid;
1038fa9e4066Sahrens 	nvlist_t *nvroot;
1039fa9e4066Sahrens 	int reason;
104046657f8dSmmusante 	const char *health;
1041fa9e4066Sahrens 	uint_t vsc;
1042fa9e4066Sahrens 	int namewidth;
1043fa9e4066Sahrens 
1044fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1045fa9e4066Sahrens 	    &name) == 0);
1046fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1047fa9e4066Sahrens 	    &guid) == 0);
1048fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1049fa9e4066Sahrens 	    &pool_state) == 0);
1050fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1051fa9e4066Sahrens 	    &nvroot) == 0);
1052fa9e4066Sahrens 
1053fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1054fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
105546657f8dSmmusante 	health = state_to_health(vs->vs_state);
1056fa9e4066Sahrens 
1057fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1058fa9e4066Sahrens 
105946657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
106046657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
106146657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
10624c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
106346657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
10644c58d714Sdarrenm 	(void) printf("\n");
1065fa9e4066Sahrens 
1066fa9e4066Sahrens 	switch (reason) {
1067fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1068fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1069fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1070fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1071fa9e4066Sahrens 		    "from the system.\n"));
1072fa9e4066Sahrens 		break;
1073fa9e4066Sahrens 
1074fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1075fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1076fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1077fa9e4066Sahrens 		    "corrupted data.\n"));
1078fa9e4066Sahrens 		break;
1079fa9e4066Sahrens 
1080fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1081fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1082fa9e4066Sahrens 		break;
1083fa9e4066Sahrens 
1084441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1085441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1086441d80aaSlling 		    "are offlined.\n"));
1087441d80aaSlling 		break;
1088441d80aaSlling 
1089ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1090ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1091ea8dc4b6Seschrock 		    "corrupted.\n"));
1092ea8dc4b6Seschrock 		break;
1093ea8dc4b6Seschrock 
1094eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1095eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1096eaca9bbdSeschrock 		    "older on-disk version.\n"));
1097eaca9bbdSeschrock 		break;
1098eaca9bbdSeschrock 
1099eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1100eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1101eaca9bbdSeschrock 		    "incompatible version.\n"));
1102eaca9bbdSeschrock 		break;
110395173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
110495173954Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
110595173954Sek110237 		    "another system.\n"));
110695173954Sek110237 		break;
11073d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
11083d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
11093d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
11103d7072f8Seschrock 		    "faulted.\n"));
11113d7072f8Seschrock 		break;
11123d7072f8Seschrock 
1113fa9e4066Sahrens 	default:
1114fa9e4066Sahrens 		/*
1115fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1116fa9e4066Sahrens 		 */
1117fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1118fa9e4066Sahrens 	}
1119fa9e4066Sahrens 
1120fa9e4066Sahrens 	/*
1121fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1122fa9e4066Sahrens 	 */
112346657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1124eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1125eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1126eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1127eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1128eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
112995173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
113095173954Sek110237 			(void) printf(gettext("action: The pool can be "
113195173954Sek110237 			    "imported using its name or numeric "
113295173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1133fa9e4066Sahrens 		else
1134eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1135eaca9bbdSeschrock 			    "imported using its name or numeric "
1136eaca9bbdSeschrock 			    "identifier.\n"));
113746657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1138fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1139fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1140eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1141fa9e4066Sahrens 	} else {
1142eaca9bbdSeschrock 		switch (reason) {
1143eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1144eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1145eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1146eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1147eaca9bbdSeschrock 			    "backup.\n"));
1148eaca9bbdSeschrock 			break;
1149eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1150eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1151eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1152fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1153fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1154fa9e4066Sahrens 			    "again.\n"));
1155eaca9bbdSeschrock 			break;
1156eaca9bbdSeschrock 		default:
1157fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1158fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1159fa9e4066Sahrens 		}
1160eaca9bbdSeschrock 	}
1161eaca9bbdSeschrock 
116246657f8dSmmusante 	/*
116346657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
116446657f8dSmmusante 	 * is "corrupt data":
116546657f8dSmmusante 	 */
116646657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
116746657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
116846657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1169eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1170eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1171eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1172eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1173eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
1174eaca9bbdSeschrock 			    "on another system, but can be imported using\n\t"
1175eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1176eaca9bbdSeschrock 	}
1177fa9e4066Sahrens 
1178fa9e4066Sahrens 	if (msgid != NULL)
1179fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1180fa9e4066Sahrens 		    msgid);
1181fa9e4066Sahrens 
1182fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1183fa9e4066Sahrens 
1184c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1185fa9e4066Sahrens 	if (namewidth < 10)
1186fa9e4066Sahrens 		namewidth = 10;
11878654d025Sperrin 
11888654d025Sperrin 	print_import_config(name, nvroot, namewidth, 0, B_FALSE);
11898654d025Sperrin 	if (num_logs(nvroot) > 0) {
11908654d025Sperrin 		(void) printf(gettext("\tlogs\n"));
11918654d025Sperrin 		print_import_config(name, nvroot, namewidth, 0, B_TRUE);
11928654d025Sperrin 	}
1193fa9e4066Sahrens 
1194fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
119546657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1196fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
119746657f8dSmmusante 		    "configuration cannot be determined.\n"));
1198fa9e4066Sahrens 	}
1199fa9e4066Sahrens }
1200fa9e4066Sahrens 
1201fa9e4066Sahrens /*
1202fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1203fa9e4066Sahrens  * lifting off to zpool_import(), and then mounts the datasets contained within
1204fa9e4066Sahrens  * the pool.
1205fa9e4066Sahrens  */
1206fa9e4066Sahrens static int
1207fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
1208ecd6cf80Smarks     const char *altroot, int force, nvlist_t *props)
1209fa9e4066Sahrens {
1210fa9e4066Sahrens 	zpool_handle_t *zhp;
1211fa9e4066Sahrens 	char *name;
1212fa9e4066Sahrens 	uint64_t state;
1213eaca9bbdSeschrock 	uint64_t version;
1214ecd6cf80Smarks 	int error = 0;
1215fa9e4066Sahrens 
1216fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1217fa9e4066Sahrens 	    &name) == 0);
1218fa9e4066Sahrens 
1219fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1220fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1221eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1222eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1223e7437265Sahrens 	if (version > SPA_VERSION) {
1224eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1225eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1226eaca9bbdSeschrock 		return (1);
1227eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
122895173954Sek110237 		uint64_t hostid;
122995173954Sek110237 
123095173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
123195173954Sek110237 		    &hostid) == 0) {
123295173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
123395173954Sek110237 				char *hostname;
123495173954Sek110237 				uint64_t timestamp;
123595173954Sek110237 				time_t t;
123695173954Sek110237 
123795173954Sek110237 				verify(nvlist_lookup_string(config,
123895173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
123995173954Sek110237 				verify(nvlist_lookup_uint64(config,
124095173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
124195173954Sek110237 				t = timestamp;
124295173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
124395173954Sek110237 				    "'%s': pool may be in use from other "
124495173954Sek110237 				    "system, it was last accessed by %s "
124595173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
124695173954Sek110237 				    (unsigned long)hostid,
124795173954Sek110237 				    asctime(localtime(&t)));
124895173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
124995173954Sek110237 				    "import anyway\n"));
1250fa9e4066Sahrens 				return (1);
1251fa9e4066Sahrens 			}
125295173954Sek110237 		} else {
125395173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
125495173954Sek110237 			    "pool may be in use from other system\n"), name);
125595173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
125695173954Sek110237 			    "anyway\n"));
125795173954Sek110237 			return (1);
125895173954Sek110237 		}
125995173954Sek110237 	}
1260fa9e4066Sahrens 
126199653d4eSeschrock 	if (zpool_import(g_zfs, config, newname, altroot) != 0)
1262fa9e4066Sahrens 		return (1);
1263fa9e4066Sahrens 
1264fa9e4066Sahrens 	if (newname != NULL)
1265fa9e4066Sahrens 		name = (char *)newname;
1266fa9e4066Sahrens 
126799653d4eSeschrock 	verify((zhp = zpool_open(g_zfs, name)) != NULL);
1268fa9e4066Sahrens 
1269ecd6cf80Smarks 	if (props) {
1270ecd6cf80Smarks 		nvpair_t *pair = nvlist_next_nvpair(props, NULL);
1271ecd6cf80Smarks 		char *value;
1272ecd6cf80Smarks 
1273ecd6cf80Smarks 		if (pair != NULL) {
1274ecd6cf80Smarks 			do {
1275ecd6cf80Smarks 				verify((nvpair_value_string(pair,
1276ecd6cf80Smarks 				    &value)) == 0);
1277ecd6cf80Smarks 
1278ecd6cf80Smarks 				if ((error = zpool_set_prop(zhp,
1279ecd6cf80Smarks 				    nvpair_name(pair), value)) != 0)
1280ecd6cf80Smarks 					break;
1281ecd6cf80Smarks 
1282ecd6cf80Smarks 			} while (pair = nvlist_next_nvpair(props, pair));
1283ecd6cf80Smarks 		}
1284ecd6cf80Smarks 	}
1285ecd6cf80Smarks 
1286ecd6cf80Smarks 
1287f3861e1aSahl 	if (zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1288fa9e4066Sahrens 		zpool_close(zhp);
1289fa9e4066Sahrens 		return (1);
1290fa9e4066Sahrens 	}
1291fa9e4066Sahrens 
1292fa9e4066Sahrens 	zpool_close(zhp);
1293ecd6cf80Smarks 	return (error);
1294fa9e4066Sahrens }
1295fa9e4066Sahrens 
1296fa9e4066Sahrens /*
12974c58d714Sdarrenm  * zpool import [-d dir] [-D]
12984c58d714Sdarrenm  *       import [-R root] [-D] [-d dir] [-f] -a
12994c58d714Sdarrenm  *       import [-R root] [-D] [-d dir] [-f] <pool | id> [newpool]
1300fa9e4066Sahrens  *
1301fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1302fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1303fa9e4066Sahrens  *
13044c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
13054c58d714Sdarrenm  *              specified destroyed pools.
13064c58d714Sdarrenm  *
1307fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1308fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1309fa9e4066Sahrens  *		is rebooted.
1310fa9e4066Sahrens  *
1311fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1312fa9e4066Sahrens  *
1313fa9e4066Sahrens  *       -a	Import all pools found.
1314fa9e4066Sahrens  *
1315ecd6cf80Smarks  *       -o	temporary mount options.
1316ecd6cf80Smarks  *
1317ecd6cf80Smarks  *       -p	property=value
1318ecd6cf80Smarks  *
1319fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1320fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1321fa9e4066Sahrens  */
1322fa9e4066Sahrens int
1323fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1324fa9e4066Sahrens {
1325fa9e4066Sahrens 	char **searchdirs = NULL;
1326fa9e4066Sahrens 	int nsearch = 0;
1327fa9e4066Sahrens 	int c;
1328fa9e4066Sahrens 	int err;
1329fa9e4066Sahrens 	nvlist_t *pools;
133099653d4eSeschrock 	boolean_t do_all = B_FALSE;
133199653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1332fa9e4066Sahrens 	char *altroot = NULL;
1333fa9e4066Sahrens 	char *mntopts = NULL;
133499653d4eSeschrock 	boolean_t do_force = B_FALSE;
1335fa9e4066Sahrens 	nvpair_t *elem;
1336fa9e4066Sahrens 	nvlist_t *config;
1337fa9e4066Sahrens 	uint64_t searchguid;
1338fa9e4066Sahrens 	char *searchname;
1339ecd6cf80Smarks 	char *propname;
1340ecd6cf80Smarks 	char *propval, *strval;
1341fa9e4066Sahrens 	nvlist_t *found_config;
1342ecd6cf80Smarks 	nvlist_t *props = NULL;
134399653d4eSeschrock 	boolean_t first;
13444c58d714Sdarrenm 	uint64_t pool_state;
1345fa9e4066Sahrens 
1346fa9e4066Sahrens 	/* check options */
1347ecd6cf80Smarks 	while ((c = getopt(argc, argv, ":Dfd:R:ao:p:")) != -1) {
1348fa9e4066Sahrens 		switch (c) {
1349fa9e4066Sahrens 		case 'a':
135099653d4eSeschrock 			do_all = B_TRUE;
1351fa9e4066Sahrens 			break;
1352fa9e4066Sahrens 		case 'd':
1353fa9e4066Sahrens 			if (searchdirs == NULL) {
1354fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1355fa9e4066Sahrens 			} else {
1356fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1357fa9e4066Sahrens 				    sizeof (char *));
1358fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1359fa9e4066Sahrens 				    sizeof (char *));
1360fa9e4066Sahrens 				free(searchdirs);
1361fa9e4066Sahrens 				searchdirs = tmp;
1362fa9e4066Sahrens 			}
1363fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1364fa9e4066Sahrens 			break;
13654c58d714Sdarrenm 		case 'D':
136699653d4eSeschrock 			do_destroyed = B_TRUE;
13674c58d714Sdarrenm 			break;
1368fa9e4066Sahrens 		case 'f':
136999653d4eSeschrock 			do_force = B_TRUE;
1370fa9e4066Sahrens 			break;
1371fa9e4066Sahrens 		case 'o':
1372fa9e4066Sahrens 			mntopts = optarg;
1373fa9e4066Sahrens 			break;
1374fa9e4066Sahrens 		case 'R':
1375fa9e4066Sahrens 			altroot = optarg;
1376fa9e4066Sahrens 			break;
1377fa9e4066Sahrens 		case ':':
1378fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1379fa9e4066Sahrens 			    "'%c' option\n"), optopt);
138099653d4eSeschrock 			usage(B_FALSE);
1381fa9e4066Sahrens 			break;
1382ecd6cf80Smarks 		case 'p':
1383ecd6cf80Smarks 			if (props == NULL &&
1384ecd6cf80Smarks 			    nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
1385ecd6cf80Smarks 				(void) fprintf(stderr,
1386ecd6cf80Smarks 				    gettext("internal error: "
1387ecd6cf80Smarks 				    "out of memory\n"));
1388ecd6cf80Smarks 				err = B_TRUE;
1389ecd6cf80Smarks 				goto error;
1390ecd6cf80Smarks 			}
1391ecd6cf80Smarks 
1392ecd6cf80Smarks 			propname = optarg;
1393ecd6cf80Smarks 			if ((propval = strchr(propname, '=')) == NULL) {
1394ecd6cf80Smarks 				(void) fprintf(stderr, gettext("missing "
1395ecd6cf80Smarks 				    "'=' for -o option\n"));
1396ecd6cf80Smarks 				err = B_TRUE;
1397ecd6cf80Smarks 				goto error;
1398ecd6cf80Smarks 			}
1399ecd6cf80Smarks 			*propval = '\0';
1400ecd6cf80Smarks 			propval++;
1401ecd6cf80Smarks 
1402ecd6cf80Smarks 			if (zpool_name_to_prop(propname) == ZFS_PROP_INVAL) {
1403ecd6cf80Smarks 				(void) fprintf(stderr,
1404ecd6cf80Smarks 				    gettext("property '%s' is "
1405ecd6cf80Smarks 				    "not a valid pool property\n"), propname);
1406ecd6cf80Smarks 				err = B_TRUE;
1407ecd6cf80Smarks 				goto error;
1408ecd6cf80Smarks 			}
1409ecd6cf80Smarks 
1410ecd6cf80Smarks 			if (nvlist_lookup_string(props, propname,
1411ecd6cf80Smarks 			    &strval) == 0) {
1412ecd6cf80Smarks 				(void) fprintf(stderr, gettext("property '%s' "
1413ecd6cf80Smarks 				    "specified multiple times\n"), propname);
1414ecd6cf80Smarks 				err = B_TRUE;
1415ecd6cf80Smarks 				goto error;
1416ecd6cf80Smarks 			}
1417ecd6cf80Smarks 			if (nvlist_add_string(props, propname, propval) != 0) {
1418ecd6cf80Smarks 				(void) fprintf(stderr, gettext("internal "
1419ecd6cf80Smarks 				    "error: out of memory\n"));
1420ecd6cf80Smarks 				err = B_TRUE;
1421ecd6cf80Smarks 				goto error;
1422ecd6cf80Smarks 			}
1423ecd6cf80Smarks 			break;
1424fa9e4066Sahrens 		case '?':
1425fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1426fa9e4066Sahrens 			    optopt);
142799653d4eSeschrock 			usage(B_FALSE);
1428fa9e4066Sahrens 		}
1429fa9e4066Sahrens 	}
1430fa9e4066Sahrens 
1431fa9e4066Sahrens 	argc -= optind;
1432fa9e4066Sahrens 	argv += optind;
1433fa9e4066Sahrens 
1434fa9e4066Sahrens 	if (searchdirs == NULL) {
1435fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1436fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1437fa9e4066Sahrens 		nsearch = 1;
1438fa9e4066Sahrens 	}
1439fa9e4066Sahrens 
1440fa9e4066Sahrens 	/* check argument count */
1441fa9e4066Sahrens 	if (do_all) {
1442fa9e4066Sahrens 		if (argc != 0) {
1443fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
144499653d4eSeschrock 			usage(B_FALSE);
1445fa9e4066Sahrens 		}
1446fa9e4066Sahrens 	} else {
1447fa9e4066Sahrens 		if (argc > 2) {
1448fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
144999653d4eSeschrock 			usage(B_FALSE);
1450fa9e4066Sahrens 		}
1451fa9e4066Sahrens 
1452fa9e4066Sahrens 		/*
1453fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1454fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1455fa9e4066Sahrens 		 * silently fail.
1456fa9e4066Sahrens 		 */
1457fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1458fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1459fa9e4066Sahrens 			    "discover pools: permission denied\n"));
146099653d4eSeschrock 			free(searchdirs);
1461fa9e4066Sahrens 			return (1);
1462fa9e4066Sahrens 		}
1463fa9e4066Sahrens 	}
1464fa9e4066Sahrens 
146599653d4eSeschrock 	if ((pools = zpool_find_import(g_zfs, nsearch, searchdirs)) == NULL) {
146699653d4eSeschrock 		free(searchdirs);
1467fa9e4066Sahrens 		return (1);
146899653d4eSeschrock 	}
1469fa9e4066Sahrens 
1470fa9e4066Sahrens 	/*
1471fa9e4066Sahrens 	 * We now have a list of all available pools in the given directories.
1472fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1473fa9e4066Sahrens 	 *
1474fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1475fa9e4066Sahrens 	 *		each one.
1476fa9e4066Sahrens 	 *
1477fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1478fa9e4066Sahrens 	 *
1479fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1480fa9e4066Sahrens 	 *		name and import that one.
14814c58d714Sdarrenm 	 *
14824c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1483fa9e4066Sahrens 	 */
1484fa9e4066Sahrens 	if (argc != 0) {
1485fa9e4066Sahrens 		char *endptr;
1486fa9e4066Sahrens 
1487fa9e4066Sahrens 		errno = 0;
1488fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1489fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1490fa9e4066Sahrens 			searchname = argv[0];
1491fa9e4066Sahrens 		else
1492fa9e4066Sahrens 			searchname = NULL;
1493fa9e4066Sahrens 		found_config = NULL;
1494fa9e4066Sahrens 	}
1495fa9e4066Sahrens 
1496fa9e4066Sahrens 	err = 0;
1497fa9e4066Sahrens 	elem = NULL;
149899653d4eSeschrock 	first = B_TRUE;
1499fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1500fa9e4066Sahrens 
1501fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1502fa9e4066Sahrens 
15034c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
15044c58d714Sdarrenm 		    &pool_state) == 0);
15054c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
15064c58d714Sdarrenm 			continue;
15074c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
15084c58d714Sdarrenm 			continue;
15094c58d714Sdarrenm 
1510fa9e4066Sahrens 		if (argc == 0) {
1511fa9e4066Sahrens 			if (first)
151299653d4eSeschrock 				first = B_FALSE;
15133bb79becSeschrock 			else if (!do_all)
1514fa9e4066Sahrens 				(void) printf("\n");
1515fa9e4066Sahrens 
1516fa9e4066Sahrens 			if (do_all)
1517fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1518ecd6cf80Smarks 				    altroot, do_force, props);
1519fa9e4066Sahrens 			else
1520fa9e4066Sahrens 				show_import(config);
1521fa9e4066Sahrens 		} else if (searchname != NULL) {
1522fa9e4066Sahrens 			char *name;
1523fa9e4066Sahrens 
1524fa9e4066Sahrens 			/*
1525fa9e4066Sahrens 			 * We are searching for a pool based on name.
1526fa9e4066Sahrens 			 */
1527fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1528fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1529fa9e4066Sahrens 
1530fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1531fa9e4066Sahrens 				if (found_config != NULL) {
1532fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1533fa9e4066Sahrens 					    "cannot import '%s': more than "
1534fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1535fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1536fa9e4066Sahrens 					    "import by numeric ID instead\n"));
153799653d4eSeschrock 					err = B_TRUE;
1538fa9e4066Sahrens 				}
1539fa9e4066Sahrens 				found_config = config;
1540fa9e4066Sahrens 			}
1541fa9e4066Sahrens 		} else {
1542fa9e4066Sahrens 			uint64_t guid;
1543fa9e4066Sahrens 
1544fa9e4066Sahrens 			/*
1545fa9e4066Sahrens 			 * Search for a pool by guid.
1546fa9e4066Sahrens 			 */
1547fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1548fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1549fa9e4066Sahrens 
1550fa9e4066Sahrens 			if (guid == searchguid)
1551fa9e4066Sahrens 				found_config = config;
1552fa9e4066Sahrens 		}
1553fa9e4066Sahrens 	}
1554fa9e4066Sahrens 
1555fa9e4066Sahrens 	/*
1556fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1557fa9e4066Sahrens 	 * pool, and then do the import.
1558fa9e4066Sahrens 	 */
1559fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1560fa9e4066Sahrens 		if (found_config == NULL) {
1561fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1562fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
156399653d4eSeschrock 			err = B_TRUE;
1564fa9e4066Sahrens 		} else {
1565fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1566ecd6cf80Smarks 			    argv[1], mntopts, altroot, do_force, props);
1567fa9e4066Sahrens 		}
1568fa9e4066Sahrens 	}
1569fa9e4066Sahrens 
1570fa9e4066Sahrens 	/*
1571fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1572fa9e4066Sahrens 	 * found.
1573fa9e4066Sahrens 	 */
1574fa9e4066Sahrens 	if (argc == 0 && first)
1575fa9e4066Sahrens 		(void) fprintf(stderr,
1576fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1577fa9e4066Sahrens 
1578ecd6cf80Smarks error:
1579ecd6cf80Smarks 	if (props)
1580ecd6cf80Smarks 		nvlist_free(props);
1581fa9e4066Sahrens 	nvlist_free(pools);
158299653d4eSeschrock 	free(searchdirs);
1583fa9e4066Sahrens 
1584fa9e4066Sahrens 	return (err ? 1 : 0);
1585fa9e4066Sahrens }
1586fa9e4066Sahrens 
1587fa9e4066Sahrens typedef struct iostat_cbdata {
1588fa9e4066Sahrens 	zpool_list_t *cb_list;
1589fa9e4066Sahrens 	int cb_verbose;
1590fa9e4066Sahrens 	int cb_iteration;
1591fa9e4066Sahrens 	int cb_namewidth;
1592fa9e4066Sahrens } iostat_cbdata_t;
1593fa9e4066Sahrens 
1594fa9e4066Sahrens static void
1595fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1596fa9e4066Sahrens {
1597fa9e4066Sahrens 	int i = 0;
1598fa9e4066Sahrens 
1599fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1600fa9e4066Sahrens 		(void) printf("-");
1601fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1602fa9e4066Sahrens }
1603fa9e4066Sahrens 
1604fa9e4066Sahrens static void
1605fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1606fa9e4066Sahrens {
1607fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1608fa9e4066Sahrens 	    cb->cb_namewidth, "");
1609fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1610fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1611fa9e4066Sahrens 	print_iostat_separator(cb);
1612fa9e4066Sahrens }
1613fa9e4066Sahrens 
1614fa9e4066Sahrens /*
1615fa9e4066Sahrens  * Display a single statistic.
1616fa9e4066Sahrens  */
1617fa9e4066Sahrens void
1618fa9e4066Sahrens print_one_stat(uint64_t value)
1619fa9e4066Sahrens {
1620fa9e4066Sahrens 	char buf[64];
1621fa9e4066Sahrens 
1622fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1623fa9e4066Sahrens 	(void) printf("  %5s", buf);
1624fa9e4066Sahrens }
1625fa9e4066Sahrens 
1626fa9e4066Sahrens /*
1627fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1628fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1629fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1630fa9e4066Sahrens  */
1631fa9e4066Sahrens void
1632c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1633c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1634fa9e4066Sahrens {
1635fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1636fa9e4066Sahrens 	uint_t c, children;
1637fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1638fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1639fa9e4066Sahrens 	uint64_t tdelta;
1640fa9e4066Sahrens 	double scale;
1641afefbcddSeschrock 	char *vname;
1642fa9e4066Sahrens 
1643fa9e4066Sahrens 	if (oldnv != NULL) {
1644fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1645fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1646fa9e4066Sahrens 	} else {
1647fa9e4066Sahrens 		oldvs = &zerovs;
1648fa9e4066Sahrens 	}
1649fa9e4066Sahrens 
1650fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1651fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1652fa9e4066Sahrens 
1653fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1654fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1655fa9e4066Sahrens 	else
1656fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1657fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1658fa9e4066Sahrens 
1659fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1660fa9e4066Sahrens 
1661fa9e4066Sahrens 	if (tdelta == 0)
1662fa9e4066Sahrens 		scale = 1.0;
1663fa9e4066Sahrens 	else
1664fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1665fa9e4066Sahrens 
1666fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1667fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1668fa9e4066Sahrens 		(void) printf("      -      -");
1669fa9e4066Sahrens 	} else {
1670fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1671fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1672fa9e4066Sahrens 	}
1673fa9e4066Sahrens 
1674fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1675fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1676fa9e4066Sahrens 
1677fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1678fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1679fa9e4066Sahrens 
1680fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1681fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1682fa9e4066Sahrens 
1683fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1684fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1685fa9e4066Sahrens 
1686fa9e4066Sahrens 	(void) printf("\n");
1687fa9e4066Sahrens 
1688fa9e4066Sahrens 	if (!cb->cb_verbose)
1689fa9e4066Sahrens 		return;
1690fa9e4066Sahrens 
1691fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1692fa9e4066Sahrens 	    &newchild, &children) != 0)
1693fa9e4066Sahrens 		return;
1694fa9e4066Sahrens 
1695fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1696fa9e4066Sahrens 	    &oldchild, &c) != 0)
1697fa9e4066Sahrens 		return;
1698fa9e4066Sahrens 
1699afefbcddSeschrock 	for (c = 0; c < children; c++) {
170099653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1701c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1702afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1703afefbcddSeschrock 		free(vname);
1704afefbcddSeschrock 	}
1705fa9e4066Sahrens }
1706fa9e4066Sahrens 
1707088e9d47Seschrock static int
1708088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
1709088e9d47Seschrock {
1710088e9d47Seschrock 	iostat_cbdata_t *cb = data;
171194de1d4cSeschrock 	boolean_t missing;
1712088e9d47Seschrock 
1713088e9d47Seschrock 	/*
1714088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
1715088e9d47Seschrock 	 */
171694de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
171794de1d4cSeschrock 		return (-1);
171894de1d4cSeschrock 
171994de1d4cSeschrock 	if (missing)
1720088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
1721088e9d47Seschrock 
1722088e9d47Seschrock 	return (0);
1723088e9d47Seschrock }
1724088e9d47Seschrock 
1725fa9e4066Sahrens /*
1726fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
1727fa9e4066Sahrens  */
1728fa9e4066Sahrens int
1729fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
1730fa9e4066Sahrens {
1731fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1732fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
1733fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
1734fa9e4066Sahrens 
1735088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
1736fa9e4066Sahrens 
1737088e9d47Seschrock 	if (cb->cb_iteration == 1)
1738fa9e4066Sahrens 		oldconfig = NULL;
1739fa9e4066Sahrens 
1740fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1741fa9e4066Sahrens 	    &newnvroot) == 0);
1742fa9e4066Sahrens 
1743088e9d47Seschrock 	if (oldconfig == NULL)
1744fa9e4066Sahrens 		oldnvroot = NULL;
1745088e9d47Seschrock 	else
1746088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
1747088e9d47Seschrock 		    &oldnvroot) == 0);
1748fa9e4066Sahrens 
1749fa9e4066Sahrens 	/*
1750fa9e4066Sahrens 	 * Print out the statistics for the pool.
1751fa9e4066Sahrens 	 */
1752c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1753fa9e4066Sahrens 
1754fa9e4066Sahrens 	if (cb->cb_verbose)
1755fa9e4066Sahrens 		print_iostat_separator(cb);
1756fa9e4066Sahrens 
1757fa9e4066Sahrens 	return (0);
1758fa9e4066Sahrens }
1759fa9e4066Sahrens 
1760fa9e4066Sahrens int
1761fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
1762fa9e4066Sahrens {
1763fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1764fa9e4066Sahrens 	nvlist_t *config, *nvroot;
1765fa9e4066Sahrens 
1766088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
1767fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1768fa9e4066Sahrens 		    &nvroot) == 0);
1769fa9e4066Sahrens 		if (!cb->cb_verbose)
1770fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1771fa9e4066Sahrens 		else
1772c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
1773fa9e4066Sahrens 	}
1774fa9e4066Sahrens 
1775fa9e4066Sahrens 	/*
1776fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
1777fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
1778fa9e4066Sahrens 	 */
1779fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
1780fa9e4066Sahrens 		cb->cb_namewidth = 10;
1781fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
1782fa9e4066Sahrens 		cb->cb_namewidth = 38;
1783fa9e4066Sahrens 
1784fa9e4066Sahrens 	return (0);
1785fa9e4066Sahrens }
1786fa9e4066Sahrens 
1787fa9e4066Sahrens /*
1788fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
1789fa9e4066Sahrens  *
1790fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
1791fa9e4066Sahrens  *
1792fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
1793fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
1794fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1795fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
1796fa9e4066Sahrens  * changes are all handled within libzfs.
1797fa9e4066Sahrens  */
1798fa9e4066Sahrens int
1799fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
1800fa9e4066Sahrens {
1801fa9e4066Sahrens 	int c;
1802fa9e4066Sahrens 	int ret;
1803fa9e4066Sahrens 	int npools;
1804fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
1805fa9e4066Sahrens 	zpool_list_t *list;
180699653d4eSeschrock 	boolean_t verbose = B_FALSE;
1807fa9e4066Sahrens 	iostat_cbdata_t cb;
1808fa9e4066Sahrens 
1809fa9e4066Sahrens 	/* check options */
1810fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
1811fa9e4066Sahrens 		switch (c) {
1812fa9e4066Sahrens 		case 'v':
181399653d4eSeschrock 			verbose = B_TRUE;
1814fa9e4066Sahrens 			break;
1815fa9e4066Sahrens 		case '?':
1816fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1817fa9e4066Sahrens 			    optopt);
181899653d4eSeschrock 			usage(B_FALSE);
1819fa9e4066Sahrens 		}
1820fa9e4066Sahrens 	}
1821fa9e4066Sahrens 
1822fa9e4066Sahrens 	argc -= optind;
1823fa9e4066Sahrens 	argv += optind;
1824fa9e4066Sahrens 
1825fa9e4066Sahrens 	/*
1826fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
1827fa9e4066Sahrens 	 */
1828fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1829fa9e4066Sahrens 		char *end;
1830fa9e4066Sahrens 
1831fa9e4066Sahrens 		errno = 0;
1832fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1833fa9e4066Sahrens 
1834fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1835fa9e4066Sahrens 			if (interval == 0) {
1836fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1837fa9e4066Sahrens 				    "cannot be zero\n"));
183899653d4eSeschrock 				usage(B_FALSE);
1839fa9e4066Sahrens 			}
1840fa9e4066Sahrens 
1841fa9e4066Sahrens 			/*
1842fa9e4066Sahrens 			 * Ignore the last parameter
1843fa9e4066Sahrens 			 */
1844fa9e4066Sahrens 			argc--;
1845fa9e4066Sahrens 		} else {
1846fa9e4066Sahrens 			/*
1847fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
1848fa9e4066Sahrens 			 * user will get a more informative error message later
1849fa9e4066Sahrens 			 * on.
1850fa9e4066Sahrens 			 */
1851fa9e4066Sahrens 			interval = 0;
1852fa9e4066Sahrens 		}
1853fa9e4066Sahrens 	}
1854fa9e4066Sahrens 
1855fa9e4066Sahrens 	/*
1856fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
1857fa9e4066Sahrens 	 * and an integer.
1858fa9e4066Sahrens 	 */
1859fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1860fa9e4066Sahrens 		char *end;
1861fa9e4066Sahrens 
1862fa9e4066Sahrens 		errno = 0;
1863fa9e4066Sahrens 		count = interval;
1864fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1865fa9e4066Sahrens 
1866fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1867fa9e4066Sahrens 			if (interval == 0) {
1868fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1869fa9e4066Sahrens 				    "cannot be zero\n"));
187099653d4eSeschrock 				usage(B_FALSE);
1871fa9e4066Sahrens 			}
1872fa9e4066Sahrens 
1873fa9e4066Sahrens 			/*
1874fa9e4066Sahrens 			 * Ignore the last parameter
1875fa9e4066Sahrens 			 */
1876fa9e4066Sahrens 			argc--;
1877fa9e4066Sahrens 		} else {
1878fa9e4066Sahrens 			interval = 0;
1879fa9e4066Sahrens 		}
1880fa9e4066Sahrens 	}
1881fa9e4066Sahrens 
1882fa9e4066Sahrens 	/*
1883fa9e4066Sahrens 	 * Construct the list of all interesting pools.
1884fa9e4066Sahrens 	 */
1885fa9e4066Sahrens 	ret = 0;
1886b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
1887fa9e4066Sahrens 		return (1);
1888fa9e4066Sahrens 
188999653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
189099653d4eSeschrock 		pool_list_free(list);
1891fa9e4066Sahrens 		return (1);
189299653d4eSeschrock 	}
1893fa9e4066Sahrens 
1894fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
189599653d4eSeschrock 		pool_list_free(list);
1896fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
1897fa9e4066Sahrens 		return (1);
1898fa9e4066Sahrens 	}
1899fa9e4066Sahrens 
1900fa9e4066Sahrens 	/*
1901fa9e4066Sahrens 	 * Enter the main iostat loop.
1902fa9e4066Sahrens 	 */
1903fa9e4066Sahrens 	cb.cb_list = list;
1904fa9e4066Sahrens 	cb.cb_verbose = verbose;
1905fa9e4066Sahrens 	cb.cb_iteration = 0;
1906fa9e4066Sahrens 	cb.cb_namewidth = 0;
1907fa9e4066Sahrens 
1908fa9e4066Sahrens 	for (;;) {
1909fa9e4066Sahrens 		pool_list_update(list);
1910fa9e4066Sahrens 
1911fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
1912fa9e4066Sahrens 			break;
1913fa9e4066Sahrens 
1914fa9e4066Sahrens 		/*
1915088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
1916088e9d47Seschrock 		 * before calculating the maximum name width, so that any
1917088e9d47Seschrock 		 * configuration changes are properly accounted for.
1918088e9d47Seschrock 		 */
191999653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
1920088e9d47Seschrock 
1921088e9d47Seschrock 		/*
1922fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
1923fa9e4066Sahrens 		 * for the pool / device name column across all pools.
1924fa9e4066Sahrens 		 */
1925fa9e4066Sahrens 		cb.cb_namewidth = 0;
192699653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
1927fa9e4066Sahrens 
1928fa9e4066Sahrens 		/*
1929fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
1930fa9e4066Sahrens 		 */
1931fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
1932fa9e4066Sahrens 			print_iostat_header(&cb);
1933fa9e4066Sahrens 
193499653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
1935fa9e4066Sahrens 
1936fa9e4066Sahrens 		/*
1937fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
1938fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
1939fa9e4066Sahrens 		 */
1940fa9e4066Sahrens 		if (npools > 1 && !verbose)
1941fa9e4066Sahrens 			print_iostat_separator(&cb);
1942fa9e4066Sahrens 
1943fa9e4066Sahrens 		if (verbose)
1944fa9e4066Sahrens 			(void) printf("\n");
1945fa9e4066Sahrens 
194639c23413Seschrock 		/*
194739c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
194839c23413Seschrock 		 * indefinitely.
194939c23413Seschrock 		 */
195039c23413Seschrock 		(void) fflush(stdout);
195139c23413Seschrock 
1952fa9e4066Sahrens 		if (interval == 0)
1953fa9e4066Sahrens 			break;
1954fa9e4066Sahrens 
1955fa9e4066Sahrens 		if (count != 0 && --count == 0)
1956fa9e4066Sahrens 			break;
1957fa9e4066Sahrens 
1958fa9e4066Sahrens 		(void) sleep(interval);
1959fa9e4066Sahrens 	}
1960fa9e4066Sahrens 
1961fa9e4066Sahrens 	pool_list_free(list);
1962fa9e4066Sahrens 
1963fa9e4066Sahrens 	return (ret);
1964fa9e4066Sahrens }
1965fa9e4066Sahrens 
1966fa9e4066Sahrens typedef struct list_cbdata {
196799653d4eSeschrock 	boolean_t	cb_scripted;
196899653d4eSeschrock 	boolean_t	cb_first;
1969fa9e4066Sahrens 	int		cb_fields[MAX_FIELDS];
1970fa9e4066Sahrens 	int		cb_fieldcount;
1971fa9e4066Sahrens } list_cbdata_t;
1972fa9e4066Sahrens 
1973fa9e4066Sahrens /*
1974fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
1975fa9e4066Sahrens  */
1976fa9e4066Sahrens void
1977fa9e4066Sahrens print_header(int *fields, size_t count)
1978fa9e4066Sahrens {
1979fa9e4066Sahrens 	int i;
1980fa9e4066Sahrens 	column_def_t *col;
1981fa9e4066Sahrens 	const char *fmt;
1982fa9e4066Sahrens 
1983fa9e4066Sahrens 	for (i = 0; i < count; i++) {
1984fa9e4066Sahrens 		col = &column_table[fields[i]];
1985fa9e4066Sahrens 		if (i != 0)
1986fa9e4066Sahrens 			(void) printf("  ");
1987fa9e4066Sahrens 		if (col->cd_justify == left_justify)
1988fa9e4066Sahrens 			fmt = "%-*s";
1989fa9e4066Sahrens 		else
1990fa9e4066Sahrens 			fmt = "%*s";
1991fa9e4066Sahrens 
1992fa9e4066Sahrens 		(void) printf(fmt, i == count - 1 ? strlen(col->cd_title) :
1993fa9e4066Sahrens 		    col->cd_width, col->cd_title);
1994fa9e4066Sahrens 	}
1995fa9e4066Sahrens 
1996fa9e4066Sahrens 	(void) printf("\n");
1997fa9e4066Sahrens }
1998fa9e4066Sahrens 
1999fa9e4066Sahrens int
2000fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2001fa9e4066Sahrens {
2002fa9e4066Sahrens 	list_cbdata_t *cbp = data;
2003fa9e4066Sahrens 	nvlist_t *config;
2004fa9e4066Sahrens 	int i;
2005fa9e4066Sahrens 	char buf[ZPOOL_MAXNAMELEN];
2006fa9e4066Sahrens 	uint64_t total;
2007fa9e4066Sahrens 	uint64_t used;
2008fa9e4066Sahrens 	const char *fmt;
2009fa9e4066Sahrens 	column_def_t *col;
2010fa9e4066Sahrens 
2011fa9e4066Sahrens 	if (cbp->cb_first) {
2012fa9e4066Sahrens 		if (!cbp->cb_scripted)
2013fa9e4066Sahrens 			print_header(cbp->cb_fields, cbp->cb_fieldcount);
201499653d4eSeschrock 		cbp->cb_first = B_FALSE;
2015fa9e4066Sahrens 	}
2016fa9e4066Sahrens 
2017fa9e4066Sahrens 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2018fa9e4066Sahrens 		config = NULL;
2019fa9e4066Sahrens 	} else {
2020088e9d47Seschrock 		config = zpool_get_config(zhp, NULL);
2021fa9e4066Sahrens 		total = zpool_get_space_total(zhp);
2022fa9e4066Sahrens 		used = zpool_get_space_used(zhp);
2023fa9e4066Sahrens 	}
2024fa9e4066Sahrens 
2025fa9e4066Sahrens 	for (i = 0; i < cbp->cb_fieldcount; i++) {
2026fa9e4066Sahrens 		if (i != 0) {
2027fa9e4066Sahrens 			if (cbp->cb_scripted)
2028fa9e4066Sahrens 				(void) printf("\t");
2029fa9e4066Sahrens 			else
2030fa9e4066Sahrens 				(void) printf("  ");
2031fa9e4066Sahrens 		}
2032fa9e4066Sahrens 
2033fa9e4066Sahrens 		col = &column_table[cbp->cb_fields[i]];
2034fa9e4066Sahrens 
2035fa9e4066Sahrens 		switch (cbp->cb_fields[i]) {
2036fa9e4066Sahrens 		case ZPOOL_FIELD_NAME:
2037fa9e4066Sahrens 			(void) strlcpy(buf, zpool_get_name(zhp), sizeof (buf));
2038fa9e4066Sahrens 			break;
2039fa9e4066Sahrens 
2040fa9e4066Sahrens 		case ZPOOL_FIELD_SIZE:
2041fa9e4066Sahrens 			if (config == NULL)
2042fa9e4066Sahrens 				(void) strlcpy(buf, "-", sizeof (buf));
2043fa9e4066Sahrens 			else
2044fa9e4066Sahrens 				zfs_nicenum(total, buf, sizeof (buf));
2045fa9e4066Sahrens 			break;
2046fa9e4066Sahrens 
2047fa9e4066Sahrens 		case ZPOOL_FIELD_USED:
2048fa9e4066Sahrens 			if (config == NULL)
2049fa9e4066Sahrens 				(void) strlcpy(buf, "-", sizeof (buf));
2050fa9e4066Sahrens 			else
2051fa9e4066Sahrens 				zfs_nicenum(used, buf, sizeof (buf));
2052fa9e4066Sahrens 			break;
2053fa9e4066Sahrens 
2054fa9e4066Sahrens 		case ZPOOL_FIELD_AVAILABLE:
2055fa9e4066Sahrens 			if (config == NULL)
2056fa9e4066Sahrens 				(void) strlcpy(buf, "-", sizeof (buf));
2057fa9e4066Sahrens 			else
2058fa9e4066Sahrens 				zfs_nicenum(total - used, buf, sizeof (buf));
2059fa9e4066Sahrens 			break;
2060fa9e4066Sahrens 
2061fa9e4066Sahrens 		case ZPOOL_FIELD_CAPACITY:
2062fa9e4066Sahrens 			if (config == NULL) {
2063fa9e4066Sahrens 				(void) strlcpy(buf, "-", sizeof (buf));
2064fa9e4066Sahrens 			} else {
2065fa9e4066Sahrens 				uint64_t capacity = (total == 0 ? 0 :
2066fa9e4066Sahrens 				    (used * 100 / total));
2067fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%llu%%",
20685ad82045Snd150628 				    (u_longlong_t)capacity);
2069fa9e4066Sahrens 			}
2070fa9e4066Sahrens 			break;
2071fa9e4066Sahrens 
2072fa9e4066Sahrens 		case ZPOOL_FIELD_HEALTH:
2073fa9e4066Sahrens 			if (config == NULL) {
2074fa9e4066Sahrens 				(void) strlcpy(buf, "FAULTED", sizeof (buf));
2075fa9e4066Sahrens 			} else {
2076fa9e4066Sahrens 				nvlist_t *nvroot;
2077fa9e4066Sahrens 				vdev_stat_t *vs;
2078fa9e4066Sahrens 				uint_t vsc;
2079fa9e4066Sahrens 
2080fa9e4066Sahrens 				verify(nvlist_lookup_nvlist(config,
2081fa9e4066Sahrens 				    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
2082fa9e4066Sahrens 				verify(nvlist_lookup_uint64_array(nvroot,
2083fa9e4066Sahrens 				    ZPOOL_CONFIG_STATS, (uint64_t **)&vs,
2084fa9e4066Sahrens 				    &vsc) == 0);
2085ea8dc4b6Seschrock 				(void) strlcpy(buf, state_to_name(vs),
2086fa9e4066Sahrens 				    sizeof (buf));
2087fa9e4066Sahrens 			}
2088fa9e4066Sahrens 			break;
2089fa9e4066Sahrens 
2090fa9e4066Sahrens 		case ZPOOL_FIELD_ROOT:
2091fa9e4066Sahrens 			if (config == NULL)
2092fa9e4066Sahrens 				(void) strlcpy(buf, "-", sizeof (buf));
2093fa9e4066Sahrens 			else if (zpool_get_root(zhp, buf, sizeof (buf)) != 0)
2094fa9e4066Sahrens 				(void) strlcpy(buf, "-", sizeof (buf));
2095fa9e4066Sahrens 			break;
2096fa9e4066Sahrens 		}
2097fa9e4066Sahrens 
2098fa9e4066Sahrens 		if (cbp->cb_scripted)
2099fa9e4066Sahrens 			(void) printf("%s", buf);
2100fa9e4066Sahrens 		else {
2101fa9e4066Sahrens 			if (col->cd_justify == left_justify)
2102fa9e4066Sahrens 				fmt = "%-*s";
2103fa9e4066Sahrens 			else
2104fa9e4066Sahrens 				fmt = "%*s";
2105fa9e4066Sahrens 
2106fa9e4066Sahrens 			(void) printf(fmt, i == cbp->cb_fieldcount - 1 ?
2107fa9e4066Sahrens 			    strlen(buf) : col->cd_width, buf);
2108fa9e4066Sahrens 		}
2109fa9e4066Sahrens 	}
2110fa9e4066Sahrens 
2111fa9e4066Sahrens 	(void) printf("\n");
2112fa9e4066Sahrens 
2113fa9e4066Sahrens 	return (0);
2114fa9e4066Sahrens }
2115fa9e4066Sahrens 
2116fa9e4066Sahrens /*
2117fa9e4066Sahrens  * zpool list [-H] [-o field[,field]*] [pool] ...
2118fa9e4066Sahrens  *
2119fa9e4066Sahrens  *	-H	Scripted mode.  Don't display headers, and separate fields by
2120fa9e4066Sahrens  *		a single tab.
2121fa9e4066Sahrens  *	-o	List of fields to display.  Defaults to all fields, or
2122fa9e4066Sahrens  *		"name,size,used,available,capacity,health,root"
2123fa9e4066Sahrens  *
2124fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2125fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2126fa9e4066Sahrens  */
2127fa9e4066Sahrens int
2128fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2129fa9e4066Sahrens {
2130fa9e4066Sahrens 	int c;
2131fa9e4066Sahrens 	int ret;
2132fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2133fa9e4066Sahrens 	static char default_fields[] =
2134fa9e4066Sahrens 	    "name,size,used,available,capacity,health,root";
2135fa9e4066Sahrens 	char *fields = default_fields;
2136fa9e4066Sahrens 	char *value;
2137fa9e4066Sahrens 
2138fa9e4066Sahrens 	/* check options */
2139fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2140fa9e4066Sahrens 		switch (c) {
2141fa9e4066Sahrens 		case 'H':
214299653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2143fa9e4066Sahrens 			break;
2144fa9e4066Sahrens 		case 'o':
2145fa9e4066Sahrens 			fields = optarg;
2146fa9e4066Sahrens 			break;
2147fa9e4066Sahrens 		case ':':
2148fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2149fa9e4066Sahrens 			    "'%c' option\n"), optopt);
215099653d4eSeschrock 			usage(B_FALSE);
2151fa9e4066Sahrens 			break;
2152fa9e4066Sahrens 		case '?':
2153fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2154fa9e4066Sahrens 			    optopt);
215599653d4eSeschrock 			usage(B_FALSE);
2156fa9e4066Sahrens 		}
2157fa9e4066Sahrens 	}
2158fa9e4066Sahrens 
2159fa9e4066Sahrens 	argc -= optind;
2160fa9e4066Sahrens 	argv += optind;
2161fa9e4066Sahrens 
2162fa9e4066Sahrens 	while (*fields != '\0') {
2163fa9e4066Sahrens 		if (cb.cb_fieldcount == MAX_FIELDS) {
2164fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many "
2165fa9e4066Sahrens 			    "properties given to -o option\n"));
216699653d4eSeschrock 			usage(B_FALSE);
2167fa9e4066Sahrens 		}
2168fa9e4066Sahrens 
2169fa9e4066Sahrens 		if ((cb.cb_fields[cb.cb_fieldcount] = getsubopt(&fields,
2170fa9e4066Sahrens 		    column_subopts, &value)) == -1) {
2171fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid property "
2172fa9e4066Sahrens 			    "'%s'\n"), value);
217399653d4eSeschrock 			usage(B_FALSE);
2174fa9e4066Sahrens 		}
2175fa9e4066Sahrens 
2176fa9e4066Sahrens 		cb.cb_fieldcount++;
2177fa9e4066Sahrens 	}
2178fa9e4066Sahrens 
2179fa9e4066Sahrens 
218099653d4eSeschrock 	cb.cb_first = B_TRUE;
2181fa9e4066Sahrens 
2182b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, list_callback, &cb);
2183fa9e4066Sahrens 
2184fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2185fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2186fa9e4066Sahrens 		return (0);
2187fa9e4066Sahrens 	}
2188fa9e4066Sahrens 
2189fa9e4066Sahrens 	return (ret);
2190fa9e4066Sahrens }
2191fa9e4066Sahrens 
2192fa9e4066Sahrens static nvlist_t *
2193fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2194fa9e4066Sahrens {
2195fa9e4066Sahrens 	nvlist_t **child;
2196fa9e4066Sahrens 	uint_t c, children;
2197fa9e4066Sahrens 	nvlist_t *match;
2198fa9e4066Sahrens 	char *path;
2199fa9e4066Sahrens 
2200fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2201fa9e4066Sahrens 	    &child, &children) != 0) {
2202fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2203fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2204fa9e4066Sahrens 			name += 9;
2205fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2206fa9e4066Sahrens 			path += 9;
2207fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2208fa9e4066Sahrens 			return (nv);
2209fa9e4066Sahrens 		return (NULL);
2210fa9e4066Sahrens 	}
2211fa9e4066Sahrens 
2212fa9e4066Sahrens 	for (c = 0; c < children; c++)
2213fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2214fa9e4066Sahrens 			return (match);
2215fa9e4066Sahrens 
2216fa9e4066Sahrens 	return (NULL);
2217fa9e4066Sahrens }
2218fa9e4066Sahrens 
2219fa9e4066Sahrens static int
2220fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2221fa9e4066Sahrens {
222299653d4eSeschrock 	boolean_t force = B_FALSE;
2223fa9e4066Sahrens 	int c;
2224fa9e4066Sahrens 	nvlist_t *nvroot;
2225fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2226fa9e4066Sahrens 	zpool_handle_t *zhp;
222799653d4eSeschrock 	int ret;
2228fa9e4066Sahrens 
2229fa9e4066Sahrens 	/* check options */
2230fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2231fa9e4066Sahrens 		switch (c) {
2232fa9e4066Sahrens 		case 'f':
223399653d4eSeschrock 			force = B_TRUE;
2234fa9e4066Sahrens 			break;
2235fa9e4066Sahrens 		case '?':
2236fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2237fa9e4066Sahrens 			    optopt);
223899653d4eSeschrock 			usage(B_FALSE);
2239fa9e4066Sahrens 		}
2240fa9e4066Sahrens 	}
2241fa9e4066Sahrens 
2242fa9e4066Sahrens 	argc -= optind;
2243fa9e4066Sahrens 	argv += optind;
2244fa9e4066Sahrens 
2245fa9e4066Sahrens 	/* get pool name and check number of arguments */
2246fa9e4066Sahrens 	if (argc < 1) {
2247fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
224899653d4eSeschrock 		usage(B_FALSE);
2249fa9e4066Sahrens 	}
2250fa9e4066Sahrens 
2251fa9e4066Sahrens 	poolname = argv[0];
2252fa9e4066Sahrens 
2253fa9e4066Sahrens 	if (argc < 2) {
2254fa9e4066Sahrens 		(void) fprintf(stderr,
2255fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
225699653d4eSeschrock 		usage(B_FALSE);
2257fa9e4066Sahrens 	}
2258fa9e4066Sahrens 
2259fa9e4066Sahrens 	old_disk = argv[1];
2260fa9e4066Sahrens 
2261fa9e4066Sahrens 	if (argc < 3) {
2262fa9e4066Sahrens 		if (!replacing) {
2263fa9e4066Sahrens 			(void) fprintf(stderr,
2264fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
226599653d4eSeschrock 			usage(B_FALSE);
2266fa9e4066Sahrens 		}
2267fa9e4066Sahrens 		new_disk = old_disk;
2268fa9e4066Sahrens 		argc -= 1;
2269fa9e4066Sahrens 		argv += 1;
2270fa9e4066Sahrens 	} else {
2271fa9e4066Sahrens 		new_disk = argv[2];
2272fa9e4066Sahrens 		argc -= 2;
2273fa9e4066Sahrens 		argv += 2;
2274fa9e4066Sahrens 	}
2275fa9e4066Sahrens 
2276fa9e4066Sahrens 	if (argc > 1) {
2277fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
227899653d4eSeschrock 		usage(B_FALSE);
2279fa9e4066Sahrens 	}
2280fa9e4066Sahrens 
228199653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2282fa9e4066Sahrens 		return (1);
2283fa9e4066Sahrens 
22848488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2285fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2286fa9e4066Sahrens 		    poolname);
2287fa9e4066Sahrens 		zpool_close(zhp);
2288fa9e4066Sahrens 		return (1);
2289fa9e4066Sahrens 	}
2290fa9e4066Sahrens 
22918488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv);
2292fa9e4066Sahrens 	if (nvroot == NULL) {
2293fa9e4066Sahrens 		zpool_close(zhp);
2294fa9e4066Sahrens 		return (1);
2295fa9e4066Sahrens 	}
2296fa9e4066Sahrens 
229799653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
229899653d4eSeschrock 
229999653d4eSeschrock 	nvlist_free(nvroot);
230099653d4eSeschrock 	zpool_close(zhp);
230199653d4eSeschrock 
230299653d4eSeschrock 	return (ret);
2303fa9e4066Sahrens }
2304fa9e4066Sahrens 
2305fa9e4066Sahrens /*
2306fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2307fa9e4066Sahrens  *
2308fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2309fa9e4066Sahrens  *
2310fa9e4066Sahrens  * Replace <device> with <new_device>.
2311fa9e4066Sahrens  */
2312fa9e4066Sahrens /* ARGSUSED */
2313fa9e4066Sahrens int
2314fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2315fa9e4066Sahrens {
2316fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2317fa9e4066Sahrens }
2318fa9e4066Sahrens 
2319fa9e4066Sahrens /*
2320fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2321fa9e4066Sahrens  *
2322fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2323fa9e4066Sahrens  *
2324fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2325fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2326fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2327fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2328fa9e4066Sahrens  */
2329fa9e4066Sahrens int
2330fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2331fa9e4066Sahrens {
2332fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2333fa9e4066Sahrens }
2334fa9e4066Sahrens 
2335fa9e4066Sahrens /*
2336fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2337fa9e4066Sahrens  *
2338fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2339fa9e4066Sahrens  *		(not supported yet)
2340fa9e4066Sahrens  *
2341fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2342fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2343fa9e4066Sahrens  * has the only valid copy of some data.
2344fa9e4066Sahrens  */
2345fa9e4066Sahrens /* ARGSUSED */
2346fa9e4066Sahrens int
2347fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2348fa9e4066Sahrens {
2349fa9e4066Sahrens 	int c;
2350fa9e4066Sahrens 	char *poolname, *path;
2351fa9e4066Sahrens 	zpool_handle_t *zhp;
235299653d4eSeschrock 	int ret;
2353fa9e4066Sahrens 
2354fa9e4066Sahrens 	/* check options */
2355fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2356fa9e4066Sahrens 		switch (c) {
2357fa9e4066Sahrens 		case 'f':
2358fa9e4066Sahrens 		case '?':
2359fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2360fa9e4066Sahrens 			    optopt);
236199653d4eSeschrock 			usage(B_FALSE);
2362fa9e4066Sahrens 		}
2363fa9e4066Sahrens 	}
2364fa9e4066Sahrens 
2365fa9e4066Sahrens 	argc -= optind;
2366fa9e4066Sahrens 	argv += optind;
2367fa9e4066Sahrens 
2368fa9e4066Sahrens 	/* get pool name and check number of arguments */
2369fa9e4066Sahrens 	if (argc < 1) {
2370fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
237199653d4eSeschrock 		usage(B_FALSE);
2372fa9e4066Sahrens 	}
2373fa9e4066Sahrens 
2374fa9e4066Sahrens 	if (argc < 2) {
2375fa9e4066Sahrens 		(void) fprintf(stderr,
2376fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
237799653d4eSeschrock 		usage(B_FALSE);
2378fa9e4066Sahrens 	}
2379fa9e4066Sahrens 
2380fa9e4066Sahrens 	poolname = argv[0];
2381fa9e4066Sahrens 	path = argv[1];
2382fa9e4066Sahrens 
238399653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2384fa9e4066Sahrens 		return (1);
2385fa9e4066Sahrens 
238699653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
238799653d4eSeschrock 
238899653d4eSeschrock 	zpool_close(zhp);
238999653d4eSeschrock 
239099653d4eSeschrock 	return (ret);
2391fa9e4066Sahrens }
2392fa9e4066Sahrens 
2393fa9e4066Sahrens /*
2394441d80aaSlling  * zpool online <pool> <device> ...
2395fa9e4066Sahrens  */
2396fa9e4066Sahrens int
2397fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2398fa9e4066Sahrens {
2399fa9e4066Sahrens 	int c, i;
2400fa9e4066Sahrens 	char *poolname;
2401fa9e4066Sahrens 	zpool_handle_t *zhp;
2402fa9e4066Sahrens 	int ret = 0;
24033d7072f8Seschrock 	vdev_state_t newstate;
2404fa9e4066Sahrens 
2405fa9e4066Sahrens 	/* check options */
2406fa9e4066Sahrens 	while ((c = getopt(argc, argv, "t")) != -1) {
2407fa9e4066Sahrens 		switch (c) {
2408fa9e4066Sahrens 		case 't':
2409fa9e4066Sahrens 		case '?':
2410fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2411fa9e4066Sahrens 			    optopt);
241299653d4eSeschrock 			usage(B_FALSE);
2413fa9e4066Sahrens 		}
2414fa9e4066Sahrens 	}
2415fa9e4066Sahrens 
2416fa9e4066Sahrens 	argc -= optind;
2417fa9e4066Sahrens 	argv += optind;
2418fa9e4066Sahrens 
2419fa9e4066Sahrens 	/* get pool name and check number of arguments */
2420fa9e4066Sahrens 	if (argc < 1) {
2421fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
242299653d4eSeschrock 		usage(B_FALSE);
2423fa9e4066Sahrens 	}
2424fa9e4066Sahrens 	if (argc < 2) {
2425fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
242699653d4eSeschrock 		usage(B_FALSE);
2427fa9e4066Sahrens 	}
2428fa9e4066Sahrens 
2429fa9e4066Sahrens 	poolname = argv[0];
2430fa9e4066Sahrens 
243199653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2432fa9e4066Sahrens 		return (1);
2433fa9e4066Sahrens 
24343d7072f8Seschrock 	for (i = 1; i < argc; i++) {
24353d7072f8Seschrock 		if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
24363d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
24373d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
24383d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
2439fa9e4066Sahrens 				    argv[i]);
24403d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
24413d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24423d7072f8Seschrock 					    "clear' to restore a faulted "
24433d7072f8Seschrock 					    "device\n"));
2444fa9e4066Sahrens 				else
24453d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24463d7072f8Seschrock 					    "replace' to replace devices "
24473d7072f8Seschrock 					    "that are no longer present\n"));
24483d7072f8Seschrock 			}
24493d7072f8Seschrock 		} else {
2450fa9e4066Sahrens 			ret = 1;
24513d7072f8Seschrock 		}
24523d7072f8Seschrock 	}
2453fa9e4066Sahrens 
245499653d4eSeschrock 	zpool_close(zhp);
245599653d4eSeschrock 
2456fa9e4066Sahrens 	return (ret);
2457fa9e4066Sahrens }
2458fa9e4066Sahrens 
2459fa9e4066Sahrens /*
2460441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2461fa9e4066Sahrens  *
2462fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2463fa9e4066Sahrens  *		so would appear to compromise pool availability.
2464fa9e4066Sahrens  *		(not supported yet)
2465fa9e4066Sahrens  *
2466fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2467fa9e4066Sahrens  *		state will not be persistent across reboots.
2468fa9e4066Sahrens  */
2469fa9e4066Sahrens /* ARGSUSED */
2470fa9e4066Sahrens int
2471fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2472fa9e4066Sahrens {
2473fa9e4066Sahrens 	int c, i;
2474fa9e4066Sahrens 	char *poolname;
2475fa9e4066Sahrens 	zpool_handle_t *zhp;
247699653d4eSeschrock 	int ret = 0;
247799653d4eSeschrock 	boolean_t istmp = B_FALSE;
2478fa9e4066Sahrens 
2479fa9e4066Sahrens 	/* check options */
2480fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2481fa9e4066Sahrens 		switch (c) {
2482fa9e4066Sahrens 		case 't':
248399653d4eSeschrock 			istmp = B_TRUE;
2484441d80aaSlling 			break;
2485441d80aaSlling 		case 'f':
2486fa9e4066Sahrens 		case '?':
2487fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2488fa9e4066Sahrens 			    optopt);
248999653d4eSeschrock 			usage(B_FALSE);
2490fa9e4066Sahrens 		}
2491fa9e4066Sahrens 	}
2492fa9e4066Sahrens 
2493fa9e4066Sahrens 	argc -= optind;
2494fa9e4066Sahrens 	argv += optind;
2495fa9e4066Sahrens 
2496fa9e4066Sahrens 	/* get pool name and check number of arguments */
2497fa9e4066Sahrens 	if (argc < 1) {
2498fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
249999653d4eSeschrock 		usage(B_FALSE);
2500fa9e4066Sahrens 	}
2501fa9e4066Sahrens 	if (argc < 2) {
2502fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
250399653d4eSeschrock 		usage(B_FALSE);
2504fa9e4066Sahrens 	}
2505fa9e4066Sahrens 
2506fa9e4066Sahrens 	poolname = argv[0];
2507fa9e4066Sahrens 
250899653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2509fa9e4066Sahrens 		return (1);
2510fa9e4066Sahrens 
25113d7072f8Seschrock 	for (i = 1; i < argc; i++) {
25123d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2513fa9e4066Sahrens 			ret = 1;
25143d7072f8Seschrock 	}
2515fa9e4066Sahrens 
251699653d4eSeschrock 	zpool_close(zhp);
251799653d4eSeschrock 
2518fa9e4066Sahrens 	return (ret);
2519fa9e4066Sahrens }
2520fa9e4066Sahrens 
2521ea8dc4b6Seschrock /*
2522ea8dc4b6Seschrock  * zpool clear <pool> [device]
2523ea8dc4b6Seschrock  *
2524ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2525ea8dc4b6Seschrock  */
2526ea8dc4b6Seschrock int
2527ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2528ea8dc4b6Seschrock {
2529ea8dc4b6Seschrock 	int ret = 0;
2530ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2531ea8dc4b6Seschrock 	char *pool, *device;
2532ea8dc4b6Seschrock 
2533ea8dc4b6Seschrock 	if (argc < 2) {
2534ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
253599653d4eSeschrock 		usage(B_FALSE);
2536ea8dc4b6Seschrock 	}
2537ea8dc4b6Seschrock 
2538ea8dc4b6Seschrock 	if (argc > 3) {
2539ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
254099653d4eSeschrock 		usage(B_FALSE);
2541ea8dc4b6Seschrock 	}
2542ea8dc4b6Seschrock 
2543ea8dc4b6Seschrock 	pool = argv[1];
2544ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2545ea8dc4b6Seschrock 
254699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, pool)) == NULL)
2547ea8dc4b6Seschrock 		return (1);
2548ea8dc4b6Seschrock 
2549ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2550ea8dc4b6Seschrock 		ret = 1;
2551ea8dc4b6Seschrock 
2552ea8dc4b6Seschrock 	zpool_close(zhp);
2553ea8dc4b6Seschrock 
2554ea8dc4b6Seschrock 	return (ret);
2555ea8dc4b6Seschrock }
2556ea8dc4b6Seschrock 
2557fa9e4066Sahrens typedef struct scrub_cbdata {
2558fa9e4066Sahrens 	int	cb_type;
255906eeb2adSek110237 	int	cb_argc;
256006eeb2adSek110237 	char	**cb_argv;
2561fa9e4066Sahrens } scrub_cbdata_t;
2562fa9e4066Sahrens 
2563fa9e4066Sahrens int
2564fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2565fa9e4066Sahrens {
2566fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
256706eeb2adSek110237 	int err;
2568fa9e4066Sahrens 
2569ea8dc4b6Seschrock 	/*
2570ea8dc4b6Seschrock 	 * Ignore faulted pools.
2571ea8dc4b6Seschrock 	 */
2572ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2573ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2574ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2575ea8dc4b6Seschrock 		return (1);
2576ea8dc4b6Seschrock 	}
2577ea8dc4b6Seschrock 
257806eeb2adSek110237 	err = zpool_scrub(zhp, cb->cb_type);
257906eeb2adSek110237 
258006eeb2adSek110237 	return (err != 0);
2581fa9e4066Sahrens }
2582fa9e4066Sahrens 
2583fa9e4066Sahrens /*
2584fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2585fa9e4066Sahrens  *
2586fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2587fa9e4066Sahrens  */
2588fa9e4066Sahrens int
2589fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2590fa9e4066Sahrens {
2591fa9e4066Sahrens 	int c;
2592fa9e4066Sahrens 	scrub_cbdata_t cb;
2593fa9e4066Sahrens 
2594fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2595fa9e4066Sahrens 
2596fa9e4066Sahrens 	/* check options */
2597fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2598fa9e4066Sahrens 		switch (c) {
2599fa9e4066Sahrens 		case 's':
2600fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2601fa9e4066Sahrens 			break;
2602fa9e4066Sahrens 		case '?':
2603fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2604fa9e4066Sahrens 			    optopt);
260599653d4eSeschrock 			usage(B_FALSE);
2606fa9e4066Sahrens 		}
2607fa9e4066Sahrens 	}
2608fa9e4066Sahrens 
260906eeb2adSek110237 	cb.cb_argc = argc;
261006eeb2adSek110237 	cb.cb_argv = argv;
2611fa9e4066Sahrens 	argc -= optind;
2612fa9e4066Sahrens 	argv += optind;
2613fa9e4066Sahrens 
2614fa9e4066Sahrens 	if (argc < 1) {
2615fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
261699653d4eSeschrock 		usage(B_FALSE);
2617fa9e4066Sahrens 	}
2618fa9e4066Sahrens 
2619b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2620fa9e4066Sahrens }
2621fa9e4066Sahrens 
2622fa9e4066Sahrens typedef struct status_cbdata {
2623fa9e4066Sahrens 	int		cb_count;
2624e9dbad6fSeschrock 	boolean_t	cb_allpools;
262599653d4eSeschrock 	boolean_t	cb_verbose;
262699653d4eSeschrock 	boolean_t	cb_explain;
262799653d4eSeschrock 	boolean_t	cb_first;
2628fa9e4066Sahrens } status_cbdata_t;
2629fa9e4066Sahrens 
2630fa9e4066Sahrens /*
2631fa9e4066Sahrens  * Print out detailed scrub status.
2632fa9e4066Sahrens  */
2633fa9e4066Sahrens void
2634fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2635fa9e4066Sahrens {
2636fa9e4066Sahrens 	vdev_stat_t *vs;
2637fa9e4066Sahrens 	uint_t vsc;
2638fa9e4066Sahrens 	time_t start, end, now;
2639fa9e4066Sahrens 	double fraction_done;
2640fa9e4066Sahrens 	uint64_t examined, total, minutes_left;
2641fa9e4066Sahrens 	char *scrub_type;
2642fa9e4066Sahrens 
2643fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2644fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2645fa9e4066Sahrens 
2646fa9e4066Sahrens 	/*
2647fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2648fa9e4066Sahrens 	 */
2649fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2650fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2651fa9e4066Sahrens 		return;
2652fa9e4066Sahrens 	}
2653fa9e4066Sahrens 
2654fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2655fa9e4066Sahrens 	    "resilver" : "scrub";
2656fa9e4066Sahrens 
2657fa9e4066Sahrens 	start = vs->vs_scrub_start;
2658fa9e4066Sahrens 	end = vs->vs_scrub_end;
2659fa9e4066Sahrens 	now = time(NULL);
2660fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2661fa9e4066Sahrens 	total = vs->vs_alloc;
2662fa9e4066Sahrens 
2663fa9e4066Sahrens 	if (end != 0) {
2664fa9e4066Sahrens 		(void) printf(gettext("%s %s with %llu errors on %s"),
2665fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
2666fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2667fa9e4066Sahrens 		return;
2668fa9e4066Sahrens 	}
2669fa9e4066Sahrens 
2670fa9e4066Sahrens 	if (examined == 0)
2671fa9e4066Sahrens 		examined = 1;
2672fa9e4066Sahrens 	if (examined > total)
2673fa9e4066Sahrens 		total = examined;
2674fa9e4066Sahrens 
2675fa9e4066Sahrens 	fraction_done = (double)examined / total;
2676fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2677fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
2678fa9e4066Sahrens 
2679fa9e4066Sahrens 	(void) printf(gettext("%s in progress, %.2f%% done, %lluh%um to go\n"),
2680fa9e4066Sahrens 	    scrub_type, 100 * fraction_done,
2681fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2682fa9e4066Sahrens }
2683fa9e4066Sahrens 
268499653d4eSeschrock typedef struct spare_cbdata {
268599653d4eSeschrock 	uint64_t	cb_guid;
268699653d4eSeschrock 	zpool_handle_t	*cb_zhp;
268799653d4eSeschrock } spare_cbdata_t;
268899653d4eSeschrock 
268999653d4eSeschrock static boolean_t
269099653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search)
269199653d4eSeschrock {
269299653d4eSeschrock 	uint64_t guid;
269399653d4eSeschrock 	nvlist_t **child;
269499653d4eSeschrock 	uint_t c, children;
269599653d4eSeschrock 
269699653d4eSeschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
269799653d4eSeschrock 	    search == guid)
269899653d4eSeschrock 		return (B_TRUE);
269999653d4eSeschrock 
270099653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
270199653d4eSeschrock 	    &child, &children) == 0) {
270299653d4eSeschrock 		for (c = 0; c < children; c++)
270399653d4eSeschrock 			if (find_vdev(child[c], search))
270499653d4eSeschrock 				return (B_TRUE);
270599653d4eSeschrock 	}
270699653d4eSeschrock 
270799653d4eSeschrock 	return (B_FALSE);
270899653d4eSeschrock }
270999653d4eSeschrock 
271099653d4eSeschrock static int
271199653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data)
271299653d4eSeschrock {
271399653d4eSeschrock 	spare_cbdata_t *cbp = data;
271499653d4eSeschrock 	nvlist_t *config, *nvroot;
271599653d4eSeschrock 
271699653d4eSeschrock 	config = zpool_get_config(zhp, NULL);
271799653d4eSeschrock 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
271899653d4eSeschrock 	    &nvroot) == 0);
271999653d4eSeschrock 
272099653d4eSeschrock 	if (find_vdev(nvroot, cbp->cb_guid)) {
272199653d4eSeschrock 		cbp->cb_zhp = zhp;
272299653d4eSeschrock 		return (1);
272399653d4eSeschrock 	}
272499653d4eSeschrock 
272599653d4eSeschrock 	zpool_close(zhp);
272699653d4eSeschrock 	return (0);
272799653d4eSeschrock }
272899653d4eSeschrock 
2729fa9e4066Sahrens /*
2730fa9e4066Sahrens  * Print out configuration state as requested by status_callback.
2731fa9e4066Sahrens  */
2732fa9e4066Sahrens void
2733c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
27348654d025Sperrin     int namewidth, int depth, boolean_t isspare, boolean_t print_logs)
2735fa9e4066Sahrens {
2736fa9e4066Sahrens 	nvlist_t **child;
2737fa9e4066Sahrens 	uint_t c, children;
2738fa9e4066Sahrens 	vdev_stat_t *vs;
2739ea8dc4b6Seschrock 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
2740afefbcddSeschrock 	char *vname;
2741ea8dc4b6Seschrock 	uint64_t notpresent;
274299653d4eSeschrock 	spare_cbdata_t cb;
274399653d4eSeschrock 	const char *state;
2744fa9e4066Sahrens 
2745fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2746fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2747fa9e4066Sahrens 
2748fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2749fa9e4066Sahrens 	    &child, &children) != 0)
2750fa9e4066Sahrens 		children = 0;
2751fa9e4066Sahrens 
275299653d4eSeschrock 	state = state_to_name(vs);
275399653d4eSeschrock 	if (isspare) {
275499653d4eSeschrock 		/*
275599653d4eSeschrock 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
275699653d4eSeschrock 		 * online drives.
275799653d4eSeschrock 		 */
275899653d4eSeschrock 		if (vs->vs_aux == VDEV_AUX_SPARED)
275999653d4eSeschrock 			state = "INUSE";
276099653d4eSeschrock 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
276199653d4eSeschrock 			state = "AVAIL";
276299653d4eSeschrock 	}
2763fa9e4066Sahrens 
276499653d4eSeschrock 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
276599653d4eSeschrock 	    name, state);
276699653d4eSeschrock 
276799653d4eSeschrock 	if (!isspare) {
2768fa9e4066Sahrens 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
2769fa9e4066Sahrens 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
2770fa9e4066Sahrens 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
2771fa9e4066Sahrens 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
277299653d4eSeschrock 	}
2773fa9e4066Sahrens 
2774ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2775ea8dc4b6Seschrock 	    &notpresent) == 0) {
2776ea8dc4b6Seschrock 		char *path;
2777ea8dc4b6Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
27780917b783Seschrock 		(void) printf("  was %s", path);
2779ea8dc4b6Seschrock 	} else if (vs->vs_aux != 0) {
2780fa9e4066Sahrens 		(void) printf("  ");
2781fa9e4066Sahrens 
2782fa9e4066Sahrens 		switch (vs->vs_aux) {
2783fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2784fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2785fa9e4066Sahrens 			break;
2786fa9e4066Sahrens 
2787fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2788fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2789fa9e4066Sahrens 			break;
2790fa9e4066Sahrens 
2791fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2792fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2793fa9e4066Sahrens 			break;
2794fa9e4066Sahrens 
2795eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
2796eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
2797eaca9bbdSeschrock 			break;
2798eaca9bbdSeschrock 
279999653d4eSeschrock 		case VDEV_AUX_SPARED:
280099653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
280199653d4eSeschrock 			    &cb.cb_guid) == 0);
280299653d4eSeschrock 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
280399653d4eSeschrock 				if (strcmp(zpool_get_name(cb.cb_zhp),
280499653d4eSeschrock 				    zpool_get_name(zhp)) == 0)
280599653d4eSeschrock 					(void) printf(gettext("currently in "
280699653d4eSeschrock 					    "use"));
280799653d4eSeschrock 				else
280899653d4eSeschrock 					(void) printf(gettext("in use by "
280999653d4eSeschrock 					    "pool '%s'"),
281099653d4eSeschrock 					    zpool_get_name(cb.cb_zhp));
281199653d4eSeschrock 				zpool_close(cb.cb_zhp);
281299653d4eSeschrock 			} else {
281399653d4eSeschrock 				(void) printf(gettext("currently in use"));
281499653d4eSeschrock 			}
281599653d4eSeschrock 			break;
281699653d4eSeschrock 
28173d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
28183d7072f8Seschrock 			(void) printf(gettext("too many errors"));
28193d7072f8Seschrock 			break;
28203d7072f8Seschrock 
2821fa9e4066Sahrens 		default:
2822fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2823fa9e4066Sahrens 			break;
2824fa9e4066Sahrens 		}
2825fa9e4066Sahrens 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2826fa9e4066Sahrens 		/*
2827fa9e4066Sahrens 		 * Report bytes resilvered/repaired on leaf devices.
2828fa9e4066Sahrens 		 */
2829fa9e4066Sahrens 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2830fa9e4066Sahrens 		(void) printf(gettext("  %s %s"), repaired,
2831fa9e4066Sahrens 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2832fa9e4066Sahrens 		    "resilvered" : "repaired");
2833fa9e4066Sahrens 	}
2834fa9e4066Sahrens 
2835fa9e4066Sahrens 	(void) printf("\n");
2836fa9e4066Sahrens 
2837afefbcddSeschrock 	for (c = 0; c < children; c++) {
28388654d025Sperrin 		uint64_t is_log = B_FALSE;
28398654d025Sperrin 
28408654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
28418654d025Sperrin 		    &is_log);
28428654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
28438654d025Sperrin 			continue;
284499653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
2845c67d9675Seschrock 		print_status_config(zhp, vname, child[c],
28468654d025Sperrin 		    namewidth, depth + 2, isspare, B_FALSE);
2847afefbcddSeschrock 		free(vname);
2848afefbcddSeschrock 	}
2849fa9e4066Sahrens }
2850fa9e4066Sahrens 
2851ea8dc4b6Seschrock static void
2852ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
2853ea8dc4b6Seschrock {
285475519f38Sek110237 	nvlist_t *nverrlist = NULL;
285555434c77Sek110237 	nvpair_t *elem;
285655434c77Sek110237 	char *pathname;
285755434c77Sek110237 	size_t len = MAXPATHLEN * 2;
2858ea8dc4b6Seschrock 
285955434c77Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2860ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
2861ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
2862ea8dc4b6Seschrock 		return;
2863ea8dc4b6Seschrock 	}
2864ea8dc4b6Seschrock 
286555434c77Sek110237 	(void) printf("errors: Permanent errors have been "
286655434c77Sek110237 	    "detected in the following files:\n\n");
2867ea8dc4b6Seschrock 
286855434c77Sek110237 	pathname = safe_malloc(len);
286955434c77Sek110237 	elem = NULL;
287055434c77Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
287155434c77Sek110237 		nvlist_t *nv;
287255434c77Sek110237 		uint64_t dsobj, obj;
2873ea8dc4b6Seschrock 
287455434c77Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
287555434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
287655434c77Sek110237 		    &dsobj) == 0);
287755434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
287855434c77Sek110237 		    &obj) == 0);
287955434c77Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
288055434c77Sek110237 		(void) printf("%7s %s\n", "", pathname);
2881ea8dc4b6Seschrock 	}
288255434c77Sek110237 	free(pathname);
288355434c77Sek110237 	nvlist_free(nverrlist);
2884ea8dc4b6Seschrock }
2885ea8dc4b6Seschrock 
288699653d4eSeschrock static void
288799653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
288899653d4eSeschrock     int namewidth)
288999653d4eSeschrock {
289099653d4eSeschrock 	uint_t i;
289199653d4eSeschrock 	char *name;
289299653d4eSeschrock 
289399653d4eSeschrock 	if (nspares == 0)
289499653d4eSeschrock 		return;
289599653d4eSeschrock 
289699653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
289799653d4eSeschrock 
289899653d4eSeschrock 	for (i = 0; i < nspares; i++) {
289999653d4eSeschrock 		name = zpool_vdev_name(g_zfs, zhp, spares[i]);
290099653d4eSeschrock 		print_status_config(zhp, name, spares[i],
29018654d025Sperrin 		    namewidth, 2, B_TRUE, B_FALSE);
290299653d4eSeschrock 		free(name);
290399653d4eSeschrock 	}
290499653d4eSeschrock }
290599653d4eSeschrock 
2906fa9e4066Sahrens /*
2907fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
2908fa9e4066Sahrens  *
2909fa9e4066Sahrens  *        pool: tank
2910fa9e4066Sahrens  *	status: DEGRADED
2911fa9e4066Sahrens  *	reason: One or more devices ...
2912fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
2913fa9e4066Sahrens  *	config:
2914fa9e4066Sahrens  *		mirror		DEGRADED
2915fa9e4066Sahrens  *                c1t0d0	OK
2916ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
2917fa9e4066Sahrens  *
2918fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
2919fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
2920fa9e4066Sahrens  */
2921fa9e4066Sahrens int
2922fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
2923fa9e4066Sahrens {
2924fa9e4066Sahrens 	status_cbdata_t *cbp = data;
2925fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2926fa9e4066Sahrens 	char *msgid;
2927fa9e4066Sahrens 	int reason;
292846657f8dSmmusante 	const char *health;
292946657f8dSmmusante 	uint_t c;
293046657f8dSmmusante 	vdev_stat_t *vs;
2931fa9e4066Sahrens 
2932088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
2933fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
2934fa9e4066Sahrens 
2935fa9e4066Sahrens 	cbp->cb_count++;
2936fa9e4066Sahrens 
2937fa9e4066Sahrens 	/*
2938fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
2939fa9e4066Sahrens 	 * problems.
2940fa9e4066Sahrens 	 */
2941e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
2942e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
2943e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
2944e9dbad6fSeschrock 			    zpool_get_name(zhp));
2945e9dbad6fSeschrock 			if (cbp->cb_first)
2946e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
2947e9dbad6fSeschrock 		}
2948fa9e4066Sahrens 		return (0);
2949e9dbad6fSeschrock 	}
2950fa9e4066Sahrens 
2951fa9e4066Sahrens 	if (cbp->cb_first)
295299653d4eSeschrock 		cbp->cb_first = B_FALSE;
2953fa9e4066Sahrens 	else
2954fa9e4066Sahrens 		(void) printf("\n");
2955fa9e4066Sahrens 
295646657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
295746657f8dSmmusante 	    &nvroot) == 0);
295846657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
295946657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
296046657f8dSmmusante 	health = state_to_name(vs);
2961fa9e4066Sahrens 
2962fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
2963fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
2964fa9e4066Sahrens 
2965fa9e4066Sahrens 	switch (reason) {
2966fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
2967fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2968fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
2969fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
2970fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2971fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2972fa9e4066Sahrens 		break;
2973fa9e4066Sahrens 
2974fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
2975fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2976fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
2977fa9e4066Sahrens 		    "pool to continue functioning.\n"));
2978fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2979fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2980fa9e4066Sahrens 		break;
2981fa9e4066Sahrens 
2982fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
2983fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2984fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
2985fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
2986fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
2987fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
2988fa9e4066Sahrens 		    "'zpool replace'.\n"));
2989fa9e4066Sahrens 		break;
2990fa9e4066Sahrens 
2991fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
2992fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2993b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
2994fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
2995fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
2996fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
2997fa9e4066Sahrens 		    "from a backup source.\n"));
2998fa9e4066Sahrens 		break;
2999fa9e4066Sahrens 
3000fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
3001fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3002fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
3003fa9e4066Sahrens 		    "made to correct the error.  Applications are "
3004fa9e4066Sahrens 		    "unaffected.\n"));
3005fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
3006fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
3007ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
3008fa9e4066Sahrens 		    "replace'.\n"));
3009fa9e4066Sahrens 		break;
3010fa9e4066Sahrens 
3011fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
3012fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3013d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
3014fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
3015fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
3016fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
3017fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
3018fa9e4066Sahrens 		    "replace'.\n"));
3019fa9e4066Sahrens 		break;
3020fa9e4066Sahrens 
3021fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
3022fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
3023fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3024fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
3025fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3026fa9e4066Sahrens 		    "complete.\n"));
3027fa9e4066Sahrens 		break;
3028fa9e4066Sahrens 
3029ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3030ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3031ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3032ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3033ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3034ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3035ea8dc4b6Seschrock 		    "backup.\n"));
3036ea8dc4b6Seschrock 		break;
3037ea8dc4b6Seschrock 
3038ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3039ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3040ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3041ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
3042ea8dc4b6Seschrock 		    "from a backup source.\n"));
3043ea8dc4b6Seschrock 		break;
3044ea8dc4b6Seschrock 
3045eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3046eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3047eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3048eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3049eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3050eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3051eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3052eaca9bbdSeschrock 		break;
3053eaca9bbdSeschrock 
3054eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3055eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3056eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3057eaca9bbdSeschrock 		    "be accessed on this system.\n"));
3058eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
3059eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
3060eaca9bbdSeschrock 		    "backup.\n"));
3061eaca9bbdSeschrock 		break;
3062eaca9bbdSeschrock 
30633d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
30643d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
30653d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
30663d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
30673d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
30683d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
30693d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
30703d7072f8Seschrock 		break;
30713d7072f8Seschrock 
30723d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
30733d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
30743d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
30753d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
30763d7072f8Seschrock 		    "functioning.\n"));
30773d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
30783d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
30793d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
30803d7072f8Seschrock 		    "to be recovered.\n"));
30813d7072f8Seschrock 		break;
30823d7072f8Seschrock 
3083fa9e4066Sahrens 	default:
3084fa9e4066Sahrens 		/*
3085fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
3086fa9e4066Sahrens 		 */
3087fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
3088fa9e4066Sahrens 	}
3089fa9e4066Sahrens 
3090fa9e4066Sahrens 	if (msgid != NULL)
3091fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3092fa9e4066Sahrens 		    msgid);
3093fa9e4066Sahrens 
3094fa9e4066Sahrens 	if (config != NULL) {
3095fa9e4066Sahrens 		int namewidth;
3096ea8dc4b6Seschrock 		uint64_t nerr;
309799653d4eSeschrock 		nvlist_t **spares;
309899653d4eSeschrock 		uint_t nspares;
3099fa9e4066Sahrens 
3100fa9e4066Sahrens 
3101fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
3102fa9e4066Sahrens 		print_scrub_status(nvroot);
3103fa9e4066Sahrens 
3104c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3105fa9e4066Sahrens 		if (namewidth < 10)
3106fa9e4066Sahrens 			namewidth = 10;
3107fa9e4066Sahrens 
3108fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
3109fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3110fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3111c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
31128654d025Sperrin 		    namewidth, 0, B_FALSE, B_FALSE);
31138654d025Sperrin 		if (num_logs(nvroot) > 0)
31148654d025Sperrin 			print_status_config(zhp, "logs", nvroot, namewidth, 0,
31158654d025Sperrin 			    B_FALSE, B_TRUE);
311699653d4eSeschrock 
311799653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
311899653d4eSeschrock 		    &spares, &nspares) == 0)
311999653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
3120ea8dc4b6Seschrock 
3121ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3122ea8dc4b6Seschrock 		    &nerr) == 0) {
312355434c77Sek110237 			nvlist_t *nverrlist = NULL;
312455434c77Sek110237 
3125ea8dc4b6Seschrock 			/*
3126ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3127ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3128ea8dc4b6Seschrock 			 * uniquifying the results.
3129ea8dc4b6Seschrock 			 */
313075519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
313155434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
313255434c77Sek110237 				nvpair_t *elem;
313355434c77Sek110237 
313455434c77Sek110237 				elem = NULL;
313555434c77Sek110237 				nerr = 0;
313655434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
313755434c77Sek110237 				    elem)) != NULL) {
313855434c77Sek110237 					nerr++;
313955434c77Sek110237 				}
314055434c77Sek110237 			}
314155434c77Sek110237 			nvlist_free(nverrlist);
3142ea8dc4b6Seschrock 
3143ea8dc4b6Seschrock 			(void) printf("\n");
314499653d4eSeschrock 
3145ea8dc4b6Seschrock 			if (nerr == 0)
3146ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3147ea8dc4b6Seschrock 				    "errors\n"));
3148ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3149e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
31505ad82045Snd150628 				    "errors, use '-v' for a list\n"),
31515ad82045Snd150628 				    (u_longlong_t)nerr);
3152ea8dc4b6Seschrock 			else
3153ea8dc4b6Seschrock 				print_error_log(zhp);
3154ea8dc4b6Seschrock 		}
3155fa9e4066Sahrens 	} else {
3156fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3157fa9e4066Sahrens 		    "determined.\n"));
3158fa9e4066Sahrens 	}
3159fa9e4066Sahrens 
3160fa9e4066Sahrens 	return (0);
3161fa9e4066Sahrens }
3162fa9e4066Sahrens 
3163fa9e4066Sahrens /*
3164fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3165fa9e4066Sahrens  *
3166fa9e4066Sahrens  *	-v	Display complete error logs
3167fa9e4066Sahrens  *	-x	Display only pools with potential problems
3168fa9e4066Sahrens  *
3169fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3170fa9e4066Sahrens  */
3171fa9e4066Sahrens int
3172fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3173fa9e4066Sahrens {
3174fa9e4066Sahrens 	int c;
3175fa9e4066Sahrens 	int ret;
3176fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3177fa9e4066Sahrens 
3178fa9e4066Sahrens 	/* check options */
3179fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3180fa9e4066Sahrens 		switch (c) {
3181fa9e4066Sahrens 		case 'v':
318299653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3183fa9e4066Sahrens 			break;
3184fa9e4066Sahrens 		case 'x':
318599653d4eSeschrock 			cb.cb_explain = B_TRUE;
3186fa9e4066Sahrens 			break;
3187fa9e4066Sahrens 		case '?':
3188fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3189fa9e4066Sahrens 			    optopt);
319099653d4eSeschrock 			usage(B_FALSE);
3191fa9e4066Sahrens 		}
3192fa9e4066Sahrens 	}
3193fa9e4066Sahrens 
3194fa9e4066Sahrens 	argc -= optind;
3195fa9e4066Sahrens 	argv += optind;
3196fa9e4066Sahrens 
319799653d4eSeschrock 	cb.cb_first = B_TRUE;
3198fa9e4066Sahrens 
3199e9dbad6fSeschrock 	if (argc == 0)
3200e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3201e9dbad6fSeschrock 
3202b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3203fa9e4066Sahrens 
3204fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3205fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3206e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3207fa9e4066Sahrens 		(void) printf(gettext("all pools are healthy\n"));
3208fa9e4066Sahrens 
3209fa9e4066Sahrens 	return (ret);
3210fa9e4066Sahrens }
3211fa9e4066Sahrens 
3212eaca9bbdSeschrock typedef struct upgrade_cbdata {
3213eaca9bbdSeschrock 	int	cb_all;
3214eaca9bbdSeschrock 	int	cb_first;
3215eaca9bbdSeschrock 	int	cb_newer;
321606eeb2adSek110237 	int	cb_argc;
3217e7437265Sahrens 	uint64_t cb_numupgraded;
3218e7437265Sahrens 	uint64_t cb_numsamegraded;
321906eeb2adSek110237 	char	**cb_argv;
3220eaca9bbdSeschrock } upgrade_cbdata_t;
3221eaca9bbdSeschrock 
3222eaca9bbdSeschrock static int
3223eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3224eaca9bbdSeschrock {
3225eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3226eaca9bbdSeschrock 	nvlist_t *config;
3227eaca9bbdSeschrock 	uint64_t version;
3228eaca9bbdSeschrock 	int ret = 0;
3229eaca9bbdSeschrock 
3230eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3231eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3232eaca9bbdSeschrock 	    &version) == 0);
3233eaca9bbdSeschrock 
3234e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3235eaca9bbdSeschrock 		if (!cbp->cb_all) {
3236eaca9bbdSeschrock 			if (cbp->cb_first) {
3237eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3238eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3239eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3240eaca9bbdSeschrock 				    "longer be accessible by older software "
3241eaca9bbdSeschrock 				    "versions.\n\n"));
3242eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3243eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
324499653d4eSeschrock 				cbp->cb_first = B_FALSE;
3245eaca9bbdSeschrock 			}
3246eaca9bbdSeschrock 
32475ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3248eaca9bbdSeschrock 			    zpool_get_name(zhp));
3249eaca9bbdSeschrock 		} else {
325099653d4eSeschrock 			cbp->cb_first = B_FALSE;
3251eaca9bbdSeschrock 			ret = zpool_upgrade(zhp);
325206eeb2adSek110237 			if (!ret) {
3253eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3254eaca9bbdSeschrock 				    "'%s'\n"), zpool_get_name(zhp));
3255eaca9bbdSeschrock 			}
325606eeb2adSek110237 		}
3257e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3258eaca9bbdSeschrock 		assert(!cbp->cb_all);
3259eaca9bbdSeschrock 
3260eaca9bbdSeschrock 		if (cbp->cb_first) {
3261eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3262eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3263eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3264eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3265eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
326699653d4eSeschrock 			cbp->cb_first = B_FALSE;
3267eaca9bbdSeschrock 		}
3268eaca9bbdSeschrock 
32695ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3270eaca9bbdSeschrock 		    zpool_get_name(zhp));
3271eaca9bbdSeschrock 	}
3272eaca9bbdSeschrock 
3273eaca9bbdSeschrock 	zpool_close(zhp);
3274eaca9bbdSeschrock 	return (ret);
3275eaca9bbdSeschrock }
3276eaca9bbdSeschrock 
3277eaca9bbdSeschrock /* ARGSUSED */
3278eaca9bbdSeschrock static int
327906eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
3280eaca9bbdSeschrock {
3281eaca9bbdSeschrock 	nvlist_t *config;
3282eaca9bbdSeschrock 	uint64_t version;
3283eaca9bbdSeschrock 	int ret;
3284eaca9bbdSeschrock 
3285eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3286eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3287eaca9bbdSeschrock 	    &version) == 0);
3288eaca9bbdSeschrock 
32898654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
32908654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
32918654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
32928654d025Sperrin 		    " to upgrade.\n"));
32938654d025Sperrin 		return (1);
32948654d025Sperrin 	}
3295e7437265Sahrens 	if (version == SPA_VERSION) {
3296eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3297eaca9bbdSeschrock 		    "using the current version.\n"), zpool_get_name(zhp));
3298eaca9bbdSeschrock 		return (0);
3299eaca9bbdSeschrock 	}
3300eaca9bbdSeschrock 
3301eaca9bbdSeschrock 	ret = zpool_upgrade(zhp);
330206eeb2adSek110237 
330306eeb2adSek110237 	if (!ret) {
330444cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
330544cd46caSbillm 		    "from version %llu to version %llu\n"), zpool_get_name(zhp),
3306e7437265Sahrens 		    (u_longlong_t)version, (u_longlong_t)SPA_VERSION);
330706eeb2adSek110237 	}
3308eaca9bbdSeschrock 
3309eaca9bbdSeschrock 	return (ret != 0);
3310eaca9bbdSeschrock }
3311eaca9bbdSeschrock 
3312eaca9bbdSeschrock /*
3313eaca9bbdSeschrock  * zpool upgrade
3314eaca9bbdSeschrock  * zpool upgrade -v
3315eaca9bbdSeschrock  * zpool upgrade <-a | pool>
3316eaca9bbdSeschrock  *
3317eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3318eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3319eaca9bbdSeschrock  * upgrade all pools.
3320eaca9bbdSeschrock  */
3321eaca9bbdSeschrock int
3322eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3323eaca9bbdSeschrock {
3324eaca9bbdSeschrock 	int c;
3325eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3326eaca9bbdSeschrock 	int ret = 0;
3327eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3328eaca9bbdSeschrock 
3329eaca9bbdSeschrock 	/* check options */
3330eaca9bbdSeschrock 	while ((c = getopt(argc, argv, "av")) != -1) {
3331eaca9bbdSeschrock 		switch (c) {
3332eaca9bbdSeschrock 		case 'a':
333399653d4eSeschrock 			cb.cb_all = B_TRUE;
3334eaca9bbdSeschrock 			break;
3335eaca9bbdSeschrock 		case 'v':
3336eaca9bbdSeschrock 			showversions = B_TRUE;
3337eaca9bbdSeschrock 			break;
3338eaca9bbdSeschrock 		case '?':
3339eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3340eaca9bbdSeschrock 			    optopt);
334199653d4eSeschrock 			usage(B_FALSE);
3342eaca9bbdSeschrock 		}
3343eaca9bbdSeschrock 	}
3344eaca9bbdSeschrock 
334506eeb2adSek110237 	cb.cb_argc = argc;
334606eeb2adSek110237 	cb.cb_argv = argv;
3347eaca9bbdSeschrock 	argc -= optind;
3348eaca9bbdSeschrock 	argv += optind;
3349eaca9bbdSeschrock 
3350eaca9bbdSeschrock 	if (showversions) {
3351eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3352eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3353eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
335499653d4eSeschrock 			usage(B_FALSE);
3355eaca9bbdSeschrock 		}
3356eaca9bbdSeschrock 	} else if (cb.cb_all) {
3357eaca9bbdSeschrock 		if (argc != 0) {
3358eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-a option is "
3359eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
336099653d4eSeschrock 			usage(B_FALSE);
3361eaca9bbdSeschrock 		}
3362eaca9bbdSeschrock 	}
3363eaca9bbdSeschrock 
3364e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3365e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
336699653d4eSeschrock 	cb.cb_first = B_TRUE;
3367eaca9bbdSeschrock 	if (showversions) {
3368eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3369d7d4af51Smmusante 		    "supported:\n\n"));
3370eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3371eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3372eaca9bbdSeschrock 		    "---------------\n");
337399653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
337444cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
337544cd46caSbillm 		    "(replicated metadata)\n"));
337699653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
337799653d4eSeschrock 		    "RAID-Z\n"));
3378d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
3379c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3380c9431fa1Sahl 		    "algorithm\n"));
3381ecd6cf80Smarks 		(void) printf(gettext(" 6   pool properties\n"));
33828654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3383ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
33848654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3385eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3386eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3387eaca9bbdSeschrock 		    "version/N\n\n");
3388eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3389eaca9bbdSeschrock 	} else if (argc == 0) {
3390eaca9bbdSeschrock 		int notfound;
3391eaca9bbdSeschrock 
339299653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3393eaca9bbdSeschrock 		notfound = cb.cb_first;
3394eaca9bbdSeschrock 
3395eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3396eaca9bbdSeschrock 			if (!cb.cb_first)
3397eaca9bbdSeschrock 				(void) printf("\n");
3398eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3399eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
340099653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3401eaca9bbdSeschrock 			if (!cb.cb_first) {
3402eaca9bbdSeschrock 				notfound = B_FALSE;
3403eaca9bbdSeschrock 				(void) printf("\n");
3404eaca9bbdSeschrock 			}
3405eaca9bbdSeschrock 		}
3406eaca9bbdSeschrock 
3407eaca9bbdSeschrock 		if (ret == 0) {
3408eaca9bbdSeschrock 			if (notfound)
3409eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3410eaca9bbdSeschrock 				    "using this version.\n"));
3411eaca9bbdSeschrock 			else if (!cb.cb_all)
3412eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3413eaca9bbdSeschrock 				    "for a list of available versions and "
3414eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3415eaca9bbdSeschrock 		}
3416eaca9bbdSeschrock 	} else {
3417b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3418b1b8ab34Slling 		    upgrade_one, &cb);
341906eeb2adSek110237 	}
342006eeb2adSek110237 
342106eeb2adSek110237 	return (ret);
342206eeb2adSek110237 }
342306eeb2adSek110237 
3424ecd6cf80Smarks typedef struct hist_cbdata {
3425ecd6cf80Smarks 	boolean_t first;
3426ecd6cf80Smarks 	int longfmt;
3427ecd6cf80Smarks 	int internal;
3428ecd6cf80Smarks } hist_cbdata_t;
3429ecd6cf80Smarks 
3430ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3431ecd6cf80Smarks 	"invalid event",
3432ecd6cf80Smarks 	"pool create",
3433ecd6cf80Smarks 	"vdev add",
3434ecd6cf80Smarks 	"pool remove",
3435ecd6cf80Smarks 	"pool destroy",
3436ecd6cf80Smarks 	"pool export",
3437ecd6cf80Smarks 	"pool import",
3438ecd6cf80Smarks 	"vdev attach",
3439ecd6cf80Smarks 	"vdev replace",
3440ecd6cf80Smarks 	"vdev detach",
3441ecd6cf80Smarks 	"vdev online",
3442ecd6cf80Smarks 	"vdev offline",
3443ecd6cf80Smarks 	"vdev upgrade",
3444ecd6cf80Smarks 	"pool clear",
3445ecd6cf80Smarks 	"pool scrub",
3446ecd6cf80Smarks 	"pool property set",
3447ecd6cf80Smarks 	"create",
3448ecd6cf80Smarks 	"clone",
3449ecd6cf80Smarks 	"destroy",
3450ecd6cf80Smarks 	"destroy_begin_sync",
3451ecd6cf80Smarks 	"inherit",
3452ecd6cf80Smarks 	"property set",
3453ecd6cf80Smarks 	"quota set",
3454ecd6cf80Smarks 	"permission update",
3455ecd6cf80Smarks 	"permission remove",
3456ecd6cf80Smarks 	"permission who remove",
3457ecd6cf80Smarks 	"promote",
3458ecd6cf80Smarks 	"receive",
3459ecd6cf80Smarks 	"rename",
3460ecd6cf80Smarks 	"reservation set",
3461ecd6cf80Smarks 	"replay_inc_sync",
3462ecd6cf80Smarks 	"replay_full_sync",
3463ecd6cf80Smarks 	"rollback",
3464ecd6cf80Smarks 	"snapshot",
3465e7437265Sahrens 	"filesystem version upgrade",
3466ecd6cf80Smarks };
3467ecd6cf80Smarks 
346806eeb2adSek110237 /*
346906eeb2adSek110237  * Print out the command history for a specific pool.
347006eeb2adSek110237  */
347106eeb2adSek110237 static int
347206eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
347306eeb2adSek110237 {
347406eeb2adSek110237 	nvlist_t *nvhis;
347506eeb2adSek110237 	nvlist_t **records;
347606eeb2adSek110237 	uint_t numrecords;
347706eeb2adSek110237 	char *cmdstr;
3478ecd6cf80Smarks 	char *pathstr;
347906eeb2adSek110237 	uint64_t dst_time;
348006eeb2adSek110237 	time_t tsec;
348106eeb2adSek110237 	struct tm t;
348206eeb2adSek110237 	char tbuf[30];
348306eeb2adSek110237 	int ret, i;
3484ecd6cf80Smarks 	uint64_t who;
3485ecd6cf80Smarks 	struct passwd *pwd;
3486ecd6cf80Smarks 	char *hostname;
3487ecd6cf80Smarks 	char *zonename;
3488ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3489ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3490ecd6cf80Smarks 	uint64_t txg;
3491ecd6cf80Smarks 	uint64_t ievent;
349206eeb2adSek110237 
3493ecd6cf80Smarks 	cb->first = B_FALSE;
349406eeb2adSek110237 
349506eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
349606eeb2adSek110237 
349706eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
349806eeb2adSek110237 		return (ret);
349906eeb2adSek110237 
350006eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
350106eeb2adSek110237 	    &records, &numrecords) == 0);
350206eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
350306eeb2adSek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3504ecd6cf80Smarks 		    &dst_time) != 0)
3505ecd6cf80Smarks 			continue;
3506ecd6cf80Smarks 
3507ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3508ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3509ecd6cf80Smarks 		    &cmdstr) != 0) {
3510ecd6cf80Smarks 			if (cb->internal == 0)
3511ecd6cf80Smarks 				continue;
3512ecd6cf80Smarks 
3513ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3514ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3515ecd6cf80Smarks 				continue;
3516ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3517ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3518ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3519ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3520ecd6cf80Smarks 			if (ievent > LOG_END)
3521ecd6cf80Smarks 				continue;
3522ecd6cf80Smarks 			(void) snprintf(internalstr,
3523ecd6cf80Smarks 			    sizeof (internalstr),
3524ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3525ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3526ecd6cf80Smarks 			    pathstr);
3527ecd6cf80Smarks 			cmdstr = internalstr;
3528ecd6cf80Smarks 		}
352906eeb2adSek110237 		tsec = dst_time;
353006eeb2adSek110237 		(void) localtime_r(&tsec, &t);
353106eeb2adSek110237 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3532ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3533ecd6cf80Smarks 
3534ecd6cf80Smarks 		if (!cb->longfmt) {
3535ecd6cf80Smarks 			(void) printf("\n");
3536ecd6cf80Smarks 			continue;
353706eeb2adSek110237 		}
3538ecd6cf80Smarks 		(void) printf(" [");
3539ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3540ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3541ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3542ecd6cf80Smarks 			if (pwd)
3543ecd6cf80Smarks 				(void) printf("user %s on",
3544ecd6cf80Smarks 				    pwd->pw_name);
3545ecd6cf80Smarks 			else
3546ecd6cf80Smarks 				(void) printf("user %d on",
3547ecd6cf80Smarks 				    (int)who);
3548ecd6cf80Smarks 		} else {
3549ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3550ecd6cf80Smarks 			continue;
3551ecd6cf80Smarks 		}
3552ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3553ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3554ecd6cf80Smarks 			(void) printf(" %s", hostname);
3555ecd6cf80Smarks 		}
3556ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3557ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3558ecd6cf80Smarks 			(void) printf(":%s", zonename);
3559ecd6cf80Smarks 		}
3560ecd6cf80Smarks 
3561ecd6cf80Smarks 		(void) printf("]");
3562ecd6cf80Smarks 		(void) printf("\n");
356306eeb2adSek110237 	}
356406eeb2adSek110237 	(void) printf("\n");
356506eeb2adSek110237 	nvlist_free(nvhis);
356606eeb2adSek110237 
356706eeb2adSek110237 	return (ret);
356806eeb2adSek110237 }
356906eeb2adSek110237 
357006eeb2adSek110237 /*
357106eeb2adSek110237  * zpool history <pool>
357206eeb2adSek110237  *
357306eeb2adSek110237  * Displays the history of commands that modified pools.
357406eeb2adSek110237  */
3575ecd6cf80Smarks 
3576ecd6cf80Smarks 
357706eeb2adSek110237 int
357806eeb2adSek110237 zpool_do_history(int argc, char **argv)
357906eeb2adSek110237 {
3580ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
358106eeb2adSek110237 	int ret;
3582ecd6cf80Smarks 	int c;
358306eeb2adSek110237 
3584ecd6cf80Smarks 	cbdata.first = B_TRUE;
3585ecd6cf80Smarks 	/* check options */
3586ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3587ecd6cf80Smarks 		switch (c) {
3588ecd6cf80Smarks 		case 'l':
3589ecd6cf80Smarks 			cbdata.longfmt = 1;
3590ecd6cf80Smarks 			break;
3591ecd6cf80Smarks 		case 'i':
3592ecd6cf80Smarks 			cbdata.internal = 1;
3593ecd6cf80Smarks 			break;
3594ecd6cf80Smarks 		case '?':
3595ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3596ecd6cf80Smarks 			    optopt);
3597ecd6cf80Smarks 			usage(B_FALSE);
3598ecd6cf80Smarks 		}
3599ecd6cf80Smarks 	}
360006eeb2adSek110237 	argc -= optind;
360106eeb2adSek110237 	argv += optind;
360206eeb2adSek110237 
3603b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3604ecd6cf80Smarks 	    &cbdata);
360506eeb2adSek110237 
3606ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
360706eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
360806eeb2adSek110237 		return (0);
3609eaca9bbdSeschrock 	}
3610eaca9bbdSeschrock 
3611eaca9bbdSeschrock 	return (ret);
3612eaca9bbdSeschrock }
3613eaca9bbdSeschrock 
3614b1b8ab34Slling static int
3615b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3616b1b8ab34Slling {
3617b1b8ab34Slling 	libzfs_get_cbdata_t *cbp = (libzfs_get_cbdata_t *)data;
3618b1b8ab34Slling 	char value[MAXNAMELEN];
3619b1b8ab34Slling 	zfs_source_t srctype;
3620b1b8ab34Slling 	zpool_proplist_t *pl;
3621b1b8ab34Slling 
3622b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3623b1b8ab34Slling 
3624b1b8ab34Slling 		/*
3625b1b8ab34Slling 		 * Skip the special fake placeholder.
3626b1b8ab34Slling 		 */
3627b1b8ab34Slling 		if (pl->pl_prop == ZFS_PROP_NAME &&
3628b1b8ab34Slling 		    pl == cbp->cb_proplist)
3629b1b8ab34Slling 			continue;
3630b1b8ab34Slling 
3631b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3632b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3633b1b8ab34Slling 			continue;
3634b1b8ab34Slling 
3635b1b8ab34Slling 		libzfs_print_one_property(zpool_get_name(zhp), cbp,
3636b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3637b1b8ab34Slling 	}
3638b1b8ab34Slling 	return (0);
3639b1b8ab34Slling }
3640b1b8ab34Slling 
3641b1b8ab34Slling int
3642b1b8ab34Slling zpool_do_get(int argc, char **argv)
3643b1b8ab34Slling {
3644b1b8ab34Slling 	libzfs_get_cbdata_t cb = { 0 };
3645b1b8ab34Slling 	zpool_proplist_t fake_name = { 0 };
3646b1b8ab34Slling 	int ret;
3647b1b8ab34Slling 
3648b1b8ab34Slling 	if (argc < 3)
3649b1b8ab34Slling 		usage(B_FALSE);
3650b1b8ab34Slling 
3651b1b8ab34Slling 	cb.cb_first = B_TRUE;
3652b1b8ab34Slling 	cb.cb_sources = ZFS_SRC_ALL;
3653b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3654b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3655b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3656b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3657b1b8ab34Slling 
3658b1b8ab34Slling 	if (zpool_get_proplist(g_zfs, argv[1],  &cb.cb_proplist) != 0)
3659b1b8ab34Slling 		usage(B_FALSE);
3660b1b8ab34Slling 
3661b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3662b1b8ab34Slling 		fake_name.pl_prop = ZFS_PROP_NAME;
3663b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3664b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3665b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3666b1b8ab34Slling 	}
3667b1b8ab34Slling 
3668b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3669b1b8ab34Slling 	    get_callback, &cb);
3670b1b8ab34Slling 
3671b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3672b1b8ab34Slling 		zfs_free_proplist(fake_name.pl_next);
3673b1b8ab34Slling 	else
3674b1b8ab34Slling 		zfs_free_proplist(cb.cb_proplist);
3675b1b8ab34Slling 
3676b1b8ab34Slling 	return (ret);
3677b1b8ab34Slling }
3678b1b8ab34Slling 
3679b1b8ab34Slling typedef struct set_cbdata {
3680b1b8ab34Slling 	char *cb_propname;
3681b1b8ab34Slling 	char *cb_value;
3682b1b8ab34Slling 	boolean_t cb_any_successful;
3683b1b8ab34Slling } set_cbdata_t;
3684b1b8ab34Slling 
3685b1b8ab34Slling int
3686b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3687b1b8ab34Slling {
3688b1b8ab34Slling 	int error;
3689b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3690b1b8ab34Slling 
3691b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3692b1b8ab34Slling 
3693b1b8ab34Slling 	if (!error)
3694b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3695b1b8ab34Slling 
3696b1b8ab34Slling 	return (error);
3697b1b8ab34Slling }
3698b1b8ab34Slling 
3699b1b8ab34Slling int
3700b1b8ab34Slling zpool_do_set(int argc, char **argv)
3701b1b8ab34Slling {
3702b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3703b1b8ab34Slling 	int error;
3704b1b8ab34Slling 
3705b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3706b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3707b1b8ab34Slling 		    argv[1][1]);
3708b1b8ab34Slling 		usage(B_FALSE);
3709b1b8ab34Slling 	}
3710b1b8ab34Slling 
3711b1b8ab34Slling 	if (argc < 2) {
3712b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3713b1b8ab34Slling 		    "argument\n"));
3714b1b8ab34Slling 		usage(B_FALSE);
3715b1b8ab34Slling 	}
3716b1b8ab34Slling 
3717b1b8ab34Slling 	if (argc < 3) {
3718b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3719b1b8ab34Slling 		usage(B_FALSE);
3720b1b8ab34Slling 	}
3721b1b8ab34Slling 
3722b1b8ab34Slling 	if (argc > 3) {
3723b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3724b1b8ab34Slling 		usage(B_FALSE);
3725b1b8ab34Slling 	}
3726b1b8ab34Slling 
3727b1b8ab34Slling 	cb.cb_propname = argv[1];
3728b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3729b1b8ab34Slling 	if (cb.cb_value == NULL) {
3730b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3731b1b8ab34Slling 		    "property=value argument\n"));
3732b1b8ab34Slling 		usage(B_FALSE);
3733b1b8ab34Slling 	}
3734b1b8ab34Slling 
3735b1b8ab34Slling 	*(cb.cb_value) = '\0';
3736b1b8ab34Slling 	cb.cb_value++;
3737b1b8ab34Slling 
3738b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3739b1b8ab34Slling 	    set_callback, &cb);
3740b1b8ab34Slling 
3741b1b8ab34Slling 	return (error);
3742b1b8ab34Slling }
3743b1b8ab34Slling 
3744b1b8ab34Slling static int
3745b1b8ab34Slling find_command_idx(char *command, int *idx)
3746b1b8ab34Slling {
3747b1b8ab34Slling 	int i;
3748b1b8ab34Slling 
3749b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3750b1b8ab34Slling 		if (command_table[i].name == NULL)
3751b1b8ab34Slling 			continue;
3752b1b8ab34Slling 
3753b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3754b1b8ab34Slling 			*idx = i;
3755b1b8ab34Slling 			return (0);
3756b1b8ab34Slling 		}
3757b1b8ab34Slling 	}
3758b1b8ab34Slling 	return (1);
3759b1b8ab34Slling }
3760b1b8ab34Slling 
3761fa9e4066Sahrens int
3762fa9e4066Sahrens main(int argc, char **argv)
3763fa9e4066Sahrens {
3764fa9e4066Sahrens 	int ret;
3765fa9e4066Sahrens 	int i;
3766fa9e4066Sahrens 	char *cmdname;
3767fa9e4066Sahrens 
3768fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3769fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3770fa9e4066Sahrens 
377199653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
377299653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3773203a47d8Snd150628 		    "initialize ZFS library\n"));
377499653d4eSeschrock 		return (1);
377599653d4eSeschrock 	}
377699653d4eSeschrock 
377799653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
377899653d4eSeschrock 
3779fa9e4066Sahrens 	opterr = 0;
3780fa9e4066Sahrens 
3781fa9e4066Sahrens 	/*
3782fa9e4066Sahrens 	 * Make sure the user has specified some command.
3783fa9e4066Sahrens 	 */
3784fa9e4066Sahrens 	if (argc < 2) {
3785fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
378699653d4eSeschrock 		usage(B_FALSE);
3787fa9e4066Sahrens 	}
3788fa9e4066Sahrens 
3789fa9e4066Sahrens 	cmdname = argv[1];
3790fa9e4066Sahrens 
3791ecd6cf80Smarks 	/* Handle special case of pool create for staging history */
3792ecd6cf80Smarks 	if (strcmp(cmdname, "create") != 0)
3793228975ccSek110237 		zpool_stage_history(g_zfs, argc, argv, B_FALSE);
3794ecd6cf80Smarks 	else
3795228975ccSek110237 		zpool_stage_history(g_zfs, argc, argv, B_FALSE);
3796ecd6cf80Smarks 
3797fa9e4066Sahrens 	/*
3798fa9e4066Sahrens 	 * Special case '-?'
3799fa9e4066Sahrens 	 */
3800fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
380199653d4eSeschrock 		usage(B_TRUE);
3802fa9e4066Sahrens 
3803fa9e4066Sahrens 	/*
3804fa9e4066Sahrens 	 * Run the appropriate command.
3805fa9e4066Sahrens 	 */
3806b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
3807fa9e4066Sahrens 		current_command = &command_table[i];
3808fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
380991ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
381091ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
381191ebeef5Sahrens 		current_command = &command_table[i];
381291ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
381391ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
3814fa9e4066Sahrens 		/*
381591ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
381691ebeef5Sahrens 		 * it as such.
3817fa9e4066Sahrens 		 */
3818ea8dc4b6Seschrock 		char buf[16384];
3819ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
3820fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
3821fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
382291ebeef5Sahrens 	} else {
3823fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
3824fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
382599653d4eSeschrock 		usage(B_FALSE);
3826fa9e4066Sahrens 	}
3827fa9e4066Sahrens 
382899653d4eSeschrock 	libzfs_fini(g_zfs);
382999653d4eSeschrock 
3830fa9e4066Sahrens 	/*
3831fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3832fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
3833fa9e4066Sahrens 	 */
3834fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
3835fa9e4066Sahrens 		(void) printf("dumping core by request\n");
3836fa9e4066Sahrens 		abort();
3837fa9e4066Sahrens 	}
3838fa9e4066Sahrens 
3839fa9e4066Sahrens 	return (ret);
3840fa9e4066Sahrens }
3841