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