xref: /titanic_53/usr/src/cmd/zpool/zpool_main.c (revision 24e697d414a4df0377b91a2875f029e7b5f97247)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5441d80aaSlling  * Common Development and Distribution License (the "License").
6441d80aaSlling  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
2199653d4eSeschrock 
22fa9e4066Sahrens /*
2318ce54dfSek110237  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28fa9e4066Sahrens 
29fa9e4066Sahrens #include <assert.h>
30fa9e4066Sahrens #include <ctype.h>
31fa9e4066Sahrens #include <dirent.h>
32fa9e4066Sahrens #include <errno.h>
33fa9e4066Sahrens #include <fcntl.h>
34fa9e4066Sahrens #include <libgen.h>
35fa9e4066Sahrens #include <libintl.h>
36fa9e4066Sahrens #include <libuutil.h>
37fa9e4066Sahrens #include <locale.h>
38fa9e4066Sahrens #include <stdio.h>
39fa9e4066Sahrens #include <stdlib.h>
40fa9e4066Sahrens #include <string.h>
41fa9e4066Sahrens #include <strings.h>
42fa9e4066Sahrens #include <unistd.h>
43fa9e4066Sahrens #include <priv.h>
44ecd6cf80Smarks #include <pwd.h>
45ecd6cf80Smarks #include <zone.h>
46b1b8ab34Slling #include <sys/fs/zfs.h>
47fa9e4066Sahrens 
48fa9e4066Sahrens #include <sys/stat.h>
49fa9e4066Sahrens 
50fa9e4066Sahrens #include <libzfs.h>
51fa9e4066Sahrens 
52fa9e4066Sahrens #include "zpool_util.h"
53b7b97454Sperrin #include "zfs_comutil.h"
54fa9e4066Sahrens 
55fa9e4066Sahrens static int zpool_do_create(int, char **);
56fa9e4066Sahrens static int zpool_do_destroy(int, char **);
57fa9e4066Sahrens 
58fa9e4066Sahrens static int zpool_do_add(int, char **);
5999653d4eSeschrock static int zpool_do_remove(int, char **);
60fa9e4066Sahrens 
61fa9e4066Sahrens static int zpool_do_list(int, char **);
62fa9e4066Sahrens static int zpool_do_iostat(int, char **);
63fa9e4066Sahrens static int zpool_do_status(int, char **);
64fa9e4066Sahrens 
65fa9e4066Sahrens static int zpool_do_online(int, char **);
66fa9e4066Sahrens static int zpool_do_offline(int, char **);
67ea8dc4b6Seschrock static int zpool_do_clear(int, char **);
68fa9e4066Sahrens 
69fa9e4066Sahrens static int zpool_do_attach(int, char **);
70fa9e4066Sahrens static int zpool_do_detach(int, char **);
71fa9e4066Sahrens static int zpool_do_replace(int, char **);
72fa9e4066Sahrens 
73fa9e4066Sahrens static int zpool_do_scrub(int, char **);
74fa9e4066Sahrens 
75fa9e4066Sahrens static int zpool_do_import(int, char **);
76fa9e4066Sahrens static int zpool_do_export(int, char **);
77fa9e4066Sahrens 
78eaca9bbdSeschrock static int zpool_do_upgrade(int, char **);
79eaca9bbdSeschrock 
8006eeb2adSek110237 static int zpool_do_history(int, char **);
8106eeb2adSek110237 
82b1b8ab34Slling static int zpool_do_get(int, char **);
83b1b8ab34Slling static int zpool_do_set(int, char **);
84b1b8ab34Slling 
85fa9e4066Sahrens /*
86fa9e4066Sahrens  * These libumem hooks provide a reasonable set of defaults for the allocator's
87fa9e4066Sahrens  * debugging facilities.
88fa9e4066Sahrens  */
89fa9e4066Sahrens const char *
9099653d4eSeschrock _umem_debug_init(void)
91fa9e4066Sahrens {
92fa9e4066Sahrens 	return ("default,verbose"); /* $UMEM_DEBUG setting */
93fa9e4066Sahrens }
94fa9e4066Sahrens 
95fa9e4066Sahrens const char *
96fa9e4066Sahrens _umem_logging_init(void)
97fa9e4066Sahrens {
98fa9e4066Sahrens 	return ("fail,contents"); /* $UMEM_LOGGING setting */
99fa9e4066Sahrens }
100fa9e4066Sahrens 
10165cd9f28Seschrock typedef enum {
10265cd9f28Seschrock 	HELP_ADD,
10365cd9f28Seschrock 	HELP_ATTACH,
104ea8dc4b6Seschrock 	HELP_CLEAR,
10565cd9f28Seschrock 	HELP_CREATE,
10665cd9f28Seschrock 	HELP_DESTROY,
10765cd9f28Seschrock 	HELP_DETACH,
10865cd9f28Seschrock 	HELP_EXPORT,
10906eeb2adSek110237 	HELP_HISTORY,
11065cd9f28Seschrock 	HELP_IMPORT,
11165cd9f28Seschrock 	HELP_IOSTAT,
11265cd9f28Seschrock 	HELP_LIST,
11365cd9f28Seschrock 	HELP_OFFLINE,
11465cd9f28Seschrock 	HELP_ONLINE,
11565cd9f28Seschrock 	HELP_REPLACE,
11699653d4eSeschrock 	HELP_REMOVE,
11765cd9f28Seschrock 	HELP_SCRUB,
118eaca9bbdSeschrock 	HELP_STATUS,
119b1b8ab34Slling 	HELP_UPGRADE,
120b1b8ab34Slling 	HELP_GET,
121b1b8ab34Slling 	HELP_SET
12265cd9f28Seschrock } zpool_help_t;
12365cd9f28Seschrock 
12465cd9f28Seschrock 
125fa9e4066Sahrens typedef struct zpool_command {
126fa9e4066Sahrens 	const char	*name;
127fa9e4066Sahrens 	int		(*func)(int, char **);
12865cd9f28Seschrock 	zpool_help_t	usage;
129fa9e4066Sahrens } zpool_command_t;
130fa9e4066Sahrens 
131fa9e4066Sahrens /*
132fa9e4066Sahrens  * Master command table.  Each ZFS command has a name, associated function, and
133ea8dc4b6Seschrock  * usage message.  The usage messages need to be internationalized, so we have
134ea8dc4b6Seschrock  * to have a function to return the usage message based on a command index.
13565cd9f28Seschrock  *
13665cd9f28Seschrock  * These commands are organized according to how they are displayed in the usage
13765cd9f28Seschrock  * message.  An empty command (one with a NULL name) indicates an empty line in
13865cd9f28Seschrock  * the generic usage message.
139fa9e4066Sahrens  */
140fa9e4066Sahrens static zpool_command_t command_table[] = {
14165cd9f28Seschrock 	{ "create",	zpool_do_create,	HELP_CREATE		},
14265cd9f28Seschrock 	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
143fa9e4066Sahrens 	{ NULL },
14465cd9f28Seschrock 	{ "add",	zpool_do_add,		HELP_ADD		},
14599653d4eSeschrock 	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
146fa9e4066Sahrens 	{ NULL },
14765cd9f28Seschrock 	{ "list",	zpool_do_list,		HELP_LIST		},
14865cd9f28Seschrock 	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
14965cd9f28Seschrock 	{ "status",	zpool_do_status,	HELP_STATUS		},
150fa9e4066Sahrens 	{ NULL },
15165cd9f28Seschrock 	{ "online",	zpool_do_online,	HELP_ONLINE		},
15265cd9f28Seschrock 	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
153ea8dc4b6Seschrock 	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
154fa9e4066Sahrens 	{ NULL },
15565cd9f28Seschrock 	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
15665cd9f28Seschrock 	{ "detach",	zpool_do_detach,	HELP_DETACH		},
15765cd9f28Seschrock 	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
158fa9e4066Sahrens 	{ NULL },
15965cd9f28Seschrock 	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
160fa9e4066Sahrens 	{ NULL },
16165cd9f28Seschrock 	{ "import",	zpool_do_import,	HELP_IMPORT		},
16265cd9f28Seschrock 	{ "export",	zpool_do_export,	HELP_EXPORT		},
16306eeb2adSek110237 	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
16406eeb2adSek110237 	{ NULL },
165b1b8ab34Slling 	{ "history",	zpool_do_history,	HELP_HISTORY		},
166b1b8ab34Slling 	{ "get",	zpool_do_get,		HELP_GET		},
167b1b8ab34Slling 	{ "set",	zpool_do_set,		HELP_SET		},
168fa9e4066Sahrens };
169fa9e4066Sahrens 
170fa9e4066Sahrens #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
171fa9e4066Sahrens 
172fa9e4066Sahrens zpool_command_t *current_command;
1732a6b87f0Sek110237 static char history_str[HIS_MAX_RECORD_LEN];
174fa9e4066Sahrens 
17565cd9f28Seschrock static const char *
17665cd9f28Seschrock get_usage(zpool_help_t idx) {
17765cd9f28Seschrock 	switch (idx) {
17865cd9f28Seschrock 	case HELP_ADD:
17965cd9f28Seschrock 		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
18065cd9f28Seschrock 	case HELP_ATTACH:
18165cd9f28Seschrock 		return (gettext("\tattach [-f] <pool> <device> "
182e45ce728Sahrens 		    "<new-device>\n"));
183ea8dc4b6Seschrock 	case HELP_CLEAR:
184ea8dc4b6Seschrock 		return (gettext("\tclear <pool> [device]\n"));
18565cd9f28Seschrock 	case HELP_CREATE:
186990b4856Slling 		return (gettext("\tcreate [-fn] [-o property=value] ... \n"
187990b4856Slling 		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
18865cd9f28Seschrock 	case HELP_DESTROY:
18965cd9f28Seschrock 		return (gettext("\tdestroy [-f] <pool>\n"));
19065cd9f28Seschrock 	case HELP_DETACH:
19165cd9f28Seschrock 		return (gettext("\tdetach <pool> <device>\n"));
19265cd9f28Seschrock 	case HELP_EXPORT:
19365cd9f28Seschrock 		return (gettext("\texport [-f] <pool> ...\n"));
19406eeb2adSek110237 	case HELP_HISTORY:
195ecd6cf80Smarks 		return (gettext("\thistory [-il] [<pool>] ...\n"));
19665cd9f28Seschrock 	case HELP_IMPORT:
1974c58d714Sdarrenm 		return (gettext("\timport [-d dir] [-D]\n"
1982f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
1992f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n"
2002f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
2012f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] "
2022f8aaab3Seschrock 		    "<pool | id> [newpool]\n"));
20365cd9f28Seschrock 	case HELP_IOSTAT:
20465cd9f28Seschrock 		return (gettext("\tiostat [-v] [pool] ... [interval "
20565cd9f28Seschrock 		    "[count]]\n"));
20665cd9f28Seschrock 	case HELP_LIST:
207990b4856Slling 		return (gettext("\tlist [-H] [-o property[,...]] "
208990b4856Slling 		    "[pool] ...\n"));
20965cd9f28Seschrock 	case HELP_OFFLINE:
210441d80aaSlling 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
21165cd9f28Seschrock 	case HELP_ONLINE:
212441d80aaSlling 		return (gettext("\tonline <pool> <device> ...\n"));
21365cd9f28Seschrock 	case HELP_REPLACE:
21465cd9f28Seschrock 		return (gettext("\treplace [-f] <pool> <device> "
215e45ce728Sahrens 		    "[new-device]\n"));
21699653d4eSeschrock 	case HELP_REMOVE:
217fa94a07fSbrendan 		return (gettext("\tremove <pool> <device> ...\n"));
21865cd9f28Seschrock 	case HELP_SCRUB:
21965cd9f28Seschrock 		return (gettext("\tscrub [-s] <pool> ...\n"));
22065cd9f28Seschrock 	case HELP_STATUS:
22165cd9f28Seschrock 		return (gettext("\tstatus [-vx] [pool] ...\n"));
222eaca9bbdSeschrock 	case HELP_UPGRADE:
223eaca9bbdSeschrock 		return (gettext("\tupgrade\n"
224eaca9bbdSeschrock 		    "\tupgrade -v\n"
225990b4856Slling 		    "\tupgrade [-V version] <-a | pool ...>\n"));
226b1b8ab34Slling 	case HELP_GET:
227e45ce728Sahrens 		return (gettext("\tget <\"all\" | property[,...]> "
228b1b8ab34Slling 		    "<pool> ...\n"));
229b1b8ab34Slling 	case HELP_SET:
230b1b8ab34Slling 		return (gettext("\tset <property=value> <pool> \n"));
23165cd9f28Seschrock 	}
23265cd9f28Seschrock 
23365cd9f28Seschrock 	abort();
23465cd9f28Seschrock 	/* NOTREACHED */
23565cd9f28Seschrock }
23665cd9f28Seschrock 
237fa9e4066Sahrens 
238fa9e4066Sahrens /*
239b1b8ab34Slling  * Callback routine that will print out a pool property value.
240b1b8ab34Slling  */
241990b4856Slling static int
242990b4856Slling print_prop_cb(int prop, void *cb)
243b1b8ab34Slling {
244b1b8ab34Slling 	FILE *fp = cb;
245b1b8ab34Slling 
246b1b8ab34Slling 	(void) fprintf(fp, "\t%-13s  ", zpool_prop_to_name(prop));
247b1b8ab34Slling 
248990b4856Slling 	if (zpool_prop_readonly(prop))
249990b4856Slling 		(void) fprintf(fp, "  NO   ");
250990b4856Slling 	else
251990b4856Slling 		(void) fprintf(fp, " YES    ");
252990b4856Slling 
253b1b8ab34Slling 	if (zpool_prop_values(prop) == NULL)
254b1b8ab34Slling 		(void) fprintf(fp, "-\n");
255b1b8ab34Slling 	else
256b1b8ab34Slling 		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
257b1b8ab34Slling 
258990b4856Slling 	return (ZPROP_CONT);
259b1b8ab34Slling }
260b1b8ab34Slling 
261b1b8ab34Slling /*
262fa9e4066Sahrens  * Display usage message.  If we're inside a command, display only the usage for
263fa9e4066Sahrens  * that command.  Otherwise, iterate over the entire command table and display
264fa9e4066Sahrens  * a complete usage message.
265fa9e4066Sahrens  */
266fa9e4066Sahrens void
26799653d4eSeschrock usage(boolean_t requested)
268fa9e4066Sahrens {
269fa9e4066Sahrens 	FILE *fp = requested ? stdout : stderr;
270fa9e4066Sahrens 
271fa9e4066Sahrens 	if (current_command == NULL) {
272fa9e4066Sahrens 		int i;
273fa9e4066Sahrens 
274fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
275fa9e4066Sahrens 		(void) fprintf(fp,
276fa9e4066Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
277fa9e4066Sahrens 
278fa9e4066Sahrens 		for (i = 0; i < NCOMMAND; i++) {
279fa9e4066Sahrens 			if (command_table[i].name == NULL)
280fa9e4066Sahrens 				(void) fprintf(fp, "\n");
281fa9e4066Sahrens 			else
282fa9e4066Sahrens 				(void) fprintf(fp, "%s",
28365cd9f28Seschrock 				    get_usage(command_table[i].usage));
284fa9e4066Sahrens 		}
285fa9e4066Sahrens 	} else {
286fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
28765cd9f28Seschrock 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
288fa9e4066Sahrens 	}
289fa9e4066Sahrens 
290b1b8ab34Slling 	if (current_command != NULL &&
291b1b8ab34Slling 	    ((strcmp(current_command->name, "set") == 0) ||
292990b4856Slling 	    (strcmp(current_command->name, "get") == 0) ||
293990b4856Slling 	    (strcmp(current_command->name, "list") == 0))) {
294b1b8ab34Slling 
295b1b8ab34Slling 		(void) fprintf(fp,
296b1b8ab34Slling 		    gettext("\nthe following properties are supported:\n"));
297b1b8ab34Slling 
298990b4856Slling 		(void) fprintf(fp, "\n\t%-13s  %s  %s\n\n",
299990b4856Slling 		    "PROPERTY", "EDIT", "VALUES");
300b1b8ab34Slling 
301b1b8ab34Slling 		/* Iterate over all properties */
302990b4856Slling 		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
303990b4856Slling 		    ZFS_TYPE_POOL);
304b1b8ab34Slling 	}
305b1b8ab34Slling 
306e9dbad6fSeschrock 	/*
307e9dbad6fSeschrock 	 * See comments at end of main().
308e9dbad6fSeschrock 	 */
309e9dbad6fSeschrock 	if (getenv("ZFS_ABORT") != NULL) {
310e9dbad6fSeschrock 		(void) printf("dumping core by request\n");
311e9dbad6fSeschrock 		abort();
312e9dbad6fSeschrock 	}
313e9dbad6fSeschrock 
314fa9e4066Sahrens 	exit(requested ? 0 : 2);
315fa9e4066Sahrens }
316fa9e4066Sahrens 
317fa9e4066Sahrens void
3188654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
3198654d025Sperrin     boolean_t print_logs)
320fa9e4066Sahrens {
321fa9e4066Sahrens 	nvlist_t **child;
322fa9e4066Sahrens 	uint_t c, children;
323afefbcddSeschrock 	char *vname;
324fa9e4066Sahrens 
325fa9e4066Sahrens 	if (name != NULL)
326fa9e4066Sahrens 		(void) printf("\t%*s%s\n", indent, "", name);
327fa9e4066Sahrens 
328fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
329fa9e4066Sahrens 	    &child, &children) != 0)
330fa9e4066Sahrens 		return;
331fa9e4066Sahrens 
332afefbcddSeschrock 	for (c = 0; c < children; c++) {
3338654d025Sperrin 		uint64_t is_log = B_FALSE;
3348654d025Sperrin 
3358654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3368654d025Sperrin 		    &is_log);
3378654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
3388654d025Sperrin 			continue;
3398654d025Sperrin 
34099653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
3418654d025Sperrin 		print_vdev_tree(zhp, vname, child[c], indent + 2,
3428654d025Sperrin 		    B_FALSE);
343afefbcddSeschrock 		free(vname);
344afefbcddSeschrock 	}
345fa9e4066Sahrens }
346fa9e4066Sahrens 
347fa9e4066Sahrens /*
348990b4856Slling  * Add a property pair (name, string-value) into a property nvlist.
349990b4856Slling  */
350990b4856Slling static int
351990b4856Slling add_prop_list(const char *propname, char *propval, nvlist_t **props)
352990b4856Slling {
353990b4856Slling 	char *strval;
354990b4856Slling 	nvlist_t *proplist;
355990b4856Slling 	zpool_prop_t prop;
356990b4856Slling 
357990b4856Slling 	if (*props == NULL &&
358990b4856Slling 	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
359990b4856Slling 		(void) fprintf(stderr,
360990b4856Slling 		    gettext("internal error: out of memory\n"));
361990b4856Slling 		return (1);
362990b4856Slling 	}
363990b4856Slling 
364990b4856Slling 	proplist = *props;
365990b4856Slling 
366990b4856Slling 	if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
367990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' is "
368990b4856Slling 		    "not a valid pool property\n"), propname);
369990b4856Slling 		return (2);
370990b4856Slling 	}
371990b4856Slling 
372990b4856Slling 	/* Use normalized property name for nvlist operations */
373990b4856Slling 	if (nvlist_lookup_string(proplist, zpool_prop_to_name(prop),
3742f8aaab3Seschrock 	    &strval) == 0 && prop != ZPOOL_PROP_CACHEFILE) {
375990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' "
376990b4856Slling 		    "specified multiple times\n"), propname);
377990b4856Slling 		return (2);
378990b4856Slling 	}
379990b4856Slling 
380990b4856Slling 	if (nvlist_add_string(proplist, zpool_prop_to_name(prop),
381990b4856Slling 	    propval) != 0) {
382990b4856Slling 		(void) fprintf(stderr, gettext("internal "
383990b4856Slling 		    "error: out of memory\n"));
384990b4856Slling 		return (1);
385990b4856Slling 	}
386990b4856Slling 
387990b4856Slling 	return (0);
388990b4856Slling }
389990b4856Slling 
390990b4856Slling /*
391fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
392fa9e4066Sahrens  *
393fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
394fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
395fa9e4066Sahrens  *		they were to be added.
396fa9e4066Sahrens  *
397fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
398fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
399fa9e4066Sahrens  * libzfs.
400fa9e4066Sahrens  */
401fa9e4066Sahrens int
402fa9e4066Sahrens zpool_do_add(int argc, char **argv)
403fa9e4066Sahrens {
40499653d4eSeschrock 	boolean_t force = B_FALSE;
40599653d4eSeschrock 	boolean_t dryrun = B_FALSE;
406fa9e4066Sahrens 	int c;
407fa9e4066Sahrens 	nvlist_t *nvroot;
408fa9e4066Sahrens 	char *poolname;
409fa9e4066Sahrens 	int ret;
410fa9e4066Sahrens 	zpool_handle_t *zhp;
411fa9e4066Sahrens 	nvlist_t *config;
412fa9e4066Sahrens 
413fa9e4066Sahrens 	/* check options */
414fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
415fa9e4066Sahrens 		switch (c) {
416fa9e4066Sahrens 		case 'f':
41799653d4eSeschrock 			force = B_TRUE;
418fa9e4066Sahrens 			break;
419fa9e4066Sahrens 		case 'n':
42099653d4eSeschrock 			dryrun = B_TRUE;
421fa9e4066Sahrens 			break;
422fa9e4066Sahrens 		case '?':
423fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
424fa9e4066Sahrens 			    optopt);
42599653d4eSeschrock 			usage(B_FALSE);
426fa9e4066Sahrens 		}
427fa9e4066Sahrens 	}
428fa9e4066Sahrens 
429fa9e4066Sahrens 	argc -= optind;
430fa9e4066Sahrens 	argv += optind;
431fa9e4066Sahrens 
432fa9e4066Sahrens 	/* get pool name and check number of arguments */
433fa9e4066Sahrens 	if (argc < 1) {
434fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
43599653d4eSeschrock 		usage(B_FALSE);
436fa9e4066Sahrens 	}
437fa9e4066Sahrens 	if (argc < 2) {
438fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
43999653d4eSeschrock 		usage(B_FALSE);
440fa9e4066Sahrens 	}
441fa9e4066Sahrens 
442fa9e4066Sahrens 	poolname = argv[0];
443fa9e4066Sahrens 
444fa9e4066Sahrens 	argc--;
445fa9e4066Sahrens 	argv++;
446fa9e4066Sahrens 
44799653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
448fa9e4066Sahrens 		return (1);
449fa9e4066Sahrens 
450088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
451fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
452fa9e4066Sahrens 		    poolname);
453fa9e4066Sahrens 		zpool_close(zhp);
454fa9e4066Sahrens 		return (1);
455fa9e4066Sahrens 	}
456fa9e4066Sahrens 
457fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
4588488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv);
459fa9e4066Sahrens 	if (nvroot == NULL) {
460fa9e4066Sahrens 		zpool_close(zhp);
461fa9e4066Sahrens 		return (1);
462fa9e4066Sahrens 	}
463fa9e4066Sahrens 
464fa9e4066Sahrens 	if (dryrun) {
465fa9e4066Sahrens 		nvlist_t *poolnvroot;
466fa9e4066Sahrens 
467fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
468fa9e4066Sahrens 		    &poolnvroot) == 0);
469fa9e4066Sahrens 
470fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
471fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
472fa9e4066Sahrens 
4738654d025Sperrin 		/* print original main pool and new tree */
4748654d025Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
4758654d025Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
4768654d025Sperrin 
4778654d025Sperrin 		/* Do the same for the logs */
4788654d025Sperrin 		if (num_logs(poolnvroot) > 0) {
4798654d025Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
4808654d025Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
4818654d025Sperrin 		} else if (num_logs(nvroot) > 0) {
4828654d025Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
4838654d025Sperrin 		}
484fa9e4066Sahrens 
485fa9e4066Sahrens 		ret = 0;
486fa9e4066Sahrens 	} else {
487fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
488fa9e4066Sahrens 	}
489fa9e4066Sahrens 
49099653d4eSeschrock 	nvlist_free(nvroot);
49199653d4eSeschrock 	zpool_close(zhp);
49299653d4eSeschrock 
49399653d4eSeschrock 	return (ret);
49499653d4eSeschrock }
49599653d4eSeschrock 
49699653d4eSeschrock /*
497fa94a07fSbrendan  * zpool remove <pool> <vdev> ...
49899653d4eSeschrock  *
49999653d4eSeschrock  * Removes the given vdev from the pool.  Currently, this only supports removing
500fa94a07fSbrendan  * spares and cache devices from the pool.  Eventually, we'll want to support
501fa94a07fSbrendan  * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs.
50299653d4eSeschrock  */
50399653d4eSeschrock int
50499653d4eSeschrock zpool_do_remove(int argc, char **argv)
50599653d4eSeschrock {
50699653d4eSeschrock 	char *poolname;
507fa94a07fSbrendan 	int i, ret = 0;
50899653d4eSeschrock 	zpool_handle_t *zhp;
50999653d4eSeschrock 
51099653d4eSeschrock 	argc--;
51199653d4eSeschrock 	argv++;
51299653d4eSeschrock 
51399653d4eSeschrock 	/* get pool name and check number of arguments */
51499653d4eSeschrock 	if (argc < 1) {
51599653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
51699653d4eSeschrock 		usage(B_FALSE);
51799653d4eSeschrock 	}
51899653d4eSeschrock 	if (argc < 2) {
51999653d4eSeschrock 		(void) fprintf(stderr, gettext("missing device\n"));
52099653d4eSeschrock 		usage(B_FALSE);
52199653d4eSeschrock 	}
52299653d4eSeschrock 
52399653d4eSeschrock 	poolname = argv[0];
52499653d4eSeschrock 
52599653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
52699653d4eSeschrock 		return (1);
52799653d4eSeschrock 
528fa94a07fSbrendan 	for (i = 1; i < argc; i++) {
529fa94a07fSbrendan 		if (zpool_vdev_remove(zhp, argv[i]) != 0)
530fa94a07fSbrendan 			ret = 1;
531fa94a07fSbrendan 	}
53299653d4eSeschrock 
533fa9e4066Sahrens 	return (ret);
534fa9e4066Sahrens }
535fa9e4066Sahrens 
536fa9e4066Sahrens /*
537990b4856Slling  * zpool create [-fn] [-o property=value] ... [-R root] [-m mountpoint]
538990b4856Slling  *		<pool> <dev> ...
539fa9e4066Sahrens  *
540fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
541fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
542fa9e4066Sahrens  *		were to be created.
543fa9e4066Sahrens  *      -R	Create a pool under an alternate root
544fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
545fa9e4066Sahrens  *      	'/<pool>'
546990b4856Slling  *	-o	Set property=value.
547fa9e4066Sahrens  *
548b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
549fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
550fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
551fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
552fa9e4066Sahrens  */
553fa9e4066Sahrens int
554fa9e4066Sahrens zpool_do_create(int argc, char **argv)
555fa9e4066Sahrens {
55699653d4eSeschrock 	boolean_t force = B_FALSE;
55799653d4eSeschrock 	boolean_t dryrun = B_FALSE;
558fa9e4066Sahrens 	int c;
559990b4856Slling 	nvlist_t *nvroot = NULL;
560fa9e4066Sahrens 	char *poolname;
561990b4856Slling 	int ret = 1;
562fa9e4066Sahrens 	char *altroot = NULL;
563fa9e4066Sahrens 	char *mountpoint = NULL;
564990b4856Slling 	nvlist_t *props = NULL;
5652f8aaab3Seschrock 	char *propval;
566fa9e4066Sahrens 
567fa9e4066Sahrens 	/* check options */
568990b4856Slling 	while ((c = getopt(argc, argv, ":fnR:m:o:")) != -1) {
569fa9e4066Sahrens 		switch (c) {
570fa9e4066Sahrens 		case 'f':
57199653d4eSeschrock 			force = B_TRUE;
572fa9e4066Sahrens 			break;
573fa9e4066Sahrens 		case 'n':
57499653d4eSeschrock 			dryrun = B_TRUE;
575fa9e4066Sahrens 			break;
576fa9e4066Sahrens 		case 'R':
577fa9e4066Sahrens 			altroot = optarg;
578990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
579990b4856Slling 			    ZPOOL_PROP_ALTROOT), optarg, &props))
580990b4856Slling 				goto errout;
5812f8aaab3Seschrock 			if (nvlist_lookup_string(props,
5822f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
5832f8aaab3Seschrock 			    &propval) == 0)
5842f8aaab3Seschrock 				break;
585990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
5862f8aaab3Seschrock 			    ZPOOL_PROP_CACHEFILE), "none", &props))
587990b4856Slling 				goto errout;
588fa9e4066Sahrens 			break;
589fa9e4066Sahrens 		case 'm':
590fa9e4066Sahrens 			mountpoint = optarg;
591fa9e4066Sahrens 			break;
592990b4856Slling 		case 'o':
593990b4856Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
594990b4856Slling 				(void) fprintf(stderr, gettext("missing "
595990b4856Slling 				    "'=' for -o option\n"));
596990b4856Slling 				goto errout;
597990b4856Slling 			}
598990b4856Slling 			*propval = '\0';
599990b4856Slling 			propval++;
600990b4856Slling 
601990b4856Slling 			if (add_prop_list(optarg, propval, &props))
602990b4856Slling 				goto errout;
603990b4856Slling 			break;
604fa9e4066Sahrens 		case ':':
605fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
606fa9e4066Sahrens 			    "'%c' option\n"), optopt);
607990b4856Slling 			goto badusage;
608fa9e4066Sahrens 		case '?':
609fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
610fa9e4066Sahrens 			    optopt);
611990b4856Slling 			goto badusage;
612fa9e4066Sahrens 		}
613fa9e4066Sahrens 	}
614fa9e4066Sahrens 
615fa9e4066Sahrens 	argc -= optind;
616fa9e4066Sahrens 	argv += optind;
617fa9e4066Sahrens 
618fa9e4066Sahrens 	/* get pool name and check number of arguments */
619fa9e4066Sahrens 	if (argc < 1) {
620fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
621990b4856Slling 		goto badusage;
622fa9e4066Sahrens 	}
623fa9e4066Sahrens 	if (argc < 2) {
624fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
625990b4856Slling 		goto badusage;
626fa9e4066Sahrens 	}
627fa9e4066Sahrens 
628fa9e4066Sahrens 	poolname = argv[0];
629fa9e4066Sahrens 
630fa9e4066Sahrens 	/*
631fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
632fa9e4066Sahrens 	 * user to use 'zfs create' instead.
633fa9e4066Sahrens 	 */
634fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
635fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
636fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
637fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
638fa9e4066Sahrens 		    "create a dataset\n"));
639990b4856Slling 		goto errout;
640fa9e4066Sahrens 	}
641fa9e4066Sahrens 
642fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
64399653d4eSeschrock 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1,
64499653d4eSeschrock 	    argv + 1);
645fa9e4066Sahrens 	if (nvroot == NULL)
646fa9e4066Sahrens 		return (1);
647fa9e4066Sahrens 
64899653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
649b7b97454Sperrin 	if (!zfs_allocatable_devs(nvroot)) {
65099653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
65199653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
65299653d4eSeschrock 		    "specified\n"));
653990b4856Slling 		goto errout;
65499653d4eSeschrock 	}
65599653d4eSeschrock 
65699653d4eSeschrock 
657fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
658fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
659e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
660990b4856Slling 		goto errout;
661fa9e4066Sahrens 	}
662fa9e4066Sahrens 
663fa9e4066Sahrens 	/*
664fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
665fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
666fa9e4066Sahrens 	 */
667fa9e4066Sahrens 	if (mountpoint == NULL ||
668fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
669fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
670fa9e4066Sahrens 		char buf[MAXPATHLEN];
67111022c7cStimh 		DIR *dirp;
672fa9e4066Sahrens 
673fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
674fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
675fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
676fa9e4066Sahrens 			    "'none'\n"), mountpoint);
677990b4856Slling 			goto errout;
678fa9e4066Sahrens 		}
679fa9e4066Sahrens 
680fa9e4066Sahrens 		if (mountpoint == NULL) {
681fa9e4066Sahrens 			if (altroot != NULL)
682fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
683fa9e4066Sahrens 				    altroot, poolname);
684fa9e4066Sahrens 			else
685fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
686fa9e4066Sahrens 				    poolname);
687fa9e4066Sahrens 		} else {
688fa9e4066Sahrens 			if (altroot != NULL)
689fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
690fa9e4066Sahrens 				    altroot, mountpoint);
691fa9e4066Sahrens 			else
692fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
693fa9e4066Sahrens 				    mountpoint);
694fa9e4066Sahrens 		}
695fa9e4066Sahrens 
69611022c7cStimh 		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
69711022c7cStimh 			(void) fprintf(stderr, gettext("mountpoint '%s' : "
69811022c7cStimh 			    "%s\n"), buf, strerror(errno));
699fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
700fa9e4066Sahrens 			    "option to provide a different default\n"));
701990b4856Slling 			goto errout;
70211022c7cStimh 		} else if (dirp) {
70311022c7cStimh 			int count = 0;
70411022c7cStimh 
70511022c7cStimh 			while (count < 3 && readdir(dirp) != NULL)
70611022c7cStimh 				count++;
70711022c7cStimh 			(void) closedir(dirp);
70811022c7cStimh 
70911022c7cStimh 			if (count > 2) {
71011022c7cStimh 				(void) fprintf(stderr, gettext("mountpoint "
71111022c7cStimh 				    "'%s' exists and is not empty\n"), buf);
71211022c7cStimh 				(void) fprintf(stderr, gettext("use '-m' "
71311022c7cStimh 				    "option to provide a "
71411022c7cStimh 				    "different default\n"));
71511022c7cStimh 				goto errout;
71611022c7cStimh 			}
717fa9e4066Sahrens 		}
718fa9e4066Sahrens 	}
719fa9e4066Sahrens 
720fa9e4066Sahrens 	if (dryrun) {
721fa9e4066Sahrens 		/*
722fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
723fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
724fa9e4066Sahrens 		 * appropriate hierarchy.
725fa9e4066Sahrens 		 */
726fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
727fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
728fa9e4066Sahrens 
7298654d025Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7308654d025Sperrin 		if (num_logs(nvroot) > 0)
7318654d025Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
732fa9e4066Sahrens 
733fa9e4066Sahrens 		ret = 0;
734fa9e4066Sahrens 	} else {
735fa9e4066Sahrens 		/*
736fa9e4066Sahrens 		 * Hand off to libzfs.
737fa9e4066Sahrens 		 */
738990b4856Slling 		if (zpool_create(g_zfs, poolname, nvroot, props) == 0) {
73999653d4eSeschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
740fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
741fa9e4066Sahrens 			if (pool != NULL) {
742fa9e4066Sahrens 				if (mountpoint != NULL)
743fa9e4066Sahrens 					verify(zfs_prop_set(pool,
744e9dbad6fSeschrock 					    zfs_prop_to_name(
745e9dbad6fSeschrock 					    ZFS_PROP_MOUNTPOINT),
746fa9e4066Sahrens 					    mountpoint) == 0);
747fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
748da6c28aaSamw 					ret = zfs_shareall(pool);
749fa9e4066Sahrens 				zfs_close(pool);
750fa9e4066Sahrens 			}
75199653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
75299653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
75399653d4eSeschrock 			    "been omitted\n"));
754fa9e4066Sahrens 		}
755fa9e4066Sahrens 	}
756fa9e4066Sahrens 
757990b4856Slling errout:
758fa9e4066Sahrens 	nvlist_free(nvroot);
759990b4856Slling 	nvlist_free(props);
760fa9e4066Sahrens 	return (ret);
761990b4856Slling badusage:
762990b4856Slling 	nvlist_free(props);
763990b4856Slling 	usage(B_FALSE);
764990b4856Slling 	return (2);
765fa9e4066Sahrens }
766fa9e4066Sahrens 
767fa9e4066Sahrens /*
768fa9e4066Sahrens  * zpool destroy <pool>
769fa9e4066Sahrens  *
770fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
771fa9e4066Sahrens  *
772fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
773fa9e4066Sahrens  */
774fa9e4066Sahrens int
775fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
776fa9e4066Sahrens {
77799653d4eSeschrock 	boolean_t force = B_FALSE;
778fa9e4066Sahrens 	int c;
779fa9e4066Sahrens 	char *pool;
780fa9e4066Sahrens 	zpool_handle_t *zhp;
781fa9e4066Sahrens 	int ret;
782fa9e4066Sahrens 
783fa9e4066Sahrens 	/* check options */
784fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
785fa9e4066Sahrens 		switch (c) {
786fa9e4066Sahrens 		case 'f':
78799653d4eSeschrock 			force = B_TRUE;
788fa9e4066Sahrens 			break;
789fa9e4066Sahrens 		case '?':
790fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
791fa9e4066Sahrens 			    optopt);
79299653d4eSeschrock 			usage(B_FALSE);
793fa9e4066Sahrens 		}
794fa9e4066Sahrens 	}
795fa9e4066Sahrens 
796fa9e4066Sahrens 	argc -= optind;
797fa9e4066Sahrens 	argv += optind;
798fa9e4066Sahrens 
799fa9e4066Sahrens 	/* check arguments */
800fa9e4066Sahrens 	if (argc < 1) {
801fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
80299653d4eSeschrock 		usage(B_FALSE);
803fa9e4066Sahrens 	}
804fa9e4066Sahrens 	if (argc > 1) {
805fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
80699653d4eSeschrock 		usage(B_FALSE);
807fa9e4066Sahrens 	}
808fa9e4066Sahrens 
809fa9e4066Sahrens 	pool = argv[0];
810fa9e4066Sahrens 
81199653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
812fa9e4066Sahrens 		/*
813fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
814fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
815fa9e4066Sahrens 		 */
816fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
817fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
818fa9e4066Sahrens 			    "destroy a dataset\n"));
819fa9e4066Sahrens 		return (1);
820fa9e4066Sahrens 	}
821fa9e4066Sahrens 
822f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
823fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
824fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
825fa9e4066Sahrens 		return (1);
826fa9e4066Sahrens 	}
827fa9e4066Sahrens 
828fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
829fa9e4066Sahrens 
830fa9e4066Sahrens 	zpool_close(zhp);
831fa9e4066Sahrens 
832fa9e4066Sahrens 	return (ret);
833fa9e4066Sahrens }
834fa9e4066Sahrens 
835fa9e4066Sahrens /*
836fa9e4066Sahrens  * zpool export [-f] <pool> ...
837fa9e4066Sahrens  *
838fa9e4066Sahrens  *	-f	Forcefully unmount datasets
839fa9e4066Sahrens  *
840b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
841fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
842fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
843fa9e4066Sahrens  */
844fa9e4066Sahrens int
845fa9e4066Sahrens zpool_do_export(int argc, char **argv)
846fa9e4066Sahrens {
84799653d4eSeschrock 	boolean_t force = B_FALSE;
848fa9e4066Sahrens 	int c;
849fa9e4066Sahrens 	zpool_handle_t *zhp;
850fa9e4066Sahrens 	int ret;
851fa9e4066Sahrens 	int i;
852fa9e4066Sahrens 
853fa9e4066Sahrens 	/* check options */
854fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
855fa9e4066Sahrens 		switch (c) {
856fa9e4066Sahrens 		case 'f':
85799653d4eSeschrock 			force = B_TRUE;
858fa9e4066Sahrens 			break;
859fa9e4066Sahrens 		case '?':
860fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
861fa9e4066Sahrens 			    optopt);
86299653d4eSeschrock 			usage(B_FALSE);
863fa9e4066Sahrens 		}
864fa9e4066Sahrens 	}
865fa9e4066Sahrens 
866fa9e4066Sahrens 	argc -= optind;
867fa9e4066Sahrens 	argv += optind;
868fa9e4066Sahrens 
869fa9e4066Sahrens 	/* check arguments */
870fa9e4066Sahrens 	if (argc < 1) {
871fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
87299653d4eSeschrock 		usage(B_FALSE);
873fa9e4066Sahrens 	}
874fa9e4066Sahrens 
875fa9e4066Sahrens 	ret = 0;
876fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
87799653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
878fa9e4066Sahrens 			ret = 1;
879fa9e4066Sahrens 			continue;
880fa9e4066Sahrens 		}
881fa9e4066Sahrens 
882f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
883fa9e4066Sahrens 			ret = 1;
884fa9e4066Sahrens 			zpool_close(zhp);
885fa9e4066Sahrens 			continue;
886fa9e4066Sahrens 		}
887fa9e4066Sahrens 
888fa9e4066Sahrens 		if (zpool_export(zhp) != 0)
889fa9e4066Sahrens 			ret = 1;
890fa9e4066Sahrens 
891fa9e4066Sahrens 		zpool_close(zhp);
892fa9e4066Sahrens 	}
893fa9e4066Sahrens 
894fa9e4066Sahrens 	return (ret);
895fa9e4066Sahrens }
896fa9e4066Sahrens 
897fa9e4066Sahrens /*
898fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
899fa9e4066Sahrens  * name column.
900fa9e4066Sahrens  */
901fa9e4066Sahrens static int
902c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
903fa9e4066Sahrens {
90499653d4eSeschrock 	char *name = zpool_vdev_name(g_zfs, zhp, nv);
905fa9e4066Sahrens 	nvlist_t **child;
906fa9e4066Sahrens 	uint_t c, children;
907fa9e4066Sahrens 	int ret;
908fa9e4066Sahrens 
909fa9e4066Sahrens 	if (strlen(name) + depth > max)
910fa9e4066Sahrens 		max = strlen(name) + depth;
911fa9e4066Sahrens 
912afefbcddSeschrock 	free(name);
913afefbcddSeschrock 
91499653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
91599653d4eSeschrock 	    &child, &children) == 0) {
916fa9e4066Sahrens 		for (c = 0; c < children; c++)
91799653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
91899653d4eSeschrock 			    max)) > max)
919fa9e4066Sahrens 				max = ret;
92099653d4eSeschrock 	}
92199653d4eSeschrock 
922fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
923fa94a07fSbrendan 	    &child, &children) == 0) {
924fa94a07fSbrendan 		for (c = 0; c < children; c++)
925fa94a07fSbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
926fa94a07fSbrendan 			    max)) > max)
927fa94a07fSbrendan 				max = ret;
928fa94a07fSbrendan 	}
929fa94a07fSbrendan 
93099653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
93199653d4eSeschrock 	    &child, &children) == 0) {
93299653d4eSeschrock 		for (c = 0; c < children; c++)
93399653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
93499653d4eSeschrock 			    max)) > max)
93599653d4eSeschrock 				max = ret;
93699653d4eSeschrock 	}
93799653d4eSeschrock 
938fa9e4066Sahrens 
939fa9e4066Sahrens 	return (max);
940fa9e4066Sahrens }
941fa9e4066Sahrens 
942fa9e4066Sahrens 
943fa9e4066Sahrens /*
944fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
945fa9e4066Sahrens  * pool, printing out the name and status for each one.
946fa9e4066Sahrens  */
947fa9e4066Sahrens void
9488654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
9498654d025Sperrin     boolean_t print_logs)
950fa9e4066Sahrens {
951fa9e4066Sahrens 	nvlist_t **child;
952fa9e4066Sahrens 	uint_t c, children;
953fa9e4066Sahrens 	vdev_stat_t *vs;
954afefbcddSeschrock 	char *type, *vname;
955fa9e4066Sahrens 
956fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
957fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
958fa9e4066Sahrens 		return;
959fa9e4066Sahrens 
960fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
961fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
962fa9e4066Sahrens 
963fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
964990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
965fa9e4066Sahrens 
966fa9e4066Sahrens 	if (vs->vs_aux != 0) {
9673d7072f8Seschrock 		(void) printf("  ");
968fa9e4066Sahrens 
969fa9e4066Sahrens 		switch (vs->vs_aux) {
970fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
971fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
972fa9e4066Sahrens 			break;
973fa9e4066Sahrens 
974fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
975fa9e4066Sahrens 			(void) printf(gettext("missing device"));
976fa9e4066Sahrens 			break;
977fa9e4066Sahrens 
978fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
979fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
980fa9e4066Sahrens 			break;
981fa9e4066Sahrens 
982eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
983eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
984eaca9bbdSeschrock 			break;
985eaca9bbdSeschrock 
9863d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
9873d7072f8Seschrock 			(void) printf(gettext("too many errors"));
9883d7072f8Seschrock 			break;
9893d7072f8Seschrock 
990fa9e4066Sahrens 		default:
991fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
992fa9e4066Sahrens 			break;
993fa9e4066Sahrens 		}
994fa9e4066Sahrens 	}
995fa9e4066Sahrens 	(void) printf("\n");
996fa9e4066Sahrens 
997fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
998fa9e4066Sahrens 	    &child, &children) != 0)
999fa9e4066Sahrens 		return;
1000fa9e4066Sahrens 
1001afefbcddSeschrock 	for (c = 0; c < children; c++) {
10028654d025Sperrin 		uint64_t is_log = B_FALSE;
10038654d025Sperrin 
10048654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
10058654d025Sperrin 		    &is_log);
10068654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
10078654d025Sperrin 			continue;
10088654d025Sperrin 
100999653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1010afefbcddSeschrock 		print_import_config(vname, child[c],
10118654d025Sperrin 		    namewidth, depth + 2, B_FALSE);
1012afefbcddSeschrock 		free(vname);
1013afefbcddSeschrock 	}
101499653d4eSeschrock 
1015fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1016fa94a07fSbrendan 	    &child, &children) == 0) {
1017fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
1018fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1019fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1020fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1021fa94a07fSbrendan 			free(vname);
1022fa94a07fSbrendan 		}
1023fa94a07fSbrendan 	}
102499653d4eSeschrock 
1025fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1026fa94a07fSbrendan 	    &child, &children) == 0) {
102799653d4eSeschrock 		(void) printf(gettext("\tspares\n"));
102899653d4eSeschrock 		for (c = 0; c < children; c++) {
102999653d4eSeschrock 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
103099653d4eSeschrock 			(void) printf("\t  %s\n", vname);
103199653d4eSeschrock 			free(vname);
103299653d4eSeschrock 		}
1033fa9e4066Sahrens 	}
1034fa94a07fSbrendan }
1035fa9e4066Sahrens 
1036fa9e4066Sahrens /*
1037fa9e4066Sahrens  * Display the status for the given pool.
1038fa9e4066Sahrens  */
1039fa9e4066Sahrens static void
1040fa9e4066Sahrens show_import(nvlist_t *config)
1041fa9e4066Sahrens {
1042fa9e4066Sahrens 	uint64_t pool_state;
1043fa9e4066Sahrens 	vdev_stat_t *vs;
1044fa9e4066Sahrens 	char *name;
1045fa9e4066Sahrens 	uint64_t guid;
1046fa9e4066Sahrens 	char *msgid;
1047fa9e4066Sahrens 	nvlist_t *nvroot;
1048fa9e4066Sahrens 	int reason;
104946657f8dSmmusante 	const char *health;
1050fa9e4066Sahrens 	uint_t vsc;
1051fa9e4066Sahrens 	int namewidth;
1052fa9e4066Sahrens 
1053fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1054fa9e4066Sahrens 	    &name) == 0);
1055fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1056fa9e4066Sahrens 	    &guid) == 0);
1057fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1058fa9e4066Sahrens 	    &pool_state) == 0);
1059fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1060fa9e4066Sahrens 	    &nvroot) == 0);
1061fa9e4066Sahrens 
1062fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1063fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1064990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1065fa9e4066Sahrens 
1066fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1067fa9e4066Sahrens 
106846657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
106946657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
107046657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
10714c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
107246657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
10734c58d714Sdarrenm 	(void) printf("\n");
1074fa9e4066Sahrens 
1075fa9e4066Sahrens 	switch (reason) {
1076fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1077fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1078fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1079fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1080fa9e4066Sahrens 		    "from the system.\n"));
1081fa9e4066Sahrens 		break;
1082fa9e4066Sahrens 
1083fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1084fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1085fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1086fa9e4066Sahrens 		    "corrupted data.\n"));
1087fa9e4066Sahrens 		break;
1088fa9e4066Sahrens 
1089fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1090fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1091fa9e4066Sahrens 		break;
1092fa9e4066Sahrens 
1093441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1094441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1095441d80aaSlling 		    "are offlined.\n"));
1096441d80aaSlling 		break;
1097441d80aaSlling 
1098ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1099ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1100ea8dc4b6Seschrock 		    "corrupted.\n"));
1101ea8dc4b6Seschrock 		break;
1102ea8dc4b6Seschrock 
1103eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1104eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1105eaca9bbdSeschrock 		    "older on-disk version.\n"));
1106eaca9bbdSeschrock 		break;
1107eaca9bbdSeschrock 
1108eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1109eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1110eaca9bbdSeschrock 		    "incompatible version.\n"));
1111eaca9bbdSeschrock 		break;
111295173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
111395173954Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
111495173954Sek110237 		    "another system.\n"));
111595173954Sek110237 		break;
11163d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
11173d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
11183d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
11193d7072f8Seschrock 		    "faulted.\n"));
11203d7072f8Seschrock 		break;
11213d7072f8Seschrock 
1122fa9e4066Sahrens 	default:
1123fa9e4066Sahrens 		/*
1124fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1125fa9e4066Sahrens 		 */
1126fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1127fa9e4066Sahrens 	}
1128fa9e4066Sahrens 
1129fa9e4066Sahrens 	/*
1130fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1131fa9e4066Sahrens 	 */
113246657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1133eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1134eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1135eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1136eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1137eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
113895173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
113995173954Sek110237 			(void) printf(gettext("action: The pool can be "
114095173954Sek110237 			    "imported using its name or numeric "
114195173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1142fa9e4066Sahrens 		else
1143eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1144eaca9bbdSeschrock 			    "imported using its name or numeric "
1145eaca9bbdSeschrock 			    "identifier.\n"));
114646657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1147fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1148fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1149eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1150fa9e4066Sahrens 	} else {
1151eaca9bbdSeschrock 		switch (reason) {
1152eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1153eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1154eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1155eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1156eaca9bbdSeschrock 			    "backup.\n"));
1157eaca9bbdSeschrock 			break;
1158eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1159eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1160eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1161fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1162fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1163fa9e4066Sahrens 			    "again.\n"));
1164eaca9bbdSeschrock 			break;
1165eaca9bbdSeschrock 		default:
1166fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1167fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1168fa9e4066Sahrens 		}
1169eaca9bbdSeschrock 	}
1170eaca9bbdSeschrock 
117146657f8dSmmusante 	/*
117246657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
117346657f8dSmmusante 	 * is "corrupt data":
117446657f8dSmmusante 	 */
117546657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
117646657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
117746657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1178eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1179eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1180eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1181eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1182eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
118318ce54dfSek110237 			    "another system, but can be imported using\n\t"
1184eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1185eaca9bbdSeschrock 	}
1186fa9e4066Sahrens 
1187fa9e4066Sahrens 	if (msgid != NULL)
1188fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1189fa9e4066Sahrens 		    msgid);
1190fa9e4066Sahrens 
1191fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1192fa9e4066Sahrens 
1193c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1194fa9e4066Sahrens 	if (namewidth < 10)
1195fa9e4066Sahrens 		namewidth = 10;
11968654d025Sperrin 
11978654d025Sperrin 	print_import_config(name, nvroot, namewidth, 0, B_FALSE);
11988654d025Sperrin 	if (num_logs(nvroot) > 0) {
11998654d025Sperrin 		(void) printf(gettext("\tlogs\n"));
12008654d025Sperrin 		print_import_config(name, nvroot, namewidth, 0, B_TRUE);
12018654d025Sperrin 	}
1202fa9e4066Sahrens 
1203fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
120446657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1205fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
120646657f8dSmmusante 		    "configuration cannot be determined.\n"));
1207fa9e4066Sahrens 	}
1208fa9e4066Sahrens }
1209fa9e4066Sahrens 
1210fa9e4066Sahrens /*
1211fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1212990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1213990b4856Slling  * within the pool.
1214fa9e4066Sahrens  */
1215fa9e4066Sahrens static int
1216fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
1217c5904d13Seschrock     int force, nvlist_t *props, boolean_t allowfaulted)
1218fa9e4066Sahrens {
1219fa9e4066Sahrens 	zpool_handle_t *zhp;
1220fa9e4066Sahrens 	char *name;
1221fa9e4066Sahrens 	uint64_t state;
1222eaca9bbdSeschrock 	uint64_t version;
1223ecd6cf80Smarks 	int error = 0;
1224fa9e4066Sahrens 
1225fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1226fa9e4066Sahrens 	    &name) == 0);
1227fa9e4066Sahrens 
1228fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1229fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1230eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1231eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1232e7437265Sahrens 	if (version > SPA_VERSION) {
1233eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1234eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1235eaca9bbdSeschrock 		return (1);
1236eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
123795173954Sek110237 		uint64_t hostid;
123895173954Sek110237 
123995173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
124095173954Sek110237 		    &hostid) == 0) {
124195173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
124295173954Sek110237 				char *hostname;
124395173954Sek110237 				uint64_t timestamp;
124495173954Sek110237 				time_t t;
124595173954Sek110237 
124695173954Sek110237 				verify(nvlist_lookup_string(config,
124795173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
124895173954Sek110237 				verify(nvlist_lookup_uint64(config,
124995173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
125095173954Sek110237 				t = timestamp;
125195173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
125295173954Sek110237 				    "'%s': pool may be in use from other "
125395173954Sek110237 				    "system, it was last accessed by %s "
125495173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
125595173954Sek110237 				    (unsigned long)hostid,
125695173954Sek110237 				    asctime(localtime(&t)));
125795173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
125895173954Sek110237 				    "import anyway\n"));
1259fa9e4066Sahrens 				return (1);
1260fa9e4066Sahrens 			}
126195173954Sek110237 		} else {
126295173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
126395173954Sek110237 			    "pool may be in use from other system\n"), name);
126495173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
126595173954Sek110237 			    "anyway\n"));
126695173954Sek110237 			return (1);
126795173954Sek110237 		}
126895173954Sek110237 	}
1269fa9e4066Sahrens 
1270c5904d13Seschrock 	if (zpool_import_props(g_zfs, config, newname, props,
1271c5904d13Seschrock 	    allowfaulted) != 0)
1272fa9e4066Sahrens 		return (1);
1273fa9e4066Sahrens 
1274fa9e4066Sahrens 	if (newname != NULL)
1275fa9e4066Sahrens 		name = (char *)newname;
1276fa9e4066Sahrens 
1277c5904d13Seschrock 	verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL);
1278fa9e4066Sahrens 
1279f3861e1aSahl 	if (zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1280fa9e4066Sahrens 		zpool_close(zhp);
1281fa9e4066Sahrens 		return (1);
1282fa9e4066Sahrens 	}
1283fa9e4066Sahrens 
1284fa9e4066Sahrens 	zpool_close(zhp);
1285ecd6cf80Smarks 	return (error);
1286fa9e4066Sahrens }
1287fa9e4066Sahrens 
1288fa9e4066Sahrens /*
12894c58d714Sdarrenm  * zpool import [-d dir] [-D]
12902f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
12912f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
12922f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
12932f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] <pool | id> [newpool]
12942f8aaab3Seschrock  *
12952f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
12962f8aaab3Seschrock  *		devices.
1297fa9e4066Sahrens  *
1298fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1299fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1300fa9e4066Sahrens  *
13014c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
13024c58d714Sdarrenm  *              specified destroyed pools.
13034c58d714Sdarrenm  *
1304fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1305fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1306fa9e4066Sahrens  *		is rebooted.
1307fa9e4066Sahrens  *
1308fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1309fa9e4066Sahrens  *
1310c5904d13Seschrock  *       -F	Import even in the presence of faulted vdevs.  This is an
1311c5904d13Seschrock  *       	intentionally undocumented option for testing purposes, and
1312c5904d13Seschrock  *       	treats the pool configuration as complete, leaving any bad
1313c5904d13Seschrock  *		vdevs in the FAULTED state.
1314c5904d13Seschrock  *
1315fa9e4066Sahrens  *       -a	Import all pools found.
1316fa9e4066Sahrens  *
1317990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1318ecd6cf80Smarks  *
1319fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1320fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1321fa9e4066Sahrens  */
1322fa9e4066Sahrens int
1323fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1324fa9e4066Sahrens {
1325fa9e4066Sahrens 	char **searchdirs = NULL;
1326fa9e4066Sahrens 	int nsearch = 0;
1327fa9e4066Sahrens 	int c;
1328fa9e4066Sahrens 	int err;
13292f8aaab3Seschrock 	nvlist_t *pools = NULL;
133099653d4eSeschrock 	boolean_t do_all = B_FALSE;
133199653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1332fa9e4066Sahrens 	char *mntopts = NULL;
133399653d4eSeschrock 	boolean_t do_force = B_FALSE;
1334fa9e4066Sahrens 	nvpair_t *elem;
1335fa9e4066Sahrens 	nvlist_t *config;
1336*24e697d4Sck153898 	uint64_t searchguid = 0;
1337*24e697d4Sck153898 	char *searchname = NULL;
1338990b4856Slling 	char *propval;
1339fa9e4066Sahrens 	nvlist_t *found_config;
1340ecd6cf80Smarks 	nvlist_t *props = NULL;
134199653d4eSeschrock 	boolean_t first;
1342c5904d13Seschrock 	boolean_t allow_faulted = B_FALSE;
13434c58d714Sdarrenm 	uint64_t pool_state;
13442f8aaab3Seschrock 	char *cachefile = NULL;
1345fa9e4066Sahrens 
1346fa9e4066Sahrens 	/* check options */
1347c5904d13Seschrock 	while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) {
1348fa9e4066Sahrens 		switch (c) {
1349fa9e4066Sahrens 		case 'a':
135099653d4eSeschrock 			do_all = B_TRUE;
1351fa9e4066Sahrens 			break;
13522f8aaab3Seschrock 		case 'c':
13532f8aaab3Seschrock 			cachefile = optarg;
13542f8aaab3Seschrock 			break;
1355fa9e4066Sahrens 		case 'd':
1356fa9e4066Sahrens 			if (searchdirs == NULL) {
1357fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1358fa9e4066Sahrens 			} else {
1359fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1360fa9e4066Sahrens 				    sizeof (char *));
1361fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1362fa9e4066Sahrens 				    sizeof (char *));
1363fa9e4066Sahrens 				free(searchdirs);
1364fa9e4066Sahrens 				searchdirs = tmp;
1365fa9e4066Sahrens 			}
1366fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1367fa9e4066Sahrens 			break;
13684c58d714Sdarrenm 		case 'D':
136999653d4eSeschrock 			do_destroyed = B_TRUE;
13704c58d714Sdarrenm 			break;
1371fa9e4066Sahrens 		case 'f':
137299653d4eSeschrock 			do_force = B_TRUE;
1373fa9e4066Sahrens 			break;
1374c5904d13Seschrock 		case 'F':
1375c5904d13Seschrock 			allow_faulted = B_TRUE;
1376c5904d13Seschrock 			break;
1377fa9e4066Sahrens 		case 'o':
1378990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1379990b4856Slling 				*propval = '\0';
1380990b4856Slling 				propval++;
1381990b4856Slling 				if (add_prop_list(optarg, propval, &props))
1382990b4856Slling 					goto error;
1383990b4856Slling 			} else {
1384fa9e4066Sahrens 				mntopts = optarg;
1385990b4856Slling 			}
1386fa9e4066Sahrens 			break;
1387fa9e4066Sahrens 		case 'R':
1388990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
1389990b4856Slling 			    ZPOOL_PROP_ALTROOT), optarg, &props))
1390990b4856Slling 				goto error;
13912f8aaab3Seschrock 			if (nvlist_lookup_string(props,
13922f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
13932f8aaab3Seschrock 			    &propval) == 0)
13942f8aaab3Seschrock 				break;
1395990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
13962f8aaab3Seschrock 			    ZPOOL_PROP_CACHEFILE), "none", &props))
1397990b4856Slling 				goto error;
1398fa9e4066Sahrens 			break;
1399fa9e4066Sahrens 		case ':':
1400fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1401fa9e4066Sahrens 			    "'%c' option\n"), optopt);
140299653d4eSeschrock 			usage(B_FALSE);
1403fa9e4066Sahrens 			break;
1404fa9e4066Sahrens 		case '?':
1405fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1406fa9e4066Sahrens 			    optopt);
140799653d4eSeschrock 			usage(B_FALSE);
1408fa9e4066Sahrens 		}
1409fa9e4066Sahrens 	}
1410fa9e4066Sahrens 
1411fa9e4066Sahrens 	argc -= optind;
1412fa9e4066Sahrens 	argv += optind;
1413fa9e4066Sahrens 
14142f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
14152f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
14162f8aaab3Seschrock 		usage(B_FALSE);
14172f8aaab3Seschrock 	}
14182f8aaab3Seschrock 
1419fa9e4066Sahrens 	if (searchdirs == NULL) {
1420fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1421fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1422fa9e4066Sahrens 		nsearch = 1;
1423fa9e4066Sahrens 	}
1424fa9e4066Sahrens 
1425fa9e4066Sahrens 	/* check argument count */
1426fa9e4066Sahrens 	if (do_all) {
1427fa9e4066Sahrens 		if (argc != 0) {
1428fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
142999653d4eSeschrock 			usage(B_FALSE);
1430fa9e4066Sahrens 		}
1431fa9e4066Sahrens 	} else {
1432fa9e4066Sahrens 		if (argc > 2) {
1433fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
143499653d4eSeschrock 			usage(B_FALSE);
1435fa9e4066Sahrens 		}
1436fa9e4066Sahrens 
1437fa9e4066Sahrens 		/*
1438fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1439fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1440fa9e4066Sahrens 		 * silently fail.
1441fa9e4066Sahrens 		 */
1442fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1443fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1444fa9e4066Sahrens 			    "discover pools: permission denied\n"));
144599653d4eSeschrock 			free(searchdirs);
1446fa9e4066Sahrens 			return (1);
1447fa9e4066Sahrens 		}
1448fa9e4066Sahrens 	}
1449fa9e4066Sahrens 
1450fa9e4066Sahrens 	/*
1451fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1452fa9e4066Sahrens 	 *
1453fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1454fa9e4066Sahrens 	 *		each one.
1455fa9e4066Sahrens 	 *
1456fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1457fa9e4066Sahrens 	 *
1458fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1459fa9e4066Sahrens 	 *		name and import that one.
14604c58d714Sdarrenm 	 *
14614c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1462fa9e4066Sahrens 	 */
1463fa9e4066Sahrens 	if (argc != 0) {
1464fa9e4066Sahrens 		char *endptr;
1465fa9e4066Sahrens 
1466fa9e4066Sahrens 		errno = 0;
1467fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1468fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1469fa9e4066Sahrens 			searchname = argv[0];
1470fa9e4066Sahrens 		found_config = NULL;
1471fa9e4066Sahrens 	}
1472fa9e4066Sahrens 
1473*24e697d4Sck153898 	if (cachefile) {
1474*24e697d4Sck153898 		pools = zpool_find_import_cached(g_zfs, cachefile, B_FALSE,
1475*24e697d4Sck153898 		    searchname, searchguid);
1476*24e697d4Sck153898 	} else if (searchname != NULL) {
1477*24e697d4Sck153898 		pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs,
1478*24e697d4Sck153898 		    searchname);
1479*24e697d4Sck153898 	} else {
1480*24e697d4Sck153898 		/*
1481*24e697d4Sck153898 		 * It's OK to search by guid even if searchguid is 0.
1482*24e697d4Sck153898 		 */
1483*24e697d4Sck153898 		pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs,
1484*24e697d4Sck153898 		    searchguid);
1485*24e697d4Sck153898 	}
1486*24e697d4Sck153898 
1487*24e697d4Sck153898 	if (pools == NULL) {
1488*24e697d4Sck153898 		if (argc != 0) {
1489*24e697d4Sck153898 			(void) fprintf(stderr, gettext("cannot import '%s': "
1490*24e697d4Sck153898 			    "no such pool available\n"), argv[0]);
1491*24e697d4Sck153898 		}
1492*24e697d4Sck153898 		free(searchdirs);
1493*24e697d4Sck153898 		return (1);
1494*24e697d4Sck153898 	}
1495*24e697d4Sck153898 
1496*24e697d4Sck153898 	/*
1497*24e697d4Sck153898 	 * At this point we have a list of import candidate configs. Even if
1498*24e697d4Sck153898 	 * we were searching by pool name or guid, we still need to
1499*24e697d4Sck153898 	 * post-process the list to deal with pool state and possible
1500*24e697d4Sck153898 	 * duplicate names.
1501*24e697d4Sck153898 	 */
1502fa9e4066Sahrens 	err = 0;
1503fa9e4066Sahrens 	elem = NULL;
150499653d4eSeschrock 	first = B_TRUE;
1505fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1506fa9e4066Sahrens 
1507fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1508fa9e4066Sahrens 
15094c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
15104c58d714Sdarrenm 		    &pool_state) == 0);
15114c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
15124c58d714Sdarrenm 			continue;
15134c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
15144c58d714Sdarrenm 			continue;
15154c58d714Sdarrenm 
1516fa9e4066Sahrens 		if (argc == 0) {
1517fa9e4066Sahrens 			if (first)
151899653d4eSeschrock 				first = B_FALSE;
15193bb79becSeschrock 			else if (!do_all)
1520fa9e4066Sahrens 				(void) printf("\n");
1521fa9e4066Sahrens 
1522fa9e4066Sahrens 			if (do_all)
1523fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1524c5904d13Seschrock 				    do_force, props, allow_faulted);
1525fa9e4066Sahrens 			else
1526fa9e4066Sahrens 				show_import(config);
1527fa9e4066Sahrens 		} else if (searchname != NULL) {
1528fa9e4066Sahrens 			char *name;
1529fa9e4066Sahrens 
1530fa9e4066Sahrens 			/*
1531fa9e4066Sahrens 			 * We are searching for a pool based on name.
1532fa9e4066Sahrens 			 */
1533fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1534fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1535fa9e4066Sahrens 
1536fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1537fa9e4066Sahrens 				if (found_config != NULL) {
1538fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1539fa9e4066Sahrens 					    "cannot import '%s': more than "
1540fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1541fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1542fa9e4066Sahrens 					    "import by numeric ID instead\n"));
154399653d4eSeschrock 					err = B_TRUE;
1544fa9e4066Sahrens 				}
1545fa9e4066Sahrens 				found_config = config;
1546fa9e4066Sahrens 			}
1547fa9e4066Sahrens 		} else {
1548fa9e4066Sahrens 			uint64_t guid;
1549fa9e4066Sahrens 
1550fa9e4066Sahrens 			/*
1551fa9e4066Sahrens 			 * Search for a pool by guid.
1552fa9e4066Sahrens 			 */
1553fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1554fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1555fa9e4066Sahrens 
1556fa9e4066Sahrens 			if (guid == searchguid)
1557fa9e4066Sahrens 				found_config = config;
1558fa9e4066Sahrens 		}
1559fa9e4066Sahrens 	}
1560fa9e4066Sahrens 
1561fa9e4066Sahrens 	/*
1562fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1563fa9e4066Sahrens 	 * pool, and then do the import.
1564fa9e4066Sahrens 	 */
1565fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1566fa9e4066Sahrens 		if (found_config == NULL) {
1567fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1568fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
156999653d4eSeschrock 			err = B_TRUE;
1570fa9e4066Sahrens 		} else {
1571fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1572c5904d13Seschrock 			    argv[1], mntopts, do_force, props, allow_faulted);
1573fa9e4066Sahrens 		}
1574fa9e4066Sahrens 	}
1575fa9e4066Sahrens 
1576fa9e4066Sahrens 	/*
1577fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1578fa9e4066Sahrens 	 * found.
1579fa9e4066Sahrens 	 */
1580fa9e4066Sahrens 	if (argc == 0 && first)
1581fa9e4066Sahrens 		(void) fprintf(stderr,
1582fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1583fa9e4066Sahrens 
1584ecd6cf80Smarks error:
1585ecd6cf80Smarks 	nvlist_free(props);
1586fa9e4066Sahrens 	nvlist_free(pools);
158799653d4eSeschrock 	free(searchdirs);
1588fa9e4066Sahrens 
1589fa9e4066Sahrens 	return (err ? 1 : 0);
1590fa9e4066Sahrens }
1591fa9e4066Sahrens 
1592fa9e4066Sahrens typedef struct iostat_cbdata {
1593fa9e4066Sahrens 	zpool_list_t *cb_list;
1594fa9e4066Sahrens 	int cb_verbose;
1595fa9e4066Sahrens 	int cb_iteration;
1596fa9e4066Sahrens 	int cb_namewidth;
1597fa9e4066Sahrens } iostat_cbdata_t;
1598fa9e4066Sahrens 
1599fa9e4066Sahrens static void
1600fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1601fa9e4066Sahrens {
1602fa9e4066Sahrens 	int i = 0;
1603fa9e4066Sahrens 
1604fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1605fa9e4066Sahrens 		(void) printf("-");
1606fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1607fa9e4066Sahrens }
1608fa9e4066Sahrens 
1609fa9e4066Sahrens static void
1610fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1611fa9e4066Sahrens {
1612fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1613fa9e4066Sahrens 	    cb->cb_namewidth, "");
1614fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1615fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1616fa9e4066Sahrens 	print_iostat_separator(cb);
1617fa9e4066Sahrens }
1618fa9e4066Sahrens 
1619fa9e4066Sahrens /*
1620fa9e4066Sahrens  * Display a single statistic.
1621fa9e4066Sahrens  */
1622990b4856Slling static void
1623fa9e4066Sahrens print_one_stat(uint64_t value)
1624fa9e4066Sahrens {
1625fa9e4066Sahrens 	char buf[64];
1626fa9e4066Sahrens 
1627fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1628fa9e4066Sahrens 	(void) printf("  %5s", buf);
1629fa9e4066Sahrens }
1630fa9e4066Sahrens 
1631fa9e4066Sahrens /*
1632fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1633fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1634fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1635fa9e4066Sahrens  */
1636fa9e4066Sahrens void
1637c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1638c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1639fa9e4066Sahrens {
1640fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1641fa9e4066Sahrens 	uint_t c, children;
1642fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1643fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1644fa9e4066Sahrens 	uint64_t tdelta;
1645fa9e4066Sahrens 	double scale;
1646afefbcddSeschrock 	char *vname;
1647fa9e4066Sahrens 
1648fa9e4066Sahrens 	if (oldnv != NULL) {
1649fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1650fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1651fa9e4066Sahrens 	} else {
1652fa9e4066Sahrens 		oldvs = &zerovs;
1653fa9e4066Sahrens 	}
1654fa9e4066Sahrens 
1655fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1656fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1657fa9e4066Sahrens 
1658fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1659fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1660fa9e4066Sahrens 	else
1661fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1662fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1663fa9e4066Sahrens 
1664fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1665fa9e4066Sahrens 
1666fa9e4066Sahrens 	if (tdelta == 0)
1667fa9e4066Sahrens 		scale = 1.0;
1668fa9e4066Sahrens 	else
1669fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1670fa9e4066Sahrens 
1671fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1672fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1673fa9e4066Sahrens 		(void) printf("      -      -");
1674fa9e4066Sahrens 	} else {
1675fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1676fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1677fa9e4066Sahrens 	}
1678fa9e4066Sahrens 
1679fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1680fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1681fa9e4066Sahrens 
1682fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1683fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1684fa9e4066Sahrens 
1685fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1686fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1687fa9e4066Sahrens 
1688fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1689fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1690fa9e4066Sahrens 
1691fa9e4066Sahrens 	(void) printf("\n");
1692fa9e4066Sahrens 
1693fa9e4066Sahrens 	if (!cb->cb_verbose)
1694fa9e4066Sahrens 		return;
1695fa9e4066Sahrens 
1696fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1697fa9e4066Sahrens 	    &newchild, &children) != 0)
1698fa9e4066Sahrens 		return;
1699fa9e4066Sahrens 
1700fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1701fa9e4066Sahrens 	    &oldchild, &c) != 0)
1702fa9e4066Sahrens 		return;
1703fa9e4066Sahrens 
1704afefbcddSeschrock 	for (c = 0; c < children; c++) {
170599653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1706c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1707afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1708afefbcddSeschrock 		free(vname);
1709afefbcddSeschrock 	}
1710fa94a07fSbrendan 
1711fa94a07fSbrendan 	/*
1712fa94a07fSbrendan 	 * Include level 2 ARC devices in iostat output
1713fa94a07fSbrendan 	 */
1714fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
1715fa94a07fSbrendan 	    &newchild, &children) != 0)
1716fa94a07fSbrendan 		return;
1717fa94a07fSbrendan 
1718fa94a07fSbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
1719fa94a07fSbrendan 	    &oldchild, &c) != 0)
1720fa94a07fSbrendan 		return;
1721fa94a07fSbrendan 
1722fa94a07fSbrendan 	if (children > 0) {
1723fa94a07fSbrendan 		(void) printf("%-*s      -      -      -      -      -      "
1724fa94a07fSbrendan 		    "-\n", cb->cb_namewidth, "cache");
1725fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1726fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1727fa94a07fSbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1728fa94a07fSbrendan 			    newchild[c], cb, depth + 2);
1729fa94a07fSbrendan 			free(vname);
1730fa94a07fSbrendan 		}
1731fa94a07fSbrendan 	}
1732fa9e4066Sahrens }
1733fa9e4066Sahrens 
1734088e9d47Seschrock static int
1735088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
1736088e9d47Seschrock {
1737088e9d47Seschrock 	iostat_cbdata_t *cb = data;
173894de1d4cSeschrock 	boolean_t missing;
1739088e9d47Seschrock 
1740088e9d47Seschrock 	/*
1741088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
1742088e9d47Seschrock 	 */
174394de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
174494de1d4cSeschrock 		return (-1);
174594de1d4cSeschrock 
174694de1d4cSeschrock 	if (missing)
1747088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
1748088e9d47Seschrock 
1749088e9d47Seschrock 	return (0);
1750088e9d47Seschrock }
1751088e9d47Seschrock 
1752fa9e4066Sahrens /*
1753fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
1754fa9e4066Sahrens  */
1755fa9e4066Sahrens int
1756fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
1757fa9e4066Sahrens {
1758fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1759fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
1760fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
1761fa9e4066Sahrens 
1762088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
1763fa9e4066Sahrens 
1764088e9d47Seschrock 	if (cb->cb_iteration == 1)
1765fa9e4066Sahrens 		oldconfig = NULL;
1766fa9e4066Sahrens 
1767fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1768fa9e4066Sahrens 	    &newnvroot) == 0);
1769fa9e4066Sahrens 
1770088e9d47Seschrock 	if (oldconfig == NULL)
1771fa9e4066Sahrens 		oldnvroot = NULL;
1772088e9d47Seschrock 	else
1773088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
1774088e9d47Seschrock 		    &oldnvroot) == 0);
1775fa9e4066Sahrens 
1776fa9e4066Sahrens 	/*
1777fa9e4066Sahrens 	 * Print out the statistics for the pool.
1778fa9e4066Sahrens 	 */
1779c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1780fa9e4066Sahrens 
1781fa9e4066Sahrens 	if (cb->cb_verbose)
1782fa9e4066Sahrens 		print_iostat_separator(cb);
1783fa9e4066Sahrens 
1784fa9e4066Sahrens 	return (0);
1785fa9e4066Sahrens }
1786fa9e4066Sahrens 
1787fa9e4066Sahrens int
1788fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
1789fa9e4066Sahrens {
1790fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1791fa9e4066Sahrens 	nvlist_t *config, *nvroot;
1792fa9e4066Sahrens 
1793088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
1794fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1795fa9e4066Sahrens 		    &nvroot) == 0);
1796fa9e4066Sahrens 		if (!cb->cb_verbose)
1797fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1798fa9e4066Sahrens 		else
1799c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
1800fa9e4066Sahrens 	}
1801fa9e4066Sahrens 
1802fa9e4066Sahrens 	/*
1803fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
1804fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
1805fa9e4066Sahrens 	 */
1806fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
1807fa9e4066Sahrens 		cb->cb_namewidth = 10;
1808fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
1809fa9e4066Sahrens 		cb->cb_namewidth = 38;
1810fa9e4066Sahrens 
1811fa9e4066Sahrens 	return (0);
1812fa9e4066Sahrens }
1813fa9e4066Sahrens 
1814fa9e4066Sahrens /*
1815fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
1816fa9e4066Sahrens  *
1817fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
1818fa9e4066Sahrens  *
1819fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
1820fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
1821fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1822fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
1823fa9e4066Sahrens  * changes are all handled within libzfs.
1824fa9e4066Sahrens  */
1825fa9e4066Sahrens int
1826fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
1827fa9e4066Sahrens {
1828fa9e4066Sahrens 	int c;
1829fa9e4066Sahrens 	int ret;
1830fa9e4066Sahrens 	int npools;
1831fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
1832fa9e4066Sahrens 	zpool_list_t *list;
183399653d4eSeschrock 	boolean_t verbose = B_FALSE;
1834fa9e4066Sahrens 	iostat_cbdata_t cb;
1835fa9e4066Sahrens 
1836fa9e4066Sahrens 	/* check options */
1837fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
1838fa9e4066Sahrens 		switch (c) {
1839fa9e4066Sahrens 		case 'v':
184099653d4eSeschrock 			verbose = B_TRUE;
1841fa9e4066Sahrens 			break;
1842fa9e4066Sahrens 		case '?':
1843fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1844fa9e4066Sahrens 			    optopt);
184599653d4eSeschrock 			usage(B_FALSE);
1846fa9e4066Sahrens 		}
1847fa9e4066Sahrens 	}
1848fa9e4066Sahrens 
1849fa9e4066Sahrens 	argc -= optind;
1850fa9e4066Sahrens 	argv += optind;
1851fa9e4066Sahrens 
1852fa9e4066Sahrens 	/*
1853fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
1854fa9e4066Sahrens 	 */
1855fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1856fa9e4066Sahrens 		char *end;
1857fa9e4066Sahrens 
1858fa9e4066Sahrens 		errno = 0;
1859fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1860fa9e4066Sahrens 
1861fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1862fa9e4066Sahrens 			if (interval == 0) {
1863fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1864fa9e4066Sahrens 				    "cannot be zero\n"));
186599653d4eSeschrock 				usage(B_FALSE);
1866fa9e4066Sahrens 			}
1867fa9e4066Sahrens 
1868fa9e4066Sahrens 			/*
1869fa9e4066Sahrens 			 * Ignore the last parameter
1870fa9e4066Sahrens 			 */
1871fa9e4066Sahrens 			argc--;
1872fa9e4066Sahrens 		} else {
1873fa9e4066Sahrens 			/*
1874fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
1875fa9e4066Sahrens 			 * user will get a more informative error message later
1876fa9e4066Sahrens 			 * on.
1877fa9e4066Sahrens 			 */
1878fa9e4066Sahrens 			interval = 0;
1879fa9e4066Sahrens 		}
1880fa9e4066Sahrens 	}
1881fa9e4066Sahrens 
1882fa9e4066Sahrens 	/*
1883fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
1884fa9e4066Sahrens 	 * and an integer.
1885fa9e4066Sahrens 	 */
1886fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1887fa9e4066Sahrens 		char *end;
1888fa9e4066Sahrens 
1889fa9e4066Sahrens 		errno = 0;
1890fa9e4066Sahrens 		count = interval;
1891fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1892fa9e4066Sahrens 
1893fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1894fa9e4066Sahrens 			if (interval == 0) {
1895fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1896fa9e4066Sahrens 				    "cannot be zero\n"));
189799653d4eSeschrock 				usage(B_FALSE);
1898fa9e4066Sahrens 			}
1899fa9e4066Sahrens 
1900fa9e4066Sahrens 			/*
1901fa9e4066Sahrens 			 * Ignore the last parameter
1902fa9e4066Sahrens 			 */
1903fa9e4066Sahrens 			argc--;
1904fa9e4066Sahrens 		} else {
1905fa9e4066Sahrens 			interval = 0;
1906fa9e4066Sahrens 		}
1907fa9e4066Sahrens 	}
1908fa9e4066Sahrens 
1909fa9e4066Sahrens 	/*
1910fa9e4066Sahrens 	 * Construct the list of all interesting pools.
1911fa9e4066Sahrens 	 */
1912fa9e4066Sahrens 	ret = 0;
1913b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
1914fa9e4066Sahrens 		return (1);
1915fa9e4066Sahrens 
191699653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
191799653d4eSeschrock 		pool_list_free(list);
1918fa9e4066Sahrens 		return (1);
191999653d4eSeschrock 	}
1920fa9e4066Sahrens 
1921fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
192299653d4eSeschrock 		pool_list_free(list);
1923fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
1924fa9e4066Sahrens 		return (1);
1925fa9e4066Sahrens 	}
1926fa9e4066Sahrens 
1927fa9e4066Sahrens 	/*
1928fa9e4066Sahrens 	 * Enter the main iostat loop.
1929fa9e4066Sahrens 	 */
1930fa9e4066Sahrens 	cb.cb_list = list;
1931fa9e4066Sahrens 	cb.cb_verbose = verbose;
1932fa9e4066Sahrens 	cb.cb_iteration = 0;
1933fa9e4066Sahrens 	cb.cb_namewidth = 0;
1934fa9e4066Sahrens 
1935fa9e4066Sahrens 	for (;;) {
1936fa9e4066Sahrens 		pool_list_update(list);
1937fa9e4066Sahrens 
1938fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
1939fa9e4066Sahrens 			break;
1940fa9e4066Sahrens 
1941fa9e4066Sahrens 		/*
1942088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
1943088e9d47Seschrock 		 * before calculating the maximum name width, so that any
1944088e9d47Seschrock 		 * configuration changes are properly accounted for.
1945088e9d47Seschrock 		 */
194699653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
1947088e9d47Seschrock 
1948088e9d47Seschrock 		/*
1949fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
1950fa9e4066Sahrens 		 * for the pool / device name column across all pools.
1951fa9e4066Sahrens 		 */
1952fa9e4066Sahrens 		cb.cb_namewidth = 0;
195399653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
1954fa9e4066Sahrens 
1955fa9e4066Sahrens 		/*
1956fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
1957fa9e4066Sahrens 		 */
1958fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
1959fa9e4066Sahrens 			print_iostat_header(&cb);
1960fa9e4066Sahrens 
196199653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
1962fa9e4066Sahrens 
1963fa9e4066Sahrens 		/*
1964fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
1965fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
1966fa9e4066Sahrens 		 */
1967fa9e4066Sahrens 		if (npools > 1 && !verbose)
1968fa9e4066Sahrens 			print_iostat_separator(&cb);
1969fa9e4066Sahrens 
1970fa9e4066Sahrens 		if (verbose)
1971fa9e4066Sahrens 			(void) printf("\n");
1972fa9e4066Sahrens 
197339c23413Seschrock 		/*
197439c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
197539c23413Seschrock 		 * indefinitely.
197639c23413Seschrock 		 */
197739c23413Seschrock 		(void) fflush(stdout);
197839c23413Seschrock 
1979fa9e4066Sahrens 		if (interval == 0)
1980fa9e4066Sahrens 			break;
1981fa9e4066Sahrens 
1982fa9e4066Sahrens 		if (count != 0 && --count == 0)
1983fa9e4066Sahrens 			break;
1984fa9e4066Sahrens 
1985fa9e4066Sahrens 		(void) sleep(interval);
1986fa9e4066Sahrens 	}
1987fa9e4066Sahrens 
1988fa9e4066Sahrens 	pool_list_free(list);
1989fa9e4066Sahrens 
1990fa9e4066Sahrens 	return (ret);
1991fa9e4066Sahrens }
1992fa9e4066Sahrens 
1993fa9e4066Sahrens typedef struct list_cbdata {
199499653d4eSeschrock 	boolean_t	cb_scripted;
199599653d4eSeschrock 	boolean_t	cb_first;
1996990b4856Slling 	zprop_list_t	*cb_proplist;
1997fa9e4066Sahrens } list_cbdata_t;
1998fa9e4066Sahrens 
1999fa9e4066Sahrens /*
2000fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
2001fa9e4066Sahrens  */
2002990b4856Slling static void
2003990b4856Slling print_header(zprop_list_t *pl)
2004fa9e4066Sahrens {
2005990b4856Slling 	const char *header;
2006990b4856Slling 	boolean_t first = B_TRUE;
2007990b4856Slling 	boolean_t right_justify;
2008fa9e4066Sahrens 
2009990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2010990b4856Slling 		if (pl->pl_prop == ZPROP_INVAL)
2011990b4856Slling 			continue;
2012990b4856Slling 
2013990b4856Slling 		if (!first)
2014fa9e4066Sahrens 			(void) printf("  ");
2015fa9e4066Sahrens 		else
2016990b4856Slling 			first = B_FALSE;
2017fa9e4066Sahrens 
2018990b4856Slling 		header = zpool_prop_column_name(pl->pl_prop);
2019990b4856Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
2020990b4856Slling 
2021990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
2022990b4856Slling 			(void) printf("%s", header);
2023990b4856Slling 		else if (right_justify)
2024990b4856Slling 			(void) printf("%*s", pl->pl_width, header);
2025990b4856Slling 		else
2026990b4856Slling 			(void) printf("%-*s", pl->pl_width, header);
2027fa9e4066Sahrens 	}
2028fa9e4066Sahrens 
2029fa9e4066Sahrens 	(void) printf("\n");
2030fa9e4066Sahrens }
2031fa9e4066Sahrens 
2032990b4856Slling /*
2033990b4856Slling  * Given a pool and a list of properties, print out all the properties according
2034990b4856Slling  * to the described layout.
2035990b4856Slling  */
2036990b4856Slling static void
2037990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
2038990b4856Slling {
2039990b4856Slling 	boolean_t first = B_TRUE;
2040990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
2041990b4856Slling 	char *propstr;
2042990b4856Slling 	boolean_t right_justify;
2043990b4856Slling 	int width;
2044990b4856Slling 
2045990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2046990b4856Slling 		if (!first) {
2047990b4856Slling 			if (scripted)
2048990b4856Slling 				(void) printf("\t");
2049990b4856Slling 			else
2050990b4856Slling 				(void) printf("  ");
2051990b4856Slling 		} else {
2052990b4856Slling 			first = B_FALSE;
2053990b4856Slling 		}
2054990b4856Slling 
2055990b4856Slling 		right_justify = B_FALSE;
2056990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
2057990b4856Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
2058990b4856Slling 			    sizeof (property), NULL) != 0)
2059990b4856Slling 				propstr = "-";
2060990b4856Slling 			else
2061990b4856Slling 				propstr = property;
2062990b4856Slling 
2063990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2064990b4856Slling 		} else {
2065990b4856Slling 			propstr = "-";
2066990b4856Slling 		}
2067990b4856Slling 
2068990b4856Slling 		width = pl->pl_width;
2069990b4856Slling 
2070990b4856Slling 		/*
2071990b4856Slling 		 * If this is being called in scripted mode, or if this is the
2072990b4856Slling 		 * last column and it is left-justified, don't include a width
2073990b4856Slling 		 * format specifier.
2074990b4856Slling 		 */
2075990b4856Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
2076990b4856Slling 			(void) printf("%s", propstr);
2077990b4856Slling 		else if (right_justify)
2078990b4856Slling 			(void) printf("%*s", width, propstr);
2079990b4856Slling 		else
2080990b4856Slling 			(void) printf("%-*s", width, propstr);
2081990b4856Slling 	}
2082990b4856Slling 
2083990b4856Slling 	(void) printf("\n");
2084990b4856Slling }
2085990b4856Slling 
2086990b4856Slling /*
2087990b4856Slling  * Generic callback function to list a pool.
2088990b4856Slling  */
2089fa9e4066Sahrens int
2090fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2091fa9e4066Sahrens {
2092fa9e4066Sahrens 	list_cbdata_t *cbp = data;
2093fa9e4066Sahrens 
2094fa9e4066Sahrens 	if (cbp->cb_first) {
2095fa9e4066Sahrens 		if (!cbp->cb_scripted)
2096990b4856Slling 			print_header(cbp->cb_proplist);
209799653d4eSeschrock 		cbp->cb_first = B_FALSE;
2098fa9e4066Sahrens 	}
2099fa9e4066Sahrens 
2100990b4856Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2101fa9e4066Sahrens 
2102fa9e4066Sahrens 	return (0);
2103fa9e4066Sahrens }
2104fa9e4066Sahrens 
2105fa9e4066Sahrens /*
2106990b4856Slling  * zpool list [-H] [-o prop[,prop]*] [pool] ...
2107fa9e4066Sahrens  *
2108990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2109990b4856Slling  *		by a single tab.
2110990b4856Slling  *	-o	List of properties to display.  Defaults to
2111990b4856Slling  *		"name,size,used,available,capacity,health,altroot"
2112fa9e4066Sahrens  *
2113fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2114fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2115fa9e4066Sahrens  */
2116fa9e4066Sahrens int
2117fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2118fa9e4066Sahrens {
2119fa9e4066Sahrens 	int c;
2120fa9e4066Sahrens 	int ret;
2121fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2122990b4856Slling 	static char default_props[] =
2123990b4856Slling 	    "name,size,used,available,capacity,health,altroot";
2124990b4856Slling 	char *props = default_props;
2125fa9e4066Sahrens 
2126fa9e4066Sahrens 	/* check options */
2127fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2128fa9e4066Sahrens 		switch (c) {
2129fa9e4066Sahrens 		case 'H':
213099653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2131fa9e4066Sahrens 			break;
2132fa9e4066Sahrens 		case 'o':
2133990b4856Slling 			props = optarg;
2134fa9e4066Sahrens 			break;
2135fa9e4066Sahrens 		case ':':
2136fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2137fa9e4066Sahrens 			    "'%c' option\n"), optopt);
213899653d4eSeschrock 			usage(B_FALSE);
2139fa9e4066Sahrens 			break;
2140fa9e4066Sahrens 		case '?':
2141fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2142fa9e4066Sahrens 			    optopt);
214399653d4eSeschrock 			usage(B_FALSE);
2144fa9e4066Sahrens 		}
2145fa9e4066Sahrens 	}
2146fa9e4066Sahrens 
2147fa9e4066Sahrens 	argc -= optind;
2148fa9e4066Sahrens 	argv += optind;
2149fa9e4066Sahrens 
2150990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
215199653d4eSeschrock 		usage(B_FALSE);
2152fa9e4066Sahrens 
215399653d4eSeschrock 	cb.cb_first = B_TRUE;
2154fa9e4066Sahrens 
2155990b4856Slling 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2156990b4856Slling 	    list_callback, &cb);
2157990b4856Slling 
2158990b4856Slling 	zprop_free_list(cb.cb_proplist);
2159fa9e4066Sahrens 
2160fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2161fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2162fa9e4066Sahrens 		return (0);
2163fa9e4066Sahrens 	}
2164fa9e4066Sahrens 
2165fa9e4066Sahrens 	return (ret);
2166fa9e4066Sahrens }
2167fa9e4066Sahrens 
2168fa9e4066Sahrens static nvlist_t *
2169fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2170fa9e4066Sahrens {
2171fa9e4066Sahrens 	nvlist_t **child;
2172fa9e4066Sahrens 	uint_t c, children;
2173fa9e4066Sahrens 	nvlist_t *match;
2174fa9e4066Sahrens 	char *path;
2175fa9e4066Sahrens 
2176fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2177fa9e4066Sahrens 	    &child, &children) != 0) {
2178fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2179fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2180fa9e4066Sahrens 			name += 9;
2181fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2182fa9e4066Sahrens 			path += 9;
2183fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2184fa9e4066Sahrens 			return (nv);
2185fa9e4066Sahrens 		return (NULL);
2186fa9e4066Sahrens 	}
2187fa9e4066Sahrens 
2188fa9e4066Sahrens 	for (c = 0; c < children; c++)
2189fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2190fa9e4066Sahrens 			return (match);
2191fa9e4066Sahrens 
2192fa9e4066Sahrens 	return (NULL);
2193fa9e4066Sahrens }
2194fa9e4066Sahrens 
2195fa9e4066Sahrens static int
2196fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2197fa9e4066Sahrens {
219899653d4eSeschrock 	boolean_t force = B_FALSE;
2199fa9e4066Sahrens 	int c;
2200fa9e4066Sahrens 	nvlist_t *nvroot;
2201fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2202fa9e4066Sahrens 	zpool_handle_t *zhp;
220399653d4eSeschrock 	int ret;
2204fa9e4066Sahrens 
2205fa9e4066Sahrens 	/* check options */
2206fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2207fa9e4066Sahrens 		switch (c) {
2208fa9e4066Sahrens 		case 'f':
220999653d4eSeschrock 			force = B_TRUE;
2210fa9e4066Sahrens 			break;
2211fa9e4066Sahrens 		case '?':
2212fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2213fa9e4066Sahrens 			    optopt);
221499653d4eSeschrock 			usage(B_FALSE);
2215fa9e4066Sahrens 		}
2216fa9e4066Sahrens 	}
2217fa9e4066Sahrens 
2218fa9e4066Sahrens 	argc -= optind;
2219fa9e4066Sahrens 	argv += optind;
2220fa9e4066Sahrens 
2221fa9e4066Sahrens 	/* get pool name and check number of arguments */
2222fa9e4066Sahrens 	if (argc < 1) {
2223fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
222499653d4eSeschrock 		usage(B_FALSE);
2225fa9e4066Sahrens 	}
2226fa9e4066Sahrens 
2227fa9e4066Sahrens 	poolname = argv[0];
2228fa9e4066Sahrens 
2229fa9e4066Sahrens 	if (argc < 2) {
2230fa9e4066Sahrens 		(void) fprintf(stderr,
2231fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
223299653d4eSeschrock 		usage(B_FALSE);
2233fa9e4066Sahrens 	}
2234fa9e4066Sahrens 
2235fa9e4066Sahrens 	old_disk = argv[1];
2236fa9e4066Sahrens 
2237fa9e4066Sahrens 	if (argc < 3) {
2238fa9e4066Sahrens 		if (!replacing) {
2239fa9e4066Sahrens 			(void) fprintf(stderr,
2240fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
224199653d4eSeschrock 			usage(B_FALSE);
2242fa9e4066Sahrens 		}
2243fa9e4066Sahrens 		new_disk = old_disk;
2244fa9e4066Sahrens 		argc -= 1;
2245fa9e4066Sahrens 		argv += 1;
2246fa9e4066Sahrens 	} else {
2247fa9e4066Sahrens 		new_disk = argv[2];
2248fa9e4066Sahrens 		argc -= 2;
2249fa9e4066Sahrens 		argv += 2;
2250fa9e4066Sahrens 	}
2251fa9e4066Sahrens 
2252fa9e4066Sahrens 	if (argc > 1) {
2253fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
225499653d4eSeschrock 		usage(B_FALSE);
2255fa9e4066Sahrens 	}
2256fa9e4066Sahrens 
225799653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2258fa9e4066Sahrens 		return (1);
2259fa9e4066Sahrens 
22608488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2261fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2262fa9e4066Sahrens 		    poolname);
2263fa9e4066Sahrens 		zpool_close(zhp);
2264fa9e4066Sahrens 		return (1);
2265fa9e4066Sahrens 	}
2266fa9e4066Sahrens 
22678488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv);
2268fa9e4066Sahrens 	if (nvroot == NULL) {
2269fa9e4066Sahrens 		zpool_close(zhp);
2270fa9e4066Sahrens 		return (1);
2271fa9e4066Sahrens 	}
2272fa9e4066Sahrens 
227399653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
227499653d4eSeschrock 
227599653d4eSeschrock 	nvlist_free(nvroot);
227699653d4eSeschrock 	zpool_close(zhp);
227799653d4eSeschrock 
227899653d4eSeschrock 	return (ret);
2279fa9e4066Sahrens }
2280fa9e4066Sahrens 
2281fa9e4066Sahrens /*
2282fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2283fa9e4066Sahrens  *
2284fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2285fa9e4066Sahrens  *
2286fa9e4066Sahrens  * Replace <device> with <new_device>.
2287fa9e4066Sahrens  */
2288fa9e4066Sahrens /* ARGSUSED */
2289fa9e4066Sahrens int
2290fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2291fa9e4066Sahrens {
2292fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2293fa9e4066Sahrens }
2294fa9e4066Sahrens 
2295fa9e4066Sahrens /*
2296fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2297fa9e4066Sahrens  *
2298fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2299fa9e4066Sahrens  *
2300fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2301fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2302fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2303fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2304fa9e4066Sahrens  */
2305fa9e4066Sahrens int
2306fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2307fa9e4066Sahrens {
2308fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2309fa9e4066Sahrens }
2310fa9e4066Sahrens 
2311fa9e4066Sahrens /*
2312fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2313fa9e4066Sahrens  *
2314fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2315fa9e4066Sahrens  *		(not supported yet)
2316fa9e4066Sahrens  *
2317fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2318fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2319fa9e4066Sahrens  * has the only valid copy of some data.
2320fa9e4066Sahrens  */
2321fa9e4066Sahrens /* ARGSUSED */
2322fa9e4066Sahrens int
2323fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2324fa9e4066Sahrens {
2325fa9e4066Sahrens 	int c;
2326fa9e4066Sahrens 	char *poolname, *path;
2327fa9e4066Sahrens 	zpool_handle_t *zhp;
232899653d4eSeschrock 	int ret;
2329fa9e4066Sahrens 
2330fa9e4066Sahrens 	/* check options */
2331fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2332fa9e4066Sahrens 		switch (c) {
2333fa9e4066Sahrens 		case 'f':
2334fa9e4066Sahrens 		case '?':
2335fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2336fa9e4066Sahrens 			    optopt);
233799653d4eSeschrock 			usage(B_FALSE);
2338fa9e4066Sahrens 		}
2339fa9e4066Sahrens 	}
2340fa9e4066Sahrens 
2341fa9e4066Sahrens 	argc -= optind;
2342fa9e4066Sahrens 	argv += optind;
2343fa9e4066Sahrens 
2344fa9e4066Sahrens 	/* get pool name and check number of arguments */
2345fa9e4066Sahrens 	if (argc < 1) {
2346fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
234799653d4eSeschrock 		usage(B_FALSE);
2348fa9e4066Sahrens 	}
2349fa9e4066Sahrens 
2350fa9e4066Sahrens 	if (argc < 2) {
2351fa9e4066Sahrens 		(void) fprintf(stderr,
2352fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
235399653d4eSeschrock 		usage(B_FALSE);
2354fa9e4066Sahrens 	}
2355fa9e4066Sahrens 
2356fa9e4066Sahrens 	poolname = argv[0];
2357fa9e4066Sahrens 	path = argv[1];
2358fa9e4066Sahrens 
235999653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2360fa9e4066Sahrens 		return (1);
2361fa9e4066Sahrens 
236299653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
236399653d4eSeschrock 
236499653d4eSeschrock 	zpool_close(zhp);
236599653d4eSeschrock 
236699653d4eSeschrock 	return (ret);
2367fa9e4066Sahrens }
2368fa9e4066Sahrens 
2369fa9e4066Sahrens /*
2370441d80aaSlling  * zpool online <pool> <device> ...
2371fa9e4066Sahrens  */
2372fa9e4066Sahrens int
2373fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2374fa9e4066Sahrens {
2375fa9e4066Sahrens 	int c, i;
2376fa9e4066Sahrens 	char *poolname;
2377fa9e4066Sahrens 	zpool_handle_t *zhp;
2378fa9e4066Sahrens 	int ret = 0;
23793d7072f8Seschrock 	vdev_state_t newstate;
2380fa9e4066Sahrens 
2381fa9e4066Sahrens 	/* check options */
2382fa9e4066Sahrens 	while ((c = getopt(argc, argv, "t")) != -1) {
2383fa9e4066Sahrens 		switch (c) {
2384fa9e4066Sahrens 		case 't':
2385fa9e4066Sahrens 		case '?':
2386fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2387fa9e4066Sahrens 			    optopt);
238899653d4eSeschrock 			usage(B_FALSE);
2389fa9e4066Sahrens 		}
2390fa9e4066Sahrens 	}
2391fa9e4066Sahrens 
2392fa9e4066Sahrens 	argc -= optind;
2393fa9e4066Sahrens 	argv += optind;
2394fa9e4066Sahrens 
2395fa9e4066Sahrens 	/* get pool name and check number of arguments */
2396fa9e4066Sahrens 	if (argc < 1) {
2397fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
239899653d4eSeschrock 		usage(B_FALSE);
2399fa9e4066Sahrens 	}
2400fa9e4066Sahrens 	if (argc < 2) {
2401fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
240299653d4eSeschrock 		usage(B_FALSE);
2403fa9e4066Sahrens 	}
2404fa9e4066Sahrens 
2405fa9e4066Sahrens 	poolname = argv[0];
2406fa9e4066Sahrens 
240799653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2408fa9e4066Sahrens 		return (1);
2409fa9e4066Sahrens 
24103d7072f8Seschrock 	for (i = 1; i < argc; i++) {
24113d7072f8Seschrock 		if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
24123d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
24133d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
24143d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
2415fa9e4066Sahrens 				    argv[i]);
24163d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
24173d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24183d7072f8Seschrock 					    "clear' to restore a faulted "
24193d7072f8Seschrock 					    "device\n"));
2420fa9e4066Sahrens 				else
24213d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24223d7072f8Seschrock 					    "replace' to replace devices "
24233d7072f8Seschrock 					    "that are no longer present\n"));
24243d7072f8Seschrock 			}
24253d7072f8Seschrock 		} else {
2426fa9e4066Sahrens 			ret = 1;
24273d7072f8Seschrock 		}
24283d7072f8Seschrock 	}
2429fa9e4066Sahrens 
243099653d4eSeschrock 	zpool_close(zhp);
243199653d4eSeschrock 
2432fa9e4066Sahrens 	return (ret);
2433fa9e4066Sahrens }
2434fa9e4066Sahrens 
2435fa9e4066Sahrens /*
2436441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2437fa9e4066Sahrens  *
2438fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2439fa9e4066Sahrens  *		so would appear to compromise pool availability.
2440fa9e4066Sahrens  *		(not supported yet)
2441fa9e4066Sahrens  *
2442fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2443fa9e4066Sahrens  *		state will not be persistent across reboots.
2444fa9e4066Sahrens  */
2445fa9e4066Sahrens /* ARGSUSED */
2446fa9e4066Sahrens int
2447fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2448fa9e4066Sahrens {
2449fa9e4066Sahrens 	int c, i;
2450fa9e4066Sahrens 	char *poolname;
2451fa9e4066Sahrens 	zpool_handle_t *zhp;
245299653d4eSeschrock 	int ret = 0;
245399653d4eSeschrock 	boolean_t istmp = B_FALSE;
2454fa9e4066Sahrens 
2455fa9e4066Sahrens 	/* check options */
2456fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2457fa9e4066Sahrens 		switch (c) {
2458fa9e4066Sahrens 		case 't':
245999653d4eSeschrock 			istmp = B_TRUE;
2460441d80aaSlling 			break;
2461441d80aaSlling 		case 'f':
2462fa9e4066Sahrens 		case '?':
2463fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2464fa9e4066Sahrens 			    optopt);
246599653d4eSeschrock 			usage(B_FALSE);
2466fa9e4066Sahrens 		}
2467fa9e4066Sahrens 	}
2468fa9e4066Sahrens 
2469fa9e4066Sahrens 	argc -= optind;
2470fa9e4066Sahrens 	argv += optind;
2471fa9e4066Sahrens 
2472fa9e4066Sahrens 	/* get pool name and check number of arguments */
2473fa9e4066Sahrens 	if (argc < 1) {
2474fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
247599653d4eSeschrock 		usage(B_FALSE);
2476fa9e4066Sahrens 	}
2477fa9e4066Sahrens 	if (argc < 2) {
2478fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
247999653d4eSeschrock 		usage(B_FALSE);
2480fa9e4066Sahrens 	}
2481fa9e4066Sahrens 
2482fa9e4066Sahrens 	poolname = argv[0];
2483fa9e4066Sahrens 
248499653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2485fa9e4066Sahrens 		return (1);
2486fa9e4066Sahrens 
24873d7072f8Seschrock 	for (i = 1; i < argc; i++) {
24883d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2489fa9e4066Sahrens 			ret = 1;
24903d7072f8Seschrock 	}
2491fa9e4066Sahrens 
249299653d4eSeschrock 	zpool_close(zhp);
249399653d4eSeschrock 
2494fa9e4066Sahrens 	return (ret);
2495fa9e4066Sahrens }
2496fa9e4066Sahrens 
2497ea8dc4b6Seschrock /*
2498ea8dc4b6Seschrock  * zpool clear <pool> [device]
2499ea8dc4b6Seschrock  *
2500ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2501ea8dc4b6Seschrock  */
2502ea8dc4b6Seschrock int
2503ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2504ea8dc4b6Seschrock {
2505ea8dc4b6Seschrock 	int ret = 0;
2506ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2507ea8dc4b6Seschrock 	char *pool, *device;
2508ea8dc4b6Seschrock 
2509ea8dc4b6Seschrock 	if (argc < 2) {
2510ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
251199653d4eSeschrock 		usage(B_FALSE);
2512ea8dc4b6Seschrock 	}
2513ea8dc4b6Seschrock 
2514ea8dc4b6Seschrock 	if (argc > 3) {
2515ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
251699653d4eSeschrock 		usage(B_FALSE);
2517ea8dc4b6Seschrock 	}
2518ea8dc4b6Seschrock 
2519ea8dc4b6Seschrock 	pool = argv[1];
2520ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2521ea8dc4b6Seschrock 
252299653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, pool)) == NULL)
2523ea8dc4b6Seschrock 		return (1);
2524ea8dc4b6Seschrock 
2525ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2526ea8dc4b6Seschrock 		ret = 1;
2527ea8dc4b6Seschrock 
2528ea8dc4b6Seschrock 	zpool_close(zhp);
2529ea8dc4b6Seschrock 
2530ea8dc4b6Seschrock 	return (ret);
2531ea8dc4b6Seschrock }
2532ea8dc4b6Seschrock 
2533fa9e4066Sahrens typedef struct scrub_cbdata {
2534fa9e4066Sahrens 	int	cb_type;
253506eeb2adSek110237 	int	cb_argc;
253606eeb2adSek110237 	char	**cb_argv;
2537fa9e4066Sahrens } scrub_cbdata_t;
2538fa9e4066Sahrens 
2539fa9e4066Sahrens int
2540fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2541fa9e4066Sahrens {
2542fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
254306eeb2adSek110237 	int err;
2544fa9e4066Sahrens 
2545ea8dc4b6Seschrock 	/*
2546ea8dc4b6Seschrock 	 * Ignore faulted pools.
2547ea8dc4b6Seschrock 	 */
2548ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2549ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2550ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2551ea8dc4b6Seschrock 		return (1);
2552ea8dc4b6Seschrock 	}
2553ea8dc4b6Seschrock 
255406eeb2adSek110237 	err = zpool_scrub(zhp, cb->cb_type);
255506eeb2adSek110237 
255606eeb2adSek110237 	return (err != 0);
2557fa9e4066Sahrens }
2558fa9e4066Sahrens 
2559fa9e4066Sahrens /*
2560fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2561fa9e4066Sahrens  *
2562fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2563fa9e4066Sahrens  */
2564fa9e4066Sahrens int
2565fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2566fa9e4066Sahrens {
2567fa9e4066Sahrens 	int c;
2568fa9e4066Sahrens 	scrub_cbdata_t cb;
2569fa9e4066Sahrens 
2570fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2571fa9e4066Sahrens 
2572fa9e4066Sahrens 	/* check options */
2573fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2574fa9e4066Sahrens 		switch (c) {
2575fa9e4066Sahrens 		case 's':
2576fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2577fa9e4066Sahrens 			break;
2578fa9e4066Sahrens 		case '?':
2579fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2580fa9e4066Sahrens 			    optopt);
258199653d4eSeschrock 			usage(B_FALSE);
2582fa9e4066Sahrens 		}
2583fa9e4066Sahrens 	}
2584fa9e4066Sahrens 
258506eeb2adSek110237 	cb.cb_argc = argc;
258606eeb2adSek110237 	cb.cb_argv = argv;
2587fa9e4066Sahrens 	argc -= optind;
2588fa9e4066Sahrens 	argv += optind;
2589fa9e4066Sahrens 
2590fa9e4066Sahrens 	if (argc < 1) {
2591fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
259299653d4eSeschrock 		usage(B_FALSE);
2593fa9e4066Sahrens 	}
2594fa9e4066Sahrens 
2595b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2596fa9e4066Sahrens }
2597fa9e4066Sahrens 
2598fa9e4066Sahrens typedef struct status_cbdata {
2599fa9e4066Sahrens 	int		cb_count;
2600e9dbad6fSeschrock 	boolean_t	cb_allpools;
260199653d4eSeschrock 	boolean_t	cb_verbose;
260299653d4eSeschrock 	boolean_t	cb_explain;
260399653d4eSeschrock 	boolean_t	cb_first;
2604fa9e4066Sahrens } status_cbdata_t;
2605fa9e4066Sahrens 
2606fa9e4066Sahrens /*
2607fa9e4066Sahrens  * Print out detailed scrub status.
2608fa9e4066Sahrens  */
2609fa9e4066Sahrens void
2610fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2611fa9e4066Sahrens {
2612fa9e4066Sahrens 	vdev_stat_t *vs;
2613fa9e4066Sahrens 	uint_t vsc;
2614fa9e4066Sahrens 	time_t start, end, now;
2615fa9e4066Sahrens 	double fraction_done;
261618ce54dfSek110237 	uint64_t examined, total, minutes_left, minutes_taken;
2617fa9e4066Sahrens 	char *scrub_type;
2618fa9e4066Sahrens 
2619fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2620fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2621fa9e4066Sahrens 
2622fa9e4066Sahrens 	/*
2623fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2624fa9e4066Sahrens 	 */
2625fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2626fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2627fa9e4066Sahrens 		return;
2628fa9e4066Sahrens 	}
2629fa9e4066Sahrens 
2630fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2631fa9e4066Sahrens 	    "resilver" : "scrub";
2632fa9e4066Sahrens 
2633fa9e4066Sahrens 	start = vs->vs_scrub_start;
2634fa9e4066Sahrens 	end = vs->vs_scrub_end;
2635fa9e4066Sahrens 	now = time(NULL);
2636fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2637fa9e4066Sahrens 	total = vs->vs_alloc;
2638fa9e4066Sahrens 
2639fa9e4066Sahrens 	if (end != 0) {
264018ce54dfSek110237 		minutes_taken = (uint64_t)((end - start) / 60);
264118ce54dfSek110237 
264218ce54dfSek110237 		(void) printf(gettext("%s %s after %lluh%um with %llu errors "
264318ce54dfSek110237 		    "on %s"),
2644fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
264518ce54dfSek110237 		    (u_longlong_t)(minutes_taken / 60),
264618ce54dfSek110237 		    (uint_t)(minutes_taken % 60),
2647fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2648fa9e4066Sahrens 		return;
2649fa9e4066Sahrens 	}
2650fa9e4066Sahrens 
2651fa9e4066Sahrens 	if (examined == 0)
2652fa9e4066Sahrens 		examined = 1;
2653fa9e4066Sahrens 	if (examined > total)
2654fa9e4066Sahrens 		total = examined;
2655fa9e4066Sahrens 
2656fa9e4066Sahrens 	fraction_done = (double)examined / total;
2657fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2658fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
265918ce54dfSek110237 	minutes_taken = (uint64_t)((now - start) / 60);
2660fa9e4066Sahrens 
266118ce54dfSek110237 	(void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, "
266218ce54dfSek110237 	    "%lluh%um to go\n"),
266318ce54dfSek110237 	    scrub_type, (u_longlong_t)(minutes_taken / 60),
266418ce54dfSek110237 	    (uint_t)(minutes_taken % 60), 100 * fraction_done,
2665fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2666fa9e4066Sahrens }
2667fa9e4066Sahrens 
266899653d4eSeschrock typedef struct spare_cbdata {
266999653d4eSeschrock 	uint64_t	cb_guid;
267099653d4eSeschrock 	zpool_handle_t	*cb_zhp;
267199653d4eSeschrock } spare_cbdata_t;
267299653d4eSeschrock 
267399653d4eSeschrock static boolean_t
267499653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search)
267599653d4eSeschrock {
267699653d4eSeschrock 	uint64_t guid;
267799653d4eSeschrock 	nvlist_t **child;
267899653d4eSeschrock 	uint_t c, children;
267999653d4eSeschrock 
268099653d4eSeschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
268199653d4eSeschrock 	    search == guid)
268299653d4eSeschrock 		return (B_TRUE);
268399653d4eSeschrock 
268499653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
268599653d4eSeschrock 	    &child, &children) == 0) {
268699653d4eSeschrock 		for (c = 0; c < children; c++)
268799653d4eSeschrock 			if (find_vdev(child[c], search))
268899653d4eSeschrock 				return (B_TRUE);
268999653d4eSeschrock 	}
269099653d4eSeschrock 
269199653d4eSeschrock 	return (B_FALSE);
269299653d4eSeschrock }
269399653d4eSeschrock 
269499653d4eSeschrock static int
269599653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data)
269699653d4eSeschrock {
269799653d4eSeschrock 	spare_cbdata_t *cbp = data;
269899653d4eSeschrock 	nvlist_t *config, *nvroot;
269999653d4eSeschrock 
270099653d4eSeschrock 	config = zpool_get_config(zhp, NULL);
270199653d4eSeschrock 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
270299653d4eSeschrock 	    &nvroot) == 0);
270399653d4eSeschrock 
270499653d4eSeschrock 	if (find_vdev(nvroot, cbp->cb_guid)) {
270599653d4eSeschrock 		cbp->cb_zhp = zhp;
270699653d4eSeschrock 		return (1);
270799653d4eSeschrock 	}
270899653d4eSeschrock 
270999653d4eSeschrock 	zpool_close(zhp);
271099653d4eSeschrock 	return (0);
271199653d4eSeschrock }
271299653d4eSeschrock 
2713fa9e4066Sahrens /*
2714fa9e4066Sahrens  * Print out configuration state as requested by status_callback.
2715fa9e4066Sahrens  */
2716fa9e4066Sahrens void
2717c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
27188654d025Sperrin     int namewidth, int depth, boolean_t isspare, boolean_t print_logs)
2719fa9e4066Sahrens {
2720fa9e4066Sahrens 	nvlist_t **child;
2721fa9e4066Sahrens 	uint_t c, children;
2722fa9e4066Sahrens 	vdev_stat_t *vs;
2723ea8dc4b6Seschrock 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
2724afefbcddSeschrock 	char *vname;
2725ea8dc4b6Seschrock 	uint64_t notpresent;
272699653d4eSeschrock 	spare_cbdata_t cb;
2727990b4856Slling 	char *state;
2728fa9e4066Sahrens 
2729fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2730fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2731fa9e4066Sahrens 
2732fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2733fa9e4066Sahrens 	    &child, &children) != 0)
2734fa9e4066Sahrens 		children = 0;
2735fa9e4066Sahrens 
2736990b4856Slling 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
273799653d4eSeschrock 	if (isspare) {
273899653d4eSeschrock 		/*
273999653d4eSeschrock 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
274099653d4eSeschrock 		 * online drives.
274199653d4eSeschrock 		 */
274299653d4eSeschrock 		if (vs->vs_aux == VDEV_AUX_SPARED)
274399653d4eSeschrock 			state = "INUSE";
274499653d4eSeschrock 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
274599653d4eSeschrock 			state = "AVAIL";
274699653d4eSeschrock 	}
2747fa9e4066Sahrens 
274899653d4eSeschrock 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
274999653d4eSeschrock 	    name, state);
275099653d4eSeschrock 
275199653d4eSeschrock 	if (!isspare) {
2752fa9e4066Sahrens 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
2753fa9e4066Sahrens 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
2754fa9e4066Sahrens 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
2755fa9e4066Sahrens 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
275699653d4eSeschrock 	}
2757fa9e4066Sahrens 
2758ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2759ea8dc4b6Seschrock 	    &notpresent) == 0) {
2760ea8dc4b6Seschrock 		char *path;
2761ea8dc4b6Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
27620917b783Seschrock 		(void) printf("  was %s", path);
2763ea8dc4b6Seschrock 	} else if (vs->vs_aux != 0) {
2764fa9e4066Sahrens 		(void) printf("  ");
2765fa9e4066Sahrens 
2766fa9e4066Sahrens 		switch (vs->vs_aux) {
2767fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2768fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2769fa9e4066Sahrens 			break;
2770fa9e4066Sahrens 
2771fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2772fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2773fa9e4066Sahrens 			break;
2774fa9e4066Sahrens 
2775fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2776fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2777fa9e4066Sahrens 			break;
2778fa9e4066Sahrens 
2779eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
2780eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
2781eaca9bbdSeschrock 			break;
2782eaca9bbdSeschrock 
278399653d4eSeschrock 		case VDEV_AUX_SPARED:
278499653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
278599653d4eSeschrock 			    &cb.cb_guid) == 0);
278699653d4eSeschrock 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
278799653d4eSeschrock 				if (strcmp(zpool_get_name(cb.cb_zhp),
278899653d4eSeschrock 				    zpool_get_name(zhp)) == 0)
278999653d4eSeschrock 					(void) printf(gettext("currently in "
279099653d4eSeschrock 					    "use"));
279199653d4eSeschrock 				else
279299653d4eSeschrock 					(void) printf(gettext("in use by "
279399653d4eSeschrock 					    "pool '%s'"),
279499653d4eSeschrock 					    zpool_get_name(cb.cb_zhp));
279599653d4eSeschrock 				zpool_close(cb.cb_zhp);
279699653d4eSeschrock 			} else {
279799653d4eSeschrock 				(void) printf(gettext("currently in use"));
279899653d4eSeschrock 			}
279999653d4eSeschrock 			break;
280099653d4eSeschrock 
28013d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
28023d7072f8Seschrock 			(void) printf(gettext("too many errors"));
28033d7072f8Seschrock 			break;
28043d7072f8Seschrock 
280532b87932Sek110237 		case VDEV_AUX_IO_FAILURE:
280632b87932Sek110237 			(void) printf(gettext("experienced I/O failures"));
280732b87932Sek110237 			break;
280832b87932Sek110237 
2809fa9e4066Sahrens 		default:
2810fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2811fa9e4066Sahrens 			break;
2812fa9e4066Sahrens 		}
2813fa9e4066Sahrens 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2814fa9e4066Sahrens 		/*
2815fa9e4066Sahrens 		 * Report bytes resilvered/repaired on leaf devices.
2816fa9e4066Sahrens 		 */
2817fa9e4066Sahrens 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2818fa9e4066Sahrens 		(void) printf(gettext("  %s %s"), repaired,
2819fa9e4066Sahrens 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2820fa9e4066Sahrens 		    "resilvered" : "repaired");
2821fa9e4066Sahrens 	}
2822fa9e4066Sahrens 
2823fa9e4066Sahrens 	(void) printf("\n");
2824fa9e4066Sahrens 
2825afefbcddSeschrock 	for (c = 0; c < children; c++) {
28268654d025Sperrin 		uint64_t is_log = B_FALSE;
28278654d025Sperrin 
28288654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
28298654d025Sperrin 		    &is_log);
28308654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
28318654d025Sperrin 			continue;
283299653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
2833c67d9675Seschrock 		print_status_config(zhp, vname, child[c],
28348654d025Sperrin 		    namewidth, depth + 2, isspare, B_FALSE);
2835afefbcddSeschrock 		free(vname);
2836afefbcddSeschrock 	}
2837fa9e4066Sahrens }
2838fa9e4066Sahrens 
2839ea8dc4b6Seschrock static void
2840ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
2841ea8dc4b6Seschrock {
284275519f38Sek110237 	nvlist_t *nverrlist = NULL;
284355434c77Sek110237 	nvpair_t *elem;
284455434c77Sek110237 	char *pathname;
284555434c77Sek110237 	size_t len = MAXPATHLEN * 2;
2846ea8dc4b6Seschrock 
284755434c77Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2848ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
2849ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
2850ea8dc4b6Seschrock 		return;
2851ea8dc4b6Seschrock 	}
2852ea8dc4b6Seschrock 
285355434c77Sek110237 	(void) printf("errors: Permanent errors have been "
285455434c77Sek110237 	    "detected in the following files:\n\n");
2855ea8dc4b6Seschrock 
285655434c77Sek110237 	pathname = safe_malloc(len);
285755434c77Sek110237 	elem = NULL;
285855434c77Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
285955434c77Sek110237 		nvlist_t *nv;
286055434c77Sek110237 		uint64_t dsobj, obj;
2861ea8dc4b6Seschrock 
286255434c77Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
286355434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
286455434c77Sek110237 		    &dsobj) == 0);
286555434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
286655434c77Sek110237 		    &obj) == 0);
286755434c77Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
286855434c77Sek110237 		(void) printf("%7s %s\n", "", pathname);
2869ea8dc4b6Seschrock 	}
287055434c77Sek110237 	free(pathname);
287155434c77Sek110237 	nvlist_free(nverrlist);
2872ea8dc4b6Seschrock }
2873ea8dc4b6Seschrock 
287499653d4eSeschrock static void
287599653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
287699653d4eSeschrock     int namewidth)
287799653d4eSeschrock {
287899653d4eSeschrock 	uint_t i;
287999653d4eSeschrock 	char *name;
288099653d4eSeschrock 
288199653d4eSeschrock 	if (nspares == 0)
288299653d4eSeschrock 		return;
288399653d4eSeschrock 
288499653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
288599653d4eSeschrock 
288699653d4eSeschrock 	for (i = 0; i < nspares; i++) {
288799653d4eSeschrock 		name = zpool_vdev_name(g_zfs, zhp, spares[i]);
288899653d4eSeschrock 		print_status_config(zhp, name, spares[i],
28898654d025Sperrin 		    namewidth, 2, B_TRUE, B_FALSE);
289099653d4eSeschrock 		free(name);
289199653d4eSeschrock 	}
289299653d4eSeschrock }
289399653d4eSeschrock 
2894fa94a07fSbrendan static void
2895fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
2896fa94a07fSbrendan     int namewidth)
2897fa94a07fSbrendan {
2898fa94a07fSbrendan 	uint_t i;
2899fa94a07fSbrendan 	char *name;
2900fa94a07fSbrendan 
2901fa94a07fSbrendan 	if (nl2cache == 0)
2902fa94a07fSbrendan 		return;
2903fa94a07fSbrendan 
2904fa94a07fSbrendan 	(void) printf(gettext("\tcache\n"));
2905fa94a07fSbrendan 
2906fa94a07fSbrendan 	for (i = 0; i < nl2cache; i++) {
2907fa94a07fSbrendan 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i]);
2908fa94a07fSbrendan 		print_status_config(zhp, name, l2cache[i],
2909fa94a07fSbrendan 		    namewidth, 2, B_FALSE, B_FALSE);
2910fa94a07fSbrendan 		free(name);
2911fa94a07fSbrendan 	}
2912fa94a07fSbrendan }
2913fa94a07fSbrendan 
2914fa9e4066Sahrens /*
2915fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
2916fa9e4066Sahrens  *
2917fa9e4066Sahrens  *        pool: tank
2918fa9e4066Sahrens  *	status: DEGRADED
2919fa9e4066Sahrens  *	reason: One or more devices ...
2920fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
2921fa9e4066Sahrens  *	config:
2922fa9e4066Sahrens  *		mirror		DEGRADED
2923fa9e4066Sahrens  *                c1t0d0	OK
2924ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
2925fa9e4066Sahrens  *
2926fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
2927fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
2928fa9e4066Sahrens  */
2929fa9e4066Sahrens int
2930fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
2931fa9e4066Sahrens {
2932fa9e4066Sahrens 	status_cbdata_t *cbp = data;
2933fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2934fa9e4066Sahrens 	char *msgid;
2935fa9e4066Sahrens 	int reason;
293646657f8dSmmusante 	const char *health;
293746657f8dSmmusante 	uint_t c;
293846657f8dSmmusante 	vdev_stat_t *vs;
2939fa9e4066Sahrens 
2940088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
2941fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
2942fa9e4066Sahrens 
2943fa9e4066Sahrens 	cbp->cb_count++;
2944fa9e4066Sahrens 
2945fa9e4066Sahrens 	/*
2946fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
2947fa9e4066Sahrens 	 * problems.
2948fa9e4066Sahrens 	 */
2949e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
2950e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
2951e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
2952e9dbad6fSeschrock 			    zpool_get_name(zhp));
2953e9dbad6fSeschrock 			if (cbp->cb_first)
2954e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
2955e9dbad6fSeschrock 		}
2956fa9e4066Sahrens 		return (0);
2957e9dbad6fSeschrock 	}
2958fa9e4066Sahrens 
2959fa9e4066Sahrens 	if (cbp->cb_first)
296099653d4eSeschrock 		cbp->cb_first = B_FALSE;
2961fa9e4066Sahrens 	else
2962fa9e4066Sahrens 		(void) printf("\n");
2963fa9e4066Sahrens 
296446657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
296546657f8dSmmusante 	    &nvroot) == 0);
296646657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
296746657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
2968990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
2969fa9e4066Sahrens 
2970fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
2971fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
2972fa9e4066Sahrens 
2973fa9e4066Sahrens 	switch (reason) {
2974fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
2975fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2976fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
2977fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
2978fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2979fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2980fa9e4066Sahrens 		break;
2981fa9e4066Sahrens 
2982fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
2983fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2984fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
2985fa9e4066Sahrens 		    "pool to continue functioning.\n"));
2986fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2987fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2988fa9e4066Sahrens 		break;
2989fa9e4066Sahrens 
2990fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
2991fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2992fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
2993fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
2994fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
2995fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
2996fa9e4066Sahrens 		    "'zpool replace'.\n"));
2997fa9e4066Sahrens 		break;
2998fa9e4066Sahrens 
2999fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3000fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3001b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
3002fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
3003fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
3004fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
3005fa9e4066Sahrens 		    "from a backup source.\n"));
3006fa9e4066Sahrens 		break;
3007fa9e4066Sahrens 
3008fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
3009fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3010fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
3011fa9e4066Sahrens 		    "made to correct the error.  Applications are "
3012fa9e4066Sahrens 		    "unaffected.\n"));
3013fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
3014fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
3015ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
3016fa9e4066Sahrens 		    "replace'.\n"));
3017fa9e4066Sahrens 		break;
3018fa9e4066Sahrens 
3019fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
3020fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3021d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
3022fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
3023fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
3024fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
3025fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
3026fa9e4066Sahrens 		    "replace'.\n"));
3027fa9e4066Sahrens 		break;
3028fa9e4066Sahrens 
3029fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
3030fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
3031fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3032fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
3033fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3034fa9e4066Sahrens 		    "complete.\n"));
3035fa9e4066Sahrens 		break;
3036fa9e4066Sahrens 
3037ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3038ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3039ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3040ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3041ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3042ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3043ea8dc4b6Seschrock 		    "backup.\n"));
3044ea8dc4b6Seschrock 		break;
3045ea8dc4b6Seschrock 
3046ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3047ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3048ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3049ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
3050ea8dc4b6Seschrock 		    "from a backup source.\n"));
3051ea8dc4b6Seschrock 		break;
3052ea8dc4b6Seschrock 
3053eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3054eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3055eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3056eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3057eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3058eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3059eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3060eaca9bbdSeschrock 		break;
3061eaca9bbdSeschrock 
3062eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3063eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3064eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3065eaca9bbdSeschrock 		    "be accessed on this system.\n"));
3066eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
3067eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
3068eaca9bbdSeschrock 		    "backup.\n"));
3069eaca9bbdSeschrock 		break;
3070eaca9bbdSeschrock 
30713d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
30723d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
30733d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
30743d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
30753d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
30763d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
30773d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
30783d7072f8Seschrock 		break;
30793d7072f8Seschrock 
30803d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
30813d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
30823d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
30833d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
30843d7072f8Seschrock 		    "functioning.\n"));
30853d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
30863d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
30873d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
30883d7072f8Seschrock 		    "to be recovered.\n"));
30893d7072f8Seschrock 		break;
30903d7072f8Seschrock 
309132b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_WAIT:
309232b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
309332b87932Sek110237 		(void) printf(gettext("status: One or more devices are "
309432b87932Sek110237 		    "faultd in response to IO failures.\n"));
309532b87932Sek110237 		(void) printf(gettext("action: Make sure the affected devices "
309632b87932Sek110237 		    "are connected, then run 'zpool clear'.\n"));
309732b87932Sek110237 		break;
309832b87932Sek110237 
3099fa9e4066Sahrens 	default:
3100fa9e4066Sahrens 		/*
3101fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
3102fa9e4066Sahrens 		 */
3103fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
3104fa9e4066Sahrens 	}
3105fa9e4066Sahrens 
3106fa9e4066Sahrens 	if (msgid != NULL)
3107fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3108fa9e4066Sahrens 		    msgid);
3109fa9e4066Sahrens 
3110fa9e4066Sahrens 	if (config != NULL) {
3111fa9e4066Sahrens 		int namewidth;
3112ea8dc4b6Seschrock 		uint64_t nerr;
3113fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
3114fa94a07fSbrendan 		uint_t nspares, nl2cache;
3115fa9e4066Sahrens 
3116fa9e4066Sahrens 
3117fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
3118fa9e4066Sahrens 		print_scrub_status(nvroot);
3119fa9e4066Sahrens 
3120c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3121fa9e4066Sahrens 		if (namewidth < 10)
3122fa9e4066Sahrens 			namewidth = 10;
3123fa9e4066Sahrens 
3124fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
3125fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3126fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3127c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
31288654d025Sperrin 		    namewidth, 0, B_FALSE, B_FALSE);
31298654d025Sperrin 		if (num_logs(nvroot) > 0)
31308654d025Sperrin 			print_status_config(zhp, "logs", nvroot, namewidth, 0,
31318654d025Sperrin 			    B_FALSE, B_TRUE);
313299653d4eSeschrock 
3133fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
3134fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
3135fa94a07fSbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
3136fa94a07fSbrendan 
313799653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
313899653d4eSeschrock 		    &spares, &nspares) == 0)
313999653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
3140ea8dc4b6Seschrock 
3141ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3142ea8dc4b6Seschrock 		    &nerr) == 0) {
314355434c77Sek110237 			nvlist_t *nverrlist = NULL;
314455434c77Sek110237 
3145ea8dc4b6Seschrock 			/*
3146ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3147ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3148ea8dc4b6Seschrock 			 * uniquifying the results.
3149ea8dc4b6Seschrock 			 */
315075519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
315155434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
315255434c77Sek110237 				nvpair_t *elem;
315355434c77Sek110237 
315455434c77Sek110237 				elem = NULL;
315555434c77Sek110237 				nerr = 0;
315655434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
315755434c77Sek110237 				    elem)) != NULL) {
315855434c77Sek110237 					nerr++;
315955434c77Sek110237 				}
316055434c77Sek110237 			}
316155434c77Sek110237 			nvlist_free(nverrlist);
3162ea8dc4b6Seschrock 
3163ea8dc4b6Seschrock 			(void) printf("\n");
316499653d4eSeschrock 
3165ea8dc4b6Seschrock 			if (nerr == 0)
3166ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3167ea8dc4b6Seschrock 				    "errors\n"));
3168ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3169e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
31705ad82045Snd150628 				    "errors, use '-v' for a list\n"),
31715ad82045Snd150628 				    (u_longlong_t)nerr);
3172ea8dc4b6Seschrock 			else
3173ea8dc4b6Seschrock 				print_error_log(zhp);
3174ea8dc4b6Seschrock 		}
3175fa9e4066Sahrens 	} else {
3176fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3177fa9e4066Sahrens 		    "determined.\n"));
3178fa9e4066Sahrens 	}
3179fa9e4066Sahrens 
3180fa9e4066Sahrens 	return (0);
3181fa9e4066Sahrens }
3182fa9e4066Sahrens 
3183fa9e4066Sahrens /*
3184fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3185fa9e4066Sahrens  *
3186fa9e4066Sahrens  *	-v	Display complete error logs
3187fa9e4066Sahrens  *	-x	Display only pools with potential problems
3188fa9e4066Sahrens  *
3189fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3190fa9e4066Sahrens  */
3191fa9e4066Sahrens int
3192fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3193fa9e4066Sahrens {
3194fa9e4066Sahrens 	int c;
3195fa9e4066Sahrens 	int ret;
3196fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3197fa9e4066Sahrens 
3198fa9e4066Sahrens 	/* check options */
3199fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3200fa9e4066Sahrens 		switch (c) {
3201fa9e4066Sahrens 		case 'v':
320299653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3203fa9e4066Sahrens 			break;
3204fa9e4066Sahrens 		case 'x':
320599653d4eSeschrock 			cb.cb_explain = B_TRUE;
3206fa9e4066Sahrens 			break;
3207fa9e4066Sahrens 		case '?':
3208fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3209fa9e4066Sahrens 			    optopt);
321099653d4eSeschrock 			usage(B_FALSE);
3211fa9e4066Sahrens 		}
3212fa9e4066Sahrens 	}
3213fa9e4066Sahrens 
3214fa9e4066Sahrens 	argc -= optind;
3215fa9e4066Sahrens 	argv += optind;
3216fa9e4066Sahrens 
321799653d4eSeschrock 	cb.cb_first = B_TRUE;
3218fa9e4066Sahrens 
3219e9dbad6fSeschrock 	if (argc == 0)
3220e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3221e9dbad6fSeschrock 
3222b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3223fa9e4066Sahrens 
3224fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3225fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3226e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3227fa9e4066Sahrens 		(void) printf(gettext("all pools are healthy\n"));
3228fa9e4066Sahrens 
3229fa9e4066Sahrens 	return (ret);
3230fa9e4066Sahrens }
3231fa9e4066Sahrens 
3232eaca9bbdSeschrock typedef struct upgrade_cbdata {
3233eaca9bbdSeschrock 	int	cb_all;
3234eaca9bbdSeschrock 	int	cb_first;
3235eaca9bbdSeschrock 	int	cb_newer;
323606eeb2adSek110237 	int	cb_argc;
3237990b4856Slling 	uint64_t cb_version;
323806eeb2adSek110237 	char	**cb_argv;
3239eaca9bbdSeschrock } upgrade_cbdata_t;
3240eaca9bbdSeschrock 
3241eaca9bbdSeschrock static int
3242eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3243eaca9bbdSeschrock {
3244eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3245eaca9bbdSeschrock 	nvlist_t *config;
3246eaca9bbdSeschrock 	uint64_t version;
3247eaca9bbdSeschrock 	int ret = 0;
3248eaca9bbdSeschrock 
3249eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3250eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3251eaca9bbdSeschrock 	    &version) == 0);
3252eaca9bbdSeschrock 
3253e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3254eaca9bbdSeschrock 		if (!cbp->cb_all) {
3255eaca9bbdSeschrock 			if (cbp->cb_first) {
3256eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3257eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3258eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3259eaca9bbdSeschrock 				    "longer be accessible by older software "
3260eaca9bbdSeschrock 				    "versions.\n\n"));
3261eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3262eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
326399653d4eSeschrock 				cbp->cb_first = B_FALSE;
3264eaca9bbdSeschrock 			}
3265eaca9bbdSeschrock 
32665ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3267eaca9bbdSeschrock 			    zpool_get_name(zhp));
3268eaca9bbdSeschrock 		} else {
326999653d4eSeschrock 			cbp->cb_first = B_FALSE;
3270990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
327106eeb2adSek110237 			if (!ret) {
3272eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3273990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
3274eaca9bbdSeschrock 			}
327506eeb2adSek110237 		}
3276e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3277eaca9bbdSeschrock 		assert(!cbp->cb_all);
3278eaca9bbdSeschrock 
3279eaca9bbdSeschrock 		if (cbp->cb_first) {
3280eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3281eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3282eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3283eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3284eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
328599653d4eSeschrock 			cbp->cb_first = B_FALSE;
3286eaca9bbdSeschrock 		}
3287eaca9bbdSeschrock 
32885ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3289eaca9bbdSeschrock 		    zpool_get_name(zhp));
3290eaca9bbdSeschrock 	}
3291eaca9bbdSeschrock 
3292eaca9bbdSeschrock 	zpool_close(zhp);
3293eaca9bbdSeschrock 	return (ret);
3294eaca9bbdSeschrock }
3295eaca9bbdSeschrock 
3296eaca9bbdSeschrock /* ARGSUSED */
3297eaca9bbdSeschrock static int
329806eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
3299eaca9bbdSeschrock {
3300990b4856Slling 	upgrade_cbdata_t *cbp = data;
3301990b4856Slling 	uint64_t cur_version;
3302eaca9bbdSeschrock 	int ret;
3303eaca9bbdSeschrock 
33048654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
33058654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
33068654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
33078654d025Sperrin 		    " to upgrade.\n"));
33088654d025Sperrin 		return (1);
33098654d025Sperrin 	}
3310990b4856Slling 
3311990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3312e6c728e1Sbrendan 	if (cur_version > cbp->cb_version) {
3313eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3314e6c728e1Sbrendan 		    "using more current version '%llu'.\n"),
3315e6c728e1Sbrendan 		    zpool_get_name(zhp), cur_version);
3316e6c728e1Sbrendan 		return (0);
3317e6c728e1Sbrendan 	}
3318e6c728e1Sbrendan 	if (cur_version == cbp->cb_version) {
3319e6c728e1Sbrendan 		(void) printf(gettext("Pool '%s' is already formatted "
3320e6c728e1Sbrendan 		    "using the current version.\n"), zpool_get_name(zhp));
3321eaca9bbdSeschrock 		return (0);
3322eaca9bbdSeschrock 	}
3323eaca9bbdSeschrock 
3324990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
332506eeb2adSek110237 
332606eeb2adSek110237 	if (!ret) {
332744cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
3328990b4856Slling 		    "from version %llu to version %llu\n\n"),
3329990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3330990b4856Slling 		    (u_longlong_t)cbp->cb_version);
333106eeb2adSek110237 	}
3332eaca9bbdSeschrock 
3333eaca9bbdSeschrock 	return (ret != 0);
3334eaca9bbdSeschrock }
3335eaca9bbdSeschrock 
3336eaca9bbdSeschrock /*
3337eaca9bbdSeschrock  * zpool upgrade
3338eaca9bbdSeschrock  * zpool upgrade -v
3339990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
3340eaca9bbdSeschrock  *
3341eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3342eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3343eaca9bbdSeschrock  * upgrade all pools.
3344eaca9bbdSeschrock  */
3345eaca9bbdSeschrock int
3346eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3347eaca9bbdSeschrock {
3348eaca9bbdSeschrock 	int c;
3349eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3350eaca9bbdSeschrock 	int ret = 0;
3351eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3352990b4856Slling 	char *end;
3353990b4856Slling 
3354eaca9bbdSeschrock 
3355eaca9bbdSeschrock 	/* check options */
3356990b4856Slling 	while ((c = getopt(argc, argv, "avV:")) != -1) {
3357eaca9bbdSeschrock 		switch (c) {
3358eaca9bbdSeschrock 		case 'a':
335999653d4eSeschrock 			cb.cb_all = B_TRUE;
3360eaca9bbdSeschrock 			break;
3361eaca9bbdSeschrock 		case 'v':
3362eaca9bbdSeschrock 			showversions = B_TRUE;
3363eaca9bbdSeschrock 			break;
3364990b4856Slling 		case 'V':
3365990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
3366351420b3Slling 			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
3367351420b3Slling 			    cb.cb_version < SPA_VERSION_1) {
3368990b4856Slling 				(void) fprintf(stderr,
3369990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
3370990b4856Slling 				usage(B_FALSE);
3371990b4856Slling 			}
3372990b4856Slling 			break;
3373eaca9bbdSeschrock 		case '?':
3374eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3375eaca9bbdSeschrock 			    optopt);
337699653d4eSeschrock 			usage(B_FALSE);
3377eaca9bbdSeschrock 		}
3378eaca9bbdSeschrock 	}
3379eaca9bbdSeschrock 
338006eeb2adSek110237 	cb.cb_argc = argc;
338106eeb2adSek110237 	cb.cb_argv = argv;
3382eaca9bbdSeschrock 	argc -= optind;
3383eaca9bbdSeschrock 	argv += optind;
3384eaca9bbdSeschrock 
3385351420b3Slling 	if (cb.cb_version == 0) {
3386351420b3Slling 		cb.cb_version = SPA_VERSION;
3387351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
3388351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
3389351420b3Slling 		    "incompatible with other arguments\n"));
3390351420b3Slling 		usage(B_FALSE);
3391351420b3Slling 	}
3392351420b3Slling 
3393eaca9bbdSeschrock 	if (showversions) {
3394eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3395eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3396eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
339799653d4eSeschrock 			usage(B_FALSE);
3398eaca9bbdSeschrock 		}
3399eaca9bbdSeschrock 	} else if (cb.cb_all) {
3400eaca9bbdSeschrock 		if (argc != 0) {
3401351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
3402351420b3Slling 			    "be used along with a pool name\n"));
340399653d4eSeschrock 			usage(B_FALSE);
3404eaca9bbdSeschrock 		}
3405eaca9bbdSeschrock 	}
3406eaca9bbdSeschrock 
3407e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3408e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
340999653d4eSeschrock 	cb.cb_first = B_TRUE;
3410eaca9bbdSeschrock 	if (showversions) {
3411eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3412d7d4af51Smmusante 		    "supported:\n\n"));
3413eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3414eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3415eaca9bbdSeschrock 		    "---------------\n");
341699653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
341744cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
341844cd46caSbillm 		    "(replicated metadata)\n"));
341999653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
342099653d4eSeschrock 		    "RAID-Z\n"));
3421d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
3422c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3423c9431fa1Sahl 		    "algorithm\n"));
3424990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
34258654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3426ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
3427a9799022Sck153898 		(void) printf(gettext(" 9   refquota and refreservation "
3428a9799022Sck153898 		    "properties\n"));
3429fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
34308654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3431eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3432eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3433eaca9bbdSeschrock 		    "version/N\n\n");
3434eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3435eaca9bbdSeschrock 	} else if (argc == 0) {
3436eaca9bbdSeschrock 		int notfound;
3437eaca9bbdSeschrock 
343899653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3439eaca9bbdSeschrock 		notfound = cb.cb_first;
3440eaca9bbdSeschrock 
3441eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3442eaca9bbdSeschrock 			if (!cb.cb_first)
3443eaca9bbdSeschrock 				(void) printf("\n");
3444eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3445eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
344699653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3447eaca9bbdSeschrock 			if (!cb.cb_first) {
3448eaca9bbdSeschrock 				notfound = B_FALSE;
3449eaca9bbdSeschrock 				(void) printf("\n");
3450eaca9bbdSeschrock 			}
3451eaca9bbdSeschrock 		}
3452eaca9bbdSeschrock 
3453eaca9bbdSeschrock 		if (ret == 0) {
3454eaca9bbdSeschrock 			if (notfound)
3455eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3456eaca9bbdSeschrock 				    "using this version.\n"));
3457eaca9bbdSeschrock 			else if (!cb.cb_all)
3458eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3459eaca9bbdSeschrock 				    "for a list of available versions and "
3460eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3461eaca9bbdSeschrock 		}
3462eaca9bbdSeschrock 	} else {
3463b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3464b1b8ab34Slling 		    upgrade_one, &cb);
346506eeb2adSek110237 	}
346606eeb2adSek110237 
346706eeb2adSek110237 	return (ret);
346806eeb2adSek110237 }
346906eeb2adSek110237 
3470ecd6cf80Smarks typedef struct hist_cbdata {
3471ecd6cf80Smarks 	boolean_t first;
3472ecd6cf80Smarks 	int longfmt;
3473ecd6cf80Smarks 	int internal;
3474ecd6cf80Smarks } hist_cbdata_t;
3475ecd6cf80Smarks 
3476ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3477ecd6cf80Smarks 	"invalid event",
3478ecd6cf80Smarks 	"pool create",
3479ecd6cf80Smarks 	"vdev add",
3480ecd6cf80Smarks 	"pool remove",
3481ecd6cf80Smarks 	"pool destroy",
3482ecd6cf80Smarks 	"pool export",
3483ecd6cf80Smarks 	"pool import",
3484ecd6cf80Smarks 	"vdev attach",
3485ecd6cf80Smarks 	"vdev replace",
3486ecd6cf80Smarks 	"vdev detach",
3487ecd6cf80Smarks 	"vdev online",
3488ecd6cf80Smarks 	"vdev offline",
3489ecd6cf80Smarks 	"vdev upgrade",
3490ecd6cf80Smarks 	"pool clear",
3491ecd6cf80Smarks 	"pool scrub",
3492ecd6cf80Smarks 	"pool property set",
3493ecd6cf80Smarks 	"create",
3494ecd6cf80Smarks 	"clone",
3495ecd6cf80Smarks 	"destroy",
3496ecd6cf80Smarks 	"destroy_begin_sync",
3497ecd6cf80Smarks 	"inherit",
3498ecd6cf80Smarks 	"property set",
3499ecd6cf80Smarks 	"quota set",
3500ecd6cf80Smarks 	"permission update",
3501ecd6cf80Smarks 	"permission remove",
3502ecd6cf80Smarks 	"permission who remove",
3503ecd6cf80Smarks 	"promote",
3504ecd6cf80Smarks 	"receive",
3505ecd6cf80Smarks 	"rename",
3506ecd6cf80Smarks 	"reservation set",
3507ecd6cf80Smarks 	"replay_inc_sync",
3508ecd6cf80Smarks 	"replay_full_sync",
3509ecd6cf80Smarks 	"rollback",
3510ecd6cf80Smarks 	"snapshot",
3511e7437265Sahrens 	"filesystem version upgrade",
3512a9799022Sck153898 	"refquota set",
3513a9799022Sck153898 	"refreservation set",
3514ecd6cf80Smarks };
3515ecd6cf80Smarks 
351606eeb2adSek110237 /*
351706eeb2adSek110237  * Print out the command history for a specific pool.
351806eeb2adSek110237  */
351906eeb2adSek110237 static int
352006eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
352106eeb2adSek110237 {
352206eeb2adSek110237 	nvlist_t *nvhis;
352306eeb2adSek110237 	nvlist_t **records;
352406eeb2adSek110237 	uint_t numrecords;
352506eeb2adSek110237 	char *cmdstr;
3526ecd6cf80Smarks 	char *pathstr;
352706eeb2adSek110237 	uint64_t dst_time;
352806eeb2adSek110237 	time_t tsec;
352906eeb2adSek110237 	struct tm t;
353006eeb2adSek110237 	char tbuf[30];
353106eeb2adSek110237 	int ret, i;
3532ecd6cf80Smarks 	uint64_t who;
3533ecd6cf80Smarks 	struct passwd *pwd;
3534ecd6cf80Smarks 	char *hostname;
3535ecd6cf80Smarks 	char *zonename;
3536ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3537ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3538ecd6cf80Smarks 	uint64_t txg;
3539ecd6cf80Smarks 	uint64_t ievent;
354006eeb2adSek110237 
3541ecd6cf80Smarks 	cb->first = B_FALSE;
354206eeb2adSek110237 
354306eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
354406eeb2adSek110237 
354506eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
354606eeb2adSek110237 		return (ret);
354706eeb2adSek110237 
354806eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
354906eeb2adSek110237 	    &records, &numrecords) == 0);
355006eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
355106eeb2adSek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3552ecd6cf80Smarks 		    &dst_time) != 0)
3553ecd6cf80Smarks 			continue;
3554ecd6cf80Smarks 
3555ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3556ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3557ecd6cf80Smarks 		    &cmdstr) != 0) {
3558ecd6cf80Smarks 			if (cb->internal == 0)
3559ecd6cf80Smarks 				continue;
3560ecd6cf80Smarks 
3561ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3562ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3563ecd6cf80Smarks 				continue;
3564ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3565ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3566ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3567ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3568ecd6cf80Smarks 			if (ievent > LOG_END)
3569ecd6cf80Smarks 				continue;
3570ecd6cf80Smarks 			(void) snprintf(internalstr,
3571ecd6cf80Smarks 			    sizeof (internalstr),
3572ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3573ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3574ecd6cf80Smarks 			    pathstr);
3575ecd6cf80Smarks 			cmdstr = internalstr;
3576ecd6cf80Smarks 		}
357706eeb2adSek110237 		tsec = dst_time;
357806eeb2adSek110237 		(void) localtime_r(&tsec, &t);
357906eeb2adSek110237 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3580ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3581ecd6cf80Smarks 
3582ecd6cf80Smarks 		if (!cb->longfmt) {
3583ecd6cf80Smarks 			(void) printf("\n");
3584ecd6cf80Smarks 			continue;
358506eeb2adSek110237 		}
3586ecd6cf80Smarks 		(void) printf(" [");
3587ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3588ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3589ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3590ecd6cf80Smarks 			if (pwd)
3591ecd6cf80Smarks 				(void) printf("user %s on",
3592ecd6cf80Smarks 				    pwd->pw_name);
3593ecd6cf80Smarks 			else
3594ecd6cf80Smarks 				(void) printf("user %d on",
3595ecd6cf80Smarks 				    (int)who);
3596ecd6cf80Smarks 		} else {
3597ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3598ecd6cf80Smarks 			continue;
3599ecd6cf80Smarks 		}
3600ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3601ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3602ecd6cf80Smarks 			(void) printf(" %s", hostname);
3603ecd6cf80Smarks 		}
3604ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3605ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3606ecd6cf80Smarks 			(void) printf(":%s", zonename);
3607ecd6cf80Smarks 		}
3608ecd6cf80Smarks 
3609ecd6cf80Smarks 		(void) printf("]");
3610ecd6cf80Smarks 		(void) printf("\n");
361106eeb2adSek110237 	}
361206eeb2adSek110237 	(void) printf("\n");
361306eeb2adSek110237 	nvlist_free(nvhis);
361406eeb2adSek110237 
361506eeb2adSek110237 	return (ret);
361606eeb2adSek110237 }
361706eeb2adSek110237 
361806eeb2adSek110237 /*
361906eeb2adSek110237  * zpool history <pool>
362006eeb2adSek110237  *
362106eeb2adSek110237  * Displays the history of commands that modified pools.
362206eeb2adSek110237  */
3623ecd6cf80Smarks 
3624ecd6cf80Smarks 
362506eeb2adSek110237 int
362606eeb2adSek110237 zpool_do_history(int argc, char **argv)
362706eeb2adSek110237 {
3628ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
362906eeb2adSek110237 	int ret;
3630ecd6cf80Smarks 	int c;
363106eeb2adSek110237 
3632ecd6cf80Smarks 	cbdata.first = B_TRUE;
3633ecd6cf80Smarks 	/* check options */
3634ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3635ecd6cf80Smarks 		switch (c) {
3636ecd6cf80Smarks 		case 'l':
3637ecd6cf80Smarks 			cbdata.longfmt = 1;
3638ecd6cf80Smarks 			break;
3639ecd6cf80Smarks 		case 'i':
3640ecd6cf80Smarks 			cbdata.internal = 1;
3641ecd6cf80Smarks 			break;
3642ecd6cf80Smarks 		case '?':
3643ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3644ecd6cf80Smarks 			    optopt);
3645ecd6cf80Smarks 			usage(B_FALSE);
3646ecd6cf80Smarks 		}
3647ecd6cf80Smarks 	}
364806eeb2adSek110237 	argc -= optind;
364906eeb2adSek110237 	argv += optind;
365006eeb2adSek110237 
3651b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3652ecd6cf80Smarks 	    &cbdata);
365306eeb2adSek110237 
3654ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
365506eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
365606eeb2adSek110237 		return (0);
3657eaca9bbdSeschrock 	}
3658eaca9bbdSeschrock 
3659eaca9bbdSeschrock 	return (ret);
3660eaca9bbdSeschrock }
3661eaca9bbdSeschrock 
3662b1b8ab34Slling static int
3663b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3664b1b8ab34Slling {
3665990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3666b1b8ab34Slling 	char value[MAXNAMELEN];
3667990b4856Slling 	zprop_source_t srctype;
3668990b4856Slling 	zprop_list_t *pl;
3669b1b8ab34Slling 
3670b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3671b1b8ab34Slling 
3672b1b8ab34Slling 		/*
3673990b4856Slling 		 * Skip the special fake placeholder. This will also skip
3674990b4856Slling 		 * over the name property when 'all' is specified.
3675b1b8ab34Slling 		 */
3676990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3677b1b8ab34Slling 		    pl == cbp->cb_proplist)
3678b1b8ab34Slling 			continue;
3679b1b8ab34Slling 
3680b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3681b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3682b1b8ab34Slling 			continue;
3683b1b8ab34Slling 
3684990b4856Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
3685b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3686b1b8ab34Slling 	}
3687b1b8ab34Slling 	return (0);
3688b1b8ab34Slling }
3689b1b8ab34Slling 
3690b1b8ab34Slling int
3691b1b8ab34Slling zpool_do_get(int argc, char **argv)
3692b1b8ab34Slling {
3693990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
3694990b4856Slling 	zprop_list_t fake_name = { 0 };
3695b1b8ab34Slling 	int ret;
3696b1b8ab34Slling 
3697b1b8ab34Slling 	if (argc < 3)
3698b1b8ab34Slling 		usage(B_FALSE);
3699b1b8ab34Slling 
3700b1b8ab34Slling 	cb.cb_first = B_TRUE;
3701990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
3702b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3703b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3704b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3705b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3706990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
3707b1b8ab34Slling 
3708990b4856Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3709990b4856Slling 	    ZFS_TYPE_POOL) != 0)
3710b1b8ab34Slling 		usage(B_FALSE);
3711b1b8ab34Slling 
3712b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3713990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
3714b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3715b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3716b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3717b1b8ab34Slling 	}
3718b1b8ab34Slling 
3719b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3720b1b8ab34Slling 	    get_callback, &cb);
3721b1b8ab34Slling 
3722b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3723990b4856Slling 		zprop_free_list(fake_name.pl_next);
3724b1b8ab34Slling 	else
3725990b4856Slling 		zprop_free_list(cb.cb_proplist);
3726b1b8ab34Slling 
3727b1b8ab34Slling 	return (ret);
3728b1b8ab34Slling }
3729b1b8ab34Slling 
3730b1b8ab34Slling typedef struct set_cbdata {
3731b1b8ab34Slling 	char *cb_propname;
3732b1b8ab34Slling 	char *cb_value;
3733b1b8ab34Slling 	boolean_t cb_any_successful;
3734b1b8ab34Slling } set_cbdata_t;
3735b1b8ab34Slling 
3736b1b8ab34Slling int
3737b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3738b1b8ab34Slling {
3739b1b8ab34Slling 	int error;
3740b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3741b1b8ab34Slling 
3742b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3743b1b8ab34Slling 
3744b1b8ab34Slling 	if (!error)
3745b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3746b1b8ab34Slling 
3747b1b8ab34Slling 	return (error);
3748b1b8ab34Slling }
3749b1b8ab34Slling 
3750b1b8ab34Slling int
3751b1b8ab34Slling zpool_do_set(int argc, char **argv)
3752b1b8ab34Slling {
3753b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3754b1b8ab34Slling 	int error;
3755b1b8ab34Slling 
3756b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3757b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3758b1b8ab34Slling 		    argv[1][1]);
3759b1b8ab34Slling 		usage(B_FALSE);
3760b1b8ab34Slling 	}
3761b1b8ab34Slling 
3762b1b8ab34Slling 	if (argc < 2) {
3763b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3764b1b8ab34Slling 		    "argument\n"));
3765b1b8ab34Slling 		usage(B_FALSE);
3766b1b8ab34Slling 	}
3767b1b8ab34Slling 
3768b1b8ab34Slling 	if (argc < 3) {
3769b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3770b1b8ab34Slling 		usage(B_FALSE);
3771b1b8ab34Slling 	}
3772b1b8ab34Slling 
3773b1b8ab34Slling 	if (argc > 3) {
3774b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3775b1b8ab34Slling 		usage(B_FALSE);
3776b1b8ab34Slling 	}
3777b1b8ab34Slling 
3778b1b8ab34Slling 	cb.cb_propname = argv[1];
3779b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3780b1b8ab34Slling 	if (cb.cb_value == NULL) {
3781b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3782b1b8ab34Slling 		    "property=value argument\n"));
3783b1b8ab34Slling 		usage(B_FALSE);
3784b1b8ab34Slling 	}
3785b1b8ab34Slling 
3786b1b8ab34Slling 	*(cb.cb_value) = '\0';
3787b1b8ab34Slling 	cb.cb_value++;
3788b1b8ab34Slling 
3789b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3790b1b8ab34Slling 	    set_callback, &cb);
3791b1b8ab34Slling 
3792b1b8ab34Slling 	return (error);
3793b1b8ab34Slling }
3794b1b8ab34Slling 
3795b1b8ab34Slling static int
3796b1b8ab34Slling find_command_idx(char *command, int *idx)
3797b1b8ab34Slling {
3798b1b8ab34Slling 	int i;
3799b1b8ab34Slling 
3800b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3801b1b8ab34Slling 		if (command_table[i].name == NULL)
3802b1b8ab34Slling 			continue;
3803b1b8ab34Slling 
3804b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3805b1b8ab34Slling 			*idx = i;
3806b1b8ab34Slling 			return (0);
3807b1b8ab34Slling 		}
3808b1b8ab34Slling 	}
3809b1b8ab34Slling 	return (1);
3810b1b8ab34Slling }
3811b1b8ab34Slling 
3812fa9e4066Sahrens int
3813fa9e4066Sahrens main(int argc, char **argv)
3814fa9e4066Sahrens {
3815fa9e4066Sahrens 	int ret;
3816fa9e4066Sahrens 	int i;
3817fa9e4066Sahrens 	char *cmdname;
3818fa9e4066Sahrens 
3819fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3820fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3821fa9e4066Sahrens 
382299653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
382399653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3824203a47d8Snd150628 		    "initialize ZFS library\n"));
382599653d4eSeschrock 		return (1);
382699653d4eSeschrock 	}
382799653d4eSeschrock 
382899653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
382999653d4eSeschrock 
3830fa9e4066Sahrens 	opterr = 0;
3831fa9e4066Sahrens 
3832fa9e4066Sahrens 	/*
3833fa9e4066Sahrens 	 * Make sure the user has specified some command.
3834fa9e4066Sahrens 	 */
3835fa9e4066Sahrens 	if (argc < 2) {
3836fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
383799653d4eSeschrock 		usage(B_FALSE);
3838fa9e4066Sahrens 	}
3839fa9e4066Sahrens 
3840fa9e4066Sahrens 	cmdname = argv[1];
3841fa9e4066Sahrens 
3842fa9e4066Sahrens 	/*
3843fa9e4066Sahrens 	 * Special case '-?'
3844fa9e4066Sahrens 	 */
3845fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
384699653d4eSeschrock 		usage(B_TRUE);
3847fa9e4066Sahrens 
38482a6b87f0Sek110237 	zpool_set_history_str("zpool", argc, argv, history_str);
38492a6b87f0Sek110237 	verify(zpool_stage_history(g_zfs, history_str) == 0);
38502a6b87f0Sek110237 
3851fa9e4066Sahrens 	/*
3852fa9e4066Sahrens 	 * Run the appropriate command.
3853fa9e4066Sahrens 	 */
3854b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
3855fa9e4066Sahrens 		current_command = &command_table[i];
3856fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
385791ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
385891ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
385991ebeef5Sahrens 		current_command = &command_table[i];
386091ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
386191ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
3862fa9e4066Sahrens 		/*
386391ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
386491ebeef5Sahrens 		 * it as such.
3865fa9e4066Sahrens 		 */
3866ea8dc4b6Seschrock 		char buf[16384];
3867ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
3868fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
3869fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
387091ebeef5Sahrens 	} else {
3871fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
3872fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
387399653d4eSeschrock 		usage(B_FALSE);
3874fa9e4066Sahrens 	}
3875fa9e4066Sahrens 
387699653d4eSeschrock 	libzfs_fini(g_zfs);
387799653d4eSeschrock 
3878fa9e4066Sahrens 	/*
3879fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3880fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
3881fa9e4066Sahrens 	 */
3882fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
3883fa9e4066Sahrens 		(void) printf("dumping core by request\n");
3884fa9e4066Sahrens 		abort();
3885fa9e4066Sahrens 	}
3886fa9e4066Sahrens 
3887fa9e4066Sahrens 	return (ret);
3888fa9e4066Sahrens }
3889