xref: /titanic_53/usr/src/cmd/zpool/zpool_main.c (revision e829d913cde9eeff0efd355502799863d4f74f69)
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  */
8929ab75c9Srm160521 
9029ab75c9Srm160521 #ifdef DEBUG
91fa9e4066Sahrens const char *
9299653d4eSeschrock _umem_debug_init(void)
93fa9e4066Sahrens {
94fa9e4066Sahrens 	return ("default,verbose"); /* $UMEM_DEBUG setting */
95fa9e4066Sahrens }
96fa9e4066Sahrens 
97fa9e4066Sahrens const char *
98fa9e4066Sahrens _umem_logging_init(void)
99fa9e4066Sahrens {
100fa9e4066Sahrens 	return ("fail,contents"); /* $UMEM_LOGGING setting */
101fa9e4066Sahrens }
10229ab75c9Srm160521 #endif
103fa9e4066Sahrens 
10465cd9f28Seschrock typedef enum {
10565cd9f28Seschrock 	HELP_ADD,
10665cd9f28Seschrock 	HELP_ATTACH,
107ea8dc4b6Seschrock 	HELP_CLEAR,
10865cd9f28Seschrock 	HELP_CREATE,
10965cd9f28Seschrock 	HELP_DESTROY,
11065cd9f28Seschrock 	HELP_DETACH,
11165cd9f28Seschrock 	HELP_EXPORT,
11206eeb2adSek110237 	HELP_HISTORY,
11365cd9f28Seschrock 	HELP_IMPORT,
11465cd9f28Seschrock 	HELP_IOSTAT,
11565cd9f28Seschrock 	HELP_LIST,
11665cd9f28Seschrock 	HELP_OFFLINE,
11765cd9f28Seschrock 	HELP_ONLINE,
11865cd9f28Seschrock 	HELP_REPLACE,
11999653d4eSeschrock 	HELP_REMOVE,
12065cd9f28Seschrock 	HELP_SCRUB,
121eaca9bbdSeschrock 	HELP_STATUS,
122b1b8ab34Slling 	HELP_UPGRADE,
123b1b8ab34Slling 	HELP_GET,
124b1b8ab34Slling 	HELP_SET
12565cd9f28Seschrock } zpool_help_t;
12665cd9f28Seschrock 
12765cd9f28Seschrock 
128fa9e4066Sahrens typedef struct zpool_command {
129fa9e4066Sahrens 	const char	*name;
130fa9e4066Sahrens 	int		(*func)(int, char **);
13165cd9f28Seschrock 	zpool_help_t	usage;
132fa9e4066Sahrens } zpool_command_t;
133fa9e4066Sahrens 
134fa9e4066Sahrens /*
135fa9e4066Sahrens  * Master command table.  Each ZFS command has a name, associated function, and
136ea8dc4b6Seschrock  * usage message.  The usage messages need to be internationalized, so we have
137ea8dc4b6Seschrock  * to have a function to return the usage message based on a command index.
13865cd9f28Seschrock  *
13965cd9f28Seschrock  * These commands are organized according to how they are displayed in the usage
14065cd9f28Seschrock  * message.  An empty command (one with a NULL name) indicates an empty line in
14165cd9f28Seschrock  * the generic usage message.
142fa9e4066Sahrens  */
143fa9e4066Sahrens static zpool_command_t command_table[] = {
14465cd9f28Seschrock 	{ "create",	zpool_do_create,	HELP_CREATE		},
14565cd9f28Seschrock 	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
146fa9e4066Sahrens 	{ NULL },
14765cd9f28Seschrock 	{ "add",	zpool_do_add,		HELP_ADD		},
14899653d4eSeschrock 	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
149fa9e4066Sahrens 	{ NULL },
15065cd9f28Seschrock 	{ "list",	zpool_do_list,		HELP_LIST		},
15165cd9f28Seschrock 	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
15265cd9f28Seschrock 	{ "status",	zpool_do_status,	HELP_STATUS		},
153fa9e4066Sahrens 	{ NULL },
15465cd9f28Seschrock 	{ "online",	zpool_do_online,	HELP_ONLINE		},
15565cd9f28Seschrock 	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
156ea8dc4b6Seschrock 	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
157fa9e4066Sahrens 	{ NULL },
15865cd9f28Seschrock 	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
15965cd9f28Seschrock 	{ "detach",	zpool_do_detach,	HELP_DETACH		},
16065cd9f28Seschrock 	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
161fa9e4066Sahrens 	{ NULL },
16265cd9f28Seschrock 	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
163fa9e4066Sahrens 	{ NULL },
16465cd9f28Seschrock 	{ "import",	zpool_do_import,	HELP_IMPORT		},
16565cd9f28Seschrock 	{ "export",	zpool_do_export,	HELP_EXPORT		},
16606eeb2adSek110237 	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
16706eeb2adSek110237 	{ NULL },
168b1b8ab34Slling 	{ "history",	zpool_do_history,	HELP_HISTORY		},
169b1b8ab34Slling 	{ "get",	zpool_do_get,		HELP_GET		},
170b1b8ab34Slling 	{ "set",	zpool_do_set,		HELP_SET		},
171fa9e4066Sahrens };
172fa9e4066Sahrens 
173fa9e4066Sahrens #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
174fa9e4066Sahrens 
175fa9e4066Sahrens zpool_command_t *current_command;
1762a6b87f0Sek110237 static char history_str[HIS_MAX_RECORD_LEN];
177fa9e4066Sahrens 
17865cd9f28Seschrock static const char *
17965cd9f28Seschrock get_usage(zpool_help_t idx) {
18065cd9f28Seschrock 	switch (idx) {
18165cd9f28Seschrock 	case HELP_ADD:
18265cd9f28Seschrock 		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
18365cd9f28Seschrock 	case HELP_ATTACH:
18465cd9f28Seschrock 		return (gettext("\tattach [-f] <pool> <device> "
185e45ce728Sahrens 		    "<new-device>\n"));
186ea8dc4b6Seschrock 	case HELP_CLEAR:
187ea8dc4b6Seschrock 		return (gettext("\tclear <pool> [device]\n"));
18865cd9f28Seschrock 	case HELP_CREATE:
189990b4856Slling 		return (gettext("\tcreate [-fn] [-o property=value] ... \n"
190990b4856Slling 		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
19165cd9f28Seschrock 	case HELP_DESTROY:
19265cd9f28Seschrock 		return (gettext("\tdestroy [-f] <pool>\n"));
19365cd9f28Seschrock 	case HELP_DETACH:
19465cd9f28Seschrock 		return (gettext("\tdetach <pool> <device>\n"));
19565cd9f28Seschrock 	case HELP_EXPORT:
19665cd9f28Seschrock 		return (gettext("\texport [-f] <pool> ...\n"));
19706eeb2adSek110237 	case HELP_HISTORY:
198ecd6cf80Smarks 		return (gettext("\thistory [-il] [<pool>] ...\n"));
19965cd9f28Seschrock 	case HELP_IMPORT:
2004c58d714Sdarrenm 		return (gettext("\timport [-d dir] [-D]\n"
2012f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
2022f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n"
2032f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
2042f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] "
2052f8aaab3Seschrock 		    "<pool | id> [newpool]\n"));
20665cd9f28Seschrock 	case HELP_IOSTAT:
20765cd9f28Seschrock 		return (gettext("\tiostat [-v] [pool] ... [interval "
20865cd9f28Seschrock 		    "[count]]\n"));
20965cd9f28Seschrock 	case HELP_LIST:
210990b4856Slling 		return (gettext("\tlist [-H] [-o property[,...]] "
211990b4856Slling 		    "[pool] ...\n"));
21265cd9f28Seschrock 	case HELP_OFFLINE:
213441d80aaSlling 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
21465cd9f28Seschrock 	case HELP_ONLINE:
215441d80aaSlling 		return (gettext("\tonline <pool> <device> ...\n"));
21665cd9f28Seschrock 	case HELP_REPLACE:
21765cd9f28Seschrock 		return (gettext("\treplace [-f] <pool> <device> "
218e45ce728Sahrens 		    "[new-device]\n"));
21999653d4eSeschrock 	case HELP_REMOVE:
220fa94a07fSbrendan 		return (gettext("\tremove <pool> <device> ...\n"));
22165cd9f28Seschrock 	case HELP_SCRUB:
22265cd9f28Seschrock 		return (gettext("\tscrub [-s] <pool> ...\n"));
22365cd9f28Seschrock 	case HELP_STATUS:
22465cd9f28Seschrock 		return (gettext("\tstatus [-vx] [pool] ...\n"));
225eaca9bbdSeschrock 	case HELP_UPGRADE:
226eaca9bbdSeschrock 		return (gettext("\tupgrade\n"
227eaca9bbdSeschrock 		    "\tupgrade -v\n"
228990b4856Slling 		    "\tupgrade [-V version] <-a | pool ...>\n"));
229b1b8ab34Slling 	case HELP_GET:
230e45ce728Sahrens 		return (gettext("\tget <\"all\" | property[,...]> "
231b1b8ab34Slling 		    "<pool> ...\n"));
232b1b8ab34Slling 	case HELP_SET:
233b1b8ab34Slling 		return (gettext("\tset <property=value> <pool> \n"));
23465cd9f28Seschrock 	}
23565cd9f28Seschrock 
23665cd9f28Seschrock 	abort();
23765cd9f28Seschrock 	/* NOTREACHED */
23865cd9f28Seschrock }
23965cd9f28Seschrock 
240fa9e4066Sahrens 
241fa9e4066Sahrens /*
242b1b8ab34Slling  * Callback routine that will print out a pool property value.
243b1b8ab34Slling  */
244990b4856Slling static int
245990b4856Slling print_prop_cb(int prop, void *cb)
246b1b8ab34Slling {
247b1b8ab34Slling 	FILE *fp = cb;
248b1b8ab34Slling 
249b1b8ab34Slling 	(void) fprintf(fp, "\t%-13s  ", zpool_prop_to_name(prop));
250b1b8ab34Slling 
251990b4856Slling 	if (zpool_prop_readonly(prop))
252990b4856Slling 		(void) fprintf(fp, "  NO   ");
253990b4856Slling 	else
254990b4856Slling 		(void) fprintf(fp, " YES    ");
255990b4856Slling 
256b1b8ab34Slling 	if (zpool_prop_values(prop) == NULL)
257b1b8ab34Slling 		(void) fprintf(fp, "-\n");
258b1b8ab34Slling 	else
259b1b8ab34Slling 		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
260b1b8ab34Slling 
261990b4856Slling 	return (ZPROP_CONT);
262b1b8ab34Slling }
263b1b8ab34Slling 
264b1b8ab34Slling /*
265fa9e4066Sahrens  * Display usage message.  If we're inside a command, display only the usage for
266fa9e4066Sahrens  * that command.  Otherwise, iterate over the entire command table and display
267fa9e4066Sahrens  * a complete usage message.
268fa9e4066Sahrens  */
269fa9e4066Sahrens void
27099653d4eSeschrock usage(boolean_t requested)
271fa9e4066Sahrens {
272fa9e4066Sahrens 	FILE *fp = requested ? stdout : stderr;
273fa9e4066Sahrens 
274fa9e4066Sahrens 	if (current_command == NULL) {
275fa9e4066Sahrens 		int i;
276fa9e4066Sahrens 
277fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
278fa9e4066Sahrens 		(void) fprintf(fp,
279fa9e4066Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
280fa9e4066Sahrens 
281fa9e4066Sahrens 		for (i = 0; i < NCOMMAND; i++) {
282fa9e4066Sahrens 			if (command_table[i].name == NULL)
283fa9e4066Sahrens 				(void) fprintf(fp, "\n");
284fa9e4066Sahrens 			else
285fa9e4066Sahrens 				(void) fprintf(fp, "%s",
28665cd9f28Seschrock 				    get_usage(command_table[i].usage));
287fa9e4066Sahrens 		}
288fa9e4066Sahrens 	} else {
289fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
29065cd9f28Seschrock 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
291fa9e4066Sahrens 	}
292fa9e4066Sahrens 
293b1b8ab34Slling 	if (current_command != NULL &&
294b1b8ab34Slling 	    ((strcmp(current_command->name, "set") == 0) ||
295990b4856Slling 	    (strcmp(current_command->name, "get") == 0) ||
296990b4856Slling 	    (strcmp(current_command->name, "list") == 0))) {
297b1b8ab34Slling 
298b1b8ab34Slling 		(void) fprintf(fp,
299b1b8ab34Slling 		    gettext("\nthe following properties are supported:\n"));
300b1b8ab34Slling 
301990b4856Slling 		(void) fprintf(fp, "\n\t%-13s  %s  %s\n\n",
302990b4856Slling 		    "PROPERTY", "EDIT", "VALUES");
303b1b8ab34Slling 
304b1b8ab34Slling 		/* Iterate over all properties */
305990b4856Slling 		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
306990b4856Slling 		    ZFS_TYPE_POOL);
307b1b8ab34Slling 	}
308b1b8ab34Slling 
309e9dbad6fSeschrock 	/*
310e9dbad6fSeschrock 	 * See comments at end of main().
311e9dbad6fSeschrock 	 */
312e9dbad6fSeschrock 	if (getenv("ZFS_ABORT") != NULL) {
313e9dbad6fSeschrock 		(void) printf("dumping core by request\n");
314e9dbad6fSeschrock 		abort();
315e9dbad6fSeschrock 	}
316e9dbad6fSeschrock 
317fa9e4066Sahrens 	exit(requested ? 0 : 2);
318fa9e4066Sahrens }
319fa9e4066Sahrens 
320fa9e4066Sahrens void
3218654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
3228654d025Sperrin     boolean_t print_logs)
323fa9e4066Sahrens {
324fa9e4066Sahrens 	nvlist_t **child;
325fa9e4066Sahrens 	uint_t c, children;
326afefbcddSeschrock 	char *vname;
327fa9e4066Sahrens 
328fa9e4066Sahrens 	if (name != NULL)
329fa9e4066Sahrens 		(void) printf("\t%*s%s\n", indent, "", name);
330fa9e4066Sahrens 
331fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
332fa9e4066Sahrens 	    &child, &children) != 0)
333fa9e4066Sahrens 		return;
334fa9e4066Sahrens 
335afefbcddSeschrock 	for (c = 0; c < children; c++) {
3368654d025Sperrin 		uint64_t is_log = B_FALSE;
3378654d025Sperrin 
3388654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3398654d025Sperrin 		    &is_log);
3408654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
3418654d025Sperrin 			continue;
3428654d025Sperrin 
34399653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
3448654d025Sperrin 		print_vdev_tree(zhp, vname, child[c], indent + 2,
3458654d025Sperrin 		    B_FALSE);
346afefbcddSeschrock 		free(vname);
347afefbcddSeschrock 	}
348fa9e4066Sahrens }
349fa9e4066Sahrens 
350fa9e4066Sahrens /*
351990b4856Slling  * Add a property pair (name, string-value) into a property nvlist.
352990b4856Slling  */
353990b4856Slling static int
354990b4856Slling add_prop_list(const char *propname, char *propval, nvlist_t **props)
355990b4856Slling {
356990b4856Slling 	char *strval;
357990b4856Slling 	nvlist_t *proplist;
358990b4856Slling 	zpool_prop_t prop;
359990b4856Slling 
360990b4856Slling 	if (*props == NULL &&
361990b4856Slling 	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
362990b4856Slling 		(void) fprintf(stderr,
363990b4856Slling 		    gettext("internal error: out of memory\n"));
364990b4856Slling 		return (1);
365990b4856Slling 	}
366990b4856Slling 
367990b4856Slling 	proplist = *props;
368990b4856Slling 
369990b4856Slling 	if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
370990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' is "
371990b4856Slling 		    "not a valid pool property\n"), propname);
372990b4856Slling 		return (2);
373990b4856Slling 	}
374990b4856Slling 
375990b4856Slling 	/* Use normalized property name for nvlist operations */
376990b4856Slling 	if (nvlist_lookup_string(proplist, zpool_prop_to_name(prop),
3772f8aaab3Seschrock 	    &strval) == 0 && prop != ZPOOL_PROP_CACHEFILE) {
378990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' "
379990b4856Slling 		    "specified multiple times\n"), propname);
380990b4856Slling 		return (2);
381990b4856Slling 	}
382990b4856Slling 
383990b4856Slling 	if (nvlist_add_string(proplist, zpool_prop_to_name(prop),
384990b4856Slling 	    propval) != 0) {
385990b4856Slling 		(void) fprintf(stderr, gettext("internal "
386990b4856Slling 		    "error: out of memory\n"));
387990b4856Slling 		return (1);
388990b4856Slling 	}
389990b4856Slling 
390990b4856Slling 	return (0);
391990b4856Slling }
392990b4856Slling 
393990b4856Slling /*
394fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
395fa9e4066Sahrens  *
396fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
397fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
398fa9e4066Sahrens  *		they were to be added.
399fa9e4066Sahrens  *
400fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
401fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
402fa9e4066Sahrens  * libzfs.
403fa9e4066Sahrens  */
404fa9e4066Sahrens int
405fa9e4066Sahrens zpool_do_add(int argc, char **argv)
406fa9e4066Sahrens {
40799653d4eSeschrock 	boolean_t force = B_FALSE;
40899653d4eSeschrock 	boolean_t dryrun = B_FALSE;
409fa9e4066Sahrens 	int c;
410fa9e4066Sahrens 	nvlist_t *nvroot;
411fa9e4066Sahrens 	char *poolname;
412fa9e4066Sahrens 	int ret;
413fa9e4066Sahrens 	zpool_handle_t *zhp;
414fa9e4066Sahrens 	nvlist_t *config;
415fa9e4066Sahrens 
416fa9e4066Sahrens 	/* check options */
417fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
418fa9e4066Sahrens 		switch (c) {
419fa9e4066Sahrens 		case 'f':
42099653d4eSeschrock 			force = B_TRUE;
421fa9e4066Sahrens 			break;
422fa9e4066Sahrens 		case 'n':
42399653d4eSeschrock 			dryrun = B_TRUE;
424fa9e4066Sahrens 			break;
425fa9e4066Sahrens 		case '?':
426fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
427fa9e4066Sahrens 			    optopt);
42899653d4eSeschrock 			usage(B_FALSE);
429fa9e4066Sahrens 		}
430fa9e4066Sahrens 	}
431fa9e4066Sahrens 
432fa9e4066Sahrens 	argc -= optind;
433fa9e4066Sahrens 	argv += optind;
434fa9e4066Sahrens 
435fa9e4066Sahrens 	/* get pool name and check number of arguments */
436fa9e4066Sahrens 	if (argc < 1) {
437fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
43899653d4eSeschrock 		usage(B_FALSE);
439fa9e4066Sahrens 	}
440fa9e4066Sahrens 	if (argc < 2) {
441fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
44299653d4eSeschrock 		usage(B_FALSE);
443fa9e4066Sahrens 	}
444fa9e4066Sahrens 
445fa9e4066Sahrens 	poolname = argv[0];
446fa9e4066Sahrens 
447fa9e4066Sahrens 	argc--;
448fa9e4066Sahrens 	argv++;
449fa9e4066Sahrens 
45099653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
451fa9e4066Sahrens 		return (1);
452fa9e4066Sahrens 
453088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
454fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
455fa9e4066Sahrens 		    poolname);
456fa9e4066Sahrens 		zpool_close(zhp);
457fa9e4066Sahrens 		return (1);
458fa9e4066Sahrens 	}
459fa9e4066Sahrens 
460fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
4618488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv);
462fa9e4066Sahrens 	if (nvroot == NULL) {
463fa9e4066Sahrens 		zpool_close(zhp);
464fa9e4066Sahrens 		return (1);
465fa9e4066Sahrens 	}
466fa9e4066Sahrens 
467fa9e4066Sahrens 	if (dryrun) {
468fa9e4066Sahrens 		nvlist_t *poolnvroot;
469fa9e4066Sahrens 
470fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
471fa9e4066Sahrens 		    &poolnvroot) == 0);
472fa9e4066Sahrens 
473fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
474fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
475fa9e4066Sahrens 
4768654d025Sperrin 		/* print original main pool and new tree */
4778654d025Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
4788654d025Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
4798654d025Sperrin 
4808654d025Sperrin 		/* Do the same for the logs */
4818654d025Sperrin 		if (num_logs(poolnvroot) > 0) {
4828654d025Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
4838654d025Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
4848654d025Sperrin 		} else if (num_logs(nvroot) > 0) {
4858654d025Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
4868654d025Sperrin 		}
487fa9e4066Sahrens 
488fa9e4066Sahrens 		ret = 0;
489fa9e4066Sahrens 	} else {
490fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
491fa9e4066Sahrens 	}
492fa9e4066Sahrens 
49399653d4eSeschrock 	nvlist_free(nvroot);
49499653d4eSeschrock 	zpool_close(zhp);
49599653d4eSeschrock 
49699653d4eSeschrock 	return (ret);
49799653d4eSeschrock }
49899653d4eSeschrock 
49999653d4eSeschrock /*
500fa94a07fSbrendan  * zpool remove <pool> <vdev> ...
50199653d4eSeschrock  *
50299653d4eSeschrock  * Removes the given vdev from the pool.  Currently, this only supports removing
503fa94a07fSbrendan  * spares and cache devices from the pool.  Eventually, we'll want to support
504fa94a07fSbrendan  * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs.
50599653d4eSeschrock  */
50699653d4eSeschrock int
50799653d4eSeschrock zpool_do_remove(int argc, char **argv)
50899653d4eSeschrock {
50999653d4eSeschrock 	char *poolname;
510fa94a07fSbrendan 	int i, ret = 0;
51199653d4eSeschrock 	zpool_handle_t *zhp;
51299653d4eSeschrock 
51399653d4eSeschrock 	argc--;
51499653d4eSeschrock 	argv++;
51599653d4eSeschrock 
51699653d4eSeschrock 	/* get pool name and check number of arguments */
51799653d4eSeschrock 	if (argc < 1) {
51899653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
51999653d4eSeschrock 		usage(B_FALSE);
52099653d4eSeschrock 	}
52199653d4eSeschrock 	if (argc < 2) {
52299653d4eSeschrock 		(void) fprintf(stderr, gettext("missing device\n"));
52399653d4eSeschrock 		usage(B_FALSE);
52499653d4eSeschrock 	}
52599653d4eSeschrock 
52699653d4eSeschrock 	poolname = argv[0];
52799653d4eSeschrock 
52899653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
52999653d4eSeschrock 		return (1);
53099653d4eSeschrock 
531fa94a07fSbrendan 	for (i = 1; i < argc; i++) {
532fa94a07fSbrendan 		if (zpool_vdev_remove(zhp, argv[i]) != 0)
533fa94a07fSbrendan 			ret = 1;
534fa94a07fSbrendan 	}
53599653d4eSeschrock 
536fa9e4066Sahrens 	return (ret);
537fa9e4066Sahrens }
538fa9e4066Sahrens 
539fa9e4066Sahrens /*
540990b4856Slling  * zpool create [-fn] [-o property=value] ... [-R root] [-m mountpoint]
541990b4856Slling  *		<pool> <dev> ...
542fa9e4066Sahrens  *
543fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
544fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
545fa9e4066Sahrens  *		were to be created.
546fa9e4066Sahrens  *      -R	Create a pool under an alternate root
547fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
548fa9e4066Sahrens  *      	'/<pool>'
549990b4856Slling  *	-o	Set property=value.
550fa9e4066Sahrens  *
551b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
552fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
553fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
554fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
555fa9e4066Sahrens  */
556fa9e4066Sahrens int
557fa9e4066Sahrens zpool_do_create(int argc, char **argv)
558fa9e4066Sahrens {
55999653d4eSeschrock 	boolean_t force = B_FALSE;
56099653d4eSeschrock 	boolean_t dryrun = B_FALSE;
561fa9e4066Sahrens 	int c;
562990b4856Slling 	nvlist_t *nvroot = NULL;
563fa9e4066Sahrens 	char *poolname;
564990b4856Slling 	int ret = 1;
565fa9e4066Sahrens 	char *altroot = NULL;
566fa9e4066Sahrens 	char *mountpoint = NULL;
567990b4856Slling 	nvlist_t *props = NULL;
5682f8aaab3Seschrock 	char *propval;
569fa9e4066Sahrens 
570fa9e4066Sahrens 	/* check options */
571990b4856Slling 	while ((c = getopt(argc, argv, ":fnR:m:o:")) != -1) {
572fa9e4066Sahrens 		switch (c) {
573fa9e4066Sahrens 		case 'f':
57499653d4eSeschrock 			force = B_TRUE;
575fa9e4066Sahrens 			break;
576fa9e4066Sahrens 		case 'n':
57799653d4eSeschrock 			dryrun = B_TRUE;
578fa9e4066Sahrens 			break;
579fa9e4066Sahrens 		case 'R':
580fa9e4066Sahrens 			altroot = optarg;
581990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
582990b4856Slling 			    ZPOOL_PROP_ALTROOT), optarg, &props))
583990b4856Slling 				goto errout;
5842f8aaab3Seschrock 			if (nvlist_lookup_string(props,
5852f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
5862f8aaab3Seschrock 			    &propval) == 0)
5872f8aaab3Seschrock 				break;
588990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
5892f8aaab3Seschrock 			    ZPOOL_PROP_CACHEFILE), "none", &props))
590990b4856Slling 				goto errout;
591fa9e4066Sahrens 			break;
592fa9e4066Sahrens 		case 'm':
593fa9e4066Sahrens 			mountpoint = optarg;
594fa9e4066Sahrens 			break;
595990b4856Slling 		case 'o':
596990b4856Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
597990b4856Slling 				(void) fprintf(stderr, gettext("missing "
598990b4856Slling 				    "'=' for -o option\n"));
599990b4856Slling 				goto errout;
600990b4856Slling 			}
601990b4856Slling 			*propval = '\0';
602990b4856Slling 			propval++;
603990b4856Slling 
604990b4856Slling 			if (add_prop_list(optarg, propval, &props))
605990b4856Slling 				goto errout;
606990b4856Slling 			break;
607fa9e4066Sahrens 		case ':':
608fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
609fa9e4066Sahrens 			    "'%c' option\n"), optopt);
610990b4856Slling 			goto badusage;
611fa9e4066Sahrens 		case '?':
612fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
613fa9e4066Sahrens 			    optopt);
614990b4856Slling 			goto badusage;
615fa9e4066Sahrens 		}
616fa9e4066Sahrens 	}
617fa9e4066Sahrens 
618fa9e4066Sahrens 	argc -= optind;
619fa9e4066Sahrens 	argv += optind;
620fa9e4066Sahrens 
621fa9e4066Sahrens 	/* get pool name and check number of arguments */
622fa9e4066Sahrens 	if (argc < 1) {
623fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
624990b4856Slling 		goto badusage;
625fa9e4066Sahrens 	}
626fa9e4066Sahrens 	if (argc < 2) {
627fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
628990b4856Slling 		goto badusage;
629fa9e4066Sahrens 	}
630fa9e4066Sahrens 
631fa9e4066Sahrens 	poolname = argv[0];
632fa9e4066Sahrens 
633fa9e4066Sahrens 	/*
634fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
635fa9e4066Sahrens 	 * user to use 'zfs create' instead.
636fa9e4066Sahrens 	 */
637fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
638fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
639fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
640fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
641fa9e4066Sahrens 		    "create a dataset\n"));
642990b4856Slling 		goto errout;
643fa9e4066Sahrens 	}
644fa9e4066Sahrens 
645fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
64699653d4eSeschrock 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1,
64799653d4eSeschrock 	    argv + 1);
648fa9e4066Sahrens 	if (nvroot == NULL)
649fa9e4066Sahrens 		return (1);
650fa9e4066Sahrens 
65199653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
652b7b97454Sperrin 	if (!zfs_allocatable_devs(nvroot)) {
65399653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
65499653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
65599653d4eSeschrock 		    "specified\n"));
656990b4856Slling 		goto errout;
65799653d4eSeschrock 	}
65899653d4eSeschrock 
65999653d4eSeschrock 
660fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
661fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
662e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
663990b4856Slling 		goto errout;
664fa9e4066Sahrens 	}
665fa9e4066Sahrens 
666fa9e4066Sahrens 	/*
667fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
668fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
669fa9e4066Sahrens 	 */
670fa9e4066Sahrens 	if (mountpoint == NULL ||
671fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
672fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
673fa9e4066Sahrens 		char buf[MAXPATHLEN];
67411022c7cStimh 		DIR *dirp;
675fa9e4066Sahrens 
676fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
677fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
678fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
679fa9e4066Sahrens 			    "'none'\n"), mountpoint);
680990b4856Slling 			goto errout;
681fa9e4066Sahrens 		}
682fa9e4066Sahrens 
683fa9e4066Sahrens 		if (mountpoint == NULL) {
684fa9e4066Sahrens 			if (altroot != NULL)
685fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
686fa9e4066Sahrens 				    altroot, poolname);
687fa9e4066Sahrens 			else
688fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
689fa9e4066Sahrens 				    poolname);
690fa9e4066Sahrens 		} else {
691fa9e4066Sahrens 			if (altroot != NULL)
692fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
693fa9e4066Sahrens 				    altroot, mountpoint);
694fa9e4066Sahrens 			else
695fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
696fa9e4066Sahrens 				    mountpoint);
697fa9e4066Sahrens 		}
698fa9e4066Sahrens 
69911022c7cStimh 		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
70011022c7cStimh 			(void) fprintf(stderr, gettext("mountpoint '%s' : "
70111022c7cStimh 			    "%s\n"), buf, strerror(errno));
702fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
703fa9e4066Sahrens 			    "option to provide a different default\n"));
704990b4856Slling 			goto errout;
70511022c7cStimh 		} else if (dirp) {
70611022c7cStimh 			int count = 0;
70711022c7cStimh 
70811022c7cStimh 			while (count < 3 && readdir(dirp) != NULL)
70911022c7cStimh 				count++;
71011022c7cStimh 			(void) closedir(dirp);
71111022c7cStimh 
71211022c7cStimh 			if (count > 2) {
71311022c7cStimh 				(void) fprintf(stderr, gettext("mountpoint "
71411022c7cStimh 				    "'%s' exists and is not empty\n"), buf);
71511022c7cStimh 				(void) fprintf(stderr, gettext("use '-m' "
71611022c7cStimh 				    "option to provide a "
71711022c7cStimh 				    "different default\n"));
71811022c7cStimh 				goto errout;
71911022c7cStimh 			}
720fa9e4066Sahrens 		}
721fa9e4066Sahrens 	}
722fa9e4066Sahrens 
723fa9e4066Sahrens 	if (dryrun) {
724fa9e4066Sahrens 		/*
725fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
726fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
727fa9e4066Sahrens 		 * appropriate hierarchy.
728fa9e4066Sahrens 		 */
729fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
730fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
731fa9e4066Sahrens 
7328654d025Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7338654d025Sperrin 		if (num_logs(nvroot) > 0)
7348654d025Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
735fa9e4066Sahrens 
736fa9e4066Sahrens 		ret = 0;
737fa9e4066Sahrens 	} else {
738fa9e4066Sahrens 		/*
739fa9e4066Sahrens 		 * Hand off to libzfs.
740fa9e4066Sahrens 		 */
741990b4856Slling 		if (zpool_create(g_zfs, poolname, nvroot, props) == 0) {
74299653d4eSeschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
743fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
744fa9e4066Sahrens 			if (pool != NULL) {
745fa9e4066Sahrens 				if (mountpoint != NULL)
746fa9e4066Sahrens 					verify(zfs_prop_set(pool,
747e9dbad6fSeschrock 					    zfs_prop_to_name(
748e9dbad6fSeschrock 					    ZFS_PROP_MOUNTPOINT),
749fa9e4066Sahrens 					    mountpoint) == 0);
750fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
751da6c28aaSamw 					ret = zfs_shareall(pool);
752fa9e4066Sahrens 				zfs_close(pool);
753fa9e4066Sahrens 			}
75499653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
75599653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
75699653d4eSeschrock 			    "been omitted\n"));
757fa9e4066Sahrens 		}
758fa9e4066Sahrens 	}
759fa9e4066Sahrens 
760990b4856Slling errout:
761fa9e4066Sahrens 	nvlist_free(nvroot);
762990b4856Slling 	nvlist_free(props);
763fa9e4066Sahrens 	return (ret);
764990b4856Slling badusage:
765990b4856Slling 	nvlist_free(props);
766990b4856Slling 	usage(B_FALSE);
767990b4856Slling 	return (2);
768fa9e4066Sahrens }
769fa9e4066Sahrens 
770fa9e4066Sahrens /*
771fa9e4066Sahrens  * zpool destroy <pool>
772fa9e4066Sahrens  *
773fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
774fa9e4066Sahrens  *
775fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
776fa9e4066Sahrens  */
777fa9e4066Sahrens int
778fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
779fa9e4066Sahrens {
78099653d4eSeschrock 	boolean_t force = B_FALSE;
781fa9e4066Sahrens 	int c;
782fa9e4066Sahrens 	char *pool;
783fa9e4066Sahrens 	zpool_handle_t *zhp;
784fa9e4066Sahrens 	int ret;
785fa9e4066Sahrens 
786fa9e4066Sahrens 	/* check options */
787fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
788fa9e4066Sahrens 		switch (c) {
789fa9e4066Sahrens 		case 'f':
79099653d4eSeschrock 			force = B_TRUE;
791fa9e4066Sahrens 			break;
792fa9e4066Sahrens 		case '?':
793fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
794fa9e4066Sahrens 			    optopt);
79599653d4eSeschrock 			usage(B_FALSE);
796fa9e4066Sahrens 		}
797fa9e4066Sahrens 	}
798fa9e4066Sahrens 
799fa9e4066Sahrens 	argc -= optind;
800fa9e4066Sahrens 	argv += optind;
801fa9e4066Sahrens 
802fa9e4066Sahrens 	/* check arguments */
803fa9e4066Sahrens 	if (argc < 1) {
804fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
80599653d4eSeschrock 		usage(B_FALSE);
806fa9e4066Sahrens 	}
807fa9e4066Sahrens 	if (argc > 1) {
808fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
80999653d4eSeschrock 		usage(B_FALSE);
810fa9e4066Sahrens 	}
811fa9e4066Sahrens 
812fa9e4066Sahrens 	pool = argv[0];
813fa9e4066Sahrens 
81499653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
815fa9e4066Sahrens 		/*
816fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
817fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
818fa9e4066Sahrens 		 */
819fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
820fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
821fa9e4066Sahrens 			    "destroy a dataset\n"));
822fa9e4066Sahrens 		return (1);
823fa9e4066Sahrens 	}
824fa9e4066Sahrens 
825f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
826fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
827fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
828fa9e4066Sahrens 		return (1);
829fa9e4066Sahrens 	}
830fa9e4066Sahrens 
831fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
832fa9e4066Sahrens 
833fa9e4066Sahrens 	zpool_close(zhp);
834fa9e4066Sahrens 
835fa9e4066Sahrens 	return (ret);
836fa9e4066Sahrens }
837fa9e4066Sahrens 
838fa9e4066Sahrens /*
839fa9e4066Sahrens  * zpool export [-f] <pool> ...
840fa9e4066Sahrens  *
841fa9e4066Sahrens  *	-f	Forcefully unmount datasets
842fa9e4066Sahrens  *
843b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
844fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
845fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
846fa9e4066Sahrens  */
847fa9e4066Sahrens int
848fa9e4066Sahrens zpool_do_export(int argc, char **argv)
849fa9e4066Sahrens {
85099653d4eSeschrock 	boolean_t force = B_FALSE;
851fa9e4066Sahrens 	int c;
852fa9e4066Sahrens 	zpool_handle_t *zhp;
853fa9e4066Sahrens 	int ret;
854fa9e4066Sahrens 	int i;
855fa9e4066Sahrens 
856fa9e4066Sahrens 	/* check options */
857fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
858fa9e4066Sahrens 		switch (c) {
859fa9e4066Sahrens 		case 'f':
86099653d4eSeschrock 			force = B_TRUE;
861fa9e4066Sahrens 			break;
862fa9e4066Sahrens 		case '?':
863fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
864fa9e4066Sahrens 			    optopt);
86599653d4eSeschrock 			usage(B_FALSE);
866fa9e4066Sahrens 		}
867fa9e4066Sahrens 	}
868fa9e4066Sahrens 
869fa9e4066Sahrens 	argc -= optind;
870fa9e4066Sahrens 	argv += optind;
871fa9e4066Sahrens 
872fa9e4066Sahrens 	/* check arguments */
873fa9e4066Sahrens 	if (argc < 1) {
874fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
87599653d4eSeschrock 		usage(B_FALSE);
876fa9e4066Sahrens 	}
877fa9e4066Sahrens 
878fa9e4066Sahrens 	ret = 0;
879fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
88099653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
881fa9e4066Sahrens 			ret = 1;
882fa9e4066Sahrens 			continue;
883fa9e4066Sahrens 		}
884fa9e4066Sahrens 
885f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
886fa9e4066Sahrens 			ret = 1;
887fa9e4066Sahrens 			zpool_close(zhp);
888fa9e4066Sahrens 			continue;
889fa9e4066Sahrens 		}
890fa9e4066Sahrens 
891fa9e4066Sahrens 		if (zpool_export(zhp) != 0)
892fa9e4066Sahrens 			ret = 1;
893fa9e4066Sahrens 
894fa9e4066Sahrens 		zpool_close(zhp);
895fa9e4066Sahrens 	}
896fa9e4066Sahrens 
897fa9e4066Sahrens 	return (ret);
898fa9e4066Sahrens }
899fa9e4066Sahrens 
900fa9e4066Sahrens /*
901fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
902fa9e4066Sahrens  * name column.
903fa9e4066Sahrens  */
904fa9e4066Sahrens static int
905c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
906fa9e4066Sahrens {
90799653d4eSeschrock 	char *name = zpool_vdev_name(g_zfs, zhp, nv);
908fa9e4066Sahrens 	nvlist_t **child;
909fa9e4066Sahrens 	uint_t c, children;
910fa9e4066Sahrens 	int ret;
911fa9e4066Sahrens 
912fa9e4066Sahrens 	if (strlen(name) + depth > max)
913fa9e4066Sahrens 		max = strlen(name) + depth;
914fa9e4066Sahrens 
915afefbcddSeschrock 	free(name);
916afefbcddSeschrock 
91799653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
91899653d4eSeschrock 	    &child, &children) == 0) {
919fa9e4066Sahrens 		for (c = 0; c < children; c++)
92099653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
92199653d4eSeschrock 			    max)) > max)
922fa9e4066Sahrens 				max = ret;
92399653d4eSeschrock 	}
92499653d4eSeschrock 
925fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
926fa94a07fSbrendan 	    &child, &children) == 0) {
927fa94a07fSbrendan 		for (c = 0; c < children; c++)
928fa94a07fSbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
929fa94a07fSbrendan 			    max)) > max)
930fa94a07fSbrendan 				max = ret;
931fa94a07fSbrendan 	}
932fa94a07fSbrendan 
93399653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
93499653d4eSeschrock 	    &child, &children) == 0) {
93599653d4eSeschrock 		for (c = 0; c < children; c++)
93699653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
93799653d4eSeschrock 			    max)) > max)
93899653d4eSeschrock 				max = ret;
93999653d4eSeschrock 	}
94099653d4eSeschrock 
941fa9e4066Sahrens 
942fa9e4066Sahrens 	return (max);
943fa9e4066Sahrens }
944fa9e4066Sahrens 
945fa9e4066Sahrens 
946fa9e4066Sahrens /*
947fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
948fa9e4066Sahrens  * pool, printing out the name and status for each one.
949fa9e4066Sahrens  */
950fa9e4066Sahrens void
9518654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
9528654d025Sperrin     boolean_t print_logs)
953fa9e4066Sahrens {
954fa9e4066Sahrens 	nvlist_t **child;
955fa9e4066Sahrens 	uint_t c, children;
956fa9e4066Sahrens 	vdev_stat_t *vs;
957afefbcddSeschrock 	char *type, *vname;
958fa9e4066Sahrens 
959fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
960fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
961fa9e4066Sahrens 		return;
962fa9e4066Sahrens 
963fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
964fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
965fa9e4066Sahrens 
966fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
967990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
968fa9e4066Sahrens 
969fa9e4066Sahrens 	if (vs->vs_aux != 0) {
9703d7072f8Seschrock 		(void) printf("  ");
971fa9e4066Sahrens 
972fa9e4066Sahrens 		switch (vs->vs_aux) {
973fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
974fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
975fa9e4066Sahrens 			break;
976fa9e4066Sahrens 
977fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
978fa9e4066Sahrens 			(void) printf(gettext("missing device"));
979fa9e4066Sahrens 			break;
980fa9e4066Sahrens 
981fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
982fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
983fa9e4066Sahrens 			break;
984fa9e4066Sahrens 
985eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
986eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
987eaca9bbdSeschrock 			break;
988eaca9bbdSeschrock 
9893d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
9903d7072f8Seschrock 			(void) printf(gettext("too many errors"));
9913d7072f8Seschrock 			break;
9923d7072f8Seschrock 
993fa9e4066Sahrens 		default:
994fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
995fa9e4066Sahrens 			break;
996fa9e4066Sahrens 		}
997fa9e4066Sahrens 	}
998fa9e4066Sahrens 	(void) printf("\n");
999fa9e4066Sahrens 
1000fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1001fa9e4066Sahrens 	    &child, &children) != 0)
1002fa9e4066Sahrens 		return;
1003fa9e4066Sahrens 
1004afefbcddSeschrock 	for (c = 0; c < children; c++) {
10058654d025Sperrin 		uint64_t is_log = B_FALSE;
10068654d025Sperrin 
10078654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
10088654d025Sperrin 		    &is_log);
10098654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
10108654d025Sperrin 			continue;
10118654d025Sperrin 
101299653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1013afefbcddSeschrock 		print_import_config(vname, child[c],
10148654d025Sperrin 		    namewidth, depth + 2, B_FALSE);
1015afefbcddSeschrock 		free(vname);
1016afefbcddSeschrock 	}
101799653d4eSeschrock 
1018fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1019fa94a07fSbrendan 	    &child, &children) == 0) {
1020fa94a07fSbrendan 		(void) printf(gettext("\tcache\n"));
1021fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1022fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1023fa94a07fSbrendan 			(void) printf("\t  %s\n", vname);
1024fa94a07fSbrendan 			free(vname);
1025fa94a07fSbrendan 		}
1026fa94a07fSbrendan 	}
102799653d4eSeschrock 
1028fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1029fa94a07fSbrendan 	    &child, &children) == 0) {
103099653d4eSeschrock 		(void) printf(gettext("\tspares\n"));
103199653d4eSeschrock 		for (c = 0; c < children; c++) {
103299653d4eSeschrock 			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
103399653d4eSeschrock 			(void) printf("\t  %s\n", vname);
103499653d4eSeschrock 			free(vname);
103599653d4eSeschrock 		}
1036fa9e4066Sahrens 	}
1037fa94a07fSbrendan }
1038fa9e4066Sahrens 
1039fa9e4066Sahrens /*
1040fa9e4066Sahrens  * Display the status for the given pool.
1041fa9e4066Sahrens  */
1042fa9e4066Sahrens static void
1043fa9e4066Sahrens show_import(nvlist_t *config)
1044fa9e4066Sahrens {
1045fa9e4066Sahrens 	uint64_t pool_state;
1046fa9e4066Sahrens 	vdev_stat_t *vs;
1047fa9e4066Sahrens 	char *name;
1048fa9e4066Sahrens 	uint64_t guid;
1049fa9e4066Sahrens 	char *msgid;
1050fa9e4066Sahrens 	nvlist_t *nvroot;
1051fa9e4066Sahrens 	int reason;
105246657f8dSmmusante 	const char *health;
1053fa9e4066Sahrens 	uint_t vsc;
1054fa9e4066Sahrens 	int namewidth;
1055fa9e4066Sahrens 
1056fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1057fa9e4066Sahrens 	    &name) == 0);
1058fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1059fa9e4066Sahrens 	    &guid) == 0);
1060fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1061fa9e4066Sahrens 	    &pool_state) == 0);
1062fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1063fa9e4066Sahrens 	    &nvroot) == 0);
1064fa9e4066Sahrens 
1065fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1066fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1067990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1068fa9e4066Sahrens 
1069fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1070fa9e4066Sahrens 
107146657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
107246657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
107346657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
10744c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
107546657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
10764c58d714Sdarrenm 	(void) printf("\n");
1077fa9e4066Sahrens 
1078fa9e4066Sahrens 	switch (reason) {
1079fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1080fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1081fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1082fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1083fa9e4066Sahrens 		    "from the system.\n"));
1084fa9e4066Sahrens 		break;
1085fa9e4066Sahrens 
1086fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1087fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1088fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1089fa9e4066Sahrens 		    "corrupted data.\n"));
1090fa9e4066Sahrens 		break;
1091fa9e4066Sahrens 
1092fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1093fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1094fa9e4066Sahrens 		break;
1095fa9e4066Sahrens 
1096441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1097441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1098441d80aaSlling 		    "are offlined.\n"));
1099441d80aaSlling 		break;
1100441d80aaSlling 
1101ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1102ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1103ea8dc4b6Seschrock 		    "corrupted.\n"));
1104ea8dc4b6Seschrock 		break;
1105ea8dc4b6Seschrock 
1106eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1107eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1108eaca9bbdSeschrock 		    "older on-disk version.\n"));
1109eaca9bbdSeschrock 		break;
1110eaca9bbdSeschrock 
1111eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1112eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1113eaca9bbdSeschrock 		    "incompatible version.\n"));
1114eaca9bbdSeschrock 		break;
111595173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
111695173954Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
111795173954Sek110237 		    "another system.\n"));
111895173954Sek110237 		break;
11193d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
11203d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
11213d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
11223d7072f8Seschrock 		    "faulted.\n"));
11233d7072f8Seschrock 		break;
11243d7072f8Seschrock 
1125fa9e4066Sahrens 	default:
1126fa9e4066Sahrens 		/*
1127fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1128fa9e4066Sahrens 		 */
1129fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1130fa9e4066Sahrens 	}
1131fa9e4066Sahrens 
1132fa9e4066Sahrens 	/*
1133fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1134fa9e4066Sahrens 	 */
113546657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1136eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1137eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1138eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1139eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1140eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
114195173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
114295173954Sek110237 			(void) printf(gettext("action: The pool can be "
114395173954Sek110237 			    "imported using its name or numeric "
114495173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1145fa9e4066Sahrens 		else
1146eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1147eaca9bbdSeschrock 			    "imported using its name or numeric "
1148eaca9bbdSeschrock 			    "identifier.\n"));
114946657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1150fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1151fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1152eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1153fa9e4066Sahrens 	} else {
1154eaca9bbdSeschrock 		switch (reason) {
1155eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1156eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1157eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1158eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1159eaca9bbdSeschrock 			    "backup.\n"));
1160eaca9bbdSeschrock 			break;
1161eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1162eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1163eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1164fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1165fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1166fa9e4066Sahrens 			    "again.\n"));
1167eaca9bbdSeschrock 			break;
1168eaca9bbdSeschrock 		default:
1169fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1170fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1171fa9e4066Sahrens 		}
1172eaca9bbdSeschrock 	}
1173eaca9bbdSeschrock 
117446657f8dSmmusante 	/*
117546657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
117646657f8dSmmusante 	 * is "corrupt data":
117746657f8dSmmusante 	 */
117846657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
117946657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
118046657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1181eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1182eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1183eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1184eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1185eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
118618ce54dfSek110237 			    "another system, but can be imported using\n\t"
1187eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1188eaca9bbdSeschrock 	}
1189fa9e4066Sahrens 
1190fa9e4066Sahrens 	if (msgid != NULL)
1191fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1192fa9e4066Sahrens 		    msgid);
1193fa9e4066Sahrens 
1194fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1195fa9e4066Sahrens 
1196c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1197fa9e4066Sahrens 	if (namewidth < 10)
1198fa9e4066Sahrens 		namewidth = 10;
11998654d025Sperrin 
12008654d025Sperrin 	print_import_config(name, nvroot, namewidth, 0, B_FALSE);
12018654d025Sperrin 	if (num_logs(nvroot) > 0) {
12028654d025Sperrin 		(void) printf(gettext("\tlogs\n"));
12038654d025Sperrin 		print_import_config(name, nvroot, namewidth, 0, B_TRUE);
12048654d025Sperrin 	}
1205fa9e4066Sahrens 
1206fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
120746657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1208fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
120946657f8dSmmusante 		    "configuration cannot be determined.\n"));
1210fa9e4066Sahrens 	}
1211fa9e4066Sahrens }
1212fa9e4066Sahrens 
1213fa9e4066Sahrens /*
1214fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1215990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1216990b4856Slling  * within the pool.
1217fa9e4066Sahrens  */
1218fa9e4066Sahrens static int
1219fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
1220c5904d13Seschrock     int force, nvlist_t *props, boolean_t allowfaulted)
1221fa9e4066Sahrens {
1222fa9e4066Sahrens 	zpool_handle_t *zhp;
1223fa9e4066Sahrens 	char *name;
1224fa9e4066Sahrens 	uint64_t state;
1225eaca9bbdSeschrock 	uint64_t version;
1226ecd6cf80Smarks 	int error = 0;
1227fa9e4066Sahrens 
1228fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1229fa9e4066Sahrens 	    &name) == 0);
1230fa9e4066Sahrens 
1231fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1232fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1233eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1234eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1235e7437265Sahrens 	if (version > SPA_VERSION) {
1236eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1237eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1238eaca9bbdSeschrock 		return (1);
1239eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
124095173954Sek110237 		uint64_t hostid;
124195173954Sek110237 
124295173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
124395173954Sek110237 		    &hostid) == 0) {
124495173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
124595173954Sek110237 				char *hostname;
124695173954Sek110237 				uint64_t timestamp;
124795173954Sek110237 				time_t t;
124895173954Sek110237 
124995173954Sek110237 				verify(nvlist_lookup_string(config,
125095173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
125195173954Sek110237 				verify(nvlist_lookup_uint64(config,
125295173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
125395173954Sek110237 				t = timestamp;
125495173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
125595173954Sek110237 				    "'%s': pool may be in use from other "
125695173954Sek110237 				    "system, it was last accessed by %s "
125795173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
125895173954Sek110237 				    (unsigned long)hostid,
125995173954Sek110237 				    asctime(localtime(&t)));
126095173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
126195173954Sek110237 				    "import anyway\n"));
1262fa9e4066Sahrens 				return (1);
1263fa9e4066Sahrens 			}
126495173954Sek110237 		} else {
126595173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
126695173954Sek110237 			    "pool may be in use from other system\n"), name);
126795173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
126895173954Sek110237 			    "anyway\n"));
126995173954Sek110237 			return (1);
127095173954Sek110237 		}
127195173954Sek110237 	}
1272fa9e4066Sahrens 
1273c5904d13Seschrock 	if (zpool_import_props(g_zfs, config, newname, props,
1274c5904d13Seschrock 	    allowfaulted) != 0)
1275fa9e4066Sahrens 		return (1);
1276fa9e4066Sahrens 
1277fa9e4066Sahrens 	if (newname != NULL)
1278fa9e4066Sahrens 		name = (char *)newname;
1279fa9e4066Sahrens 
1280c5904d13Seschrock 	verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL);
1281fa9e4066Sahrens 
1282f3861e1aSahl 	if (zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1283fa9e4066Sahrens 		zpool_close(zhp);
1284fa9e4066Sahrens 		return (1);
1285fa9e4066Sahrens 	}
1286fa9e4066Sahrens 
1287fa9e4066Sahrens 	zpool_close(zhp);
1288ecd6cf80Smarks 	return (error);
1289fa9e4066Sahrens }
1290fa9e4066Sahrens 
1291fa9e4066Sahrens /*
12924c58d714Sdarrenm  * zpool import [-d dir] [-D]
12932f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
12942f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
12952f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
12962f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] <pool | id> [newpool]
12972f8aaab3Seschrock  *
12982f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
12992f8aaab3Seschrock  *		devices.
1300fa9e4066Sahrens  *
1301fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1302fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1303fa9e4066Sahrens  *
13044c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
13054c58d714Sdarrenm  *              specified destroyed pools.
13064c58d714Sdarrenm  *
1307fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1308fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1309fa9e4066Sahrens  *		is rebooted.
1310fa9e4066Sahrens  *
1311fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1312fa9e4066Sahrens  *
1313c5904d13Seschrock  *       -F	Import even in the presence of faulted vdevs.  This is an
1314c5904d13Seschrock  *       	intentionally undocumented option for testing purposes, and
1315c5904d13Seschrock  *       	treats the pool configuration as complete, leaving any bad
1316c5904d13Seschrock  *		vdevs in the FAULTED state.
1317c5904d13Seschrock  *
1318fa9e4066Sahrens  *       -a	Import all pools found.
1319fa9e4066Sahrens  *
1320990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1321ecd6cf80Smarks  *
1322fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1323fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1324fa9e4066Sahrens  */
1325fa9e4066Sahrens int
1326fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1327fa9e4066Sahrens {
1328fa9e4066Sahrens 	char **searchdirs = NULL;
1329fa9e4066Sahrens 	int nsearch = 0;
1330fa9e4066Sahrens 	int c;
1331fa9e4066Sahrens 	int err;
13322f8aaab3Seschrock 	nvlist_t *pools = NULL;
133399653d4eSeschrock 	boolean_t do_all = B_FALSE;
133499653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1335fa9e4066Sahrens 	char *mntopts = NULL;
133699653d4eSeschrock 	boolean_t do_force = B_FALSE;
1337fa9e4066Sahrens 	nvpair_t *elem;
1338fa9e4066Sahrens 	nvlist_t *config;
133924e697d4Sck153898 	uint64_t searchguid = 0;
134024e697d4Sck153898 	char *searchname = NULL;
1341990b4856Slling 	char *propval;
1342fa9e4066Sahrens 	nvlist_t *found_config;
1343ecd6cf80Smarks 	nvlist_t *props = NULL;
134499653d4eSeschrock 	boolean_t first;
1345c5904d13Seschrock 	boolean_t allow_faulted = B_FALSE;
13464c58d714Sdarrenm 	uint64_t pool_state;
13472f8aaab3Seschrock 	char *cachefile = NULL;
1348fa9e4066Sahrens 
1349fa9e4066Sahrens 	/* check options */
1350c5904d13Seschrock 	while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) {
1351fa9e4066Sahrens 		switch (c) {
1352fa9e4066Sahrens 		case 'a':
135399653d4eSeschrock 			do_all = B_TRUE;
1354fa9e4066Sahrens 			break;
13552f8aaab3Seschrock 		case 'c':
13562f8aaab3Seschrock 			cachefile = optarg;
13572f8aaab3Seschrock 			break;
1358fa9e4066Sahrens 		case 'd':
1359fa9e4066Sahrens 			if (searchdirs == NULL) {
1360fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1361fa9e4066Sahrens 			} else {
1362fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1363fa9e4066Sahrens 				    sizeof (char *));
1364fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1365fa9e4066Sahrens 				    sizeof (char *));
1366fa9e4066Sahrens 				free(searchdirs);
1367fa9e4066Sahrens 				searchdirs = tmp;
1368fa9e4066Sahrens 			}
1369fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1370fa9e4066Sahrens 			break;
13714c58d714Sdarrenm 		case 'D':
137299653d4eSeschrock 			do_destroyed = B_TRUE;
13734c58d714Sdarrenm 			break;
1374fa9e4066Sahrens 		case 'f':
137599653d4eSeschrock 			do_force = B_TRUE;
1376fa9e4066Sahrens 			break;
1377c5904d13Seschrock 		case 'F':
1378c5904d13Seschrock 			allow_faulted = B_TRUE;
1379c5904d13Seschrock 			break;
1380fa9e4066Sahrens 		case 'o':
1381990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1382990b4856Slling 				*propval = '\0';
1383990b4856Slling 				propval++;
1384990b4856Slling 				if (add_prop_list(optarg, propval, &props))
1385990b4856Slling 					goto error;
1386990b4856Slling 			} else {
1387fa9e4066Sahrens 				mntopts = optarg;
1388990b4856Slling 			}
1389fa9e4066Sahrens 			break;
1390fa9e4066Sahrens 		case 'R':
1391990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
1392990b4856Slling 			    ZPOOL_PROP_ALTROOT), optarg, &props))
1393990b4856Slling 				goto error;
13942f8aaab3Seschrock 			if (nvlist_lookup_string(props,
13952f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
13962f8aaab3Seschrock 			    &propval) == 0)
13972f8aaab3Seschrock 				break;
1398990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
13992f8aaab3Seschrock 			    ZPOOL_PROP_CACHEFILE), "none", &props))
1400990b4856Slling 				goto error;
1401fa9e4066Sahrens 			break;
1402fa9e4066Sahrens 		case ':':
1403fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1404fa9e4066Sahrens 			    "'%c' option\n"), optopt);
140599653d4eSeschrock 			usage(B_FALSE);
1406fa9e4066Sahrens 			break;
1407fa9e4066Sahrens 		case '?':
1408fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1409fa9e4066Sahrens 			    optopt);
141099653d4eSeschrock 			usage(B_FALSE);
1411fa9e4066Sahrens 		}
1412fa9e4066Sahrens 	}
1413fa9e4066Sahrens 
1414fa9e4066Sahrens 	argc -= optind;
1415fa9e4066Sahrens 	argv += optind;
1416fa9e4066Sahrens 
14172f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
14182f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
14192f8aaab3Seschrock 		usage(B_FALSE);
14202f8aaab3Seschrock 	}
14212f8aaab3Seschrock 
1422fa9e4066Sahrens 	if (searchdirs == NULL) {
1423fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1424fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1425fa9e4066Sahrens 		nsearch = 1;
1426fa9e4066Sahrens 	}
1427fa9e4066Sahrens 
1428fa9e4066Sahrens 	/* check argument count */
1429fa9e4066Sahrens 	if (do_all) {
1430fa9e4066Sahrens 		if (argc != 0) {
1431fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
143299653d4eSeschrock 			usage(B_FALSE);
1433fa9e4066Sahrens 		}
1434fa9e4066Sahrens 	} else {
1435fa9e4066Sahrens 		if (argc > 2) {
1436fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
143799653d4eSeschrock 			usage(B_FALSE);
1438fa9e4066Sahrens 		}
1439fa9e4066Sahrens 
1440fa9e4066Sahrens 		/*
1441fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1442fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1443fa9e4066Sahrens 		 * silently fail.
1444fa9e4066Sahrens 		 */
1445fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1446fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1447fa9e4066Sahrens 			    "discover pools: permission denied\n"));
144899653d4eSeschrock 			free(searchdirs);
1449fa9e4066Sahrens 			return (1);
1450fa9e4066Sahrens 		}
1451fa9e4066Sahrens 	}
1452fa9e4066Sahrens 
1453fa9e4066Sahrens 	/*
1454fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1455fa9e4066Sahrens 	 *
1456fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1457fa9e4066Sahrens 	 *		each one.
1458fa9e4066Sahrens 	 *
1459fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1460fa9e4066Sahrens 	 *
1461fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1462fa9e4066Sahrens 	 *		name and import that one.
14634c58d714Sdarrenm 	 *
14644c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1465fa9e4066Sahrens 	 */
1466fa9e4066Sahrens 	if (argc != 0) {
1467fa9e4066Sahrens 		char *endptr;
1468fa9e4066Sahrens 
1469fa9e4066Sahrens 		errno = 0;
1470fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1471fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1472fa9e4066Sahrens 			searchname = argv[0];
1473fa9e4066Sahrens 		found_config = NULL;
1474fa9e4066Sahrens 	}
1475fa9e4066Sahrens 
147624e697d4Sck153898 	if (cachefile) {
1477*e829d913Sck153898 		pools = zpool_find_import_cached(g_zfs, cachefile, searchname,
1478*e829d913Sck153898 		    searchguid);
147924e697d4Sck153898 	} else if (searchname != NULL) {
148024e697d4Sck153898 		pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs,
148124e697d4Sck153898 		    searchname);
148224e697d4Sck153898 	} else {
148324e697d4Sck153898 		/*
148424e697d4Sck153898 		 * It's OK to search by guid even if searchguid is 0.
148524e697d4Sck153898 		 */
148624e697d4Sck153898 		pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs,
148724e697d4Sck153898 		    searchguid);
148824e697d4Sck153898 	}
148924e697d4Sck153898 
149024e697d4Sck153898 	if (pools == NULL) {
149124e697d4Sck153898 		if (argc != 0) {
149224e697d4Sck153898 			(void) fprintf(stderr, gettext("cannot import '%s': "
149324e697d4Sck153898 			    "no such pool available\n"), argv[0]);
149424e697d4Sck153898 		}
149524e697d4Sck153898 		free(searchdirs);
149624e697d4Sck153898 		return (1);
149724e697d4Sck153898 	}
149824e697d4Sck153898 
149924e697d4Sck153898 	/*
150024e697d4Sck153898 	 * At this point we have a list of import candidate configs. Even if
150124e697d4Sck153898 	 * we were searching by pool name or guid, we still need to
150224e697d4Sck153898 	 * post-process the list to deal with pool state and possible
150324e697d4Sck153898 	 * duplicate names.
150424e697d4Sck153898 	 */
1505fa9e4066Sahrens 	err = 0;
1506fa9e4066Sahrens 	elem = NULL;
150799653d4eSeschrock 	first = B_TRUE;
1508fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1509fa9e4066Sahrens 
1510fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1511fa9e4066Sahrens 
15124c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
15134c58d714Sdarrenm 		    &pool_state) == 0);
15144c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
15154c58d714Sdarrenm 			continue;
15164c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
15174c58d714Sdarrenm 			continue;
15184c58d714Sdarrenm 
1519fa9e4066Sahrens 		if (argc == 0) {
1520fa9e4066Sahrens 			if (first)
152199653d4eSeschrock 				first = B_FALSE;
15223bb79becSeschrock 			else if (!do_all)
1523fa9e4066Sahrens 				(void) printf("\n");
1524fa9e4066Sahrens 
1525fa9e4066Sahrens 			if (do_all)
1526fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1527c5904d13Seschrock 				    do_force, props, allow_faulted);
1528fa9e4066Sahrens 			else
1529fa9e4066Sahrens 				show_import(config);
1530fa9e4066Sahrens 		} else if (searchname != NULL) {
1531fa9e4066Sahrens 			char *name;
1532fa9e4066Sahrens 
1533fa9e4066Sahrens 			/*
1534fa9e4066Sahrens 			 * We are searching for a pool based on name.
1535fa9e4066Sahrens 			 */
1536fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1537fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1538fa9e4066Sahrens 
1539fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1540fa9e4066Sahrens 				if (found_config != NULL) {
1541fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1542fa9e4066Sahrens 					    "cannot import '%s': more than "
1543fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1544fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1545fa9e4066Sahrens 					    "import by numeric ID instead\n"));
154699653d4eSeschrock 					err = B_TRUE;
1547fa9e4066Sahrens 				}
1548fa9e4066Sahrens 				found_config = config;
1549fa9e4066Sahrens 			}
1550fa9e4066Sahrens 		} else {
1551fa9e4066Sahrens 			uint64_t guid;
1552fa9e4066Sahrens 
1553fa9e4066Sahrens 			/*
1554fa9e4066Sahrens 			 * Search for a pool by guid.
1555fa9e4066Sahrens 			 */
1556fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1557fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1558fa9e4066Sahrens 
1559fa9e4066Sahrens 			if (guid == searchguid)
1560fa9e4066Sahrens 				found_config = config;
1561fa9e4066Sahrens 		}
1562fa9e4066Sahrens 	}
1563fa9e4066Sahrens 
1564fa9e4066Sahrens 	/*
1565fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1566fa9e4066Sahrens 	 * pool, and then do the import.
1567fa9e4066Sahrens 	 */
1568fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1569fa9e4066Sahrens 		if (found_config == NULL) {
1570fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1571fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
157299653d4eSeschrock 			err = B_TRUE;
1573fa9e4066Sahrens 		} else {
1574fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1575c5904d13Seschrock 			    argv[1], mntopts, do_force, props, allow_faulted);
1576fa9e4066Sahrens 		}
1577fa9e4066Sahrens 	}
1578fa9e4066Sahrens 
1579fa9e4066Sahrens 	/*
1580fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1581fa9e4066Sahrens 	 * found.
1582fa9e4066Sahrens 	 */
1583fa9e4066Sahrens 	if (argc == 0 && first)
1584fa9e4066Sahrens 		(void) fprintf(stderr,
1585fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1586fa9e4066Sahrens 
1587ecd6cf80Smarks error:
1588ecd6cf80Smarks 	nvlist_free(props);
1589fa9e4066Sahrens 	nvlist_free(pools);
159099653d4eSeschrock 	free(searchdirs);
1591fa9e4066Sahrens 
1592fa9e4066Sahrens 	return (err ? 1 : 0);
1593fa9e4066Sahrens }
1594fa9e4066Sahrens 
1595fa9e4066Sahrens typedef struct iostat_cbdata {
1596fa9e4066Sahrens 	zpool_list_t *cb_list;
1597fa9e4066Sahrens 	int cb_verbose;
1598fa9e4066Sahrens 	int cb_iteration;
1599fa9e4066Sahrens 	int cb_namewidth;
1600fa9e4066Sahrens } iostat_cbdata_t;
1601fa9e4066Sahrens 
1602fa9e4066Sahrens static void
1603fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1604fa9e4066Sahrens {
1605fa9e4066Sahrens 	int i = 0;
1606fa9e4066Sahrens 
1607fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1608fa9e4066Sahrens 		(void) printf("-");
1609fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1610fa9e4066Sahrens }
1611fa9e4066Sahrens 
1612fa9e4066Sahrens static void
1613fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1614fa9e4066Sahrens {
1615fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1616fa9e4066Sahrens 	    cb->cb_namewidth, "");
1617fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1618fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1619fa9e4066Sahrens 	print_iostat_separator(cb);
1620fa9e4066Sahrens }
1621fa9e4066Sahrens 
1622fa9e4066Sahrens /*
1623fa9e4066Sahrens  * Display a single statistic.
1624fa9e4066Sahrens  */
1625990b4856Slling static void
1626fa9e4066Sahrens print_one_stat(uint64_t value)
1627fa9e4066Sahrens {
1628fa9e4066Sahrens 	char buf[64];
1629fa9e4066Sahrens 
1630fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1631fa9e4066Sahrens 	(void) printf("  %5s", buf);
1632fa9e4066Sahrens }
1633fa9e4066Sahrens 
1634fa9e4066Sahrens /*
1635fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1636fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1637fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1638fa9e4066Sahrens  */
1639fa9e4066Sahrens void
1640c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1641c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1642fa9e4066Sahrens {
1643fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1644fa9e4066Sahrens 	uint_t c, children;
1645fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1646fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1647fa9e4066Sahrens 	uint64_t tdelta;
1648fa9e4066Sahrens 	double scale;
1649afefbcddSeschrock 	char *vname;
1650fa9e4066Sahrens 
1651fa9e4066Sahrens 	if (oldnv != NULL) {
1652fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1653fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1654fa9e4066Sahrens 	} else {
1655fa9e4066Sahrens 		oldvs = &zerovs;
1656fa9e4066Sahrens 	}
1657fa9e4066Sahrens 
1658fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1659fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1660fa9e4066Sahrens 
1661fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1662fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1663fa9e4066Sahrens 	else
1664fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1665fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1666fa9e4066Sahrens 
1667fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1668fa9e4066Sahrens 
1669fa9e4066Sahrens 	if (tdelta == 0)
1670fa9e4066Sahrens 		scale = 1.0;
1671fa9e4066Sahrens 	else
1672fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1673fa9e4066Sahrens 
1674fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1675fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1676fa9e4066Sahrens 		(void) printf("      -      -");
1677fa9e4066Sahrens 	} else {
1678fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1679fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1680fa9e4066Sahrens 	}
1681fa9e4066Sahrens 
1682fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1683fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1684fa9e4066Sahrens 
1685fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1686fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1687fa9e4066Sahrens 
1688fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1689fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1690fa9e4066Sahrens 
1691fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1692fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1693fa9e4066Sahrens 
1694fa9e4066Sahrens 	(void) printf("\n");
1695fa9e4066Sahrens 
1696fa9e4066Sahrens 	if (!cb->cb_verbose)
1697fa9e4066Sahrens 		return;
1698fa9e4066Sahrens 
1699fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1700fa9e4066Sahrens 	    &newchild, &children) != 0)
1701fa9e4066Sahrens 		return;
1702fa9e4066Sahrens 
1703fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1704fa9e4066Sahrens 	    &oldchild, &c) != 0)
1705fa9e4066Sahrens 		return;
1706fa9e4066Sahrens 
1707afefbcddSeschrock 	for (c = 0; c < children; c++) {
170899653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1709c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1710afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1711afefbcddSeschrock 		free(vname);
1712afefbcddSeschrock 	}
1713fa94a07fSbrendan 
1714fa94a07fSbrendan 	/*
1715fa94a07fSbrendan 	 * Include level 2 ARC devices in iostat output
1716fa94a07fSbrendan 	 */
1717fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
1718fa94a07fSbrendan 	    &newchild, &children) != 0)
1719fa94a07fSbrendan 		return;
1720fa94a07fSbrendan 
1721fa94a07fSbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
1722fa94a07fSbrendan 	    &oldchild, &c) != 0)
1723fa94a07fSbrendan 		return;
1724fa94a07fSbrendan 
1725fa94a07fSbrendan 	if (children > 0) {
1726fa94a07fSbrendan 		(void) printf("%-*s      -      -      -      -      -      "
1727fa94a07fSbrendan 		    "-\n", cb->cb_namewidth, "cache");
1728fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1729fa94a07fSbrendan 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1730fa94a07fSbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1731fa94a07fSbrendan 			    newchild[c], cb, depth + 2);
1732fa94a07fSbrendan 			free(vname);
1733fa94a07fSbrendan 		}
1734fa94a07fSbrendan 	}
1735fa9e4066Sahrens }
1736fa9e4066Sahrens 
1737088e9d47Seschrock static int
1738088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
1739088e9d47Seschrock {
1740088e9d47Seschrock 	iostat_cbdata_t *cb = data;
174194de1d4cSeschrock 	boolean_t missing;
1742088e9d47Seschrock 
1743088e9d47Seschrock 	/*
1744088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
1745088e9d47Seschrock 	 */
174694de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
174794de1d4cSeschrock 		return (-1);
174894de1d4cSeschrock 
174994de1d4cSeschrock 	if (missing)
1750088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
1751088e9d47Seschrock 
1752088e9d47Seschrock 	return (0);
1753088e9d47Seschrock }
1754088e9d47Seschrock 
1755fa9e4066Sahrens /*
1756fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
1757fa9e4066Sahrens  */
1758fa9e4066Sahrens int
1759fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
1760fa9e4066Sahrens {
1761fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1762fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
1763fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
1764fa9e4066Sahrens 
1765088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
1766fa9e4066Sahrens 
1767088e9d47Seschrock 	if (cb->cb_iteration == 1)
1768fa9e4066Sahrens 		oldconfig = NULL;
1769fa9e4066Sahrens 
1770fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1771fa9e4066Sahrens 	    &newnvroot) == 0);
1772fa9e4066Sahrens 
1773088e9d47Seschrock 	if (oldconfig == NULL)
1774fa9e4066Sahrens 		oldnvroot = NULL;
1775088e9d47Seschrock 	else
1776088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
1777088e9d47Seschrock 		    &oldnvroot) == 0);
1778fa9e4066Sahrens 
1779fa9e4066Sahrens 	/*
1780fa9e4066Sahrens 	 * Print out the statistics for the pool.
1781fa9e4066Sahrens 	 */
1782c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1783fa9e4066Sahrens 
1784fa9e4066Sahrens 	if (cb->cb_verbose)
1785fa9e4066Sahrens 		print_iostat_separator(cb);
1786fa9e4066Sahrens 
1787fa9e4066Sahrens 	return (0);
1788fa9e4066Sahrens }
1789fa9e4066Sahrens 
1790fa9e4066Sahrens int
1791fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
1792fa9e4066Sahrens {
1793fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1794fa9e4066Sahrens 	nvlist_t *config, *nvroot;
1795fa9e4066Sahrens 
1796088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
1797fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1798fa9e4066Sahrens 		    &nvroot) == 0);
1799fa9e4066Sahrens 		if (!cb->cb_verbose)
1800fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1801fa9e4066Sahrens 		else
1802c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
1803fa9e4066Sahrens 	}
1804fa9e4066Sahrens 
1805fa9e4066Sahrens 	/*
1806fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
1807fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
1808fa9e4066Sahrens 	 */
1809fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
1810fa9e4066Sahrens 		cb->cb_namewidth = 10;
1811fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
1812fa9e4066Sahrens 		cb->cb_namewidth = 38;
1813fa9e4066Sahrens 
1814fa9e4066Sahrens 	return (0);
1815fa9e4066Sahrens }
1816fa9e4066Sahrens 
1817fa9e4066Sahrens /*
1818fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
1819fa9e4066Sahrens  *
1820fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
1821fa9e4066Sahrens  *
1822fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
1823fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
1824fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1825fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
1826fa9e4066Sahrens  * changes are all handled within libzfs.
1827fa9e4066Sahrens  */
1828fa9e4066Sahrens int
1829fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
1830fa9e4066Sahrens {
1831fa9e4066Sahrens 	int c;
1832fa9e4066Sahrens 	int ret;
1833fa9e4066Sahrens 	int npools;
1834fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
1835fa9e4066Sahrens 	zpool_list_t *list;
183699653d4eSeschrock 	boolean_t verbose = B_FALSE;
1837fa9e4066Sahrens 	iostat_cbdata_t cb;
1838fa9e4066Sahrens 
1839fa9e4066Sahrens 	/* check options */
1840fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
1841fa9e4066Sahrens 		switch (c) {
1842fa9e4066Sahrens 		case 'v':
184399653d4eSeschrock 			verbose = B_TRUE;
1844fa9e4066Sahrens 			break;
1845fa9e4066Sahrens 		case '?':
1846fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1847fa9e4066Sahrens 			    optopt);
184899653d4eSeschrock 			usage(B_FALSE);
1849fa9e4066Sahrens 		}
1850fa9e4066Sahrens 	}
1851fa9e4066Sahrens 
1852fa9e4066Sahrens 	argc -= optind;
1853fa9e4066Sahrens 	argv += optind;
1854fa9e4066Sahrens 
1855fa9e4066Sahrens 	/*
1856fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
1857fa9e4066Sahrens 	 */
1858fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1859fa9e4066Sahrens 		char *end;
1860fa9e4066Sahrens 
1861fa9e4066Sahrens 		errno = 0;
1862fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1863fa9e4066Sahrens 
1864fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1865fa9e4066Sahrens 			if (interval == 0) {
1866fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1867fa9e4066Sahrens 				    "cannot be zero\n"));
186899653d4eSeschrock 				usage(B_FALSE);
1869fa9e4066Sahrens 			}
1870fa9e4066Sahrens 
1871fa9e4066Sahrens 			/*
1872fa9e4066Sahrens 			 * Ignore the last parameter
1873fa9e4066Sahrens 			 */
1874fa9e4066Sahrens 			argc--;
1875fa9e4066Sahrens 		} else {
1876fa9e4066Sahrens 			/*
1877fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
1878fa9e4066Sahrens 			 * user will get a more informative error message later
1879fa9e4066Sahrens 			 * on.
1880fa9e4066Sahrens 			 */
1881fa9e4066Sahrens 			interval = 0;
1882fa9e4066Sahrens 		}
1883fa9e4066Sahrens 	}
1884fa9e4066Sahrens 
1885fa9e4066Sahrens 	/*
1886fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
1887fa9e4066Sahrens 	 * and an integer.
1888fa9e4066Sahrens 	 */
1889fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1890fa9e4066Sahrens 		char *end;
1891fa9e4066Sahrens 
1892fa9e4066Sahrens 		errno = 0;
1893fa9e4066Sahrens 		count = interval;
1894fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1895fa9e4066Sahrens 
1896fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1897fa9e4066Sahrens 			if (interval == 0) {
1898fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1899fa9e4066Sahrens 				    "cannot be zero\n"));
190099653d4eSeschrock 				usage(B_FALSE);
1901fa9e4066Sahrens 			}
1902fa9e4066Sahrens 
1903fa9e4066Sahrens 			/*
1904fa9e4066Sahrens 			 * Ignore the last parameter
1905fa9e4066Sahrens 			 */
1906fa9e4066Sahrens 			argc--;
1907fa9e4066Sahrens 		} else {
1908fa9e4066Sahrens 			interval = 0;
1909fa9e4066Sahrens 		}
1910fa9e4066Sahrens 	}
1911fa9e4066Sahrens 
1912fa9e4066Sahrens 	/*
1913fa9e4066Sahrens 	 * Construct the list of all interesting pools.
1914fa9e4066Sahrens 	 */
1915fa9e4066Sahrens 	ret = 0;
1916b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
1917fa9e4066Sahrens 		return (1);
1918fa9e4066Sahrens 
191999653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
192099653d4eSeschrock 		pool_list_free(list);
1921fa9e4066Sahrens 		return (1);
192299653d4eSeschrock 	}
1923fa9e4066Sahrens 
1924fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
192599653d4eSeschrock 		pool_list_free(list);
1926fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
1927fa9e4066Sahrens 		return (1);
1928fa9e4066Sahrens 	}
1929fa9e4066Sahrens 
1930fa9e4066Sahrens 	/*
1931fa9e4066Sahrens 	 * Enter the main iostat loop.
1932fa9e4066Sahrens 	 */
1933fa9e4066Sahrens 	cb.cb_list = list;
1934fa9e4066Sahrens 	cb.cb_verbose = verbose;
1935fa9e4066Sahrens 	cb.cb_iteration = 0;
1936fa9e4066Sahrens 	cb.cb_namewidth = 0;
1937fa9e4066Sahrens 
1938fa9e4066Sahrens 	for (;;) {
1939fa9e4066Sahrens 		pool_list_update(list);
1940fa9e4066Sahrens 
1941fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
1942fa9e4066Sahrens 			break;
1943fa9e4066Sahrens 
1944fa9e4066Sahrens 		/*
1945088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
1946088e9d47Seschrock 		 * before calculating the maximum name width, so that any
1947088e9d47Seschrock 		 * configuration changes are properly accounted for.
1948088e9d47Seschrock 		 */
194999653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
1950088e9d47Seschrock 
1951088e9d47Seschrock 		/*
1952fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
1953fa9e4066Sahrens 		 * for the pool / device name column across all pools.
1954fa9e4066Sahrens 		 */
1955fa9e4066Sahrens 		cb.cb_namewidth = 0;
195699653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
1957fa9e4066Sahrens 
1958fa9e4066Sahrens 		/*
1959fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
1960fa9e4066Sahrens 		 */
1961fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
1962fa9e4066Sahrens 			print_iostat_header(&cb);
1963fa9e4066Sahrens 
196499653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
1965fa9e4066Sahrens 
1966fa9e4066Sahrens 		/*
1967fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
1968fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
1969fa9e4066Sahrens 		 */
1970fa9e4066Sahrens 		if (npools > 1 && !verbose)
1971fa9e4066Sahrens 			print_iostat_separator(&cb);
1972fa9e4066Sahrens 
1973fa9e4066Sahrens 		if (verbose)
1974fa9e4066Sahrens 			(void) printf("\n");
1975fa9e4066Sahrens 
197639c23413Seschrock 		/*
197739c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
197839c23413Seschrock 		 * indefinitely.
197939c23413Seschrock 		 */
198039c23413Seschrock 		(void) fflush(stdout);
198139c23413Seschrock 
1982fa9e4066Sahrens 		if (interval == 0)
1983fa9e4066Sahrens 			break;
1984fa9e4066Sahrens 
1985fa9e4066Sahrens 		if (count != 0 && --count == 0)
1986fa9e4066Sahrens 			break;
1987fa9e4066Sahrens 
1988fa9e4066Sahrens 		(void) sleep(interval);
1989fa9e4066Sahrens 	}
1990fa9e4066Sahrens 
1991fa9e4066Sahrens 	pool_list_free(list);
1992fa9e4066Sahrens 
1993fa9e4066Sahrens 	return (ret);
1994fa9e4066Sahrens }
1995fa9e4066Sahrens 
1996fa9e4066Sahrens typedef struct list_cbdata {
199799653d4eSeschrock 	boolean_t	cb_scripted;
199899653d4eSeschrock 	boolean_t	cb_first;
1999990b4856Slling 	zprop_list_t	*cb_proplist;
2000fa9e4066Sahrens } list_cbdata_t;
2001fa9e4066Sahrens 
2002fa9e4066Sahrens /*
2003fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
2004fa9e4066Sahrens  */
2005990b4856Slling static void
2006990b4856Slling print_header(zprop_list_t *pl)
2007fa9e4066Sahrens {
2008990b4856Slling 	const char *header;
2009990b4856Slling 	boolean_t first = B_TRUE;
2010990b4856Slling 	boolean_t right_justify;
2011fa9e4066Sahrens 
2012990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2013990b4856Slling 		if (pl->pl_prop == ZPROP_INVAL)
2014990b4856Slling 			continue;
2015990b4856Slling 
2016990b4856Slling 		if (!first)
2017fa9e4066Sahrens 			(void) printf("  ");
2018fa9e4066Sahrens 		else
2019990b4856Slling 			first = B_FALSE;
2020fa9e4066Sahrens 
2021990b4856Slling 		header = zpool_prop_column_name(pl->pl_prop);
2022990b4856Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
2023990b4856Slling 
2024990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
2025990b4856Slling 			(void) printf("%s", header);
2026990b4856Slling 		else if (right_justify)
2027990b4856Slling 			(void) printf("%*s", pl->pl_width, header);
2028990b4856Slling 		else
2029990b4856Slling 			(void) printf("%-*s", pl->pl_width, header);
2030fa9e4066Sahrens 	}
2031fa9e4066Sahrens 
2032fa9e4066Sahrens 	(void) printf("\n");
2033fa9e4066Sahrens }
2034fa9e4066Sahrens 
2035990b4856Slling /*
2036990b4856Slling  * Given a pool and a list of properties, print out all the properties according
2037990b4856Slling  * to the described layout.
2038990b4856Slling  */
2039990b4856Slling static void
2040990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
2041990b4856Slling {
2042990b4856Slling 	boolean_t first = B_TRUE;
2043990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
2044990b4856Slling 	char *propstr;
2045990b4856Slling 	boolean_t right_justify;
2046990b4856Slling 	int width;
2047990b4856Slling 
2048990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
2049990b4856Slling 		if (!first) {
2050990b4856Slling 			if (scripted)
2051990b4856Slling 				(void) printf("\t");
2052990b4856Slling 			else
2053990b4856Slling 				(void) printf("  ");
2054990b4856Slling 		} else {
2055990b4856Slling 			first = B_FALSE;
2056990b4856Slling 		}
2057990b4856Slling 
2058990b4856Slling 		right_justify = B_FALSE;
2059990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
2060990b4856Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
2061990b4856Slling 			    sizeof (property), NULL) != 0)
2062990b4856Slling 				propstr = "-";
2063990b4856Slling 			else
2064990b4856Slling 				propstr = property;
2065990b4856Slling 
2066990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
2067990b4856Slling 		} else {
2068990b4856Slling 			propstr = "-";
2069990b4856Slling 		}
2070990b4856Slling 
2071990b4856Slling 		width = pl->pl_width;
2072990b4856Slling 
2073990b4856Slling 		/*
2074990b4856Slling 		 * If this is being called in scripted mode, or if this is the
2075990b4856Slling 		 * last column and it is left-justified, don't include a width
2076990b4856Slling 		 * format specifier.
2077990b4856Slling 		 */
2078990b4856Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
2079990b4856Slling 			(void) printf("%s", propstr);
2080990b4856Slling 		else if (right_justify)
2081990b4856Slling 			(void) printf("%*s", width, propstr);
2082990b4856Slling 		else
2083990b4856Slling 			(void) printf("%-*s", width, propstr);
2084990b4856Slling 	}
2085990b4856Slling 
2086990b4856Slling 	(void) printf("\n");
2087990b4856Slling }
2088990b4856Slling 
2089990b4856Slling /*
2090990b4856Slling  * Generic callback function to list a pool.
2091990b4856Slling  */
2092fa9e4066Sahrens int
2093fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2094fa9e4066Sahrens {
2095fa9e4066Sahrens 	list_cbdata_t *cbp = data;
2096fa9e4066Sahrens 
2097fa9e4066Sahrens 	if (cbp->cb_first) {
2098fa9e4066Sahrens 		if (!cbp->cb_scripted)
2099990b4856Slling 			print_header(cbp->cb_proplist);
210099653d4eSeschrock 		cbp->cb_first = B_FALSE;
2101fa9e4066Sahrens 	}
2102fa9e4066Sahrens 
2103990b4856Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2104fa9e4066Sahrens 
2105fa9e4066Sahrens 	return (0);
2106fa9e4066Sahrens }
2107fa9e4066Sahrens 
2108fa9e4066Sahrens /*
2109990b4856Slling  * zpool list [-H] [-o prop[,prop]*] [pool] ...
2110fa9e4066Sahrens  *
2111990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2112990b4856Slling  *		by a single tab.
2113990b4856Slling  *	-o	List of properties to display.  Defaults to
2114990b4856Slling  *		"name,size,used,available,capacity,health,altroot"
2115fa9e4066Sahrens  *
2116fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2117fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2118fa9e4066Sahrens  */
2119fa9e4066Sahrens int
2120fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2121fa9e4066Sahrens {
2122fa9e4066Sahrens 	int c;
2123fa9e4066Sahrens 	int ret;
2124fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2125990b4856Slling 	static char default_props[] =
2126990b4856Slling 	    "name,size,used,available,capacity,health,altroot";
2127990b4856Slling 	char *props = default_props;
2128fa9e4066Sahrens 
2129fa9e4066Sahrens 	/* check options */
2130fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2131fa9e4066Sahrens 		switch (c) {
2132fa9e4066Sahrens 		case 'H':
213399653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2134fa9e4066Sahrens 			break;
2135fa9e4066Sahrens 		case 'o':
2136990b4856Slling 			props = optarg;
2137fa9e4066Sahrens 			break;
2138fa9e4066Sahrens 		case ':':
2139fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2140fa9e4066Sahrens 			    "'%c' option\n"), optopt);
214199653d4eSeschrock 			usage(B_FALSE);
2142fa9e4066Sahrens 			break;
2143fa9e4066Sahrens 		case '?':
2144fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2145fa9e4066Sahrens 			    optopt);
214699653d4eSeschrock 			usage(B_FALSE);
2147fa9e4066Sahrens 		}
2148fa9e4066Sahrens 	}
2149fa9e4066Sahrens 
2150fa9e4066Sahrens 	argc -= optind;
2151fa9e4066Sahrens 	argv += optind;
2152fa9e4066Sahrens 
2153990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
215499653d4eSeschrock 		usage(B_FALSE);
2155fa9e4066Sahrens 
215699653d4eSeschrock 	cb.cb_first = B_TRUE;
2157fa9e4066Sahrens 
2158990b4856Slling 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2159990b4856Slling 	    list_callback, &cb);
2160990b4856Slling 
2161990b4856Slling 	zprop_free_list(cb.cb_proplist);
2162fa9e4066Sahrens 
2163fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2164fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2165fa9e4066Sahrens 		return (0);
2166fa9e4066Sahrens 	}
2167fa9e4066Sahrens 
2168fa9e4066Sahrens 	return (ret);
2169fa9e4066Sahrens }
2170fa9e4066Sahrens 
2171fa9e4066Sahrens static nvlist_t *
2172fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2173fa9e4066Sahrens {
2174fa9e4066Sahrens 	nvlist_t **child;
2175fa9e4066Sahrens 	uint_t c, children;
2176fa9e4066Sahrens 	nvlist_t *match;
2177fa9e4066Sahrens 	char *path;
2178fa9e4066Sahrens 
2179fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2180fa9e4066Sahrens 	    &child, &children) != 0) {
2181fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2182fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2183fa9e4066Sahrens 			name += 9;
2184fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2185fa9e4066Sahrens 			path += 9;
2186fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2187fa9e4066Sahrens 			return (nv);
2188fa9e4066Sahrens 		return (NULL);
2189fa9e4066Sahrens 	}
2190fa9e4066Sahrens 
2191fa9e4066Sahrens 	for (c = 0; c < children; c++)
2192fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2193fa9e4066Sahrens 			return (match);
2194fa9e4066Sahrens 
2195fa9e4066Sahrens 	return (NULL);
2196fa9e4066Sahrens }
2197fa9e4066Sahrens 
2198fa9e4066Sahrens static int
2199fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2200fa9e4066Sahrens {
220199653d4eSeschrock 	boolean_t force = B_FALSE;
2202fa9e4066Sahrens 	int c;
2203fa9e4066Sahrens 	nvlist_t *nvroot;
2204fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2205fa9e4066Sahrens 	zpool_handle_t *zhp;
220699653d4eSeschrock 	int ret;
2207fa9e4066Sahrens 
2208fa9e4066Sahrens 	/* check options */
2209fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2210fa9e4066Sahrens 		switch (c) {
2211fa9e4066Sahrens 		case 'f':
221299653d4eSeschrock 			force = B_TRUE;
2213fa9e4066Sahrens 			break;
2214fa9e4066Sahrens 		case '?':
2215fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2216fa9e4066Sahrens 			    optopt);
221799653d4eSeschrock 			usage(B_FALSE);
2218fa9e4066Sahrens 		}
2219fa9e4066Sahrens 	}
2220fa9e4066Sahrens 
2221fa9e4066Sahrens 	argc -= optind;
2222fa9e4066Sahrens 	argv += optind;
2223fa9e4066Sahrens 
2224fa9e4066Sahrens 	/* get pool name and check number of arguments */
2225fa9e4066Sahrens 	if (argc < 1) {
2226fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
222799653d4eSeschrock 		usage(B_FALSE);
2228fa9e4066Sahrens 	}
2229fa9e4066Sahrens 
2230fa9e4066Sahrens 	poolname = argv[0];
2231fa9e4066Sahrens 
2232fa9e4066Sahrens 	if (argc < 2) {
2233fa9e4066Sahrens 		(void) fprintf(stderr,
2234fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
223599653d4eSeschrock 		usage(B_FALSE);
2236fa9e4066Sahrens 	}
2237fa9e4066Sahrens 
2238fa9e4066Sahrens 	old_disk = argv[1];
2239fa9e4066Sahrens 
2240fa9e4066Sahrens 	if (argc < 3) {
2241fa9e4066Sahrens 		if (!replacing) {
2242fa9e4066Sahrens 			(void) fprintf(stderr,
2243fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
224499653d4eSeschrock 			usage(B_FALSE);
2245fa9e4066Sahrens 		}
2246fa9e4066Sahrens 		new_disk = old_disk;
2247fa9e4066Sahrens 		argc -= 1;
2248fa9e4066Sahrens 		argv += 1;
2249fa9e4066Sahrens 	} else {
2250fa9e4066Sahrens 		new_disk = argv[2];
2251fa9e4066Sahrens 		argc -= 2;
2252fa9e4066Sahrens 		argv += 2;
2253fa9e4066Sahrens 	}
2254fa9e4066Sahrens 
2255fa9e4066Sahrens 	if (argc > 1) {
2256fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
225799653d4eSeschrock 		usage(B_FALSE);
2258fa9e4066Sahrens 	}
2259fa9e4066Sahrens 
226099653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2261fa9e4066Sahrens 		return (1);
2262fa9e4066Sahrens 
22638488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2264fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2265fa9e4066Sahrens 		    poolname);
2266fa9e4066Sahrens 		zpool_close(zhp);
2267fa9e4066Sahrens 		return (1);
2268fa9e4066Sahrens 	}
2269fa9e4066Sahrens 
22708488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv);
2271fa9e4066Sahrens 	if (nvroot == NULL) {
2272fa9e4066Sahrens 		zpool_close(zhp);
2273fa9e4066Sahrens 		return (1);
2274fa9e4066Sahrens 	}
2275fa9e4066Sahrens 
227699653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
227799653d4eSeschrock 
227899653d4eSeschrock 	nvlist_free(nvroot);
227999653d4eSeschrock 	zpool_close(zhp);
228099653d4eSeschrock 
228199653d4eSeschrock 	return (ret);
2282fa9e4066Sahrens }
2283fa9e4066Sahrens 
2284fa9e4066Sahrens /*
2285fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2286fa9e4066Sahrens  *
2287fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2288fa9e4066Sahrens  *
2289fa9e4066Sahrens  * Replace <device> with <new_device>.
2290fa9e4066Sahrens  */
2291fa9e4066Sahrens /* ARGSUSED */
2292fa9e4066Sahrens int
2293fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2294fa9e4066Sahrens {
2295fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2296fa9e4066Sahrens }
2297fa9e4066Sahrens 
2298fa9e4066Sahrens /*
2299fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2300fa9e4066Sahrens  *
2301fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2302fa9e4066Sahrens  *
2303fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2304fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2305fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2306fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2307fa9e4066Sahrens  */
2308fa9e4066Sahrens int
2309fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2310fa9e4066Sahrens {
2311fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2312fa9e4066Sahrens }
2313fa9e4066Sahrens 
2314fa9e4066Sahrens /*
2315fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2316fa9e4066Sahrens  *
2317fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2318fa9e4066Sahrens  *		(not supported yet)
2319fa9e4066Sahrens  *
2320fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2321fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2322fa9e4066Sahrens  * has the only valid copy of some data.
2323fa9e4066Sahrens  */
2324fa9e4066Sahrens /* ARGSUSED */
2325fa9e4066Sahrens int
2326fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2327fa9e4066Sahrens {
2328fa9e4066Sahrens 	int c;
2329fa9e4066Sahrens 	char *poolname, *path;
2330fa9e4066Sahrens 	zpool_handle_t *zhp;
233199653d4eSeschrock 	int ret;
2332fa9e4066Sahrens 
2333fa9e4066Sahrens 	/* check options */
2334fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2335fa9e4066Sahrens 		switch (c) {
2336fa9e4066Sahrens 		case 'f':
2337fa9e4066Sahrens 		case '?':
2338fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2339fa9e4066Sahrens 			    optopt);
234099653d4eSeschrock 			usage(B_FALSE);
2341fa9e4066Sahrens 		}
2342fa9e4066Sahrens 	}
2343fa9e4066Sahrens 
2344fa9e4066Sahrens 	argc -= optind;
2345fa9e4066Sahrens 	argv += optind;
2346fa9e4066Sahrens 
2347fa9e4066Sahrens 	/* get pool name and check number of arguments */
2348fa9e4066Sahrens 	if (argc < 1) {
2349fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
235099653d4eSeschrock 		usage(B_FALSE);
2351fa9e4066Sahrens 	}
2352fa9e4066Sahrens 
2353fa9e4066Sahrens 	if (argc < 2) {
2354fa9e4066Sahrens 		(void) fprintf(stderr,
2355fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
235699653d4eSeschrock 		usage(B_FALSE);
2357fa9e4066Sahrens 	}
2358fa9e4066Sahrens 
2359fa9e4066Sahrens 	poolname = argv[0];
2360fa9e4066Sahrens 	path = argv[1];
2361fa9e4066Sahrens 
236299653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2363fa9e4066Sahrens 		return (1);
2364fa9e4066Sahrens 
236599653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
236699653d4eSeschrock 
236799653d4eSeschrock 	zpool_close(zhp);
236899653d4eSeschrock 
236999653d4eSeschrock 	return (ret);
2370fa9e4066Sahrens }
2371fa9e4066Sahrens 
2372fa9e4066Sahrens /*
2373441d80aaSlling  * zpool online <pool> <device> ...
2374fa9e4066Sahrens  */
2375fa9e4066Sahrens int
2376fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2377fa9e4066Sahrens {
2378fa9e4066Sahrens 	int c, i;
2379fa9e4066Sahrens 	char *poolname;
2380fa9e4066Sahrens 	zpool_handle_t *zhp;
2381fa9e4066Sahrens 	int ret = 0;
23823d7072f8Seschrock 	vdev_state_t newstate;
2383fa9e4066Sahrens 
2384fa9e4066Sahrens 	/* check options */
2385fa9e4066Sahrens 	while ((c = getopt(argc, argv, "t")) != -1) {
2386fa9e4066Sahrens 		switch (c) {
2387fa9e4066Sahrens 		case 't':
2388fa9e4066Sahrens 		case '?':
2389fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2390fa9e4066Sahrens 			    optopt);
239199653d4eSeschrock 			usage(B_FALSE);
2392fa9e4066Sahrens 		}
2393fa9e4066Sahrens 	}
2394fa9e4066Sahrens 
2395fa9e4066Sahrens 	argc -= optind;
2396fa9e4066Sahrens 	argv += optind;
2397fa9e4066Sahrens 
2398fa9e4066Sahrens 	/* get pool name and check number of arguments */
2399fa9e4066Sahrens 	if (argc < 1) {
2400fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
240199653d4eSeschrock 		usage(B_FALSE);
2402fa9e4066Sahrens 	}
2403fa9e4066Sahrens 	if (argc < 2) {
2404fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
240599653d4eSeschrock 		usage(B_FALSE);
2406fa9e4066Sahrens 	}
2407fa9e4066Sahrens 
2408fa9e4066Sahrens 	poolname = argv[0];
2409fa9e4066Sahrens 
241099653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2411fa9e4066Sahrens 		return (1);
2412fa9e4066Sahrens 
24133d7072f8Seschrock 	for (i = 1; i < argc; i++) {
24143d7072f8Seschrock 		if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
24153d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
24163d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
24173d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
2418fa9e4066Sahrens 				    argv[i]);
24193d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
24203d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24213d7072f8Seschrock 					    "clear' to restore a faulted "
24223d7072f8Seschrock 					    "device\n"));
2423fa9e4066Sahrens 				else
24243d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
24253d7072f8Seschrock 					    "replace' to replace devices "
24263d7072f8Seschrock 					    "that are no longer present\n"));
24273d7072f8Seschrock 			}
24283d7072f8Seschrock 		} else {
2429fa9e4066Sahrens 			ret = 1;
24303d7072f8Seschrock 		}
24313d7072f8Seschrock 	}
2432fa9e4066Sahrens 
243399653d4eSeschrock 	zpool_close(zhp);
243499653d4eSeschrock 
2435fa9e4066Sahrens 	return (ret);
2436fa9e4066Sahrens }
2437fa9e4066Sahrens 
2438fa9e4066Sahrens /*
2439441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2440fa9e4066Sahrens  *
2441fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2442fa9e4066Sahrens  *		so would appear to compromise pool availability.
2443fa9e4066Sahrens  *		(not supported yet)
2444fa9e4066Sahrens  *
2445fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2446fa9e4066Sahrens  *		state will not be persistent across reboots.
2447fa9e4066Sahrens  */
2448fa9e4066Sahrens /* ARGSUSED */
2449fa9e4066Sahrens int
2450fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2451fa9e4066Sahrens {
2452fa9e4066Sahrens 	int c, i;
2453fa9e4066Sahrens 	char *poolname;
2454fa9e4066Sahrens 	zpool_handle_t *zhp;
245599653d4eSeschrock 	int ret = 0;
245699653d4eSeschrock 	boolean_t istmp = B_FALSE;
2457fa9e4066Sahrens 
2458fa9e4066Sahrens 	/* check options */
2459fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2460fa9e4066Sahrens 		switch (c) {
2461fa9e4066Sahrens 		case 't':
246299653d4eSeschrock 			istmp = B_TRUE;
2463441d80aaSlling 			break;
2464441d80aaSlling 		case 'f':
2465fa9e4066Sahrens 		case '?':
2466fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2467fa9e4066Sahrens 			    optopt);
246899653d4eSeschrock 			usage(B_FALSE);
2469fa9e4066Sahrens 		}
2470fa9e4066Sahrens 	}
2471fa9e4066Sahrens 
2472fa9e4066Sahrens 	argc -= optind;
2473fa9e4066Sahrens 	argv += optind;
2474fa9e4066Sahrens 
2475fa9e4066Sahrens 	/* get pool name and check number of arguments */
2476fa9e4066Sahrens 	if (argc < 1) {
2477fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
247899653d4eSeschrock 		usage(B_FALSE);
2479fa9e4066Sahrens 	}
2480fa9e4066Sahrens 	if (argc < 2) {
2481fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
248299653d4eSeschrock 		usage(B_FALSE);
2483fa9e4066Sahrens 	}
2484fa9e4066Sahrens 
2485fa9e4066Sahrens 	poolname = argv[0];
2486fa9e4066Sahrens 
248799653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2488fa9e4066Sahrens 		return (1);
2489fa9e4066Sahrens 
24903d7072f8Seschrock 	for (i = 1; i < argc; i++) {
24913d7072f8Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2492fa9e4066Sahrens 			ret = 1;
24933d7072f8Seschrock 	}
2494fa9e4066Sahrens 
249599653d4eSeschrock 	zpool_close(zhp);
249699653d4eSeschrock 
2497fa9e4066Sahrens 	return (ret);
2498fa9e4066Sahrens }
2499fa9e4066Sahrens 
2500ea8dc4b6Seschrock /*
2501ea8dc4b6Seschrock  * zpool clear <pool> [device]
2502ea8dc4b6Seschrock  *
2503ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2504ea8dc4b6Seschrock  */
2505ea8dc4b6Seschrock int
2506ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2507ea8dc4b6Seschrock {
2508ea8dc4b6Seschrock 	int ret = 0;
2509ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2510ea8dc4b6Seschrock 	char *pool, *device;
2511ea8dc4b6Seschrock 
2512ea8dc4b6Seschrock 	if (argc < 2) {
2513ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
251499653d4eSeschrock 		usage(B_FALSE);
2515ea8dc4b6Seschrock 	}
2516ea8dc4b6Seschrock 
2517ea8dc4b6Seschrock 	if (argc > 3) {
2518ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
251999653d4eSeschrock 		usage(B_FALSE);
2520ea8dc4b6Seschrock 	}
2521ea8dc4b6Seschrock 
2522ea8dc4b6Seschrock 	pool = argv[1];
2523ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2524ea8dc4b6Seschrock 
252599653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, pool)) == NULL)
2526ea8dc4b6Seschrock 		return (1);
2527ea8dc4b6Seschrock 
2528ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2529ea8dc4b6Seschrock 		ret = 1;
2530ea8dc4b6Seschrock 
2531ea8dc4b6Seschrock 	zpool_close(zhp);
2532ea8dc4b6Seschrock 
2533ea8dc4b6Seschrock 	return (ret);
2534ea8dc4b6Seschrock }
2535ea8dc4b6Seschrock 
2536fa9e4066Sahrens typedef struct scrub_cbdata {
2537fa9e4066Sahrens 	int	cb_type;
253806eeb2adSek110237 	int	cb_argc;
253906eeb2adSek110237 	char	**cb_argv;
2540fa9e4066Sahrens } scrub_cbdata_t;
2541fa9e4066Sahrens 
2542fa9e4066Sahrens int
2543fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2544fa9e4066Sahrens {
2545fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
254606eeb2adSek110237 	int err;
2547fa9e4066Sahrens 
2548ea8dc4b6Seschrock 	/*
2549ea8dc4b6Seschrock 	 * Ignore faulted pools.
2550ea8dc4b6Seschrock 	 */
2551ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2552ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2553ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2554ea8dc4b6Seschrock 		return (1);
2555ea8dc4b6Seschrock 	}
2556ea8dc4b6Seschrock 
255706eeb2adSek110237 	err = zpool_scrub(zhp, cb->cb_type);
255806eeb2adSek110237 
255906eeb2adSek110237 	return (err != 0);
2560fa9e4066Sahrens }
2561fa9e4066Sahrens 
2562fa9e4066Sahrens /*
2563fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2564fa9e4066Sahrens  *
2565fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2566fa9e4066Sahrens  */
2567fa9e4066Sahrens int
2568fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2569fa9e4066Sahrens {
2570fa9e4066Sahrens 	int c;
2571fa9e4066Sahrens 	scrub_cbdata_t cb;
2572fa9e4066Sahrens 
2573fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2574fa9e4066Sahrens 
2575fa9e4066Sahrens 	/* check options */
2576fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2577fa9e4066Sahrens 		switch (c) {
2578fa9e4066Sahrens 		case 's':
2579fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2580fa9e4066Sahrens 			break;
2581fa9e4066Sahrens 		case '?':
2582fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2583fa9e4066Sahrens 			    optopt);
258499653d4eSeschrock 			usage(B_FALSE);
2585fa9e4066Sahrens 		}
2586fa9e4066Sahrens 	}
2587fa9e4066Sahrens 
258806eeb2adSek110237 	cb.cb_argc = argc;
258906eeb2adSek110237 	cb.cb_argv = argv;
2590fa9e4066Sahrens 	argc -= optind;
2591fa9e4066Sahrens 	argv += optind;
2592fa9e4066Sahrens 
2593fa9e4066Sahrens 	if (argc < 1) {
2594fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
259599653d4eSeschrock 		usage(B_FALSE);
2596fa9e4066Sahrens 	}
2597fa9e4066Sahrens 
2598b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2599fa9e4066Sahrens }
2600fa9e4066Sahrens 
2601fa9e4066Sahrens typedef struct status_cbdata {
2602fa9e4066Sahrens 	int		cb_count;
2603e9dbad6fSeschrock 	boolean_t	cb_allpools;
260499653d4eSeschrock 	boolean_t	cb_verbose;
260599653d4eSeschrock 	boolean_t	cb_explain;
260699653d4eSeschrock 	boolean_t	cb_first;
2607fa9e4066Sahrens } status_cbdata_t;
2608fa9e4066Sahrens 
2609fa9e4066Sahrens /*
2610fa9e4066Sahrens  * Print out detailed scrub status.
2611fa9e4066Sahrens  */
2612fa9e4066Sahrens void
2613fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2614fa9e4066Sahrens {
2615fa9e4066Sahrens 	vdev_stat_t *vs;
2616fa9e4066Sahrens 	uint_t vsc;
2617fa9e4066Sahrens 	time_t start, end, now;
2618fa9e4066Sahrens 	double fraction_done;
261918ce54dfSek110237 	uint64_t examined, total, minutes_left, minutes_taken;
2620fa9e4066Sahrens 	char *scrub_type;
2621fa9e4066Sahrens 
2622fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2623fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2624fa9e4066Sahrens 
2625fa9e4066Sahrens 	/*
2626fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2627fa9e4066Sahrens 	 */
2628fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2629fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2630fa9e4066Sahrens 		return;
2631fa9e4066Sahrens 	}
2632fa9e4066Sahrens 
2633fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2634fa9e4066Sahrens 	    "resilver" : "scrub";
2635fa9e4066Sahrens 
2636fa9e4066Sahrens 	start = vs->vs_scrub_start;
2637fa9e4066Sahrens 	end = vs->vs_scrub_end;
2638fa9e4066Sahrens 	now = time(NULL);
2639fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2640fa9e4066Sahrens 	total = vs->vs_alloc;
2641fa9e4066Sahrens 
2642fa9e4066Sahrens 	if (end != 0) {
264318ce54dfSek110237 		minutes_taken = (uint64_t)((end - start) / 60);
264418ce54dfSek110237 
264518ce54dfSek110237 		(void) printf(gettext("%s %s after %lluh%um with %llu errors "
264618ce54dfSek110237 		    "on %s"),
2647fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
264818ce54dfSek110237 		    (u_longlong_t)(minutes_taken / 60),
264918ce54dfSek110237 		    (uint_t)(minutes_taken % 60),
2650fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2651fa9e4066Sahrens 		return;
2652fa9e4066Sahrens 	}
2653fa9e4066Sahrens 
2654fa9e4066Sahrens 	if (examined == 0)
2655fa9e4066Sahrens 		examined = 1;
2656fa9e4066Sahrens 	if (examined > total)
2657fa9e4066Sahrens 		total = examined;
2658fa9e4066Sahrens 
2659fa9e4066Sahrens 	fraction_done = (double)examined / total;
2660fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2661fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
266218ce54dfSek110237 	minutes_taken = (uint64_t)((now - start) / 60);
2663fa9e4066Sahrens 
266418ce54dfSek110237 	(void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, "
266518ce54dfSek110237 	    "%lluh%um to go\n"),
266618ce54dfSek110237 	    scrub_type, (u_longlong_t)(minutes_taken / 60),
266718ce54dfSek110237 	    (uint_t)(minutes_taken % 60), 100 * fraction_done,
2668fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2669fa9e4066Sahrens }
2670fa9e4066Sahrens 
267199653d4eSeschrock typedef struct spare_cbdata {
267299653d4eSeschrock 	uint64_t	cb_guid;
267399653d4eSeschrock 	zpool_handle_t	*cb_zhp;
267499653d4eSeschrock } spare_cbdata_t;
267599653d4eSeschrock 
267699653d4eSeschrock static boolean_t
267799653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search)
267899653d4eSeschrock {
267999653d4eSeschrock 	uint64_t guid;
268099653d4eSeschrock 	nvlist_t **child;
268199653d4eSeschrock 	uint_t c, children;
268299653d4eSeschrock 
268399653d4eSeschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
268499653d4eSeschrock 	    search == guid)
268599653d4eSeschrock 		return (B_TRUE);
268699653d4eSeschrock 
268799653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
268899653d4eSeschrock 	    &child, &children) == 0) {
268999653d4eSeschrock 		for (c = 0; c < children; c++)
269099653d4eSeschrock 			if (find_vdev(child[c], search))
269199653d4eSeschrock 				return (B_TRUE);
269299653d4eSeschrock 	}
269399653d4eSeschrock 
269499653d4eSeschrock 	return (B_FALSE);
269599653d4eSeschrock }
269699653d4eSeschrock 
269799653d4eSeschrock static int
269899653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data)
269999653d4eSeschrock {
270099653d4eSeschrock 	spare_cbdata_t *cbp = data;
270199653d4eSeschrock 	nvlist_t *config, *nvroot;
270299653d4eSeschrock 
270399653d4eSeschrock 	config = zpool_get_config(zhp, NULL);
270499653d4eSeschrock 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
270599653d4eSeschrock 	    &nvroot) == 0);
270699653d4eSeschrock 
270799653d4eSeschrock 	if (find_vdev(nvroot, cbp->cb_guid)) {
270899653d4eSeschrock 		cbp->cb_zhp = zhp;
270999653d4eSeschrock 		return (1);
271099653d4eSeschrock 	}
271199653d4eSeschrock 
271299653d4eSeschrock 	zpool_close(zhp);
271399653d4eSeschrock 	return (0);
271499653d4eSeschrock }
271599653d4eSeschrock 
2716fa9e4066Sahrens /*
2717fa9e4066Sahrens  * Print out configuration state as requested by status_callback.
2718fa9e4066Sahrens  */
2719fa9e4066Sahrens void
2720c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
27218654d025Sperrin     int namewidth, int depth, boolean_t isspare, boolean_t print_logs)
2722fa9e4066Sahrens {
2723fa9e4066Sahrens 	nvlist_t **child;
2724fa9e4066Sahrens 	uint_t c, children;
2725fa9e4066Sahrens 	vdev_stat_t *vs;
2726ea8dc4b6Seschrock 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
2727afefbcddSeschrock 	char *vname;
2728ea8dc4b6Seschrock 	uint64_t notpresent;
272999653d4eSeschrock 	spare_cbdata_t cb;
2730990b4856Slling 	char *state;
2731fa9e4066Sahrens 
2732fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2733fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2734fa9e4066Sahrens 
2735fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2736fa9e4066Sahrens 	    &child, &children) != 0)
2737fa9e4066Sahrens 		children = 0;
2738fa9e4066Sahrens 
2739990b4856Slling 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
274099653d4eSeschrock 	if (isspare) {
274199653d4eSeschrock 		/*
274299653d4eSeschrock 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
274399653d4eSeschrock 		 * online drives.
274499653d4eSeschrock 		 */
274599653d4eSeschrock 		if (vs->vs_aux == VDEV_AUX_SPARED)
274699653d4eSeschrock 			state = "INUSE";
274799653d4eSeschrock 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
274899653d4eSeschrock 			state = "AVAIL";
274999653d4eSeschrock 	}
2750fa9e4066Sahrens 
275199653d4eSeschrock 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
275299653d4eSeschrock 	    name, state);
275399653d4eSeschrock 
275499653d4eSeschrock 	if (!isspare) {
2755fa9e4066Sahrens 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
2756fa9e4066Sahrens 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
2757fa9e4066Sahrens 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
2758fa9e4066Sahrens 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
275999653d4eSeschrock 	}
2760fa9e4066Sahrens 
2761ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2762ea8dc4b6Seschrock 	    &notpresent) == 0) {
2763ea8dc4b6Seschrock 		char *path;
2764ea8dc4b6Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
27650917b783Seschrock 		(void) printf("  was %s", path);
2766ea8dc4b6Seschrock 	} else if (vs->vs_aux != 0) {
2767fa9e4066Sahrens 		(void) printf("  ");
2768fa9e4066Sahrens 
2769fa9e4066Sahrens 		switch (vs->vs_aux) {
2770fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2771fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2772fa9e4066Sahrens 			break;
2773fa9e4066Sahrens 
2774fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2775fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2776fa9e4066Sahrens 			break;
2777fa9e4066Sahrens 
2778fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2779fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2780fa9e4066Sahrens 			break;
2781fa9e4066Sahrens 
2782eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
2783eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
2784eaca9bbdSeschrock 			break;
2785eaca9bbdSeschrock 
278699653d4eSeschrock 		case VDEV_AUX_SPARED:
278799653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
278899653d4eSeschrock 			    &cb.cb_guid) == 0);
278999653d4eSeschrock 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
279099653d4eSeschrock 				if (strcmp(zpool_get_name(cb.cb_zhp),
279199653d4eSeschrock 				    zpool_get_name(zhp)) == 0)
279299653d4eSeschrock 					(void) printf(gettext("currently in "
279399653d4eSeschrock 					    "use"));
279499653d4eSeschrock 				else
279599653d4eSeschrock 					(void) printf(gettext("in use by "
279699653d4eSeschrock 					    "pool '%s'"),
279799653d4eSeschrock 					    zpool_get_name(cb.cb_zhp));
279899653d4eSeschrock 				zpool_close(cb.cb_zhp);
279999653d4eSeschrock 			} else {
280099653d4eSeschrock 				(void) printf(gettext("currently in use"));
280199653d4eSeschrock 			}
280299653d4eSeschrock 			break;
280399653d4eSeschrock 
28043d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
28053d7072f8Seschrock 			(void) printf(gettext("too many errors"));
28063d7072f8Seschrock 			break;
28073d7072f8Seschrock 
280832b87932Sek110237 		case VDEV_AUX_IO_FAILURE:
280932b87932Sek110237 			(void) printf(gettext("experienced I/O failures"));
281032b87932Sek110237 			break;
281132b87932Sek110237 
2812fa9e4066Sahrens 		default:
2813fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2814fa9e4066Sahrens 			break;
2815fa9e4066Sahrens 		}
2816fa9e4066Sahrens 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2817fa9e4066Sahrens 		/*
2818fa9e4066Sahrens 		 * Report bytes resilvered/repaired on leaf devices.
2819fa9e4066Sahrens 		 */
2820fa9e4066Sahrens 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2821fa9e4066Sahrens 		(void) printf(gettext("  %s %s"), repaired,
2822fa9e4066Sahrens 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2823fa9e4066Sahrens 		    "resilvered" : "repaired");
2824fa9e4066Sahrens 	}
2825fa9e4066Sahrens 
2826fa9e4066Sahrens 	(void) printf("\n");
2827fa9e4066Sahrens 
2828afefbcddSeschrock 	for (c = 0; c < children; c++) {
28298654d025Sperrin 		uint64_t is_log = B_FALSE;
28308654d025Sperrin 
28318654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
28328654d025Sperrin 		    &is_log);
28338654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
28348654d025Sperrin 			continue;
283599653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
2836c67d9675Seschrock 		print_status_config(zhp, vname, child[c],
28378654d025Sperrin 		    namewidth, depth + 2, isspare, B_FALSE);
2838afefbcddSeschrock 		free(vname);
2839afefbcddSeschrock 	}
2840fa9e4066Sahrens }
2841fa9e4066Sahrens 
2842ea8dc4b6Seschrock static void
2843ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
2844ea8dc4b6Seschrock {
284575519f38Sek110237 	nvlist_t *nverrlist = NULL;
284655434c77Sek110237 	nvpair_t *elem;
284755434c77Sek110237 	char *pathname;
284855434c77Sek110237 	size_t len = MAXPATHLEN * 2;
2849ea8dc4b6Seschrock 
285055434c77Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2851ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
2852ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
2853ea8dc4b6Seschrock 		return;
2854ea8dc4b6Seschrock 	}
2855ea8dc4b6Seschrock 
285655434c77Sek110237 	(void) printf("errors: Permanent errors have been "
285755434c77Sek110237 	    "detected in the following files:\n\n");
2858ea8dc4b6Seschrock 
285955434c77Sek110237 	pathname = safe_malloc(len);
286055434c77Sek110237 	elem = NULL;
286155434c77Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
286255434c77Sek110237 		nvlist_t *nv;
286355434c77Sek110237 		uint64_t dsobj, obj;
2864ea8dc4b6Seschrock 
286555434c77Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
286655434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
286755434c77Sek110237 		    &dsobj) == 0);
286855434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
286955434c77Sek110237 		    &obj) == 0);
287055434c77Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
287155434c77Sek110237 		(void) printf("%7s %s\n", "", pathname);
2872ea8dc4b6Seschrock 	}
287355434c77Sek110237 	free(pathname);
287455434c77Sek110237 	nvlist_free(nverrlist);
2875ea8dc4b6Seschrock }
2876ea8dc4b6Seschrock 
287799653d4eSeschrock static void
287899653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
287999653d4eSeschrock     int namewidth)
288099653d4eSeschrock {
288199653d4eSeschrock 	uint_t i;
288299653d4eSeschrock 	char *name;
288399653d4eSeschrock 
288499653d4eSeschrock 	if (nspares == 0)
288599653d4eSeschrock 		return;
288699653d4eSeschrock 
288799653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
288899653d4eSeschrock 
288999653d4eSeschrock 	for (i = 0; i < nspares; i++) {
289099653d4eSeschrock 		name = zpool_vdev_name(g_zfs, zhp, spares[i]);
289199653d4eSeschrock 		print_status_config(zhp, name, spares[i],
28928654d025Sperrin 		    namewidth, 2, B_TRUE, B_FALSE);
289399653d4eSeschrock 		free(name);
289499653d4eSeschrock 	}
289599653d4eSeschrock }
289699653d4eSeschrock 
2897fa94a07fSbrendan static void
2898fa94a07fSbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
2899fa94a07fSbrendan     int namewidth)
2900fa94a07fSbrendan {
2901fa94a07fSbrendan 	uint_t i;
2902fa94a07fSbrendan 	char *name;
2903fa94a07fSbrendan 
2904fa94a07fSbrendan 	if (nl2cache == 0)
2905fa94a07fSbrendan 		return;
2906fa94a07fSbrendan 
2907fa94a07fSbrendan 	(void) printf(gettext("\tcache\n"));
2908fa94a07fSbrendan 
2909fa94a07fSbrendan 	for (i = 0; i < nl2cache; i++) {
2910fa94a07fSbrendan 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i]);
2911fa94a07fSbrendan 		print_status_config(zhp, name, l2cache[i],
2912fa94a07fSbrendan 		    namewidth, 2, B_FALSE, B_FALSE);
2913fa94a07fSbrendan 		free(name);
2914fa94a07fSbrendan 	}
2915fa94a07fSbrendan }
2916fa94a07fSbrendan 
2917fa9e4066Sahrens /*
2918fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
2919fa9e4066Sahrens  *
2920fa9e4066Sahrens  *        pool: tank
2921fa9e4066Sahrens  *	status: DEGRADED
2922fa9e4066Sahrens  *	reason: One or more devices ...
2923fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
2924fa9e4066Sahrens  *	config:
2925fa9e4066Sahrens  *		mirror		DEGRADED
2926fa9e4066Sahrens  *                c1t0d0	OK
2927ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
2928fa9e4066Sahrens  *
2929fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
2930fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
2931fa9e4066Sahrens  */
2932fa9e4066Sahrens int
2933fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
2934fa9e4066Sahrens {
2935fa9e4066Sahrens 	status_cbdata_t *cbp = data;
2936fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2937fa9e4066Sahrens 	char *msgid;
2938fa9e4066Sahrens 	int reason;
293946657f8dSmmusante 	const char *health;
294046657f8dSmmusante 	uint_t c;
294146657f8dSmmusante 	vdev_stat_t *vs;
2942fa9e4066Sahrens 
2943088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
2944fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
2945fa9e4066Sahrens 
2946fa9e4066Sahrens 	cbp->cb_count++;
2947fa9e4066Sahrens 
2948fa9e4066Sahrens 	/*
2949fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
2950fa9e4066Sahrens 	 * problems.
2951fa9e4066Sahrens 	 */
2952e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
2953e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
2954e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
2955e9dbad6fSeschrock 			    zpool_get_name(zhp));
2956e9dbad6fSeschrock 			if (cbp->cb_first)
2957e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
2958e9dbad6fSeschrock 		}
2959fa9e4066Sahrens 		return (0);
2960e9dbad6fSeschrock 	}
2961fa9e4066Sahrens 
2962fa9e4066Sahrens 	if (cbp->cb_first)
296399653d4eSeschrock 		cbp->cb_first = B_FALSE;
2964fa9e4066Sahrens 	else
2965fa9e4066Sahrens 		(void) printf("\n");
2966fa9e4066Sahrens 
296746657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
296846657f8dSmmusante 	    &nvroot) == 0);
296946657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
297046657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
2971990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
2972fa9e4066Sahrens 
2973fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
2974fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
2975fa9e4066Sahrens 
2976fa9e4066Sahrens 	switch (reason) {
2977fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
2978fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2979fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
2980fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
2981fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2982fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2983fa9e4066Sahrens 		break;
2984fa9e4066Sahrens 
2985fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
2986fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2987fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
2988fa9e4066Sahrens 		    "pool to continue functioning.\n"));
2989fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2990fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2991fa9e4066Sahrens 		break;
2992fa9e4066Sahrens 
2993fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
2994fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2995fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
2996fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
2997fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
2998fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
2999fa9e4066Sahrens 		    "'zpool replace'.\n"));
3000fa9e4066Sahrens 		break;
3001fa9e4066Sahrens 
3002fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3003fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
3004b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
3005fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
3006fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
3007fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
3008fa9e4066Sahrens 		    "from a backup source.\n"));
3009fa9e4066Sahrens 		break;
3010fa9e4066Sahrens 
3011fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
3012fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3013fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
3014fa9e4066Sahrens 		    "made to correct the error.  Applications are "
3015fa9e4066Sahrens 		    "unaffected.\n"));
3016fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
3017fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
3018ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
3019fa9e4066Sahrens 		    "replace'.\n"));
3020fa9e4066Sahrens 		break;
3021fa9e4066Sahrens 
3022fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
3023fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
3024d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
3025fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
3026fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
3027fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
3028fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
3029fa9e4066Sahrens 		    "replace'.\n"));
3030fa9e4066Sahrens 		break;
3031fa9e4066Sahrens 
3032fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
3033fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
3034fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3035fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
3036fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3037fa9e4066Sahrens 		    "complete.\n"));
3038fa9e4066Sahrens 		break;
3039fa9e4066Sahrens 
3040ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
3041ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
3042ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
3043ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
3044ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
3045ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
3046ea8dc4b6Seschrock 		    "backup.\n"));
3047ea8dc4b6Seschrock 		break;
3048ea8dc4b6Seschrock 
3049ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
3050ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
3051ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
3052ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
3053ea8dc4b6Seschrock 		    "from a backup source.\n"));
3054ea8dc4b6Seschrock 		break;
3055ea8dc4b6Seschrock 
3056eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
3057eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
3058eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
3059eaca9bbdSeschrock 		    "some features are unavailable.\n"));
3060eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3061eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3062eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
3063eaca9bbdSeschrock 		break;
3064eaca9bbdSeschrock 
3065eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
3066eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
3067eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3068eaca9bbdSeschrock 		    "be accessed on this system.\n"));
3069eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
3070eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
3071eaca9bbdSeschrock 		    "backup.\n"));
3072eaca9bbdSeschrock 		break;
3073eaca9bbdSeschrock 
30743d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
30753d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
30763d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
30773d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
30783d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
30793d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
30803d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
30813d7072f8Seschrock 		break;
30823d7072f8Seschrock 
30833d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
30843d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
30853d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
30863d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
30873d7072f8Seschrock 		    "functioning.\n"));
30883d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
30893d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
30903d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
30913d7072f8Seschrock 		    "to be recovered.\n"));
30923d7072f8Seschrock 		break;
30933d7072f8Seschrock 
309432b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_WAIT:
309532b87932Sek110237 	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
309632b87932Sek110237 		(void) printf(gettext("status: One or more devices are "
309732b87932Sek110237 		    "faultd in response to IO failures.\n"));
309832b87932Sek110237 		(void) printf(gettext("action: Make sure the affected devices "
309932b87932Sek110237 		    "are connected, then run 'zpool clear'.\n"));
310032b87932Sek110237 		break;
310132b87932Sek110237 
3102fa9e4066Sahrens 	default:
3103fa9e4066Sahrens 		/*
3104fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
3105fa9e4066Sahrens 		 */
3106fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
3107fa9e4066Sahrens 	}
3108fa9e4066Sahrens 
3109fa9e4066Sahrens 	if (msgid != NULL)
3110fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3111fa9e4066Sahrens 		    msgid);
3112fa9e4066Sahrens 
3113fa9e4066Sahrens 	if (config != NULL) {
3114fa9e4066Sahrens 		int namewidth;
3115ea8dc4b6Seschrock 		uint64_t nerr;
3116fa94a07fSbrendan 		nvlist_t **spares, **l2cache;
3117fa94a07fSbrendan 		uint_t nspares, nl2cache;
3118fa9e4066Sahrens 
3119fa9e4066Sahrens 
3120fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
3121fa9e4066Sahrens 		print_scrub_status(nvroot);
3122fa9e4066Sahrens 
3123c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3124fa9e4066Sahrens 		if (namewidth < 10)
3125fa9e4066Sahrens 			namewidth = 10;
3126fa9e4066Sahrens 
3127fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
3128fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3129fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3130c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
31318654d025Sperrin 		    namewidth, 0, B_FALSE, B_FALSE);
31328654d025Sperrin 		if (num_logs(nvroot) > 0)
31338654d025Sperrin 			print_status_config(zhp, "logs", nvroot, namewidth, 0,
31348654d025Sperrin 			    B_FALSE, B_TRUE);
313599653d4eSeschrock 
3136fa94a07fSbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
3137fa94a07fSbrendan 		    &l2cache, &nl2cache) == 0)
3138fa94a07fSbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
3139fa94a07fSbrendan 
314099653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
314199653d4eSeschrock 		    &spares, &nspares) == 0)
314299653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
3143ea8dc4b6Seschrock 
3144ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3145ea8dc4b6Seschrock 		    &nerr) == 0) {
314655434c77Sek110237 			nvlist_t *nverrlist = NULL;
314755434c77Sek110237 
3148ea8dc4b6Seschrock 			/*
3149ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3150ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3151ea8dc4b6Seschrock 			 * uniquifying the results.
3152ea8dc4b6Seschrock 			 */
315375519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
315455434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
315555434c77Sek110237 				nvpair_t *elem;
315655434c77Sek110237 
315755434c77Sek110237 				elem = NULL;
315855434c77Sek110237 				nerr = 0;
315955434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
316055434c77Sek110237 				    elem)) != NULL) {
316155434c77Sek110237 					nerr++;
316255434c77Sek110237 				}
316355434c77Sek110237 			}
316455434c77Sek110237 			nvlist_free(nverrlist);
3165ea8dc4b6Seschrock 
3166ea8dc4b6Seschrock 			(void) printf("\n");
316799653d4eSeschrock 
3168ea8dc4b6Seschrock 			if (nerr == 0)
3169ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3170ea8dc4b6Seschrock 				    "errors\n"));
3171ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3172e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
31735ad82045Snd150628 				    "errors, use '-v' for a list\n"),
31745ad82045Snd150628 				    (u_longlong_t)nerr);
3175ea8dc4b6Seschrock 			else
3176ea8dc4b6Seschrock 				print_error_log(zhp);
3177ea8dc4b6Seschrock 		}
3178fa9e4066Sahrens 	} else {
3179fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3180fa9e4066Sahrens 		    "determined.\n"));
3181fa9e4066Sahrens 	}
3182fa9e4066Sahrens 
3183fa9e4066Sahrens 	return (0);
3184fa9e4066Sahrens }
3185fa9e4066Sahrens 
3186fa9e4066Sahrens /*
3187fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3188fa9e4066Sahrens  *
3189fa9e4066Sahrens  *	-v	Display complete error logs
3190fa9e4066Sahrens  *	-x	Display only pools with potential problems
3191fa9e4066Sahrens  *
3192fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3193fa9e4066Sahrens  */
3194fa9e4066Sahrens int
3195fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3196fa9e4066Sahrens {
3197fa9e4066Sahrens 	int c;
3198fa9e4066Sahrens 	int ret;
3199fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3200fa9e4066Sahrens 
3201fa9e4066Sahrens 	/* check options */
3202fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3203fa9e4066Sahrens 		switch (c) {
3204fa9e4066Sahrens 		case 'v':
320599653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3206fa9e4066Sahrens 			break;
3207fa9e4066Sahrens 		case 'x':
320899653d4eSeschrock 			cb.cb_explain = B_TRUE;
3209fa9e4066Sahrens 			break;
3210fa9e4066Sahrens 		case '?':
3211fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3212fa9e4066Sahrens 			    optopt);
321399653d4eSeschrock 			usage(B_FALSE);
3214fa9e4066Sahrens 		}
3215fa9e4066Sahrens 	}
3216fa9e4066Sahrens 
3217fa9e4066Sahrens 	argc -= optind;
3218fa9e4066Sahrens 	argv += optind;
3219fa9e4066Sahrens 
322099653d4eSeschrock 	cb.cb_first = B_TRUE;
3221fa9e4066Sahrens 
3222e9dbad6fSeschrock 	if (argc == 0)
3223e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3224e9dbad6fSeschrock 
3225b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3226fa9e4066Sahrens 
3227fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3228fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3229e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3230fa9e4066Sahrens 		(void) printf(gettext("all pools are healthy\n"));
3231fa9e4066Sahrens 
3232fa9e4066Sahrens 	return (ret);
3233fa9e4066Sahrens }
3234fa9e4066Sahrens 
3235eaca9bbdSeschrock typedef struct upgrade_cbdata {
3236eaca9bbdSeschrock 	int	cb_all;
3237eaca9bbdSeschrock 	int	cb_first;
3238eaca9bbdSeschrock 	int	cb_newer;
323906eeb2adSek110237 	int	cb_argc;
3240990b4856Slling 	uint64_t cb_version;
324106eeb2adSek110237 	char	**cb_argv;
3242eaca9bbdSeschrock } upgrade_cbdata_t;
3243eaca9bbdSeschrock 
3244eaca9bbdSeschrock static int
3245eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3246eaca9bbdSeschrock {
3247eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3248eaca9bbdSeschrock 	nvlist_t *config;
3249eaca9bbdSeschrock 	uint64_t version;
3250eaca9bbdSeschrock 	int ret = 0;
3251eaca9bbdSeschrock 
3252eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3253eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3254eaca9bbdSeschrock 	    &version) == 0);
3255eaca9bbdSeschrock 
3256e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3257eaca9bbdSeschrock 		if (!cbp->cb_all) {
3258eaca9bbdSeschrock 			if (cbp->cb_first) {
3259eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3260eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3261eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3262eaca9bbdSeschrock 				    "longer be accessible by older software "
3263eaca9bbdSeschrock 				    "versions.\n\n"));
3264eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3265eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
326699653d4eSeschrock 				cbp->cb_first = B_FALSE;
3267eaca9bbdSeschrock 			}
3268eaca9bbdSeschrock 
32695ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3270eaca9bbdSeschrock 			    zpool_get_name(zhp));
3271eaca9bbdSeschrock 		} else {
327299653d4eSeschrock 			cbp->cb_first = B_FALSE;
3273990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
327406eeb2adSek110237 			if (!ret) {
3275eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3276990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
3277eaca9bbdSeschrock 			}
327806eeb2adSek110237 		}
3279e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3280eaca9bbdSeschrock 		assert(!cbp->cb_all);
3281eaca9bbdSeschrock 
3282eaca9bbdSeschrock 		if (cbp->cb_first) {
3283eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3284eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3285eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3286eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3287eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
328899653d4eSeschrock 			cbp->cb_first = B_FALSE;
3289eaca9bbdSeschrock 		}
3290eaca9bbdSeschrock 
32915ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3292eaca9bbdSeschrock 		    zpool_get_name(zhp));
3293eaca9bbdSeschrock 	}
3294eaca9bbdSeschrock 
3295eaca9bbdSeschrock 	zpool_close(zhp);
3296eaca9bbdSeschrock 	return (ret);
3297eaca9bbdSeschrock }
3298eaca9bbdSeschrock 
3299eaca9bbdSeschrock /* ARGSUSED */
3300eaca9bbdSeschrock static int
330106eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
3302eaca9bbdSeschrock {
3303990b4856Slling 	upgrade_cbdata_t *cbp = data;
3304990b4856Slling 	uint64_t cur_version;
3305eaca9bbdSeschrock 	int ret;
3306eaca9bbdSeschrock 
33078654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
33088654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
33098654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
33108654d025Sperrin 		    " to upgrade.\n"));
33118654d025Sperrin 		return (1);
33128654d025Sperrin 	}
3313990b4856Slling 
3314990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3315e6c728e1Sbrendan 	if (cur_version > cbp->cb_version) {
3316eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3317e6c728e1Sbrendan 		    "using more current version '%llu'.\n"),
3318e6c728e1Sbrendan 		    zpool_get_name(zhp), cur_version);
3319e6c728e1Sbrendan 		return (0);
3320e6c728e1Sbrendan 	}
3321e6c728e1Sbrendan 	if (cur_version == cbp->cb_version) {
3322e6c728e1Sbrendan 		(void) printf(gettext("Pool '%s' is already formatted "
3323e6c728e1Sbrendan 		    "using the current version.\n"), zpool_get_name(zhp));
3324eaca9bbdSeschrock 		return (0);
3325eaca9bbdSeschrock 	}
3326eaca9bbdSeschrock 
3327990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
332806eeb2adSek110237 
332906eeb2adSek110237 	if (!ret) {
333044cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
3331990b4856Slling 		    "from version %llu to version %llu\n\n"),
3332990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3333990b4856Slling 		    (u_longlong_t)cbp->cb_version);
333406eeb2adSek110237 	}
3335eaca9bbdSeschrock 
3336eaca9bbdSeschrock 	return (ret != 0);
3337eaca9bbdSeschrock }
3338eaca9bbdSeschrock 
3339eaca9bbdSeschrock /*
3340eaca9bbdSeschrock  * zpool upgrade
3341eaca9bbdSeschrock  * zpool upgrade -v
3342990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
3343eaca9bbdSeschrock  *
3344eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3345eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3346eaca9bbdSeschrock  * upgrade all pools.
3347eaca9bbdSeschrock  */
3348eaca9bbdSeschrock int
3349eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3350eaca9bbdSeschrock {
3351eaca9bbdSeschrock 	int c;
3352eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3353eaca9bbdSeschrock 	int ret = 0;
3354eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3355990b4856Slling 	char *end;
3356990b4856Slling 
3357eaca9bbdSeschrock 
3358eaca9bbdSeschrock 	/* check options */
3359990b4856Slling 	while ((c = getopt(argc, argv, "avV:")) != -1) {
3360eaca9bbdSeschrock 		switch (c) {
3361eaca9bbdSeschrock 		case 'a':
336299653d4eSeschrock 			cb.cb_all = B_TRUE;
3363eaca9bbdSeschrock 			break;
3364eaca9bbdSeschrock 		case 'v':
3365eaca9bbdSeschrock 			showversions = B_TRUE;
3366eaca9bbdSeschrock 			break;
3367990b4856Slling 		case 'V':
3368990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
3369351420b3Slling 			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
3370351420b3Slling 			    cb.cb_version < SPA_VERSION_1) {
3371990b4856Slling 				(void) fprintf(stderr,
3372990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
3373990b4856Slling 				usage(B_FALSE);
3374990b4856Slling 			}
3375990b4856Slling 			break;
3376eaca9bbdSeschrock 		case '?':
3377eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3378eaca9bbdSeschrock 			    optopt);
337999653d4eSeschrock 			usage(B_FALSE);
3380eaca9bbdSeschrock 		}
3381eaca9bbdSeschrock 	}
3382eaca9bbdSeschrock 
338306eeb2adSek110237 	cb.cb_argc = argc;
338406eeb2adSek110237 	cb.cb_argv = argv;
3385eaca9bbdSeschrock 	argc -= optind;
3386eaca9bbdSeschrock 	argv += optind;
3387eaca9bbdSeschrock 
3388351420b3Slling 	if (cb.cb_version == 0) {
3389351420b3Slling 		cb.cb_version = SPA_VERSION;
3390351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
3391351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
3392351420b3Slling 		    "incompatible with other arguments\n"));
3393351420b3Slling 		usage(B_FALSE);
3394351420b3Slling 	}
3395351420b3Slling 
3396eaca9bbdSeschrock 	if (showversions) {
3397eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3398eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3399eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
340099653d4eSeschrock 			usage(B_FALSE);
3401eaca9bbdSeschrock 		}
3402eaca9bbdSeschrock 	} else if (cb.cb_all) {
3403eaca9bbdSeschrock 		if (argc != 0) {
3404351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
3405351420b3Slling 			    "be used along with a pool name\n"));
340699653d4eSeschrock 			usage(B_FALSE);
3407eaca9bbdSeschrock 		}
3408eaca9bbdSeschrock 	}
3409eaca9bbdSeschrock 
3410e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3411e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
341299653d4eSeschrock 	cb.cb_first = B_TRUE;
3413eaca9bbdSeschrock 	if (showversions) {
3414eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3415d7d4af51Smmusante 		    "supported:\n\n"));
3416eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3417eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3418eaca9bbdSeschrock 		    "---------------\n");
341999653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
342044cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
342144cd46caSbillm 		    "(replicated metadata)\n"));
342299653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
342399653d4eSeschrock 		    "RAID-Z\n"));
3424d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
3425c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3426c9431fa1Sahl 		    "algorithm\n"));
3427990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
34288654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3429ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
3430a9799022Sck153898 		(void) printf(gettext(" 9   refquota and refreservation "
3431a9799022Sck153898 		    "properties\n"));
3432fa94a07fSbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
34338654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3434eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3435eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3436eaca9bbdSeschrock 		    "version/N\n\n");
3437eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3438eaca9bbdSeschrock 	} else if (argc == 0) {
3439eaca9bbdSeschrock 		int notfound;
3440eaca9bbdSeschrock 
344199653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3442eaca9bbdSeschrock 		notfound = cb.cb_first;
3443eaca9bbdSeschrock 
3444eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3445eaca9bbdSeschrock 			if (!cb.cb_first)
3446eaca9bbdSeschrock 				(void) printf("\n");
3447eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3448eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
344999653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3450eaca9bbdSeschrock 			if (!cb.cb_first) {
3451eaca9bbdSeschrock 				notfound = B_FALSE;
3452eaca9bbdSeschrock 				(void) printf("\n");
3453eaca9bbdSeschrock 			}
3454eaca9bbdSeschrock 		}
3455eaca9bbdSeschrock 
3456eaca9bbdSeschrock 		if (ret == 0) {
3457eaca9bbdSeschrock 			if (notfound)
3458eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3459eaca9bbdSeschrock 				    "using this version.\n"));
3460eaca9bbdSeschrock 			else if (!cb.cb_all)
3461eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3462eaca9bbdSeschrock 				    "for a list of available versions and "
3463eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3464eaca9bbdSeschrock 		}
3465eaca9bbdSeschrock 	} else {
3466b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3467b1b8ab34Slling 		    upgrade_one, &cb);
346806eeb2adSek110237 	}
346906eeb2adSek110237 
347006eeb2adSek110237 	return (ret);
347106eeb2adSek110237 }
347206eeb2adSek110237 
3473ecd6cf80Smarks typedef struct hist_cbdata {
3474ecd6cf80Smarks 	boolean_t first;
3475ecd6cf80Smarks 	int longfmt;
3476ecd6cf80Smarks 	int internal;
3477ecd6cf80Smarks } hist_cbdata_t;
3478ecd6cf80Smarks 
3479ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3480ecd6cf80Smarks 	"invalid event",
3481ecd6cf80Smarks 	"pool create",
3482ecd6cf80Smarks 	"vdev add",
3483ecd6cf80Smarks 	"pool remove",
3484ecd6cf80Smarks 	"pool destroy",
3485ecd6cf80Smarks 	"pool export",
3486ecd6cf80Smarks 	"pool import",
3487ecd6cf80Smarks 	"vdev attach",
3488ecd6cf80Smarks 	"vdev replace",
3489ecd6cf80Smarks 	"vdev detach",
3490ecd6cf80Smarks 	"vdev online",
3491ecd6cf80Smarks 	"vdev offline",
3492ecd6cf80Smarks 	"vdev upgrade",
3493ecd6cf80Smarks 	"pool clear",
3494ecd6cf80Smarks 	"pool scrub",
3495ecd6cf80Smarks 	"pool property set",
3496ecd6cf80Smarks 	"create",
3497ecd6cf80Smarks 	"clone",
3498ecd6cf80Smarks 	"destroy",
3499ecd6cf80Smarks 	"destroy_begin_sync",
3500ecd6cf80Smarks 	"inherit",
3501ecd6cf80Smarks 	"property set",
3502ecd6cf80Smarks 	"quota set",
3503ecd6cf80Smarks 	"permission update",
3504ecd6cf80Smarks 	"permission remove",
3505ecd6cf80Smarks 	"permission who remove",
3506ecd6cf80Smarks 	"promote",
3507ecd6cf80Smarks 	"receive",
3508ecd6cf80Smarks 	"rename",
3509ecd6cf80Smarks 	"reservation set",
3510ecd6cf80Smarks 	"replay_inc_sync",
3511ecd6cf80Smarks 	"replay_full_sync",
3512ecd6cf80Smarks 	"rollback",
3513ecd6cf80Smarks 	"snapshot",
3514e7437265Sahrens 	"filesystem version upgrade",
3515a9799022Sck153898 	"refquota set",
3516a9799022Sck153898 	"refreservation set",
3517ecd6cf80Smarks };
3518ecd6cf80Smarks 
351906eeb2adSek110237 /*
352006eeb2adSek110237  * Print out the command history for a specific pool.
352106eeb2adSek110237  */
352206eeb2adSek110237 static int
352306eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
352406eeb2adSek110237 {
352506eeb2adSek110237 	nvlist_t *nvhis;
352606eeb2adSek110237 	nvlist_t **records;
352706eeb2adSek110237 	uint_t numrecords;
352806eeb2adSek110237 	char *cmdstr;
3529ecd6cf80Smarks 	char *pathstr;
353006eeb2adSek110237 	uint64_t dst_time;
353106eeb2adSek110237 	time_t tsec;
353206eeb2adSek110237 	struct tm t;
353306eeb2adSek110237 	char tbuf[30];
353406eeb2adSek110237 	int ret, i;
3535ecd6cf80Smarks 	uint64_t who;
3536ecd6cf80Smarks 	struct passwd *pwd;
3537ecd6cf80Smarks 	char *hostname;
3538ecd6cf80Smarks 	char *zonename;
3539ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3540ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3541ecd6cf80Smarks 	uint64_t txg;
3542ecd6cf80Smarks 	uint64_t ievent;
354306eeb2adSek110237 
3544ecd6cf80Smarks 	cb->first = B_FALSE;
354506eeb2adSek110237 
354606eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
354706eeb2adSek110237 
354806eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
354906eeb2adSek110237 		return (ret);
355006eeb2adSek110237 
355106eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
355206eeb2adSek110237 	    &records, &numrecords) == 0);
355306eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
355406eeb2adSek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3555ecd6cf80Smarks 		    &dst_time) != 0)
3556ecd6cf80Smarks 			continue;
3557ecd6cf80Smarks 
3558ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3559ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3560ecd6cf80Smarks 		    &cmdstr) != 0) {
3561ecd6cf80Smarks 			if (cb->internal == 0)
3562ecd6cf80Smarks 				continue;
3563ecd6cf80Smarks 
3564ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3565ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3566ecd6cf80Smarks 				continue;
3567ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3568ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3569ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3570ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3571ecd6cf80Smarks 			if (ievent > LOG_END)
3572ecd6cf80Smarks 				continue;
3573ecd6cf80Smarks 			(void) snprintf(internalstr,
3574ecd6cf80Smarks 			    sizeof (internalstr),
3575ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3576ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3577ecd6cf80Smarks 			    pathstr);
3578ecd6cf80Smarks 			cmdstr = internalstr;
3579ecd6cf80Smarks 		}
358006eeb2adSek110237 		tsec = dst_time;
358106eeb2adSek110237 		(void) localtime_r(&tsec, &t);
358206eeb2adSek110237 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3583ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3584ecd6cf80Smarks 
3585ecd6cf80Smarks 		if (!cb->longfmt) {
3586ecd6cf80Smarks 			(void) printf("\n");
3587ecd6cf80Smarks 			continue;
358806eeb2adSek110237 		}
3589ecd6cf80Smarks 		(void) printf(" [");
3590ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3591ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3592ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3593ecd6cf80Smarks 			if (pwd)
3594ecd6cf80Smarks 				(void) printf("user %s on",
3595ecd6cf80Smarks 				    pwd->pw_name);
3596ecd6cf80Smarks 			else
3597ecd6cf80Smarks 				(void) printf("user %d on",
3598ecd6cf80Smarks 				    (int)who);
3599ecd6cf80Smarks 		} else {
3600ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3601ecd6cf80Smarks 			continue;
3602ecd6cf80Smarks 		}
3603ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3604ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3605ecd6cf80Smarks 			(void) printf(" %s", hostname);
3606ecd6cf80Smarks 		}
3607ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3608ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3609ecd6cf80Smarks 			(void) printf(":%s", zonename);
3610ecd6cf80Smarks 		}
3611ecd6cf80Smarks 
3612ecd6cf80Smarks 		(void) printf("]");
3613ecd6cf80Smarks 		(void) printf("\n");
361406eeb2adSek110237 	}
361506eeb2adSek110237 	(void) printf("\n");
361606eeb2adSek110237 	nvlist_free(nvhis);
361706eeb2adSek110237 
361806eeb2adSek110237 	return (ret);
361906eeb2adSek110237 }
362006eeb2adSek110237 
362106eeb2adSek110237 /*
362206eeb2adSek110237  * zpool history <pool>
362306eeb2adSek110237  *
362406eeb2adSek110237  * Displays the history of commands that modified pools.
362506eeb2adSek110237  */
3626ecd6cf80Smarks 
3627ecd6cf80Smarks 
362806eeb2adSek110237 int
362906eeb2adSek110237 zpool_do_history(int argc, char **argv)
363006eeb2adSek110237 {
3631ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
363206eeb2adSek110237 	int ret;
3633ecd6cf80Smarks 	int c;
363406eeb2adSek110237 
3635ecd6cf80Smarks 	cbdata.first = B_TRUE;
3636ecd6cf80Smarks 	/* check options */
3637ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3638ecd6cf80Smarks 		switch (c) {
3639ecd6cf80Smarks 		case 'l':
3640ecd6cf80Smarks 			cbdata.longfmt = 1;
3641ecd6cf80Smarks 			break;
3642ecd6cf80Smarks 		case 'i':
3643ecd6cf80Smarks 			cbdata.internal = 1;
3644ecd6cf80Smarks 			break;
3645ecd6cf80Smarks 		case '?':
3646ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3647ecd6cf80Smarks 			    optopt);
3648ecd6cf80Smarks 			usage(B_FALSE);
3649ecd6cf80Smarks 		}
3650ecd6cf80Smarks 	}
365106eeb2adSek110237 	argc -= optind;
365206eeb2adSek110237 	argv += optind;
365306eeb2adSek110237 
3654b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3655ecd6cf80Smarks 	    &cbdata);
365606eeb2adSek110237 
3657ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
365806eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
365906eeb2adSek110237 		return (0);
3660eaca9bbdSeschrock 	}
3661eaca9bbdSeschrock 
3662eaca9bbdSeschrock 	return (ret);
3663eaca9bbdSeschrock }
3664eaca9bbdSeschrock 
3665b1b8ab34Slling static int
3666b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3667b1b8ab34Slling {
3668990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3669b1b8ab34Slling 	char value[MAXNAMELEN];
3670990b4856Slling 	zprop_source_t srctype;
3671990b4856Slling 	zprop_list_t *pl;
3672b1b8ab34Slling 
3673b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3674b1b8ab34Slling 
3675b1b8ab34Slling 		/*
3676990b4856Slling 		 * Skip the special fake placeholder. This will also skip
3677990b4856Slling 		 * over the name property when 'all' is specified.
3678b1b8ab34Slling 		 */
3679990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3680b1b8ab34Slling 		    pl == cbp->cb_proplist)
3681b1b8ab34Slling 			continue;
3682b1b8ab34Slling 
3683b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3684b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3685b1b8ab34Slling 			continue;
3686b1b8ab34Slling 
3687990b4856Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
3688b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3689b1b8ab34Slling 	}
3690b1b8ab34Slling 	return (0);
3691b1b8ab34Slling }
3692b1b8ab34Slling 
3693b1b8ab34Slling int
3694b1b8ab34Slling zpool_do_get(int argc, char **argv)
3695b1b8ab34Slling {
3696990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
3697990b4856Slling 	zprop_list_t fake_name = { 0 };
3698b1b8ab34Slling 	int ret;
3699b1b8ab34Slling 
3700b1b8ab34Slling 	if (argc < 3)
3701b1b8ab34Slling 		usage(B_FALSE);
3702b1b8ab34Slling 
3703b1b8ab34Slling 	cb.cb_first = B_TRUE;
3704990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
3705b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3706b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3707b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3708b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3709990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
3710b1b8ab34Slling 
3711990b4856Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3712990b4856Slling 	    ZFS_TYPE_POOL) != 0)
3713b1b8ab34Slling 		usage(B_FALSE);
3714b1b8ab34Slling 
3715b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3716990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
3717b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3718b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3719b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3720b1b8ab34Slling 	}
3721b1b8ab34Slling 
3722b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3723b1b8ab34Slling 	    get_callback, &cb);
3724b1b8ab34Slling 
3725b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3726990b4856Slling 		zprop_free_list(fake_name.pl_next);
3727b1b8ab34Slling 	else
3728990b4856Slling 		zprop_free_list(cb.cb_proplist);
3729b1b8ab34Slling 
3730b1b8ab34Slling 	return (ret);
3731b1b8ab34Slling }
3732b1b8ab34Slling 
3733b1b8ab34Slling typedef struct set_cbdata {
3734b1b8ab34Slling 	char *cb_propname;
3735b1b8ab34Slling 	char *cb_value;
3736b1b8ab34Slling 	boolean_t cb_any_successful;
3737b1b8ab34Slling } set_cbdata_t;
3738b1b8ab34Slling 
3739b1b8ab34Slling int
3740b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3741b1b8ab34Slling {
3742b1b8ab34Slling 	int error;
3743b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3744b1b8ab34Slling 
3745b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3746b1b8ab34Slling 
3747b1b8ab34Slling 	if (!error)
3748b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3749b1b8ab34Slling 
3750b1b8ab34Slling 	return (error);
3751b1b8ab34Slling }
3752b1b8ab34Slling 
3753b1b8ab34Slling int
3754b1b8ab34Slling zpool_do_set(int argc, char **argv)
3755b1b8ab34Slling {
3756b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3757b1b8ab34Slling 	int error;
3758b1b8ab34Slling 
3759b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3760b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3761b1b8ab34Slling 		    argv[1][1]);
3762b1b8ab34Slling 		usage(B_FALSE);
3763b1b8ab34Slling 	}
3764b1b8ab34Slling 
3765b1b8ab34Slling 	if (argc < 2) {
3766b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3767b1b8ab34Slling 		    "argument\n"));
3768b1b8ab34Slling 		usage(B_FALSE);
3769b1b8ab34Slling 	}
3770b1b8ab34Slling 
3771b1b8ab34Slling 	if (argc < 3) {
3772b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3773b1b8ab34Slling 		usage(B_FALSE);
3774b1b8ab34Slling 	}
3775b1b8ab34Slling 
3776b1b8ab34Slling 	if (argc > 3) {
3777b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3778b1b8ab34Slling 		usage(B_FALSE);
3779b1b8ab34Slling 	}
3780b1b8ab34Slling 
3781b1b8ab34Slling 	cb.cb_propname = argv[1];
3782b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3783b1b8ab34Slling 	if (cb.cb_value == NULL) {
3784b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3785b1b8ab34Slling 		    "property=value argument\n"));
3786b1b8ab34Slling 		usage(B_FALSE);
3787b1b8ab34Slling 	}
3788b1b8ab34Slling 
3789b1b8ab34Slling 	*(cb.cb_value) = '\0';
3790b1b8ab34Slling 	cb.cb_value++;
3791b1b8ab34Slling 
3792b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3793b1b8ab34Slling 	    set_callback, &cb);
3794b1b8ab34Slling 
3795b1b8ab34Slling 	return (error);
3796b1b8ab34Slling }
3797b1b8ab34Slling 
3798b1b8ab34Slling static int
3799b1b8ab34Slling find_command_idx(char *command, int *idx)
3800b1b8ab34Slling {
3801b1b8ab34Slling 	int i;
3802b1b8ab34Slling 
3803b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3804b1b8ab34Slling 		if (command_table[i].name == NULL)
3805b1b8ab34Slling 			continue;
3806b1b8ab34Slling 
3807b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3808b1b8ab34Slling 			*idx = i;
3809b1b8ab34Slling 			return (0);
3810b1b8ab34Slling 		}
3811b1b8ab34Slling 	}
3812b1b8ab34Slling 	return (1);
3813b1b8ab34Slling }
3814b1b8ab34Slling 
3815fa9e4066Sahrens int
3816fa9e4066Sahrens main(int argc, char **argv)
3817fa9e4066Sahrens {
3818fa9e4066Sahrens 	int ret;
3819fa9e4066Sahrens 	int i;
3820fa9e4066Sahrens 	char *cmdname;
3821fa9e4066Sahrens 
3822fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3823fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3824fa9e4066Sahrens 
382599653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
382699653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3827203a47d8Snd150628 		    "initialize ZFS library\n"));
382899653d4eSeschrock 		return (1);
382999653d4eSeschrock 	}
383099653d4eSeschrock 
383199653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
383299653d4eSeschrock 
3833fa9e4066Sahrens 	opterr = 0;
3834fa9e4066Sahrens 
3835fa9e4066Sahrens 	/*
3836fa9e4066Sahrens 	 * Make sure the user has specified some command.
3837fa9e4066Sahrens 	 */
3838fa9e4066Sahrens 	if (argc < 2) {
3839fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
384099653d4eSeschrock 		usage(B_FALSE);
3841fa9e4066Sahrens 	}
3842fa9e4066Sahrens 
3843fa9e4066Sahrens 	cmdname = argv[1];
3844fa9e4066Sahrens 
3845fa9e4066Sahrens 	/*
3846fa9e4066Sahrens 	 * Special case '-?'
3847fa9e4066Sahrens 	 */
3848fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
384999653d4eSeschrock 		usage(B_TRUE);
3850fa9e4066Sahrens 
38512a6b87f0Sek110237 	zpool_set_history_str("zpool", argc, argv, history_str);
38522a6b87f0Sek110237 	verify(zpool_stage_history(g_zfs, history_str) == 0);
38532a6b87f0Sek110237 
3854fa9e4066Sahrens 	/*
3855fa9e4066Sahrens 	 * Run the appropriate command.
3856fa9e4066Sahrens 	 */
3857b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
3858fa9e4066Sahrens 		current_command = &command_table[i];
3859fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
386091ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
386191ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
386291ebeef5Sahrens 		current_command = &command_table[i];
386391ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
386491ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
3865fa9e4066Sahrens 		/*
386691ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
386791ebeef5Sahrens 		 * it as such.
3868fa9e4066Sahrens 		 */
3869ea8dc4b6Seschrock 		char buf[16384];
3870ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
3871fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
3872fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
387391ebeef5Sahrens 	} else {
3874fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
3875fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
387699653d4eSeschrock 		usage(B_FALSE);
3877fa9e4066Sahrens 	}
3878fa9e4066Sahrens 
387999653d4eSeschrock 	libzfs_fini(g_zfs);
388099653d4eSeschrock 
3881fa9e4066Sahrens 	/*
3882fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3883fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
3884fa9e4066Sahrens 	 */
3885fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
3886fa9e4066Sahrens 		(void) printf("dumping core by request\n");
3887fa9e4066Sahrens 		abort();
3888fa9e4066Sahrens 	}
3889fa9e4066Sahrens 
3890fa9e4066Sahrens 	return (ret);
3891fa9e4066Sahrens }
3892