xref: /titanic_53/usr/src/cmd/zpool/zpool_main.c (revision a9799022bd90b13722204e80112efaa5bf573099)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5441d80aaSlling  * Common Development and Distribution License (the "License").
6441d80aaSlling  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
2199653d4eSeschrock 
22fa9e4066Sahrens /*
2339c23413Seschrock  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28fa9e4066Sahrens 
29fa9e4066Sahrens #include <assert.h>
30fa9e4066Sahrens #include <ctype.h>
31fa9e4066Sahrens #include <dirent.h>
32fa9e4066Sahrens #include <errno.h>
33fa9e4066Sahrens #include <fcntl.h>
34fa9e4066Sahrens #include <libgen.h>
35fa9e4066Sahrens #include <libintl.h>
36fa9e4066Sahrens #include <libuutil.h>
37fa9e4066Sahrens #include <locale.h>
38fa9e4066Sahrens #include <stdio.h>
39fa9e4066Sahrens #include <stdlib.h>
40fa9e4066Sahrens #include <string.h>
41fa9e4066Sahrens #include <strings.h>
42fa9e4066Sahrens #include <unistd.h>
43fa9e4066Sahrens #include <priv.h>
44ecd6cf80Smarks #include <pwd.h>
45ecd6cf80Smarks #include <zone.h>
46b1b8ab34Slling #include <sys/fs/zfs.h>
47fa9e4066Sahrens 
48fa9e4066Sahrens #include <sys/stat.h>
49fa9e4066Sahrens 
50fa9e4066Sahrens #include <libzfs.h>
51fa9e4066Sahrens 
52fa9e4066Sahrens #include "zpool_util.h"
53fa9e4066Sahrens 
54fa9e4066Sahrens static int zpool_do_create(int, char **);
55fa9e4066Sahrens static int zpool_do_destroy(int, char **);
56fa9e4066Sahrens 
57fa9e4066Sahrens static int zpool_do_add(int, char **);
5899653d4eSeschrock static int zpool_do_remove(int, char **);
59fa9e4066Sahrens 
60fa9e4066Sahrens static int zpool_do_list(int, char **);
61fa9e4066Sahrens static int zpool_do_iostat(int, char **);
62fa9e4066Sahrens static int zpool_do_status(int, char **);
63fa9e4066Sahrens 
64fa9e4066Sahrens static int zpool_do_online(int, char **);
65fa9e4066Sahrens static int zpool_do_offline(int, char **);
66ea8dc4b6Seschrock static int zpool_do_clear(int, char **);
67fa9e4066Sahrens 
68fa9e4066Sahrens static int zpool_do_attach(int, char **);
69fa9e4066Sahrens static int zpool_do_detach(int, char **);
70fa9e4066Sahrens static int zpool_do_replace(int, char **);
71fa9e4066Sahrens 
72fa9e4066Sahrens static int zpool_do_scrub(int, char **);
73fa9e4066Sahrens 
74fa9e4066Sahrens static int zpool_do_import(int, char **);
75fa9e4066Sahrens static int zpool_do_export(int, char **);
76fa9e4066Sahrens 
77eaca9bbdSeschrock static int zpool_do_upgrade(int, char **);
78eaca9bbdSeschrock 
7906eeb2adSek110237 static int zpool_do_history(int, char **);
8006eeb2adSek110237 
81b1b8ab34Slling static int zpool_do_get(int, char **);
82b1b8ab34Slling static int zpool_do_set(int, char **);
83b1b8ab34Slling 
84fa9e4066Sahrens /*
85fa9e4066Sahrens  * These libumem hooks provide a reasonable set of defaults for the allocator's
86fa9e4066Sahrens  * debugging facilities.
87fa9e4066Sahrens  */
88fa9e4066Sahrens const char *
8999653d4eSeschrock _umem_debug_init(void)
90fa9e4066Sahrens {
91fa9e4066Sahrens 	return ("default,verbose"); /* $UMEM_DEBUG setting */
92fa9e4066Sahrens }
93fa9e4066Sahrens 
94fa9e4066Sahrens const char *
95fa9e4066Sahrens _umem_logging_init(void)
96fa9e4066Sahrens {
97fa9e4066Sahrens 	return ("fail,contents"); /* $UMEM_LOGGING setting */
98fa9e4066Sahrens }
99fa9e4066Sahrens 
10065cd9f28Seschrock typedef enum {
10165cd9f28Seschrock 	HELP_ADD,
10265cd9f28Seschrock 	HELP_ATTACH,
103ea8dc4b6Seschrock 	HELP_CLEAR,
10465cd9f28Seschrock 	HELP_CREATE,
10565cd9f28Seschrock 	HELP_DESTROY,
10665cd9f28Seschrock 	HELP_DETACH,
10765cd9f28Seschrock 	HELP_EXPORT,
10806eeb2adSek110237 	HELP_HISTORY,
10965cd9f28Seschrock 	HELP_IMPORT,
11065cd9f28Seschrock 	HELP_IOSTAT,
11165cd9f28Seschrock 	HELP_LIST,
11265cd9f28Seschrock 	HELP_OFFLINE,
11365cd9f28Seschrock 	HELP_ONLINE,
11465cd9f28Seschrock 	HELP_REPLACE,
11599653d4eSeschrock 	HELP_REMOVE,
11665cd9f28Seschrock 	HELP_SCRUB,
117eaca9bbdSeschrock 	HELP_STATUS,
118b1b8ab34Slling 	HELP_UPGRADE,
119b1b8ab34Slling 	HELP_GET,
120b1b8ab34Slling 	HELP_SET
12165cd9f28Seschrock } zpool_help_t;
12265cd9f28Seschrock 
12365cd9f28Seschrock 
124fa9e4066Sahrens typedef struct zpool_command {
125fa9e4066Sahrens 	const char	*name;
126fa9e4066Sahrens 	int		(*func)(int, char **);
12765cd9f28Seschrock 	zpool_help_t	usage;
128fa9e4066Sahrens } zpool_command_t;
129fa9e4066Sahrens 
130fa9e4066Sahrens /*
131fa9e4066Sahrens  * Master command table.  Each ZFS command has a name, associated function, and
132ea8dc4b6Seschrock  * usage message.  The usage messages need to be internationalized, so we have
133ea8dc4b6Seschrock  * to have a function to return the usage message based on a command index.
13465cd9f28Seschrock  *
13565cd9f28Seschrock  * These commands are organized according to how they are displayed in the usage
13665cd9f28Seschrock  * message.  An empty command (one with a NULL name) indicates an empty line in
13765cd9f28Seschrock  * the generic usage message.
138fa9e4066Sahrens  */
139fa9e4066Sahrens static zpool_command_t command_table[] = {
14065cd9f28Seschrock 	{ "create",	zpool_do_create,	HELP_CREATE		},
14165cd9f28Seschrock 	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
142fa9e4066Sahrens 	{ NULL },
14365cd9f28Seschrock 	{ "add",	zpool_do_add,		HELP_ADD		},
14499653d4eSeschrock 	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
145fa9e4066Sahrens 	{ NULL },
14665cd9f28Seschrock 	{ "list",	zpool_do_list,		HELP_LIST		},
14765cd9f28Seschrock 	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
14865cd9f28Seschrock 	{ "status",	zpool_do_status,	HELP_STATUS		},
149fa9e4066Sahrens 	{ NULL },
15065cd9f28Seschrock 	{ "online",	zpool_do_online,	HELP_ONLINE		},
15165cd9f28Seschrock 	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
152ea8dc4b6Seschrock 	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
153fa9e4066Sahrens 	{ NULL },
15465cd9f28Seschrock 	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
15565cd9f28Seschrock 	{ "detach",	zpool_do_detach,	HELP_DETACH		},
15665cd9f28Seschrock 	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
157fa9e4066Sahrens 	{ NULL },
15865cd9f28Seschrock 	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
159fa9e4066Sahrens 	{ NULL },
16065cd9f28Seschrock 	{ "import",	zpool_do_import,	HELP_IMPORT		},
16165cd9f28Seschrock 	{ "export",	zpool_do_export,	HELP_EXPORT		},
16206eeb2adSek110237 	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
16306eeb2adSek110237 	{ NULL },
164b1b8ab34Slling 	{ "history",	zpool_do_history,	HELP_HISTORY		},
165b1b8ab34Slling 	{ "get",	zpool_do_get,		HELP_GET		},
166b1b8ab34Slling 	{ "set",	zpool_do_set,		HELP_SET		},
167fa9e4066Sahrens };
168fa9e4066Sahrens 
169fa9e4066Sahrens #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
170fa9e4066Sahrens 
171fa9e4066Sahrens zpool_command_t *current_command;
1722a6b87f0Sek110237 static char history_str[HIS_MAX_RECORD_LEN];
173fa9e4066Sahrens 
17465cd9f28Seschrock static const char *
17565cd9f28Seschrock get_usage(zpool_help_t idx) {
17665cd9f28Seschrock 	switch (idx) {
17765cd9f28Seschrock 	case HELP_ADD:
17865cd9f28Seschrock 		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
17965cd9f28Seschrock 	case HELP_ATTACH:
18065cd9f28Seschrock 		return (gettext("\tattach [-f] <pool> <device> "
181e45ce728Sahrens 		    "<new-device>\n"));
182ea8dc4b6Seschrock 	case HELP_CLEAR:
183ea8dc4b6Seschrock 		return (gettext("\tclear <pool> [device]\n"));
18465cd9f28Seschrock 	case HELP_CREATE:
185990b4856Slling 		return (gettext("\tcreate [-fn] [-o property=value] ... \n"
186990b4856Slling 		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
18765cd9f28Seschrock 	case HELP_DESTROY:
18865cd9f28Seschrock 		return (gettext("\tdestroy [-f] <pool>\n"));
18965cd9f28Seschrock 	case HELP_DETACH:
19065cd9f28Seschrock 		return (gettext("\tdetach <pool> <device>\n"));
19165cd9f28Seschrock 	case HELP_EXPORT:
19265cd9f28Seschrock 		return (gettext("\texport [-f] <pool> ...\n"));
19306eeb2adSek110237 	case HELP_HISTORY:
194ecd6cf80Smarks 		return (gettext("\thistory [-il] [<pool>] ...\n"));
19565cd9f28Seschrock 	case HELP_IMPORT:
1964c58d714Sdarrenm 		return (gettext("\timport [-d dir] [-D]\n"
1972f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
1982f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n"
1992f8aaab3Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
2002f8aaab3Seschrock 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] "
2012f8aaab3Seschrock 		    "<pool | id> [newpool]\n"));
20265cd9f28Seschrock 	case HELP_IOSTAT:
20365cd9f28Seschrock 		return (gettext("\tiostat [-v] [pool] ... [interval "
20465cd9f28Seschrock 		    "[count]]\n"));
20565cd9f28Seschrock 	case HELP_LIST:
206990b4856Slling 		return (gettext("\tlist [-H] [-o property[,...]] "
207990b4856Slling 		    "[pool] ...\n"));
20865cd9f28Seschrock 	case HELP_OFFLINE:
209441d80aaSlling 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
21065cd9f28Seschrock 	case HELP_ONLINE:
211441d80aaSlling 		return (gettext("\tonline <pool> <device> ...\n"));
21265cd9f28Seschrock 	case HELP_REPLACE:
21365cd9f28Seschrock 		return (gettext("\treplace [-f] <pool> <device> "
214e45ce728Sahrens 		    "[new-device]\n"));
21599653d4eSeschrock 	case HELP_REMOVE:
21699653d4eSeschrock 		return (gettext("\tremove <pool> <device>\n"));
21765cd9f28Seschrock 	case HELP_SCRUB:
21865cd9f28Seschrock 		return (gettext("\tscrub [-s] <pool> ...\n"));
21965cd9f28Seschrock 	case HELP_STATUS:
22065cd9f28Seschrock 		return (gettext("\tstatus [-vx] [pool] ...\n"));
221eaca9bbdSeschrock 	case HELP_UPGRADE:
222eaca9bbdSeschrock 		return (gettext("\tupgrade\n"
223eaca9bbdSeschrock 		    "\tupgrade -v\n"
224990b4856Slling 		    "\tupgrade [-V version] <-a | pool ...>\n"));
225b1b8ab34Slling 	case HELP_GET:
226e45ce728Sahrens 		return (gettext("\tget <\"all\" | property[,...]> "
227b1b8ab34Slling 		    "<pool> ...\n"));
228b1b8ab34Slling 	case HELP_SET:
229b1b8ab34Slling 		return (gettext("\tset <property=value> <pool> \n"));
23065cd9f28Seschrock 	}
23165cd9f28Seschrock 
23265cd9f28Seschrock 	abort();
23365cd9f28Seschrock 	/* NOTREACHED */
23465cd9f28Seschrock }
23565cd9f28Seschrock 
236fa9e4066Sahrens 
237fa9e4066Sahrens /*
238b1b8ab34Slling  * Callback routine that will print out a pool property value.
239b1b8ab34Slling  */
240990b4856Slling static int
241990b4856Slling print_prop_cb(int prop, void *cb)
242b1b8ab34Slling {
243b1b8ab34Slling 	FILE *fp = cb;
244b1b8ab34Slling 
245b1b8ab34Slling 	(void) fprintf(fp, "\t%-13s  ", zpool_prop_to_name(prop));
246b1b8ab34Slling 
247990b4856Slling 	if (zpool_prop_readonly(prop))
248990b4856Slling 		(void) fprintf(fp, "  NO   ");
249990b4856Slling 	else
250990b4856Slling 		(void) fprintf(fp, " YES    ");
251990b4856Slling 
252b1b8ab34Slling 	if (zpool_prop_values(prop) == NULL)
253b1b8ab34Slling 		(void) fprintf(fp, "-\n");
254b1b8ab34Slling 	else
255b1b8ab34Slling 		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
256b1b8ab34Slling 
257990b4856Slling 	return (ZPROP_CONT);
258b1b8ab34Slling }
259b1b8ab34Slling 
260b1b8ab34Slling /*
261fa9e4066Sahrens  * Display usage message.  If we're inside a command, display only the usage for
262fa9e4066Sahrens  * that command.  Otherwise, iterate over the entire command table and display
263fa9e4066Sahrens  * a complete usage message.
264fa9e4066Sahrens  */
265fa9e4066Sahrens void
26699653d4eSeschrock usage(boolean_t requested)
267fa9e4066Sahrens {
268fa9e4066Sahrens 	FILE *fp = requested ? stdout : stderr;
269fa9e4066Sahrens 
270fa9e4066Sahrens 	if (current_command == NULL) {
271fa9e4066Sahrens 		int i;
272fa9e4066Sahrens 
273fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
274fa9e4066Sahrens 		(void) fprintf(fp,
275fa9e4066Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
276fa9e4066Sahrens 
277fa9e4066Sahrens 		for (i = 0; i < NCOMMAND; i++) {
278fa9e4066Sahrens 			if (command_table[i].name == NULL)
279fa9e4066Sahrens 				(void) fprintf(fp, "\n");
280fa9e4066Sahrens 			else
281fa9e4066Sahrens 				(void) fprintf(fp, "%s",
28265cd9f28Seschrock 				    get_usage(command_table[i].usage));
283fa9e4066Sahrens 		}
284fa9e4066Sahrens 	} else {
285fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
28665cd9f28Seschrock 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
287fa9e4066Sahrens 	}
288fa9e4066Sahrens 
289b1b8ab34Slling 	if (current_command != NULL &&
290b1b8ab34Slling 	    ((strcmp(current_command->name, "set") == 0) ||
291990b4856Slling 	    (strcmp(current_command->name, "get") == 0) ||
292990b4856Slling 	    (strcmp(current_command->name, "list") == 0))) {
293b1b8ab34Slling 
294b1b8ab34Slling 		(void) fprintf(fp,
295b1b8ab34Slling 		    gettext("\nthe following properties are supported:\n"));
296b1b8ab34Slling 
297990b4856Slling 		(void) fprintf(fp, "\n\t%-13s  %s  %s\n\n",
298990b4856Slling 		    "PROPERTY", "EDIT", "VALUES");
299b1b8ab34Slling 
300b1b8ab34Slling 		/* Iterate over all properties */
301990b4856Slling 		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
302990b4856Slling 		    ZFS_TYPE_POOL);
303b1b8ab34Slling 	}
304b1b8ab34Slling 
305e9dbad6fSeschrock 	/*
306e9dbad6fSeschrock 	 * See comments at end of main().
307e9dbad6fSeschrock 	 */
308e9dbad6fSeschrock 	if (getenv("ZFS_ABORT") != NULL) {
309e9dbad6fSeschrock 		(void) printf("dumping core by request\n");
310e9dbad6fSeschrock 		abort();
311e9dbad6fSeschrock 	}
312e9dbad6fSeschrock 
313fa9e4066Sahrens 	exit(requested ? 0 : 2);
314fa9e4066Sahrens }
315fa9e4066Sahrens 
316fa9e4066Sahrens void
3178654d025Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
3188654d025Sperrin     boolean_t print_logs)
319fa9e4066Sahrens {
320fa9e4066Sahrens 	nvlist_t **child;
321fa9e4066Sahrens 	uint_t c, children;
322afefbcddSeschrock 	char *vname;
323fa9e4066Sahrens 
324fa9e4066Sahrens 	if (name != NULL)
325fa9e4066Sahrens 		(void) printf("\t%*s%s\n", indent, "", name);
326fa9e4066Sahrens 
327fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
328fa9e4066Sahrens 	    &child, &children) != 0)
329fa9e4066Sahrens 		return;
330fa9e4066Sahrens 
331afefbcddSeschrock 	for (c = 0; c < children; c++) {
3328654d025Sperrin 		uint64_t is_log = B_FALSE;
3338654d025Sperrin 
3348654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3358654d025Sperrin 		    &is_log);
3368654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
3378654d025Sperrin 			continue;
3388654d025Sperrin 
33999653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
3408654d025Sperrin 		print_vdev_tree(zhp, vname, child[c], indent + 2,
3418654d025Sperrin 		    B_FALSE);
342afefbcddSeschrock 		free(vname);
343afefbcddSeschrock 	}
344fa9e4066Sahrens }
345fa9e4066Sahrens 
346fa9e4066Sahrens /*
347990b4856Slling  * Add a property pair (name, string-value) into a property nvlist.
348990b4856Slling  */
349990b4856Slling static int
350990b4856Slling add_prop_list(const char *propname, char *propval, nvlist_t **props)
351990b4856Slling {
352990b4856Slling 	char *strval;
353990b4856Slling 	nvlist_t *proplist;
354990b4856Slling 	zpool_prop_t prop;
355990b4856Slling 
356990b4856Slling 	if (*props == NULL &&
357990b4856Slling 	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
358990b4856Slling 		(void) fprintf(stderr,
359990b4856Slling 		    gettext("internal error: out of memory\n"));
360990b4856Slling 		return (1);
361990b4856Slling 	}
362990b4856Slling 
363990b4856Slling 	proplist = *props;
364990b4856Slling 
365990b4856Slling 	if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
366990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' is "
367990b4856Slling 		    "not a valid pool property\n"), propname);
368990b4856Slling 		return (2);
369990b4856Slling 	}
370990b4856Slling 
371990b4856Slling 	/* Use normalized property name for nvlist operations */
372990b4856Slling 	if (nvlist_lookup_string(proplist, zpool_prop_to_name(prop),
3732f8aaab3Seschrock 	    &strval) == 0 && prop != ZPOOL_PROP_CACHEFILE) {
374990b4856Slling 		(void) fprintf(stderr, gettext("property '%s' "
375990b4856Slling 		    "specified multiple times\n"), propname);
376990b4856Slling 		return (2);
377990b4856Slling 	}
378990b4856Slling 
379990b4856Slling 	if (nvlist_add_string(proplist, zpool_prop_to_name(prop),
380990b4856Slling 	    propval) != 0) {
381990b4856Slling 		(void) fprintf(stderr, gettext("internal "
382990b4856Slling 		    "error: out of memory\n"));
383990b4856Slling 		return (1);
384990b4856Slling 	}
385990b4856Slling 
386990b4856Slling 	return (0);
387990b4856Slling }
388990b4856Slling 
389990b4856Slling /*
390fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
391fa9e4066Sahrens  *
392fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
393fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
394fa9e4066Sahrens  *		they were to be added.
395fa9e4066Sahrens  *
396fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
397fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
398fa9e4066Sahrens  * libzfs.
399fa9e4066Sahrens  */
400fa9e4066Sahrens int
401fa9e4066Sahrens zpool_do_add(int argc, char **argv)
402fa9e4066Sahrens {
40399653d4eSeschrock 	boolean_t force = B_FALSE;
40499653d4eSeschrock 	boolean_t dryrun = B_FALSE;
405fa9e4066Sahrens 	int c;
406fa9e4066Sahrens 	nvlist_t *nvroot;
407fa9e4066Sahrens 	char *poolname;
408fa9e4066Sahrens 	int ret;
409fa9e4066Sahrens 	zpool_handle_t *zhp;
410fa9e4066Sahrens 	nvlist_t *config;
411fa9e4066Sahrens 
412fa9e4066Sahrens 	/* check options */
413fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
414fa9e4066Sahrens 		switch (c) {
415fa9e4066Sahrens 		case 'f':
41699653d4eSeschrock 			force = B_TRUE;
417fa9e4066Sahrens 			break;
418fa9e4066Sahrens 		case 'n':
41999653d4eSeschrock 			dryrun = B_TRUE;
420fa9e4066Sahrens 			break;
421fa9e4066Sahrens 		case '?':
422fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
423fa9e4066Sahrens 			    optopt);
42499653d4eSeschrock 			usage(B_FALSE);
425fa9e4066Sahrens 		}
426fa9e4066Sahrens 	}
427fa9e4066Sahrens 
428fa9e4066Sahrens 	argc -= optind;
429fa9e4066Sahrens 	argv += optind;
430fa9e4066Sahrens 
431fa9e4066Sahrens 	/* get pool name and check number of arguments */
432fa9e4066Sahrens 	if (argc < 1) {
433fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
43499653d4eSeschrock 		usage(B_FALSE);
435fa9e4066Sahrens 	}
436fa9e4066Sahrens 	if (argc < 2) {
437fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
43899653d4eSeschrock 		usage(B_FALSE);
439fa9e4066Sahrens 	}
440fa9e4066Sahrens 
441fa9e4066Sahrens 	poolname = argv[0];
442fa9e4066Sahrens 
443fa9e4066Sahrens 	argc--;
444fa9e4066Sahrens 	argv++;
445fa9e4066Sahrens 
44699653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
447fa9e4066Sahrens 		return (1);
448fa9e4066Sahrens 
449088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
450fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
451fa9e4066Sahrens 		    poolname);
452fa9e4066Sahrens 		zpool_close(zhp);
453fa9e4066Sahrens 		return (1);
454fa9e4066Sahrens 	}
455fa9e4066Sahrens 
456fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
4578488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, argc, argv);
458fa9e4066Sahrens 	if (nvroot == NULL) {
459fa9e4066Sahrens 		zpool_close(zhp);
460fa9e4066Sahrens 		return (1);
461fa9e4066Sahrens 	}
462fa9e4066Sahrens 
463fa9e4066Sahrens 	if (dryrun) {
464fa9e4066Sahrens 		nvlist_t *poolnvroot;
465fa9e4066Sahrens 
466fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
467fa9e4066Sahrens 		    &poolnvroot) == 0);
468fa9e4066Sahrens 
469fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
470fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
471fa9e4066Sahrens 
4728654d025Sperrin 		/* print original main pool and new tree */
4738654d025Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
4748654d025Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
4758654d025Sperrin 
4768654d025Sperrin 		/* Do the same for the logs */
4778654d025Sperrin 		if (num_logs(poolnvroot) > 0) {
4788654d025Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
4798654d025Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
4808654d025Sperrin 		} else if (num_logs(nvroot) > 0) {
4818654d025Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
4828654d025Sperrin 		}
483fa9e4066Sahrens 
484fa9e4066Sahrens 		ret = 0;
485fa9e4066Sahrens 	} else {
486fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
487fa9e4066Sahrens 	}
488fa9e4066Sahrens 
48999653d4eSeschrock 	nvlist_free(nvroot);
49099653d4eSeschrock 	zpool_close(zhp);
49199653d4eSeschrock 
49299653d4eSeschrock 	return (ret);
49399653d4eSeschrock }
49499653d4eSeschrock 
49599653d4eSeschrock /*
49699653d4eSeschrock  * zpool remove <pool> <vdev>
49799653d4eSeschrock  *
49899653d4eSeschrock  * Removes the given vdev from the pool.  Currently, this only supports removing
49999653d4eSeschrock  * spares from the pool.  Eventually, we'll want to support removing leaf vdevs
50099653d4eSeschrock  * (as an alias for 'detach') as well as toplevel vdevs.
50199653d4eSeschrock  */
50299653d4eSeschrock int
50399653d4eSeschrock zpool_do_remove(int argc, char **argv)
50499653d4eSeschrock {
50599653d4eSeschrock 	char *poolname;
50699653d4eSeschrock 	int ret;
50799653d4eSeschrock 	zpool_handle_t *zhp;
50899653d4eSeschrock 
50999653d4eSeschrock 	argc--;
51099653d4eSeschrock 	argv++;
51199653d4eSeschrock 
51299653d4eSeschrock 	/* get pool name and check number of arguments */
51399653d4eSeschrock 	if (argc < 1) {
51499653d4eSeschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
51599653d4eSeschrock 		usage(B_FALSE);
51699653d4eSeschrock 	}
51799653d4eSeschrock 	if (argc < 2) {
51899653d4eSeschrock 		(void) fprintf(stderr, gettext("missing device\n"));
51999653d4eSeschrock 		usage(B_FALSE);
52099653d4eSeschrock 	}
52199653d4eSeschrock 
52299653d4eSeschrock 	poolname = argv[0];
52399653d4eSeschrock 
52499653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
52599653d4eSeschrock 		return (1);
52699653d4eSeschrock 
52799653d4eSeschrock 	ret = (zpool_vdev_remove(zhp, argv[1]) != 0);
52899653d4eSeschrock 
529fa9e4066Sahrens 	return (ret);
530fa9e4066Sahrens }
531fa9e4066Sahrens 
532fa9e4066Sahrens /*
533990b4856Slling  * zpool create [-fn] [-o property=value] ... [-R root] [-m mountpoint]
534990b4856Slling  *		<pool> <dev> ...
535fa9e4066Sahrens  *
536fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
537fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
538fa9e4066Sahrens  *		were to be created.
539fa9e4066Sahrens  *      -R	Create a pool under an alternate root
540fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
541fa9e4066Sahrens  *      	'/<pool>'
542990b4856Slling  *	-o	Set property=value.
543fa9e4066Sahrens  *
544b1b8ab34Slling  * Creates the named pool according to the given vdev specification.  The
545fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
546fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
547fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
548fa9e4066Sahrens  */
549fa9e4066Sahrens int
550fa9e4066Sahrens zpool_do_create(int argc, char **argv)
551fa9e4066Sahrens {
55299653d4eSeschrock 	boolean_t force = B_FALSE;
55399653d4eSeschrock 	boolean_t dryrun = B_FALSE;
554fa9e4066Sahrens 	int c;
555990b4856Slling 	nvlist_t *nvroot = NULL;
556fa9e4066Sahrens 	char *poolname;
557990b4856Slling 	int ret = 1;
558fa9e4066Sahrens 	char *altroot = NULL;
559fa9e4066Sahrens 	char *mountpoint = NULL;
56099653d4eSeschrock 	nvlist_t **child;
56199653d4eSeschrock 	uint_t children;
562990b4856Slling 	nvlist_t *props = NULL;
5632f8aaab3Seschrock 	char *propval;
564fa9e4066Sahrens 
565fa9e4066Sahrens 	/* check options */
566990b4856Slling 	while ((c = getopt(argc, argv, ":fnR:m:o:")) != -1) {
567fa9e4066Sahrens 		switch (c) {
568fa9e4066Sahrens 		case 'f':
56999653d4eSeschrock 			force = B_TRUE;
570fa9e4066Sahrens 			break;
571fa9e4066Sahrens 		case 'n':
57299653d4eSeschrock 			dryrun = B_TRUE;
573fa9e4066Sahrens 			break;
574fa9e4066Sahrens 		case 'R':
575fa9e4066Sahrens 			altroot = optarg;
576990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
577990b4856Slling 			    ZPOOL_PROP_ALTROOT), optarg, &props))
578990b4856Slling 				goto errout;
5792f8aaab3Seschrock 			if (nvlist_lookup_string(props,
5802f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
5812f8aaab3Seschrock 			    &propval) == 0)
5822f8aaab3Seschrock 				break;
583990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
5842f8aaab3Seschrock 			    ZPOOL_PROP_CACHEFILE), "none", &props))
585990b4856Slling 				goto errout;
586fa9e4066Sahrens 			break;
587fa9e4066Sahrens 		case 'm':
588fa9e4066Sahrens 			mountpoint = optarg;
589fa9e4066Sahrens 			break;
590990b4856Slling 		case 'o':
591990b4856Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
592990b4856Slling 				(void) fprintf(stderr, gettext("missing "
593990b4856Slling 				    "'=' for -o option\n"));
594990b4856Slling 				goto errout;
595990b4856Slling 			}
596990b4856Slling 			*propval = '\0';
597990b4856Slling 			propval++;
598990b4856Slling 
599990b4856Slling 			if (add_prop_list(optarg, propval, &props))
600990b4856Slling 				goto errout;
601990b4856Slling 			break;
602fa9e4066Sahrens 		case ':':
603fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
604fa9e4066Sahrens 			    "'%c' option\n"), optopt);
605990b4856Slling 			goto badusage;
606fa9e4066Sahrens 		case '?':
607fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
608fa9e4066Sahrens 			    optopt);
609990b4856Slling 			goto badusage;
610fa9e4066Sahrens 		}
611fa9e4066Sahrens 	}
612fa9e4066Sahrens 
613fa9e4066Sahrens 	argc -= optind;
614fa9e4066Sahrens 	argv += optind;
615fa9e4066Sahrens 
616fa9e4066Sahrens 	/* get pool name and check number of arguments */
617fa9e4066Sahrens 	if (argc < 1) {
618fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
619990b4856Slling 		goto badusage;
620fa9e4066Sahrens 	}
621fa9e4066Sahrens 	if (argc < 2) {
622fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
623990b4856Slling 		goto badusage;
624fa9e4066Sahrens 	}
625fa9e4066Sahrens 
626fa9e4066Sahrens 	poolname = argv[0];
627fa9e4066Sahrens 
628fa9e4066Sahrens 	/*
629fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
630fa9e4066Sahrens 	 * user to use 'zfs create' instead.
631fa9e4066Sahrens 	 */
632fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
633fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
634fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
635fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
636fa9e4066Sahrens 		    "create a dataset\n"));
637990b4856Slling 		goto errout;
638fa9e4066Sahrens 	}
639fa9e4066Sahrens 
640fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
64199653d4eSeschrock 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, argc - 1,
64299653d4eSeschrock 	    argv + 1);
643fa9e4066Sahrens 	if (nvroot == NULL)
644fa9e4066Sahrens 		return (1);
645fa9e4066Sahrens 
64699653d4eSeschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
64799653d4eSeschrock 	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
64899653d4eSeschrock 	    &child, &children) == 0);
64999653d4eSeschrock 	if (children == 0) {
65099653d4eSeschrock 		(void) fprintf(stderr, gettext("invalid vdev "
65199653d4eSeschrock 		    "specification: at least one toplevel vdev must be "
65299653d4eSeschrock 		    "specified\n"));
653990b4856Slling 		goto errout;
65499653d4eSeschrock 	}
65599653d4eSeschrock 
65699653d4eSeschrock 
657fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
658fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
659e9dbad6fSeschrock 		    "must be an absolute path\n"), altroot);
660990b4856Slling 		goto errout;
661fa9e4066Sahrens 	}
662fa9e4066Sahrens 
663fa9e4066Sahrens 	/*
664fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
665fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
666fa9e4066Sahrens 	 */
667fa9e4066Sahrens 	if (mountpoint == NULL ||
668fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
669fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
670fa9e4066Sahrens 		char buf[MAXPATHLEN];
671fa9e4066Sahrens 		struct stat64 statbuf;
672fa9e4066Sahrens 
673fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
674fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
675fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
676fa9e4066Sahrens 			    "'none'\n"), mountpoint);
677990b4856Slling 			goto errout;
678fa9e4066Sahrens 		}
679fa9e4066Sahrens 
680fa9e4066Sahrens 		if (mountpoint == NULL) {
681fa9e4066Sahrens 			if (altroot != NULL)
682fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
683fa9e4066Sahrens 				    altroot, poolname);
684fa9e4066Sahrens 			else
685fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
686fa9e4066Sahrens 				    poolname);
687fa9e4066Sahrens 		} else {
688fa9e4066Sahrens 			if (altroot != NULL)
689fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
690fa9e4066Sahrens 				    altroot, mountpoint);
691fa9e4066Sahrens 			else
692fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
693fa9e4066Sahrens 				    mountpoint);
694fa9e4066Sahrens 		}
695fa9e4066Sahrens 
696fa9e4066Sahrens 		if (stat64(buf, &statbuf) == 0 &&
697fa9e4066Sahrens 		    statbuf.st_nlink != 2) {
698fa9e4066Sahrens 			if (mountpoint == NULL)
699fa9e4066Sahrens 				(void) fprintf(stderr, gettext("default "
700fa9e4066Sahrens 				    "mountpoint '%s' exists and is not "
701fa9e4066Sahrens 				    "empty\n"), buf);
702fa9e4066Sahrens 			else
703fa9e4066Sahrens 				(void) fprintf(stderr, gettext("mountpoint "
704fa9e4066Sahrens 				    "'%s' exists and is not empty\n"), buf);
705fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
706fa9e4066Sahrens 			    "option to provide a different default\n"));
707990b4856Slling 			goto errout;
708fa9e4066Sahrens 		}
709fa9e4066Sahrens 	}
710fa9e4066Sahrens 
711fa9e4066Sahrens 	if (dryrun) {
712fa9e4066Sahrens 		/*
713fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
714fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
715fa9e4066Sahrens 		 * appropriate hierarchy.
716fa9e4066Sahrens 		 */
717fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
718fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
719fa9e4066Sahrens 
7208654d025Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7218654d025Sperrin 		if (num_logs(nvroot) > 0)
7228654d025Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
723fa9e4066Sahrens 
724fa9e4066Sahrens 		ret = 0;
725fa9e4066Sahrens 	} else {
726fa9e4066Sahrens 		/*
727fa9e4066Sahrens 		 * Hand off to libzfs.
728fa9e4066Sahrens 		 */
729990b4856Slling 		if (zpool_create(g_zfs, poolname, nvroot, props) == 0) {
73099653d4eSeschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
731fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
732fa9e4066Sahrens 			if (pool != NULL) {
733fa9e4066Sahrens 				if (mountpoint != NULL)
734fa9e4066Sahrens 					verify(zfs_prop_set(pool,
735e9dbad6fSeschrock 					    zfs_prop_to_name(
736e9dbad6fSeschrock 					    ZFS_PROP_MOUNTPOINT),
737fa9e4066Sahrens 					    mountpoint) == 0);
738fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
739da6c28aaSamw 					ret = zfs_shareall(pool);
740fa9e4066Sahrens 				zfs_close(pool);
741fa9e4066Sahrens 			}
74299653d4eSeschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
74399653d4eSeschrock 			(void) fprintf(stderr, gettext("pool name may have "
74499653d4eSeschrock 			    "been omitted\n"));
745fa9e4066Sahrens 		}
746fa9e4066Sahrens 	}
747fa9e4066Sahrens 
748990b4856Slling errout:
749fa9e4066Sahrens 	nvlist_free(nvroot);
750990b4856Slling 	nvlist_free(props);
751fa9e4066Sahrens 	return (ret);
752990b4856Slling badusage:
753990b4856Slling 	nvlist_free(props);
754990b4856Slling 	usage(B_FALSE);
755990b4856Slling 	return (2);
756fa9e4066Sahrens }
757fa9e4066Sahrens 
758fa9e4066Sahrens /*
759fa9e4066Sahrens  * zpool destroy <pool>
760fa9e4066Sahrens  *
761fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
762fa9e4066Sahrens  *
763fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
764fa9e4066Sahrens  */
765fa9e4066Sahrens int
766fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
767fa9e4066Sahrens {
76899653d4eSeschrock 	boolean_t force = B_FALSE;
769fa9e4066Sahrens 	int c;
770fa9e4066Sahrens 	char *pool;
771fa9e4066Sahrens 	zpool_handle_t *zhp;
772fa9e4066Sahrens 	int ret;
773fa9e4066Sahrens 
774fa9e4066Sahrens 	/* check options */
775fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
776fa9e4066Sahrens 		switch (c) {
777fa9e4066Sahrens 		case 'f':
77899653d4eSeschrock 			force = B_TRUE;
779fa9e4066Sahrens 			break;
780fa9e4066Sahrens 		case '?':
781fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
782fa9e4066Sahrens 			    optopt);
78399653d4eSeschrock 			usage(B_FALSE);
784fa9e4066Sahrens 		}
785fa9e4066Sahrens 	}
786fa9e4066Sahrens 
787fa9e4066Sahrens 	argc -= optind;
788fa9e4066Sahrens 	argv += optind;
789fa9e4066Sahrens 
790fa9e4066Sahrens 	/* check arguments */
791fa9e4066Sahrens 	if (argc < 1) {
792fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
79399653d4eSeschrock 		usage(B_FALSE);
794fa9e4066Sahrens 	}
795fa9e4066Sahrens 	if (argc > 1) {
796fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
79799653d4eSeschrock 		usage(B_FALSE);
798fa9e4066Sahrens 	}
799fa9e4066Sahrens 
800fa9e4066Sahrens 	pool = argv[0];
801fa9e4066Sahrens 
80299653d4eSeschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
803fa9e4066Sahrens 		/*
804fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
805fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
806fa9e4066Sahrens 		 */
807fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
808fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
809fa9e4066Sahrens 			    "destroy a dataset\n"));
810fa9e4066Sahrens 		return (1);
811fa9e4066Sahrens 	}
812fa9e4066Sahrens 
813f3861e1aSahl 	if (zpool_disable_datasets(zhp, force) != 0) {
814fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
815fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
816fa9e4066Sahrens 		return (1);
817fa9e4066Sahrens 	}
818fa9e4066Sahrens 
819fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
820fa9e4066Sahrens 
821fa9e4066Sahrens 	zpool_close(zhp);
822fa9e4066Sahrens 
823fa9e4066Sahrens 	return (ret);
824fa9e4066Sahrens }
825fa9e4066Sahrens 
826fa9e4066Sahrens /*
827fa9e4066Sahrens  * zpool export [-f] <pool> ...
828fa9e4066Sahrens  *
829fa9e4066Sahrens  *	-f	Forcefully unmount datasets
830fa9e4066Sahrens  *
831b1b8ab34Slling  * Export the given pools.  By default, the command will attempt to cleanly
832fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
833fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
834fa9e4066Sahrens  */
835fa9e4066Sahrens int
836fa9e4066Sahrens zpool_do_export(int argc, char **argv)
837fa9e4066Sahrens {
83899653d4eSeschrock 	boolean_t force = B_FALSE;
839fa9e4066Sahrens 	int c;
840fa9e4066Sahrens 	zpool_handle_t *zhp;
841fa9e4066Sahrens 	int ret;
842fa9e4066Sahrens 	int i;
843fa9e4066Sahrens 
844fa9e4066Sahrens 	/* check options */
845fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
846fa9e4066Sahrens 		switch (c) {
847fa9e4066Sahrens 		case 'f':
84899653d4eSeschrock 			force = B_TRUE;
849fa9e4066Sahrens 			break;
850fa9e4066Sahrens 		case '?':
851fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
852fa9e4066Sahrens 			    optopt);
85399653d4eSeschrock 			usage(B_FALSE);
854fa9e4066Sahrens 		}
855fa9e4066Sahrens 	}
856fa9e4066Sahrens 
857fa9e4066Sahrens 	argc -= optind;
858fa9e4066Sahrens 	argv += optind;
859fa9e4066Sahrens 
860fa9e4066Sahrens 	/* check arguments */
861fa9e4066Sahrens 	if (argc < 1) {
862fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
86399653d4eSeschrock 		usage(B_FALSE);
864fa9e4066Sahrens 	}
865fa9e4066Sahrens 
866fa9e4066Sahrens 	ret = 0;
867fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
86899653d4eSeschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
869fa9e4066Sahrens 			ret = 1;
870fa9e4066Sahrens 			continue;
871fa9e4066Sahrens 		}
872fa9e4066Sahrens 
873f3861e1aSahl 		if (zpool_disable_datasets(zhp, force) != 0) {
874fa9e4066Sahrens 			ret = 1;
875fa9e4066Sahrens 			zpool_close(zhp);
876fa9e4066Sahrens 			continue;
877fa9e4066Sahrens 		}
878fa9e4066Sahrens 
879fa9e4066Sahrens 		if (zpool_export(zhp) != 0)
880fa9e4066Sahrens 			ret = 1;
881fa9e4066Sahrens 
882fa9e4066Sahrens 		zpool_close(zhp);
883fa9e4066Sahrens 	}
884fa9e4066Sahrens 
885fa9e4066Sahrens 	return (ret);
886fa9e4066Sahrens }
887fa9e4066Sahrens 
888fa9e4066Sahrens /*
889fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
890fa9e4066Sahrens  * name column.
891fa9e4066Sahrens  */
892fa9e4066Sahrens static int
893c67d9675Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
894fa9e4066Sahrens {
89599653d4eSeschrock 	char *name = zpool_vdev_name(g_zfs, zhp, nv);
896fa9e4066Sahrens 	nvlist_t **child;
897fa9e4066Sahrens 	uint_t c, children;
898fa9e4066Sahrens 	int ret;
899fa9e4066Sahrens 
900fa9e4066Sahrens 	if (strlen(name) + depth > max)
901fa9e4066Sahrens 		max = strlen(name) + depth;
902fa9e4066Sahrens 
903afefbcddSeschrock 	free(name);
904afefbcddSeschrock 
90599653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
90699653d4eSeschrock 	    &child, &children) == 0) {
907fa9e4066Sahrens 		for (c = 0; c < children; c++)
90899653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
90999653d4eSeschrock 			    max)) > max)
910fa9e4066Sahrens 				max = ret;
91199653d4eSeschrock 	}
91299653d4eSeschrock 
91399653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
91499653d4eSeschrock 	    &child, &children) == 0) {
91599653d4eSeschrock 		for (c = 0; c < children; c++)
91699653d4eSeschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
91799653d4eSeschrock 			    max)) > max)
91899653d4eSeschrock 				max = ret;
91999653d4eSeschrock 	}
92099653d4eSeschrock 
921fa9e4066Sahrens 
922fa9e4066Sahrens 	return (max);
923fa9e4066Sahrens }
924fa9e4066Sahrens 
925fa9e4066Sahrens 
926fa9e4066Sahrens /*
927fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
928fa9e4066Sahrens  * pool, printing out the name and status for each one.
929fa9e4066Sahrens  */
930fa9e4066Sahrens void
9318654d025Sperrin print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
9328654d025Sperrin     boolean_t print_logs)
933fa9e4066Sahrens {
934fa9e4066Sahrens 	nvlist_t **child;
935fa9e4066Sahrens 	uint_t c, children;
936fa9e4066Sahrens 	vdev_stat_t *vs;
937afefbcddSeschrock 	char *type, *vname;
938fa9e4066Sahrens 
939fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
940fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
941fa9e4066Sahrens 		return;
942fa9e4066Sahrens 
943fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
944fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
945fa9e4066Sahrens 
946fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
947990b4856Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
948fa9e4066Sahrens 
949fa9e4066Sahrens 	if (vs->vs_aux != 0) {
9503d7072f8Seschrock 		(void) printf("  ");
951fa9e4066Sahrens 
952fa9e4066Sahrens 		switch (vs->vs_aux) {
953fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
954fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
955fa9e4066Sahrens 			break;
956fa9e4066Sahrens 
957fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
958fa9e4066Sahrens 			(void) printf(gettext("missing device"));
959fa9e4066Sahrens 			break;
960fa9e4066Sahrens 
961fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
962fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
963fa9e4066Sahrens 			break;
964fa9e4066Sahrens 
965eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
966eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
967eaca9bbdSeschrock 			break;
968eaca9bbdSeschrock 
9693d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
9703d7072f8Seschrock 			(void) printf(gettext("too many errors"));
9713d7072f8Seschrock 			break;
9723d7072f8Seschrock 
973fa9e4066Sahrens 		default:
974fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
975fa9e4066Sahrens 			break;
976fa9e4066Sahrens 		}
977fa9e4066Sahrens 	}
978fa9e4066Sahrens 	(void) printf("\n");
979fa9e4066Sahrens 
980fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
981fa9e4066Sahrens 	    &child, &children) != 0)
982fa9e4066Sahrens 		return;
983fa9e4066Sahrens 
984afefbcddSeschrock 	for (c = 0; c < children; c++) {
9858654d025Sperrin 		uint64_t is_log = B_FALSE;
9868654d025Sperrin 
9878654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
9888654d025Sperrin 		    &is_log);
9898654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
9908654d025Sperrin 			continue;
9918654d025Sperrin 
99299653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
993afefbcddSeschrock 		print_import_config(vname, child[c],
9948654d025Sperrin 		    namewidth, depth + 2, B_FALSE);
995afefbcddSeschrock 		free(vname);
996afefbcddSeschrock 	}
99799653d4eSeschrock 
99899653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
99999653d4eSeschrock 	    &child, &children) != 0)
100099653d4eSeschrock 		return;
100199653d4eSeschrock 
100299653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
100399653d4eSeschrock 	for (c = 0; c < children; c++) {
100499653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
100599653d4eSeschrock 		(void) printf("\t  %s\n", vname);
100699653d4eSeschrock 		free(vname);
100799653d4eSeschrock 	}
1008fa9e4066Sahrens }
1009fa9e4066Sahrens 
1010fa9e4066Sahrens /*
1011fa9e4066Sahrens  * Display the status for the given pool.
1012fa9e4066Sahrens  */
1013fa9e4066Sahrens static void
1014fa9e4066Sahrens show_import(nvlist_t *config)
1015fa9e4066Sahrens {
1016fa9e4066Sahrens 	uint64_t pool_state;
1017fa9e4066Sahrens 	vdev_stat_t *vs;
1018fa9e4066Sahrens 	char *name;
1019fa9e4066Sahrens 	uint64_t guid;
1020fa9e4066Sahrens 	char *msgid;
1021fa9e4066Sahrens 	nvlist_t *nvroot;
1022fa9e4066Sahrens 	int reason;
102346657f8dSmmusante 	const char *health;
1024fa9e4066Sahrens 	uint_t vsc;
1025fa9e4066Sahrens 	int namewidth;
1026fa9e4066Sahrens 
1027fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1028fa9e4066Sahrens 	    &name) == 0);
1029fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1030fa9e4066Sahrens 	    &guid) == 0);
1031fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1032fa9e4066Sahrens 	    &pool_state) == 0);
1033fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1034fa9e4066Sahrens 	    &nvroot) == 0);
1035fa9e4066Sahrens 
1036fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1037fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
1038990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1039fa9e4066Sahrens 
1040fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
1041fa9e4066Sahrens 
104246657f8dSmmusante 	(void) printf(gettext("  pool: %s\n"), name);
104346657f8dSmmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
104446657f8dSmmusante 	(void) printf(gettext(" state: %s"), health);
10454c58d714Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
104646657f8dSmmusante 		(void) printf(gettext(" (DESTROYED)"));
10474c58d714Sdarrenm 	(void) printf("\n");
1048fa9e4066Sahrens 
1049fa9e4066Sahrens 	switch (reason) {
1050fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1051fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1052fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1053fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1054fa9e4066Sahrens 		    "from the system.\n"));
1055fa9e4066Sahrens 		break;
1056fa9e4066Sahrens 
1057fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1058fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1059fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
1060fa9e4066Sahrens 		    "corrupted data.\n"));
1061fa9e4066Sahrens 		break;
1062fa9e4066Sahrens 
1063fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1064fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1065fa9e4066Sahrens 		break;
1066fa9e4066Sahrens 
1067441d80aaSlling 	case ZPOOL_STATUS_OFFLINE_DEV:
1068441d80aaSlling 		(void) printf(gettext("status: One or more devices "
1069441d80aaSlling 		    "are offlined.\n"));
1070441d80aaSlling 		break;
1071441d80aaSlling 
1072ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
1073ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is "
1074ea8dc4b6Seschrock 		    "corrupted.\n"));
1075ea8dc4b6Seschrock 		break;
1076ea8dc4b6Seschrock 
1077eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
1078eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1079eaca9bbdSeschrock 		    "older on-disk version.\n"));
1080eaca9bbdSeschrock 		break;
1081eaca9bbdSeschrock 
1082eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
1083eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
1084eaca9bbdSeschrock 		    "incompatible version.\n"));
1085eaca9bbdSeschrock 		break;
108695173954Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
108795173954Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
108895173954Sek110237 		    "another system.\n"));
108995173954Sek110237 		break;
10903d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
10913d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
10923d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
10933d7072f8Seschrock 		    "faulted.\n"));
10943d7072f8Seschrock 		break;
10953d7072f8Seschrock 
1096fa9e4066Sahrens 	default:
1097fa9e4066Sahrens 		/*
1098fa9e4066Sahrens 		 * No other status can be seen when importing pools.
1099fa9e4066Sahrens 		 */
1100fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1101fa9e4066Sahrens 	}
1102fa9e4066Sahrens 
1103fa9e4066Sahrens 	/*
1104fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
1105fa9e4066Sahrens 	 */
110646657f8dSmmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1107eaca9bbdSeschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1108eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1109eaca9bbdSeschrock 			    "imported using its name or numeric identifier, "
1110eaca9bbdSeschrock 			    "though\n\tsome features will not be available "
1111eaca9bbdSeschrock 			    "without an explicit 'zpool upgrade'.\n"));
111295173954Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
111395173954Sek110237 			(void) printf(gettext("action: The pool can be "
111495173954Sek110237 			    "imported using its name or numeric "
111595173954Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1116fa9e4066Sahrens 		else
1117eaca9bbdSeschrock 			(void) printf(gettext("action: The pool can be "
1118eaca9bbdSeschrock 			    "imported using its name or numeric "
1119eaca9bbdSeschrock 			    "identifier.\n"));
112046657f8dSmmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1121fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
1122fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
1123eaca9bbdSeschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1124fa9e4066Sahrens 	} else {
1125eaca9bbdSeschrock 		switch (reason) {
1126eaca9bbdSeschrock 		case ZPOOL_STATUS_VERSION_NEWER:
1127eaca9bbdSeschrock 			(void) printf(gettext("action: The pool cannot be "
1128eaca9bbdSeschrock 			    "imported.  Access the pool on a system running "
1129eaca9bbdSeschrock 			    "newer\n\tsoftware, or recreate the pool from "
1130eaca9bbdSeschrock 			    "backup.\n"));
1131eaca9bbdSeschrock 			break;
1132eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
1133eaca9bbdSeschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
1134eaca9bbdSeschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1135fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1136fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1137fa9e4066Sahrens 			    "again.\n"));
1138eaca9bbdSeschrock 			break;
1139eaca9bbdSeschrock 		default:
1140fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
1141fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
1142fa9e4066Sahrens 		}
1143eaca9bbdSeschrock 	}
1144eaca9bbdSeschrock 
114546657f8dSmmusante 	/*
114646657f8dSmmusante 	 * If the state is "closed" or "can't open", and the aux state
114746657f8dSmmusante 	 * is "corrupt data":
114846657f8dSmmusante 	 */
114946657f8dSmmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
115046657f8dSmmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
115146657f8dSmmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1152eaca9bbdSeschrock 		if (pool_state == POOL_STATE_DESTROYED)
1153eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool was destroyed, "
1154eaca9bbdSeschrock 			    "but can be imported using the '-Df' flags.\n"));
1155eaca9bbdSeschrock 		else if (pool_state != POOL_STATE_EXPORTED)
1156eaca9bbdSeschrock 			(void) printf(gettext("\tThe pool may be active on "
1157eaca9bbdSeschrock 			    "on another system, but can be imported using\n\t"
1158eaca9bbdSeschrock 			    "the '-f' flag.\n"));
1159eaca9bbdSeschrock 	}
1160fa9e4066Sahrens 
1161fa9e4066Sahrens 	if (msgid != NULL)
1162fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1163fa9e4066Sahrens 		    msgid);
1164fa9e4066Sahrens 
1165fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
1166fa9e4066Sahrens 
1167c67d9675Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1168fa9e4066Sahrens 	if (namewidth < 10)
1169fa9e4066Sahrens 		namewidth = 10;
11708654d025Sperrin 
11718654d025Sperrin 	print_import_config(name, nvroot, namewidth, 0, B_FALSE);
11728654d025Sperrin 	if (num_logs(nvroot) > 0) {
11738654d025Sperrin 		(void) printf(gettext("\tlogs\n"));
11748654d025Sperrin 		print_import_config(name, nvroot, namewidth, 0, B_TRUE);
11758654d025Sperrin 	}
1176fa9e4066Sahrens 
1177fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
117846657f8dSmmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1179fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
118046657f8dSmmusante 		    "configuration cannot be determined.\n"));
1181fa9e4066Sahrens 	}
1182fa9e4066Sahrens }
1183fa9e4066Sahrens 
1184fa9e4066Sahrens /*
1185fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
1186990b4856Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
1187990b4856Slling  * within the pool.
1188fa9e4066Sahrens  */
1189fa9e4066Sahrens static int
1190fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
1191990b4856Slling     int force, nvlist_t *props)
1192fa9e4066Sahrens {
1193fa9e4066Sahrens 	zpool_handle_t *zhp;
1194fa9e4066Sahrens 	char *name;
1195fa9e4066Sahrens 	uint64_t state;
1196eaca9bbdSeschrock 	uint64_t version;
1197ecd6cf80Smarks 	int error = 0;
1198fa9e4066Sahrens 
1199fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1200fa9e4066Sahrens 	    &name) == 0);
1201fa9e4066Sahrens 
1202fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
1203fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1204eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config,
1205eaca9bbdSeschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
1206e7437265Sahrens 	if (version > SPA_VERSION) {
1207eaca9bbdSeschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1208eaca9bbdSeschrock 		    "is formatted using a newer ZFS version\n"), name);
1209eaca9bbdSeschrock 		return (1);
1210eaca9bbdSeschrock 	} else if (state != POOL_STATE_EXPORTED && !force) {
121195173954Sek110237 		uint64_t hostid;
121295173954Sek110237 
121395173954Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
121495173954Sek110237 		    &hostid) == 0) {
121595173954Sek110237 			if ((unsigned long)hostid != gethostid()) {
121695173954Sek110237 				char *hostname;
121795173954Sek110237 				uint64_t timestamp;
121895173954Sek110237 				time_t t;
121995173954Sek110237 
122095173954Sek110237 				verify(nvlist_lookup_string(config,
122195173954Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
122295173954Sek110237 				verify(nvlist_lookup_uint64(config,
122395173954Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
122495173954Sek110237 				t = timestamp;
122595173954Sek110237 				(void) fprintf(stderr, gettext("cannot import "
122695173954Sek110237 				    "'%s': pool may be in use from other "
122795173954Sek110237 				    "system, it was last accessed by %s "
122895173954Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
122995173954Sek110237 				    (unsigned long)hostid,
123095173954Sek110237 				    asctime(localtime(&t)));
123195173954Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
123295173954Sek110237 				    "import anyway\n"));
1233fa9e4066Sahrens 				return (1);
1234fa9e4066Sahrens 			}
123595173954Sek110237 		} else {
123695173954Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
123795173954Sek110237 			    "pool may be in use from other system\n"), name);
123895173954Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
123995173954Sek110237 			    "anyway\n"));
124095173954Sek110237 			return (1);
124195173954Sek110237 		}
124295173954Sek110237 	}
1243fa9e4066Sahrens 
1244990b4856Slling 	if (zpool_import_props(g_zfs, config, newname, props) != 0)
1245fa9e4066Sahrens 		return (1);
1246fa9e4066Sahrens 
1247fa9e4066Sahrens 	if (newname != NULL)
1248fa9e4066Sahrens 		name = (char *)newname;
1249fa9e4066Sahrens 
125099653d4eSeschrock 	verify((zhp = zpool_open(g_zfs, name)) != NULL);
1251fa9e4066Sahrens 
1252f3861e1aSahl 	if (zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1253fa9e4066Sahrens 		zpool_close(zhp);
1254fa9e4066Sahrens 		return (1);
1255fa9e4066Sahrens 	}
1256fa9e4066Sahrens 
1257fa9e4066Sahrens 	zpool_close(zhp);
1258ecd6cf80Smarks 	return (error);
1259fa9e4066Sahrens }
1260fa9e4066Sahrens 
1261fa9e4066Sahrens /*
12624c58d714Sdarrenm  * zpool import [-d dir] [-D]
12632f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
12642f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] -a
12652f8aaab3Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
12662f8aaab3Seschrock  *              [-d dir | -c cachefile] [-f] <pool | id> [newpool]
12672f8aaab3Seschrock  *
12682f8aaab3Seschrock  *	 -c	Read pool information from a cachefile instead of searching
12692f8aaab3Seschrock  *		devices.
1270fa9e4066Sahrens  *
1271fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1272fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
1273fa9e4066Sahrens  *
12744c58d714Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
12754c58d714Sdarrenm  *              specified destroyed pools.
12764c58d714Sdarrenm  *
1277fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1278fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
1279fa9e4066Sahrens  *		is rebooted.
1280fa9e4066Sahrens  *
1281fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
1282fa9e4066Sahrens  *
1283fa9e4066Sahrens  *       -a	Import all pools found.
1284fa9e4066Sahrens  *
1285990b4856Slling  *       -o	Set property=value and/or temporary mount options (without '=').
1286ecd6cf80Smarks  *
1287fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
1288fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1289fa9e4066Sahrens  */
1290fa9e4066Sahrens int
1291fa9e4066Sahrens zpool_do_import(int argc, char **argv)
1292fa9e4066Sahrens {
1293fa9e4066Sahrens 	char **searchdirs = NULL;
1294fa9e4066Sahrens 	int nsearch = 0;
1295fa9e4066Sahrens 	int c;
1296fa9e4066Sahrens 	int err;
12972f8aaab3Seschrock 	nvlist_t *pools = NULL;
129899653d4eSeschrock 	boolean_t do_all = B_FALSE;
129999653d4eSeschrock 	boolean_t do_destroyed = B_FALSE;
1300fa9e4066Sahrens 	char *mntopts = NULL;
130199653d4eSeschrock 	boolean_t do_force = B_FALSE;
1302fa9e4066Sahrens 	nvpair_t *elem;
1303fa9e4066Sahrens 	nvlist_t *config;
1304fa9e4066Sahrens 	uint64_t searchguid;
1305fa9e4066Sahrens 	char *searchname;
1306990b4856Slling 	char *propval;
1307fa9e4066Sahrens 	nvlist_t *found_config;
1308ecd6cf80Smarks 	nvlist_t *props = NULL;
130999653d4eSeschrock 	boolean_t first;
13104c58d714Sdarrenm 	uint64_t pool_state;
13112f8aaab3Seschrock 	char *cachefile = NULL;
1312fa9e4066Sahrens 
1313fa9e4066Sahrens 	/* check options */
13142f8aaab3Seschrock 	while ((c = getopt(argc, argv, ":afc:d:Do:p:R:")) != -1) {
1315fa9e4066Sahrens 		switch (c) {
1316fa9e4066Sahrens 		case 'a':
131799653d4eSeschrock 			do_all = B_TRUE;
1318fa9e4066Sahrens 			break;
13192f8aaab3Seschrock 		case 'c':
13202f8aaab3Seschrock 			cachefile = optarg;
13212f8aaab3Seschrock 			break;
1322fa9e4066Sahrens 		case 'd':
1323fa9e4066Sahrens 			if (searchdirs == NULL) {
1324fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1325fa9e4066Sahrens 			} else {
1326fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1327fa9e4066Sahrens 				    sizeof (char *));
1328fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
1329fa9e4066Sahrens 				    sizeof (char *));
1330fa9e4066Sahrens 				free(searchdirs);
1331fa9e4066Sahrens 				searchdirs = tmp;
1332fa9e4066Sahrens 			}
1333fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
1334fa9e4066Sahrens 			break;
13354c58d714Sdarrenm 		case 'D':
133699653d4eSeschrock 			do_destroyed = B_TRUE;
13374c58d714Sdarrenm 			break;
1338fa9e4066Sahrens 		case 'f':
133999653d4eSeschrock 			do_force = B_TRUE;
1340fa9e4066Sahrens 			break;
1341fa9e4066Sahrens 		case 'o':
1342990b4856Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
1343990b4856Slling 				*propval = '\0';
1344990b4856Slling 				propval++;
1345990b4856Slling 				if (add_prop_list(optarg, propval, &props))
1346990b4856Slling 					goto error;
1347990b4856Slling 			} else {
1348fa9e4066Sahrens 				mntopts = optarg;
1349990b4856Slling 			}
1350fa9e4066Sahrens 			break;
1351fa9e4066Sahrens 		case 'R':
1352990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
1353990b4856Slling 			    ZPOOL_PROP_ALTROOT), optarg, &props))
1354990b4856Slling 				goto error;
13552f8aaab3Seschrock 			if (nvlist_lookup_string(props,
13562f8aaab3Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
13572f8aaab3Seschrock 			    &propval) == 0)
13582f8aaab3Seschrock 				break;
1359990b4856Slling 			if (add_prop_list(zpool_prop_to_name(
13602f8aaab3Seschrock 			    ZPOOL_PROP_CACHEFILE), "none", &props))
1361990b4856Slling 				goto error;
1362fa9e4066Sahrens 			break;
1363fa9e4066Sahrens 		case ':':
1364fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1365fa9e4066Sahrens 			    "'%c' option\n"), optopt);
136699653d4eSeschrock 			usage(B_FALSE);
1367fa9e4066Sahrens 			break;
1368fa9e4066Sahrens 		case '?':
1369fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1370fa9e4066Sahrens 			    optopt);
137199653d4eSeschrock 			usage(B_FALSE);
1372fa9e4066Sahrens 		}
1373fa9e4066Sahrens 	}
1374fa9e4066Sahrens 
1375fa9e4066Sahrens 	argc -= optind;
1376fa9e4066Sahrens 	argv += optind;
1377fa9e4066Sahrens 
13782f8aaab3Seschrock 	if (cachefile && nsearch != 0) {
13792f8aaab3Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
13802f8aaab3Seschrock 		usage(B_FALSE);
13812f8aaab3Seschrock 	}
13822f8aaab3Seschrock 
1383fa9e4066Sahrens 	if (searchdirs == NULL) {
1384fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1385fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1386fa9e4066Sahrens 		nsearch = 1;
1387fa9e4066Sahrens 	}
1388fa9e4066Sahrens 
1389fa9e4066Sahrens 	/* check argument count */
1390fa9e4066Sahrens 	if (do_all) {
1391fa9e4066Sahrens 		if (argc != 0) {
1392fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
139399653d4eSeschrock 			usage(B_FALSE);
1394fa9e4066Sahrens 		}
1395fa9e4066Sahrens 	} else {
1396fa9e4066Sahrens 		if (argc > 2) {
1397fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
139899653d4eSeschrock 			usage(B_FALSE);
1399fa9e4066Sahrens 		}
1400fa9e4066Sahrens 
1401fa9e4066Sahrens 		/*
1402fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1403fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1404fa9e4066Sahrens 		 * silently fail.
1405fa9e4066Sahrens 		 */
1406fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1407fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1408fa9e4066Sahrens 			    "discover pools: permission denied\n"));
140999653d4eSeschrock 			free(searchdirs);
1410fa9e4066Sahrens 			return (1);
1411fa9e4066Sahrens 		}
1412fa9e4066Sahrens 	}
1413fa9e4066Sahrens 
14142f8aaab3Seschrock 	if (cachefile)
14152f8aaab3Seschrock 		pools = zpool_find_import_cached(g_zfs, cachefile);
14162f8aaab3Seschrock 	else
14172f8aaab3Seschrock 		pools = zpool_find_import(g_zfs, nsearch, searchdirs);
14182f8aaab3Seschrock 
14192f8aaab3Seschrock 	if (pools == NULL) {
142099653d4eSeschrock 		free(searchdirs);
1421fa9e4066Sahrens 		return (1);
142299653d4eSeschrock 	}
1423fa9e4066Sahrens 
1424fa9e4066Sahrens 	/*
1425fa9e4066Sahrens 	 * We now have a list of all available pools in the given directories.
1426fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1427fa9e4066Sahrens 	 *
1428fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1429fa9e4066Sahrens 	 *		each one.
1430fa9e4066Sahrens 	 *
1431fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1432fa9e4066Sahrens 	 *
1433fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1434fa9e4066Sahrens 	 *		name and import that one.
14354c58d714Sdarrenm 	 *
14364c58d714Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1437fa9e4066Sahrens 	 */
1438fa9e4066Sahrens 	if (argc != 0) {
1439fa9e4066Sahrens 		char *endptr;
1440fa9e4066Sahrens 
1441fa9e4066Sahrens 		errno = 0;
1442fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1443fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1444fa9e4066Sahrens 			searchname = argv[0];
1445fa9e4066Sahrens 		else
1446fa9e4066Sahrens 			searchname = NULL;
1447fa9e4066Sahrens 		found_config = NULL;
1448fa9e4066Sahrens 	}
1449fa9e4066Sahrens 
1450fa9e4066Sahrens 	err = 0;
1451fa9e4066Sahrens 	elem = NULL;
145299653d4eSeschrock 	first = B_TRUE;
1453fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1454fa9e4066Sahrens 
1455fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1456fa9e4066Sahrens 
14574c58d714Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
14584c58d714Sdarrenm 		    &pool_state) == 0);
14594c58d714Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
14604c58d714Sdarrenm 			continue;
14614c58d714Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
14624c58d714Sdarrenm 			continue;
14634c58d714Sdarrenm 
1464fa9e4066Sahrens 		if (argc == 0) {
1465fa9e4066Sahrens 			if (first)
146699653d4eSeschrock 				first = B_FALSE;
14673bb79becSeschrock 			else if (!do_all)
1468fa9e4066Sahrens 				(void) printf("\n");
1469fa9e4066Sahrens 
1470fa9e4066Sahrens 			if (do_all)
1471fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1472990b4856Slling 				    do_force, props);
1473fa9e4066Sahrens 			else
1474fa9e4066Sahrens 				show_import(config);
1475fa9e4066Sahrens 		} else if (searchname != NULL) {
1476fa9e4066Sahrens 			char *name;
1477fa9e4066Sahrens 
1478fa9e4066Sahrens 			/*
1479fa9e4066Sahrens 			 * We are searching for a pool based on name.
1480fa9e4066Sahrens 			 */
1481fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1482fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1483fa9e4066Sahrens 
1484fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1485fa9e4066Sahrens 				if (found_config != NULL) {
1486fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1487fa9e4066Sahrens 					    "cannot import '%s': more than "
1488fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1489fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1490fa9e4066Sahrens 					    "import by numeric ID instead\n"));
149199653d4eSeschrock 					err = B_TRUE;
1492fa9e4066Sahrens 				}
1493fa9e4066Sahrens 				found_config = config;
1494fa9e4066Sahrens 			}
1495fa9e4066Sahrens 		} else {
1496fa9e4066Sahrens 			uint64_t guid;
1497fa9e4066Sahrens 
1498fa9e4066Sahrens 			/*
1499fa9e4066Sahrens 			 * Search for a pool by guid.
1500fa9e4066Sahrens 			 */
1501fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1502fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1503fa9e4066Sahrens 
1504fa9e4066Sahrens 			if (guid == searchguid)
1505fa9e4066Sahrens 				found_config = config;
1506fa9e4066Sahrens 		}
1507fa9e4066Sahrens 	}
1508fa9e4066Sahrens 
1509fa9e4066Sahrens 	/*
1510fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1511fa9e4066Sahrens 	 * pool, and then do the import.
1512fa9e4066Sahrens 	 */
1513fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1514fa9e4066Sahrens 		if (found_config == NULL) {
1515fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1516fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
151799653d4eSeschrock 			err = B_TRUE;
1518fa9e4066Sahrens 		} else {
1519fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1520990b4856Slling 			    argv[1], mntopts, do_force, props);
1521fa9e4066Sahrens 		}
1522fa9e4066Sahrens 	}
1523fa9e4066Sahrens 
1524fa9e4066Sahrens 	/*
1525fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1526fa9e4066Sahrens 	 * found.
1527fa9e4066Sahrens 	 */
1528fa9e4066Sahrens 	if (argc == 0 && first)
1529fa9e4066Sahrens 		(void) fprintf(stderr,
1530fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1531fa9e4066Sahrens 
1532ecd6cf80Smarks error:
1533ecd6cf80Smarks 	nvlist_free(props);
1534fa9e4066Sahrens 	nvlist_free(pools);
153599653d4eSeschrock 	free(searchdirs);
1536fa9e4066Sahrens 
1537fa9e4066Sahrens 	return (err ? 1 : 0);
1538fa9e4066Sahrens }
1539fa9e4066Sahrens 
1540fa9e4066Sahrens typedef struct iostat_cbdata {
1541fa9e4066Sahrens 	zpool_list_t *cb_list;
1542fa9e4066Sahrens 	int cb_verbose;
1543fa9e4066Sahrens 	int cb_iteration;
1544fa9e4066Sahrens 	int cb_namewidth;
1545fa9e4066Sahrens } iostat_cbdata_t;
1546fa9e4066Sahrens 
1547fa9e4066Sahrens static void
1548fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1549fa9e4066Sahrens {
1550fa9e4066Sahrens 	int i = 0;
1551fa9e4066Sahrens 
1552fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1553fa9e4066Sahrens 		(void) printf("-");
1554fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1555fa9e4066Sahrens }
1556fa9e4066Sahrens 
1557fa9e4066Sahrens static void
1558fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1559fa9e4066Sahrens {
1560fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1561fa9e4066Sahrens 	    cb->cb_namewidth, "");
1562fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1563fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1564fa9e4066Sahrens 	print_iostat_separator(cb);
1565fa9e4066Sahrens }
1566fa9e4066Sahrens 
1567fa9e4066Sahrens /*
1568fa9e4066Sahrens  * Display a single statistic.
1569fa9e4066Sahrens  */
1570990b4856Slling static void
1571fa9e4066Sahrens print_one_stat(uint64_t value)
1572fa9e4066Sahrens {
1573fa9e4066Sahrens 	char buf[64];
1574fa9e4066Sahrens 
1575fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1576fa9e4066Sahrens 	(void) printf("  %5s", buf);
1577fa9e4066Sahrens }
1578fa9e4066Sahrens 
1579fa9e4066Sahrens /*
1580fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1581fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1582fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1583fa9e4066Sahrens  */
1584fa9e4066Sahrens void
1585c67d9675Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1586c67d9675Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1587fa9e4066Sahrens {
1588fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1589fa9e4066Sahrens 	uint_t c, children;
1590fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1591fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1592fa9e4066Sahrens 	uint64_t tdelta;
1593fa9e4066Sahrens 	double scale;
1594afefbcddSeschrock 	char *vname;
1595fa9e4066Sahrens 
1596fa9e4066Sahrens 	if (oldnv != NULL) {
1597fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1598fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1599fa9e4066Sahrens 	} else {
1600fa9e4066Sahrens 		oldvs = &zerovs;
1601fa9e4066Sahrens 	}
1602fa9e4066Sahrens 
1603fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1604fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1605fa9e4066Sahrens 
1606fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1607fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1608fa9e4066Sahrens 	else
1609fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1610fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1611fa9e4066Sahrens 
1612fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1613fa9e4066Sahrens 
1614fa9e4066Sahrens 	if (tdelta == 0)
1615fa9e4066Sahrens 		scale = 1.0;
1616fa9e4066Sahrens 	else
1617fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1618fa9e4066Sahrens 
1619fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1620fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1621fa9e4066Sahrens 		(void) printf("      -      -");
1622fa9e4066Sahrens 	} else {
1623fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1624fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1625fa9e4066Sahrens 	}
1626fa9e4066Sahrens 
1627fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1628fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1629fa9e4066Sahrens 
1630fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1631fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1632fa9e4066Sahrens 
1633fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1634fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1635fa9e4066Sahrens 
1636fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1637fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1638fa9e4066Sahrens 
1639fa9e4066Sahrens 	(void) printf("\n");
1640fa9e4066Sahrens 
1641fa9e4066Sahrens 	if (!cb->cb_verbose)
1642fa9e4066Sahrens 		return;
1643fa9e4066Sahrens 
1644fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1645fa9e4066Sahrens 	    &newchild, &children) != 0)
1646fa9e4066Sahrens 		return;
1647fa9e4066Sahrens 
1648fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1649fa9e4066Sahrens 	    &oldchild, &c) != 0)
1650fa9e4066Sahrens 		return;
1651fa9e4066Sahrens 
1652afefbcddSeschrock 	for (c = 0; c < children; c++) {
165399653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1654c67d9675Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1655afefbcddSeschrock 		    newchild[c], cb, depth + 2);
1656afefbcddSeschrock 		free(vname);
1657afefbcddSeschrock 	}
1658fa9e4066Sahrens }
1659fa9e4066Sahrens 
1660088e9d47Seschrock static int
1661088e9d47Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
1662088e9d47Seschrock {
1663088e9d47Seschrock 	iostat_cbdata_t *cb = data;
166494de1d4cSeschrock 	boolean_t missing;
1665088e9d47Seschrock 
1666088e9d47Seschrock 	/*
1667088e9d47Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
1668088e9d47Seschrock 	 */
166994de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
167094de1d4cSeschrock 		return (-1);
167194de1d4cSeschrock 
167294de1d4cSeschrock 	if (missing)
1673088e9d47Seschrock 		pool_list_remove(cb->cb_list, zhp);
1674088e9d47Seschrock 
1675088e9d47Seschrock 	return (0);
1676088e9d47Seschrock }
1677088e9d47Seschrock 
1678fa9e4066Sahrens /*
1679fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
1680fa9e4066Sahrens  */
1681fa9e4066Sahrens int
1682fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
1683fa9e4066Sahrens {
1684fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1685fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
1686fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
1687fa9e4066Sahrens 
1688088e9d47Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
1689fa9e4066Sahrens 
1690088e9d47Seschrock 	if (cb->cb_iteration == 1)
1691fa9e4066Sahrens 		oldconfig = NULL;
1692fa9e4066Sahrens 
1693fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1694fa9e4066Sahrens 	    &newnvroot) == 0);
1695fa9e4066Sahrens 
1696088e9d47Seschrock 	if (oldconfig == NULL)
1697fa9e4066Sahrens 		oldnvroot = NULL;
1698088e9d47Seschrock 	else
1699088e9d47Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
1700088e9d47Seschrock 		    &oldnvroot) == 0);
1701fa9e4066Sahrens 
1702fa9e4066Sahrens 	/*
1703fa9e4066Sahrens 	 * Print out the statistics for the pool.
1704fa9e4066Sahrens 	 */
1705c67d9675Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1706fa9e4066Sahrens 
1707fa9e4066Sahrens 	if (cb->cb_verbose)
1708fa9e4066Sahrens 		print_iostat_separator(cb);
1709fa9e4066Sahrens 
1710fa9e4066Sahrens 	return (0);
1711fa9e4066Sahrens }
1712fa9e4066Sahrens 
1713fa9e4066Sahrens int
1714fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
1715fa9e4066Sahrens {
1716fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1717fa9e4066Sahrens 	nvlist_t *config, *nvroot;
1718fa9e4066Sahrens 
1719088e9d47Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
1720fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1721fa9e4066Sahrens 		    &nvroot) == 0);
1722fa9e4066Sahrens 		if (!cb->cb_verbose)
1723fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1724fa9e4066Sahrens 		else
1725c67d9675Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
1726fa9e4066Sahrens 	}
1727fa9e4066Sahrens 
1728fa9e4066Sahrens 	/*
1729fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
1730fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
1731fa9e4066Sahrens 	 */
1732fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
1733fa9e4066Sahrens 		cb->cb_namewidth = 10;
1734fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
1735fa9e4066Sahrens 		cb->cb_namewidth = 38;
1736fa9e4066Sahrens 
1737fa9e4066Sahrens 	return (0);
1738fa9e4066Sahrens }
1739fa9e4066Sahrens 
1740fa9e4066Sahrens /*
1741fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
1742fa9e4066Sahrens  *
1743fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
1744fa9e4066Sahrens  *
1745fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
1746fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
1747fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1748fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
1749fa9e4066Sahrens  * changes are all handled within libzfs.
1750fa9e4066Sahrens  */
1751fa9e4066Sahrens int
1752fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
1753fa9e4066Sahrens {
1754fa9e4066Sahrens 	int c;
1755fa9e4066Sahrens 	int ret;
1756fa9e4066Sahrens 	int npools;
1757fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
1758fa9e4066Sahrens 	zpool_list_t *list;
175999653d4eSeschrock 	boolean_t verbose = B_FALSE;
1760fa9e4066Sahrens 	iostat_cbdata_t cb;
1761fa9e4066Sahrens 
1762fa9e4066Sahrens 	/* check options */
1763fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
1764fa9e4066Sahrens 		switch (c) {
1765fa9e4066Sahrens 		case 'v':
176699653d4eSeschrock 			verbose = B_TRUE;
1767fa9e4066Sahrens 			break;
1768fa9e4066Sahrens 		case '?':
1769fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1770fa9e4066Sahrens 			    optopt);
177199653d4eSeschrock 			usage(B_FALSE);
1772fa9e4066Sahrens 		}
1773fa9e4066Sahrens 	}
1774fa9e4066Sahrens 
1775fa9e4066Sahrens 	argc -= optind;
1776fa9e4066Sahrens 	argv += optind;
1777fa9e4066Sahrens 
1778fa9e4066Sahrens 	/*
1779fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
1780fa9e4066Sahrens 	 */
1781fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1782fa9e4066Sahrens 		char *end;
1783fa9e4066Sahrens 
1784fa9e4066Sahrens 		errno = 0;
1785fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1786fa9e4066Sahrens 
1787fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1788fa9e4066Sahrens 			if (interval == 0) {
1789fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1790fa9e4066Sahrens 				    "cannot be zero\n"));
179199653d4eSeschrock 				usage(B_FALSE);
1792fa9e4066Sahrens 			}
1793fa9e4066Sahrens 
1794fa9e4066Sahrens 			/*
1795fa9e4066Sahrens 			 * Ignore the last parameter
1796fa9e4066Sahrens 			 */
1797fa9e4066Sahrens 			argc--;
1798fa9e4066Sahrens 		} else {
1799fa9e4066Sahrens 			/*
1800fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
1801fa9e4066Sahrens 			 * user will get a more informative error message later
1802fa9e4066Sahrens 			 * on.
1803fa9e4066Sahrens 			 */
1804fa9e4066Sahrens 			interval = 0;
1805fa9e4066Sahrens 		}
1806fa9e4066Sahrens 	}
1807fa9e4066Sahrens 
1808fa9e4066Sahrens 	/*
1809fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
1810fa9e4066Sahrens 	 * and an integer.
1811fa9e4066Sahrens 	 */
1812fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1813fa9e4066Sahrens 		char *end;
1814fa9e4066Sahrens 
1815fa9e4066Sahrens 		errno = 0;
1816fa9e4066Sahrens 		count = interval;
1817fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1818fa9e4066Sahrens 
1819fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1820fa9e4066Sahrens 			if (interval == 0) {
1821fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1822fa9e4066Sahrens 				    "cannot be zero\n"));
182399653d4eSeschrock 				usage(B_FALSE);
1824fa9e4066Sahrens 			}
1825fa9e4066Sahrens 
1826fa9e4066Sahrens 			/*
1827fa9e4066Sahrens 			 * Ignore the last parameter
1828fa9e4066Sahrens 			 */
1829fa9e4066Sahrens 			argc--;
1830fa9e4066Sahrens 		} else {
1831fa9e4066Sahrens 			interval = 0;
1832fa9e4066Sahrens 		}
1833fa9e4066Sahrens 	}
1834fa9e4066Sahrens 
1835fa9e4066Sahrens 	/*
1836fa9e4066Sahrens 	 * Construct the list of all interesting pools.
1837fa9e4066Sahrens 	 */
1838fa9e4066Sahrens 	ret = 0;
1839b1b8ab34Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
1840fa9e4066Sahrens 		return (1);
1841fa9e4066Sahrens 
184299653d4eSeschrock 	if (pool_list_count(list) == 0 && argc != 0) {
184399653d4eSeschrock 		pool_list_free(list);
1844fa9e4066Sahrens 		return (1);
184599653d4eSeschrock 	}
1846fa9e4066Sahrens 
1847fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
184899653d4eSeschrock 		pool_list_free(list);
1849fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
1850fa9e4066Sahrens 		return (1);
1851fa9e4066Sahrens 	}
1852fa9e4066Sahrens 
1853fa9e4066Sahrens 	/*
1854fa9e4066Sahrens 	 * Enter the main iostat loop.
1855fa9e4066Sahrens 	 */
1856fa9e4066Sahrens 	cb.cb_list = list;
1857fa9e4066Sahrens 	cb.cb_verbose = verbose;
1858fa9e4066Sahrens 	cb.cb_iteration = 0;
1859fa9e4066Sahrens 	cb.cb_namewidth = 0;
1860fa9e4066Sahrens 
1861fa9e4066Sahrens 	for (;;) {
1862fa9e4066Sahrens 		pool_list_update(list);
1863fa9e4066Sahrens 
1864fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
1865fa9e4066Sahrens 			break;
1866fa9e4066Sahrens 
1867fa9e4066Sahrens 		/*
1868088e9d47Seschrock 		 * Refresh all statistics.  This is done as an explicit step
1869088e9d47Seschrock 		 * before calculating the maximum name width, so that any
1870088e9d47Seschrock 		 * configuration changes are properly accounted for.
1871088e9d47Seschrock 		 */
187299653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
1873088e9d47Seschrock 
1874088e9d47Seschrock 		/*
1875fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
1876fa9e4066Sahrens 		 * for the pool / device name column across all pools.
1877fa9e4066Sahrens 		 */
1878fa9e4066Sahrens 		cb.cb_namewidth = 0;
187999653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
1880fa9e4066Sahrens 
1881fa9e4066Sahrens 		/*
1882fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
1883fa9e4066Sahrens 		 */
1884fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
1885fa9e4066Sahrens 			print_iostat_header(&cb);
1886fa9e4066Sahrens 
188799653d4eSeschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
1888fa9e4066Sahrens 
1889fa9e4066Sahrens 		/*
1890fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
1891fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
1892fa9e4066Sahrens 		 */
1893fa9e4066Sahrens 		if (npools > 1 && !verbose)
1894fa9e4066Sahrens 			print_iostat_separator(&cb);
1895fa9e4066Sahrens 
1896fa9e4066Sahrens 		if (verbose)
1897fa9e4066Sahrens 			(void) printf("\n");
1898fa9e4066Sahrens 
189939c23413Seschrock 		/*
190039c23413Seschrock 		 * Flush the output so that redirection to a file isn't buffered
190139c23413Seschrock 		 * indefinitely.
190239c23413Seschrock 		 */
190339c23413Seschrock 		(void) fflush(stdout);
190439c23413Seschrock 
1905fa9e4066Sahrens 		if (interval == 0)
1906fa9e4066Sahrens 			break;
1907fa9e4066Sahrens 
1908fa9e4066Sahrens 		if (count != 0 && --count == 0)
1909fa9e4066Sahrens 			break;
1910fa9e4066Sahrens 
1911fa9e4066Sahrens 		(void) sleep(interval);
1912fa9e4066Sahrens 	}
1913fa9e4066Sahrens 
1914fa9e4066Sahrens 	pool_list_free(list);
1915fa9e4066Sahrens 
1916fa9e4066Sahrens 	return (ret);
1917fa9e4066Sahrens }
1918fa9e4066Sahrens 
1919fa9e4066Sahrens typedef struct list_cbdata {
192099653d4eSeschrock 	boolean_t	cb_scripted;
192199653d4eSeschrock 	boolean_t	cb_first;
1922990b4856Slling 	zprop_list_t	*cb_proplist;
1923fa9e4066Sahrens } list_cbdata_t;
1924fa9e4066Sahrens 
1925fa9e4066Sahrens /*
1926fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
1927fa9e4066Sahrens  */
1928990b4856Slling static void
1929990b4856Slling print_header(zprop_list_t *pl)
1930fa9e4066Sahrens {
1931990b4856Slling 	const char *header;
1932990b4856Slling 	boolean_t first = B_TRUE;
1933990b4856Slling 	boolean_t right_justify;
1934fa9e4066Sahrens 
1935990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
1936990b4856Slling 		if (pl->pl_prop == ZPROP_INVAL)
1937990b4856Slling 			continue;
1938990b4856Slling 
1939990b4856Slling 		if (!first)
1940fa9e4066Sahrens 			(void) printf("  ");
1941fa9e4066Sahrens 		else
1942990b4856Slling 			first = B_FALSE;
1943fa9e4066Sahrens 
1944990b4856Slling 		header = zpool_prop_column_name(pl->pl_prop);
1945990b4856Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
1946990b4856Slling 
1947990b4856Slling 		if (pl->pl_next == NULL && !right_justify)
1948990b4856Slling 			(void) printf("%s", header);
1949990b4856Slling 		else if (right_justify)
1950990b4856Slling 			(void) printf("%*s", pl->pl_width, header);
1951990b4856Slling 		else
1952990b4856Slling 			(void) printf("%-*s", pl->pl_width, header);
1953fa9e4066Sahrens 	}
1954fa9e4066Sahrens 
1955fa9e4066Sahrens 	(void) printf("\n");
1956fa9e4066Sahrens }
1957fa9e4066Sahrens 
1958990b4856Slling /*
1959990b4856Slling  * Given a pool and a list of properties, print out all the properties according
1960990b4856Slling  * to the described layout.
1961990b4856Slling  */
1962990b4856Slling static void
1963990b4856Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
1964990b4856Slling {
1965990b4856Slling 	boolean_t first = B_TRUE;
1966990b4856Slling 	char property[ZPOOL_MAXPROPLEN];
1967990b4856Slling 	char *propstr;
1968990b4856Slling 	boolean_t right_justify;
1969990b4856Slling 	int width;
1970990b4856Slling 
1971990b4856Slling 	for (; pl != NULL; pl = pl->pl_next) {
1972990b4856Slling 		if (!first) {
1973990b4856Slling 			if (scripted)
1974990b4856Slling 				(void) printf("\t");
1975990b4856Slling 			else
1976990b4856Slling 				(void) printf("  ");
1977990b4856Slling 		} else {
1978990b4856Slling 			first = B_FALSE;
1979990b4856Slling 		}
1980990b4856Slling 
1981990b4856Slling 		right_justify = B_FALSE;
1982990b4856Slling 		if (pl->pl_prop != ZPROP_INVAL) {
1983990b4856Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
1984990b4856Slling 			    sizeof (property), NULL) != 0)
1985990b4856Slling 				propstr = "-";
1986990b4856Slling 			else
1987990b4856Slling 				propstr = property;
1988990b4856Slling 
1989990b4856Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
1990990b4856Slling 		} else {
1991990b4856Slling 			propstr = "-";
1992990b4856Slling 		}
1993990b4856Slling 
1994990b4856Slling 		width = pl->pl_width;
1995990b4856Slling 
1996990b4856Slling 		/*
1997990b4856Slling 		 * If this is being called in scripted mode, or if this is the
1998990b4856Slling 		 * last column and it is left-justified, don't include a width
1999990b4856Slling 		 * format specifier.
2000990b4856Slling 		 */
2001990b4856Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
2002990b4856Slling 			(void) printf("%s", propstr);
2003990b4856Slling 		else if (right_justify)
2004990b4856Slling 			(void) printf("%*s", width, propstr);
2005990b4856Slling 		else
2006990b4856Slling 			(void) printf("%-*s", width, propstr);
2007990b4856Slling 	}
2008990b4856Slling 
2009990b4856Slling 	(void) printf("\n");
2010990b4856Slling }
2011990b4856Slling 
2012990b4856Slling /*
2013990b4856Slling  * Generic callback function to list a pool.
2014990b4856Slling  */
2015fa9e4066Sahrens int
2016fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
2017fa9e4066Sahrens {
2018fa9e4066Sahrens 	list_cbdata_t *cbp = data;
2019fa9e4066Sahrens 
2020fa9e4066Sahrens 	if (cbp->cb_first) {
2021fa9e4066Sahrens 		if (!cbp->cb_scripted)
2022990b4856Slling 			print_header(cbp->cb_proplist);
202399653d4eSeschrock 		cbp->cb_first = B_FALSE;
2024fa9e4066Sahrens 	}
2025fa9e4066Sahrens 
2026990b4856Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2027fa9e4066Sahrens 
2028fa9e4066Sahrens 	return (0);
2029fa9e4066Sahrens }
2030fa9e4066Sahrens 
2031fa9e4066Sahrens /*
2032990b4856Slling  * zpool list [-H] [-o prop[,prop]*] [pool] ...
2033fa9e4066Sahrens  *
2034990b4856Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
2035990b4856Slling  *		by a single tab.
2036990b4856Slling  *	-o	List of properties to display.  Defaults to
2037990b4856Slling  *		"name,size,used,available,capacity,health,altroot"
2038fa9e4066Sahrens  *
2039fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2040fa9e4066Sahrens  * statistics for each one, as well as health status summary.
2041fa9e4066Sahrens  */
2042fa9e4066Sahrens int
2043fa9e4066Sahrens zpool_do_list(int argc, char **argv)
2044fa9e4066Sahrens {
2045fa9e4066Sahrens 	int c;
2046fa9e4066Sahrens 	int ret;
2047fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
2048990b4856Slling 	static char default_props[] =
2049990b4856Slling 	    "name,size,used,available,capacity,health,altroot";
2050990b4856Slling 	char *props = default_props;
2051fa9e4066Sahrens 
2052fa9e4066Sahrens 	/* check options */
2053fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2054fa9e4066Sahrens 		switch (c) {
2055fa9e4066Sahrens 		case 'H':
205699653d4eSeschrock 			cb.cb_scripted = B_TRUE;
2057fa9e4066Sahrens 			break;
2058fa9e4066Sahrens 		case 'o':
2059990b4856Slling 			props = optarg;
2060fa9e4066Sahrens 			break;
2061fa9e4066Sahrens 		case ':':
2062fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2063fa9e4066Sahrens 			    "'%c' option\n"), optopt);
206499653d4eSeschrock 			usage(B_FALSE);
2065fa9e4066Sahrens 			break;
2066fa9e4066Sahrens 		case '?':
2067fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2068fa9e4066Sahrens 			    optopt);
206999653d4eSeschrock 			usage(B_FALSE);
2070fa9e4066Sahrens 		}
2071fa9e4066Sahrens 	}
2072fa9e4066Sahrens 
2073fa9e4066Sahrens 	argc -= optind;
2074fa9e4066Sahrens 	argv += optind;
2075fa9e4066Sahrens 
2076990b4856Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
207799653d4eSeschrock 		usage(B_FALSE);
2078fa9e4066Sahrens 
207999653d4eSeschrock 	cb.cb_first = B_TRUE;
2080fa9e4066Sahrens 
2081990b4856Slling 	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2082990b4856Slling 	    list_callback, &cb);
2083990b4856Slling 
2084990b4856Slling 	zprop_free_list(cb.cb_proplist);
2085fa9e4066Sahrens 
2086fce7d82bSmmusante 	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2087fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2088fa9e4066Sahrens 		return (0);
2089fa9e4066Sahrens 	}
2090fa9e4066Sahrens 
2091fa9e4066Sahrens 	return (ret);
2092fa9e4066Sahrens }
2093fa9e4066Sahrens 
2094fa9e4066Sahrens static nvlist_t *
2095fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2096fa9e4066Sahrens {
2097fa9e4066Sahrens 	nvlist_t **child;
2098fa9e4066Sahrens 	uint_t c, children;
2099fa9e4066Sahrens 	nvlist_t *match;
2100fa9e4066Sahrens 	char *path;
2101fa9e4066Sahrens 
2102fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2103fa9e4066Sahrens 	    &child, &children) != 0) {
2104fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2105fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2106fa9e4066Sahrens 			name += 9;
2107fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2108fa9e4066Sahrens 			path += 9;
2109fa9e4066Sahrens 		if (strcmp(name, path) == 0)
2110fa9e4066Sahrens 			return (nv);
2111fa9e4066Sahrens 		return (NULL);
2112fa9e4066Sahrens 	}
2113fa9e4066Sahrens 
2114fa9e4066Sahrens 	for (c = 0; c < children; c++)
2115fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2116fa9e4066Sahrens 			return (match);
2117fa9e4066Sahrens 
2118fa9e4066Sahrens 	return (NULL);
2119fa9e4066Sahrens }
2120fa9e4066Sahrens 
2121fa9e4066Sahrens static int
2122fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2123fa9e4066Sahrens {
212499653d4eSeschrock 	boolean_t force = B_FALSE;
2125fa9e4066Sahrens 	int c;
2126fa9e4066Sahrens 	nvlist_t *nvroot;
2127fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
2128fa9e4066Sahrens 	zpool_handle_t *zhp;
212999653d4eSeschrock 	int ret;
2130fa9e4066Sahrens 
2131fa9e4066Sahrens 	/* check options */
2132fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2133fa9e4066Sahrens 		switch (c) {
2134fa9e4066Sahrens 		case 'f':
213599653d4eSeschrock 			force = B_TRUE;
2136fa9e4066Sahrens 			break;
2137fa9e4066Sahrens 		case '?':
2138fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2139fa9e4066Sahrens 			    optopt);
214099653d4eSeschrock 			usage(B_FALSE);
2141fa9e4066Sahrens 		}
2142fa9e4066Sahrens 	}
2143fa9e4066Sahrens 
2144fa9e4066Sahrens 	argc -= optind;
2145fa9e4066Sahrens 	argv += optind;
2146fa9e4066Sahrens 
2147fa9e4066Sahrens 	/* get pool name and check number of arguments */
2148fa9e4066Sahrens 	if (argc < 1) {
2149fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
215099653d4eSeschrock 		usage(B_FALSE);
2151fa9e4066Sahrens 	}
2152fa9e4066Sahrens 
2153fa9e4066Sahrens 	poolname = argv[0];
2154fa9e4066Sahrens 
2155fa9e4066Sahrens 	if (argc < 2) {
2156fa9e4066Sahrens 		(void) fprintf(stderr,
2157fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
215899653d4eSeschrock 		usage(B_FALSE);
2159fa9e4066Sahrens 	}
2160fa9e4066Sahrens 
2161fa9e4066Sahrens 	old_disk = argv[1];
2162fa9e4066Sahrens 
2163fa9e4066Sahrens 	if (argc < 3) {
2164fa9e4066Sahrens 		if (!replacing) {
2165fa9e4066Sahrens 			(void) fprintf(stderr,
2166fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
216799653d4eSeschrock 			usage(B_FALSE);
2168fa9e4066Sahrens 		}
2169fa9e4066Sahrens 		new_disk = old_disk;
2170fa9e4066Sahrens 		argc -= 1;
2171fa9e4066Sahrens 		argv += 1;
2172fa9e4066Sahrens 	} else {
2173fa9e4066Sahrens 		new_disk = argv[2];
2174fa9e4066Sahrens 		argc -= 2;
2175fa9e4066Sahrens 		argv += 2;
2176fa9e4066Sahrens 	}
2177fa9e4066Sahrens 
2178fa9e4066Sahrens 	if (argc > 1) {
2179fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
218099653d4eSeschrock 		usage(B_FALSE);
2181fa9e4066Sahrens 	}
2182fa9e4066Sahrens 
218399653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2184fa9e4066Sahrens 		return (1);
2185fa9e4066Sahrens 
21868488aeb5Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2187fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2188fa9e4066Sahrens 		    poolname);
2189fa9e4066Sahrens 		zpool_close(zhp);
2190fa9e4066Sahrens 		return (1);
2191fa9e4066Sahrens 	}
2192fa9e4066Sahrens 
21938488aeb5Staylor 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, argc, argv);
2194fa9e4066Sahrens 	if (nvroot == NULL) {
2195fa9e4066Sahrens 		zpool_close(zhp);
2196fa9e4066Sahrens 		return (1);
2197fa9e4066Sahrens 	}
2198fa9e4066Sahrens 
219999653d4eSeschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
220099653d4eSeschrock 
220199653d4eSeschrock 	nvlist_free(nvroot);
220299653d4eSeschrock 	zpool_close(zhp);
220399653d4eSeschrock 
220499653d4eSeschrock 	return (ret);
2205fa9e4066Sahrens }
2206fa9e4066Sahrens 
2207fa9e4066Sahrens /*
2208fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2209fa9e4066Sahrens  *
2210fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2211fa9e4066Sahrens  *
2212fa9e4066Sahrens  * Replace <device> with <new_device>.
2213fa9e4066Sahrens  */
2214fa9e4066Sahrens /* ARGSUSED */
2215fa9e4066Sahrens int
2216fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
2217fa9e4066Sahrens {
2218fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2219fa9e4066Sahrens }
2220fa9e4066Sahrens 
2221fa9e4066Sahrens /*
2222fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2223fa9e4066Sahrens  *
2224fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2225fa9e4066Sahrens  *
2226fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2227fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2228fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2229fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2230fa9e4066Sahrens  */
2231fa9e4066Sahrens int
2232fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
2233fa9e4066Sahrens {
2234fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2235fa9e4066Sahrens }
2236fa9e4066Sahrens 
2237fa9e4066Sahrens /*
2238fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
2239fa9e4066Sahrens  *
2240fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2241fa9e4066Sahrens  *		(not supported yet)
2242fa9e4066Sahrens  *
2243fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2244fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2245fa9e4066Sahrens  * has the only valid copy of some data.
2246fa9e4066Sahrens  */
2247fa9e4066Sahrens /* ARGSUSED */
2248fa9e4066Sahrens int
2249fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
2250fa9e4066Sahrens {
2251fa9e4066Sahrens 	int c;
2252fa9e4066Sahrens 	char *poolname, *path;
2253fa9e4066Sahrens 	zpool_handle_t *zhp;
225499653d4eSeschrock 	int ret;
2255fa9e4066Sahrens 
2256fa9e4066Sahrens 	/* check options */
2257fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2258fa9e4066Sahrens 		switch (c) {
2259fa9e4066Sahrens 		case 'f':
2260fa9e4066Sahrens 		case '?':
2261fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2262fa9e4066Sahrens 			    optopt);
226399653d4eSeschrock 			usage(B_FALSE);
2264fa9e4066Sahrens 		}
2265fa9e4066Sahrens 	}
2266fa9e4066Sahrens 
2267fa9e4066Sahrens 	argc -= optind;
2268fa9e4066Sahrens 	argv += optind;
2269fa9e4066Sahrens 
2270fa9e4066Sahrens 	/* get pool name and check number of arguments */
2271fa9e4066Sahrens 	if (argc < 1) {
2272fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
227399653d4eSeschrock 		usage(B_FALSE);
2274fa9e4066Sahrens 	}
2275fa9e4066Sahrens 
2276fa9e4066Sahrens 	if (argc < 2) {
2277fa9e4066Sahrens 		(void) fprintf(stderr,
2278fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
227999653d4eSeschrock 		usage(B_FALSE);
2280fa9e4066Sahrens 	}
2281fa9e4066Sahrens 
2282fa9e4066Sahrens 	poolname = argv[0];
2283fa9e4066Sahrens 	path = argv[1];
2284fa9e4066Sahrens 
228599653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2286fa9e4066Sahrens 		return (1);
2287fa9e4066Sahrens 
228899653d4eSeschrock 	ret = zpool_vdev_detach(zhp, path);
228999653d4eSeschrock 
229099653d4eSeschrock 	zpool_close(zhp);
229199653d4eSeschrock 
229299653d4eSeschrock 	return (ret);
2293fa9e4066Sahrens }
2294fa9e4066Sahrens 
2295fa9e4066Sahrens /*
2296441d80aaSlling  * zpool online <pool> <device> ...
2297fa9e4066Sahrens  */
2298fa9e4066Sahrens int
2299fa9e4066Sahrens zpool_do_online(int argc, char **argv)
2300fa9e4066Sahrens {
2301fa9e4066Sahrens 	int c, i;
2302fa9e4066Sahrens 	char *poolname;
2303fa9e4066Sahrens 	zpool_handle_t *zhp;
2304fa9e4066Sahrens 	int ret = 0;
23053d7072f8Seschrock 	vdev_state_t newstate;
2306fa9e4066Sahrens 
2307fa9e4066Sahrens 	/* check options */
2308fa9e4066Sahrens 	while ((c = getopt(argc, argv, "t")) != -1) {
2309fa9e4066Sahrens 		switch (c) {
2310fa9e4066Sahrens 		case 't':
2311fa9e4066Sahrens 		case '?':
2312fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2313fa9e4066Sahrens 			    optopt);
231499653d4eSeschrock 			usage(B_FALSE);
2315fa9e4066Sahrens 		}
2316fa9e4066Sahrens 	}
2317fa9e4066Sahrens 
2318fa9e4066Sahrens 	argc -= optind;
2319fa9e4066Sahrens 	argv += optind;
2320fa9e4066Sahrens 
2321fa9e4066Sahrens 	/* get pool name and check number of arguments */
2322fa9e4066Sahrens 	if (argc < 1) {
2323fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
232499653d4eSeschrock 		usage(B_FALSE);
2325fa9e4066Sahrens 	}
2326fa9e4066Sahrens 	if (argc < 2) {
2327fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
232899653d4eSeschrock 		usage(B_FALSE);
2329fa9e4066Sahrens 	}
2330fa9e4066Sahrens 
2331fa9e4066Sahrens 	poolname = argv[0];
2332fa9e4066Sahrens 
233399653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2334fa9e4066Sahrens 		return (1);
2335fa9e4066Sahrens 
23363d7072f8Seschrock 	for (i = 1; i < argc; i++) {
23373d7072f8Seschrock 		if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
23383d7072f8Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
23393d7072f8Seschrock 				(void) printf(gettext("warning: device '%s' "
23403d7072f8Seschrock 				    "onlined, but remains in faulted state\n"),
2341fa9e4066Sahrens 				    argv[i]);
23423d7072f8Seschrock 				if (newstate == VDEV_STATE_FAULTED)
23433d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
23443d7072f8Seschrock 					    "clear' to restore a faulted "
23453d7072f8Seschrock 					    "device\n"));
2346fa9e4066Sahrens 				else
23473d7072f8Seschrock 					(void) printf(gettext("use 'zpool "
23483d7072f8Seschrock 					    "replace' to replace devices "
23493d7072f8Seschrock 					    "that are no longer present\n"));
23503d7072f8Seschrock 			}
23513d7072f8Seschrock 		} else {
2352fa9e4066Sahrens 			ret = 1;
23533d7072f8Seschrock 		}
23543d7072f8Seschrock 	}
2355fa9e4066Sahrens 
235699653d4eSeschrock 	zpool_close(zhp);
235799653d4eSeschrock 
2358fa9e4066Sahrens 	return (ret);
2359fa9e4066Sahrens }
2360fa9e4066Sahrens 
2361fa9e4066Sahrens /*
2362441d80aaSlling  * zpool offline [-ft] <pool> <device> ...
2363fa9e4066Sahrens  *
2364fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
2365fa9e4066Sahrens  *		so would appear to compromise pool availability.
2366fa9e4066Sahrens  *		(not supported yet)
2367fa9e4066Sahrens  *
2368fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
2369fa9e4066Sahrens  *		state will not be persistent across reboots.
2370fa9e4066Sahrens  */
2371fa9e4066Sahrens /* ARGSUSED */
2372fa9e4066Sahrens int
2373fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
2374fa9e4066Sahrens {
2375fa9e4066Sahrens 	int c, i;
2376fa9e4066Sahrens 	char *poolname;
2377fa9e4066Sahrens 	zpool_handle_t *zhp;
237899653d4eSeschrock 	int ret = 0;
237999653d4eSeschrock 	boolean_t istmp = B_FALSE;
2380fa9e4066Sahrens 
2381fa9e4066Sahrens 	/* check options */
2382fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
2383fa9e4066Sahrens 		switch (c) {
2384fa9e4066Sahrens 		case 't':
238599653d4eSeschrock 			istmp = B_TRUE;
2386441d80aaSlling 			break;
2387441d80aaSlling 		case 'f':
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_offline(zhp, argv[i], istmp) != 0)
2415fa9e4066Sahrens 			ret = 1;
24163d7072f8Seschrock 	}
2417fa9e4066Sahrens 
241899653d4eSeschrock 	zpool_close(zhp);
241999653d4eSeschrock 
2420fa9e4066Sahrens 	return (ret);
2421fa9e4066Sahrens }
2422fa9e4066Sahrens 
2423ea8dc4b6Seschrock /*
2424ea8dc4b6Seschrock  * zpool clear <pool> [device]
2425ea8dc4b6Seschrock  *
2426ea8dc4b6Seschrock  * Clear all errors associated with a pool or a particular device.
2427ea8dc4b6Seschrock  */
2428ea8dc4b6Seschrock int
2429ea8dc4b6Seschrock zpool_do_clear(int argc, char **argv)
2430ea8dc4b6Seschrock {
2431ea8dc4b6Seschrock 	int ret = 0;
2432ea8dc4b6Seschrock 	zpool_handle_t *zhp;
2433ea8dc4b6Seschrock 	char *pool, *device;
2434ea8dc4b6Seschrock 
2435ea8dc4b6Seschrock 	if (argc < 2) {
2436ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
243799653d4eSeschrock 		usage(B_FALSE);
2438ea8dc4b6Seschrock 	}
2439ea8dc4b6Seschrock 
2440ea8dc4b6Seschrock 	if (argc > 3) {
2441ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
244299653d4eSeschrock 		usage(B_FALSE);
2443ea8dc4b6Seschrock 	}
2444ea8dc4b6Seschrock 
2445ea8dc4b6Seschrock 	pool = argv[1];
2446ea8dc4b6Seschrock 	device = argc == 3 ? argv[2] : NULL;
2447ea8dc4b6Seschrock 
244899653d4eSeschrock 	if ((zhp = zpool_open(g_zfs, pool)) == NULL)
2449ea8dc4b6Seschrock 		return (1);
2450ea8dc4b6Seschrock 
2451ea8dc4b6Seschrock 	if (zpool_clear(zhp, device) != 0)
2452ea8dc4b6Seschrock 		ret = 1;
2453ea8dc4b6Seschrock 
2454ea8dc4b6Seschrock 	zpool_close(zhp);
2455ea8dc4b6Seschrock 
2456ea8dc4b6Seschrock 	return (ret);
2457ea8dc4b6Seschrock }
2458ea8dc4b6Seschrock 
2459fa9e4066Sahrens typedef struct scrub_cbdata {
2460fa9e4066Sahrens 	int	cb_type;
246106eeb2adSek110237 	int	cb_argc;
246206eeb2adSek110237 	char	**cb_argv;
2463fa9e4066Sahrens } scrub_cbdata_t;
2464fa9e4066Sahrens 
2465fa9e4066Sahrens int
2466fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2467fa9e4066Sahrens {
2468fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
246906eeb2adSek110237 	int err;
2470fa9e4066Sahrens 
2471ea8dc4b6Seschrock 	/*
2472ea8dc4b6Seschrock 	 * Ignore faulted pools.
2473ea8dc4b6Seschrock 	 */
2474ea8dc4b6Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2475ea8dc4b6Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2476ea8dc4b6Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
2477ea8dc4b6Seschrock 		return (1);
2478ea8dc4b6Seschrock 	}
2479ea8dc4b6Seschrock 
248006eeb2adSek110237 	err = zpool_scrub(zhp, cb->cb_type);
248106eeb2adSek110237 
248206eeb2adSek110237 	return (err != 0);
2483fa9e4066Sahrens }
2484fa9e4066Sahrens 
2485fa9e4066Sahrens /*
2486fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2487fa9e4066Sahrens  *
2488fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2489fa9e4066Sahrens  */
2490fa9e4066Sahrens int
2491fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2492fa9e4066Sahrens {
2493fa9e4066Sahrens 	int c;
2494fa9e4066Sahrens 	scrub_cbdata_t cb;
2495fa9e4066Sahrens 
2496fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2497fa9e4066Sahrens 
2498fa9e4066Sahrens 	/* check options */
2499fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2500fa9e4066Sahrens 		switch (c) {
2501fa9e4066Sahrens 		case 's':
2502fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2503fa9e4066Sahrens 			break;
2504fa9e4066Sahrens 		case '?':
2505fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2506fa9e4066Sahrens 			    optopt);
250799653d4eSeschrock 			usage(B_FALSE);
2508fa9e4066Sahrens 		}
2509fa9e4066Sahrens 	}
2510fa9e4066Sahrens 
251106eeb2adSek110237 	cb.cb_argc = argc;
251206eeb2adSek110237 	cb.cb_argv = argv;
2513fa9e4066Sahrens 	argc -= optind;
2514fa9e4066Sahrens 	argv += optind;
2515fa9e4066Sahrens 
2516fa9e4066Sahrens 	if (argc < 1) {
2517fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
251899653d4eSeschrock 		usage(B_FALSE);
2519fa9e4066Sahrens 	}
2520fa9e4066Sahrens 
2521b1b8ab34Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2522fa9e4066Sahrens }
2523fa9e4066Sahrens 
2524fa9e4066Sahrens typedef struct status_cbdata {
2525fa9e4066Sahrens 	int		cb_count;
2526e9dbad6fSeschrock 	boolean_t	cb_allpools;
252799653d4eSeschrock 	boolean_t	cb_verbose;
252899653d4eSeschrock 	boolean_t	cb_explain;
252999653d4eSeschrock 	boolean_t	cb_first;
2530fa9e4066Sahrens } status_cbdata_t;
2531fa9e4066Sahrens 
2532fa9e4066Sahrens /*
2533fa9e4066Sahrens  * Print out detailed scrub status.
2534fa9e4066Sahrens  */
2535fa9e4066Sahrens void
2536fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2537fa9e4066Sahrens {
2538fa9e4066Sahrens 	vdev_stat_t *vs;
2539fa9e4066Sahrens 	uint_t vsc;
2540fa9e4066Sahrens 	time_t start, end, now;
2541fa9e4066Sahrens 	double fraction_done;
2542fa9e4066Sahrens 	uint64_t examined, total, minutes_left;
2543fa9e4066Sahrens 	char *scrub_type;
2544fa9e4066Sahrens 
2545fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2546fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2547fa9e4066Sahrens 
2548fa9e4066Sahrens 	/*
2549fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2550fa9e4066Sahrens 	 */
2551fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2552fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2553fa9e4066Sahrens 		return;
2554fa9e4066Sahrens 	}
2555fa9e4066Sahrens 
2556fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2557fa9e4066Sahrens 	    "resilver" : "scrub";
2558fa9e4066Sahrens 
2559fa9e4066Sahrens 	start = vs->vs_scrub_start;
2560fa9e4066Sahrens 	end = vs->vs_scrub_end;
2561fa9e4066Sahrens 	now = time(NULL);
2562fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2563fa9e4066Sahrens 	total = vs->vs_alloc;
2564fa9e4066Sahrens 
2565fa9e4066Sahrens 	if (end != 0) {
2566fa9e4066Sahrens 		(void) printf(gettext("%s %s with %llu errors on %s"),
2567fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
2568fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2569fa9e4066Sahrens 		return;
2570fa9e4066Sahrens 	}
2571fa9e4066Sahrens 
2572fa9e4066Sahrens 	if (examined == 0)
2573fa9e4066Sahrens 		examined = 1;
2574fa9e4066Sahrens 	if (examined > total)
2575fa9e4066Sahrens 		total = examined;
2576fa9e4066Sahrens 
2577fa9e4066Sahrens 	fraction_done = (double)examined / total;
2578fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2579fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
2580fa9e4066Sahrens 
2581fa9e4066Sahrens 	(void) printf(gettext("%s in progress, %.2f%% done, %lluh%um to go\n"),
2582fa9e4066Sahrens 	    scrub_type, 100 * fraction_done,
2583fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2584fa9e4066Sahrens }
2585fa9e4066Sahrens 
258699653d4eSeschrock typedef struct spare_cbdata {
258799653d4eSeschrock 	uint64_t	cb_guid;
258899653d4eSeschrock 	zpool_handle_t	*cb_zhp;
258999653d4eSeschrock } spare_cbdata_t;
259099653d4eSeschrock 
259199653d4eSeschrock static boolean_t
259299653d4eSeschrock find_vdev(nvlist_t *nv, uint64_t search)
259399653d4eSeschrock {
259499653d4eSeschrock 	uint64_t guid;
259599653d4eSeschrock 	nvlist_t **child;
259699653d4eSeschrock 	uint_t c, children;
259799653d4eSeschrock 
259899653d4eSeschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
259999653d4eSeschrock 	    search == guid)
260099653d4eSeschrock 		return (B_TRUE);
260199653d4eSeschrock 
260299653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
260399653d4eSeschrock 	    &child, &children) == 0) {
260499653d4eSeschrock 		for (c = 0; c < children; c++)
260599653d4eSeschrock 			if (find_vdev(child[c], search))
260699653d4eSeschrock 				return (B_TRUE);
260799653d4eSeschrock 	}
260899653d4eSeschrock 
260999653d4eSeschrock 	return (B_FALSE);
261099653d4eSeschrock }
261199653d4eSeschrock 
261299653d4eSeschrock static int
261399653d4eSeschrock find_spare(zpool_handle_t *zhp, void *data)
261499653d4eSeschrock {
261599653d4eSeschrock 	spare_cbdata_t *cbp = data;
261699653d4eSeschrock 	nvlist_t *config, *nvroot;
261799653d4eSeschrock 
261899653d4eSeschrock 	config = zpool_get_config(zhp, NULL);
261999653d4eSeschrock 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
262099653d4eSeschrock 	    &nvroot) == 0);
262199653d4eSeschrock 
262299653d4eSeschrock 	if (find_vdev(nvroot, cbp->cb_guid)) {
262399653d4eSeschrock 		cbp->cb_zhp = zhp;
262499653d4eSeschrock 		return (1);
262599653d4eSeschrock 	}
262699653d4eSeschrock 
262799653d4eSeschrock 	zpool_close(zhp);
262899653d4eSeschrock 	return (0);
262999653d4eSeschrock }
263099653d4eSeschrock 
2631fa9e4066Sahrens /*
2632fa9e4066Sahrens  * Print out configuration state as requested by status_callback.
2633fa9e4066Sahrens  */
2634fa9e4066Sahrens void
2635c67d9675Seschrock print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
26368654d025Sperrin     int namewidth, int depth, boolean_t isspare, boolean_t print_logs)
2637fa9e4066Sahrens {
2638fa9e4066Sahrens 	nvlist_t **child;
2639fa9e4066Sahrens 	uint_t c, children;
2640fa9e4066Sahrens 	vdev_stat_t *vs;
2641ea8dc4b6Seschrock 	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
2642afefbcddSeschrock 	char *vname;
2643ea8dc4b6Seschrock 	uint64_t notpresent;
264499653d4eSeschrock 	spare_cbdata_t cb;
2645990b4856Slling 	char *state;
2646fa9e4066Sahrens 
2647fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2648fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2649fa9e4066Sahrens 
2650fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2651fa9e4066Sahrens 	    &child, &children) != 0)
2652fa9e4066Sahrens 		children = 0;
2653fa9e4066Sahrens 
2654990b4856Slling 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
265599653d4eSeschrock 	if (isspare) {
265699653d4eSeschrock 		/*
265799653d4eSeschrock 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
265899653d4eSeschrock 		 * online drives.
265999653d4eSeschrock 		 */
266099653d4eSeschrock 		if (vs->vs_aux == VDEV_AUX_SPARED)
266199653d4eSeschrock 			state = "INUSE";
266299653d4eSeschrock 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
266399653d4eSeschrock 			state = "AVAIL";
266499653d4eSeschrock 	}
2665fa9e4066Sahrens 
266699653d4eSeschrock 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
266799653d4eSeschrock 	    name, state);
266899653d4eSeschrock 
266999653d4eSeschrock 	if (!isspare) {
2670fa9e4066Sahrens 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
2671fa9e4066Sahrens 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
2672fa9e4066Sahrens 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
2673fa9e4066Sahrens 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
267499653d4eSeschrock 	}
2675fa9e4066Sahrens 
2676ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2677ea8dc4b6Seschrock 	    &notpresent) == 0) {
2678ea8dc4b6Seschrock 		char *path;
2679ea8dc4b6Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
26800917b783Seschrock 		(void) printf("  was %s", path);
2681ea8dc4b6Seschrock 	} else if (vs->vs_aux != 0) {
2682fa9e4066Sahrens 		(void) printf("  ");
2683fa9e4066Sahrens 
2684fa9e4066Sahrens 		switch (vs->vs_aux) {
2685fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2686fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2687fa9e4066Sahrens 			break;
2688fa9e4066Sahrens 
2689fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2690fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2691fa9e4066Sahrens 			break;
2692fa9e4066Sahrens 
2693fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2694fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2695fa9e4066Sahrens 			break;
2696fa9e4066Sahrens 
2697eaca9bbdSeschrock 		case VDEV_AUX_VERSION_NEWER:
2698eaca9bbdSeschrock 			(void) printf(gettext("newer version"));
2699eaca9bbdSeschrock 			break;
2700eaca9bbdSeschrock 
270199653d4eSeschrock 		case VDEV_AUX_SPARED:
270299653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
270399653d4eSeschrock 			    &cb.cb_guid) == 0);
270499653d4eSeschrock 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
270599653d4eSeschrock 				if (strcmp(zpool_get_name(cb.cb_zhp),
270699653d4eSeschrock 				    zpool_get_name(zhp)) == 0)
270799653d4eSeschrock 					(void) printf(gettext("currently in "
270899653d4eSeschrock 					    "use"));
270999653d4eSeschrock 				else
271099653d4eSeschrock 					(void) printf(gettext("in use by "
271199653d4eSeschrock 					    "pool '%s'"),
271299653d4eSeschrock 					    zpool_get_name(cb.cb_zhp));
271399653d4eSeschrock 				zpool_close(cb.cb_zhp);
271499653d4eSeschrock 			} else {
271599653d4eSeschrock 				(void) printf(gettext("currently in use"));
271699653d4eSeschrock 			}
271799653d4eSeschrock 			break;
271899653d4eSeschrock 
27193d7072f8Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
27203d7072f8Seschrock 			(void) printf(gettext("too many errors"));
27213d7072f8Seschrock 			break;
27223d7072f8Seschrock 
2723fa9e4066Sahrens 		default:
2724fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2725fa9e4066Sahrens 			break;
2726fa9e4066Sahrens 		}
2727fa9e4066Sahrens 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2728fa9e4066Sahrens 		/*
2729fa9e4066Sahrens 		 * Report bytes resilvered/repaired on leaf devices.
2730fa9e4066Sahrens 		 */
2731fa9e4066Sahrens 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2732fa9e4066Sahrens 		(void) printf(gettext("  %s %s"), repaired,
2733fa9e4066Sahrens 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2734fa9e4066Sahrens 		    "resilvered" : "repaired");
2735fa9e4066Sahrens 	}
2736fa9e4066Sahrens 
2737fa9e4066Sahrens 	(void) printf("\n");
2738fa9e4066Sahrens 
2739afefbcddSeschrock 	for (c = 0; c < children; c++) {
27408654d025Sperrin 		uint64_t is_log = B_FALSE;
27418654d025Sperrin 
27428654d025Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
27438654d025Sperrin 		    &is_log);
27448654d025Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
27458654d025Sperrin 			continue;
274699653d4eSeschrock 		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
2747c67d9675Seschrock 		print_status_config(zhp, vname, child[c],
27488654d025Sperrin 		    namewidth, depth + 2, isspare, B_FALSE);
2749afefbcddSeschrock 		free(vname);
2750afefbcddSeschrock 	}
2751fa9e4066Sahrens }
2752fa9e4066Sahrens 
2753ea8dc4b6Seschrock static void
2754ea8dc4b6Seschrock print_error_log(zpool_handle_t *zhp)
2755ea8dc4b6Seschrock {
275675519f38Sek110237 	nvlist_t *nverrlist = NULL;
275755434c77Sek110237 	nvpair_t *elem;
275855434c77Sek110237 	char *pathname;
275955434c77Sek110237 	size_t len = MAXPATHLEN * 2;
2760ea8dc4b6Seschrock 
276155434c77Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2762ea8dc4b6Seschrock 		(void) printf("errors: List of errors unavailable "
2763ea8dc4b6Seschrock 		    "(insufficient privileges)\n");
2764ea8dc4b6Seschrock 		return;
2765ea8dc4b6Seschrock 	}
2766ea8dc4b6Seschrock 
276755434c77Sek110237 	(void) printf("errors: Permanent errors have been "
276855434c77Sek110237 	    "detected in the following files:\n\n");
2769ea8dc4b6Seschrock 
277055434c77Sek110237 	pathname = safe_malloc(len);
277155434c77Sek110237 	elem = NULL;
277255434c77Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
277355434c77Sek110237 		nvlist_t *nv;
277455434c77Sek110237 		uint64_t dsobj, obj;
2775ea8dc4b6Seschrock 
277655434c77Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
277755434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
277855434c77Sek110237 		    &dsobj) == 0);
277955434c77Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
278055434c77Sek110237 		    &obj) == 0);
278155434c77Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
278255434c77Sek110237 		(void) printf("%7s %s\n", "", pathname);
2783ea8dc4b6Seschrock 	}
278455434c77Sek110237 	free(pathname);
278555434c77Sek110237 	nvlist_free(nverrlist);
2786ea8dc4b6Seschrock }
2787ea8dc4b6Seschrock 
278899653d4eSeschrock static void
278999653d4eSeschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
279099653d4eSeschrock     int namewidth)
279199653d4eSeschrock {
279299653d4eSeschrock 	uint_t i;
279399653d4eSeschrock 	char *name;
279499653d4eSeschrock 
279599653d4eSeschrock 	if (nspares == 0)
279699653d4eSeschrock 		return;
279799653d4eSeschrock 
279899653d4eSeschrock 	(void) printf(gettext("\tspares\n"));
279999653d4eSeschrock 
280099653d4eSeschrock 	for (i = 0; i < nspares; i++) {
280199653d4eSeschrock 		name = zpool_vdev_name(g_zfs, zhp, spares[i]);
280299653d4eSeschrock 		print_status_config(zhp, name, spares[i],
28038654d025Sperrin 		    namewidth, 2, B_TRUE, B_FALSE);
280499653d4eSeschrock 		free(name);
280599653d4eSeschrock 	}
280699653d4eSeschrock }
280799653d4eSeschrock 
2808fa9e4066Sahrens /*
2809fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
2810fa9e4066Sahrens  *
2811fa9e4066Sahrens  *        pool: tank
2812fa9e4066Sahrens  *	status: DEGRADED
2813fa9e4066Sahrens  *	reason: One or more devices ...
2814fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
2815fa9e4066Sahrens  *	config:
2816fa9e4066Sahrens  *		mirror		DEGRADED
2817fa9e4066Sahrens  *                c1t0d0	OK
2818ea8dc4b6Seschrock  *                c2t0d0	UNAVAIL
2819fa9e4066Sahrens  *
2820fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
2821fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
2822fa9e4066Sahrens  */
2823fa9e4066Sahrens int
2824fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
2825fa9e4066Sahrens {
2826fa9e4066Sahrens 	status_cbdata_t *cbp = data;
2827fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2828fa9e4066Sahrens 	char *msgid;
2829fa9e4066Sahrens 	int reason;
283046657f8dSmmusante 	const char *health;
283146657f8dSmmusante 	uint_t c;
283246657f8dSmmusante 	vdev_stat_t *vs;
2833fa9e4066Sahrens 
2834088e9d47Seschrock 	config = zpool_get_config(zhp, NULL);
2835fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
2836fa9e4066Sahrens 
2837fa9e4066Sahrens 	cbp->cb_count++;
2838fa9e4066Sahrens 
2839fa9e4066Sahrens 	/*
2840fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
2841fa9e4066Sahrens 	 * problems.
2842fa9e4066Sahrens 	 */
2843e9dbad6fSeschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
2844e9dbad6fSeschrock 		if (!cbp->cb_allpools) {
2845e9dbad6fSeschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
2846e9dbad6fSeschrock 			    zpool_get_name(zhp));
2847e9dbad6fSeschrock 			if (cbp->cb_first)
2848e9dbad6fSeschrock 				cbp->cb_first = B_FALSE;
2849e9dbad6fSeschrock 		}
2850fa9e4066Sahrens 		return (0);
2851e9dbad6fSeschrock 	}
2852fa9e4066Sahrens 
2853fa9e4066Sahrens 	if (cbp->cb_first)
285499653d4eSeschrock 		cbp->cb_first = B_FALSE;
2855fa9e4066Sahrens 	else
2856fa9e4066Sahrens 		(void) printf("\n");
2857fa9e4066Sahrens 
285846657f8dSmmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
285946657f8dSmmusante 	    &nvroot) == 0);
286046657f8dSmmusante 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
286146657f8dSmmusante 	    (uint64_t **)&vs, &c) == 0);
2862990b4856Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
2863fa9e4066Sahrens 
2864fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
2865fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
2866fa9e4066Sahrens 
2867fa9e4066Sahrens 	switch (reason) {
2868fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
2869fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2870fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
2871fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
2872fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2873fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2874fa9e4066Sahrens 		break;
2875fa9e4066Sahrens 
2876fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
2877fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2878fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
2879fa9e4066Sahrens 		    "pool to continue functioning.\n"));
2880fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2881fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2882fa9e4066Sahrens 		break;
2883fa9e4066Sahrens 
2884fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
2885fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2886fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
2887fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
2888fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
2889fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
2890fa9e4066Sahrens 		    "'zpool replace'.\n"));
2891fa9e4066Sahrens 		break;
2892fa9e4066Sahrens 
2893fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
2894fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2895b1b8ab34Slling 		    "be used because the label is missing \n\tor invalid.  "
2896fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
2897fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
2898fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
2899fa9e4066Sahrens 		    "from a backup source.\n"));
2900fa9e4066Sahrens 		break;
2901fa9e4066Sahrens 
2902fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
2903fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
2904fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
2905fa9e4066Sahrens 		    "made to correct the error.  Applications are "
2906fa9e4066Sahrens 		    "unaffected.\n"));
2907fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
2908fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
2909ea8dc4b6Seschrock 		    "'zpool clear' or replace the device with 'zpool "
2910fa9e4066Sahrens 		    "replace'.\n"));
2911fa9e4066Sahrens 		break;
2912fa9e4066Sahrens 
2913fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
2914fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
2915d7d4af51Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
2916fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
2917fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
2918fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
2919fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
2920fa9e4066Sahrens 		    "replace'.\n"));
2921fa9e4066Sahrens 		break;
2922fa9e4066Sahrens 
2923fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
2924fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
2925fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
2926fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
2927fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
2928fa9e4066Sahrens 		    "complete.\n"));
2929fa9e4066Sahrens 		break;
2930fa9e4066Sahrens 
2931ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
2932ea8dc4b6Seschrock 		(void) printf(gettext("status: One or more devices has "
2933ea8dc4b6Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
2934ea8dc4b6Seschrock 		    "Applications may be affected.\n"));
2935ea8dc4b6Seschrock 		(void) printf(gettext("action: Restore the file in question "
2936ea8dc4b6Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
2937ea8dc4b6Seschrock 		    "backup.\n"));
2938ea8dc4b6Seschrock 		break;
2939ea8dc4b6Seschrock 
2940ea8dc4b6Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
2941ea8dc4b6Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
2942ea8dc4b6Seschrock 		    "and the pool cannot be opened.\n"));
2943ea8dc4b6Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
2944ea8dc4b6Seschrock 		    "from a backup source.\n"));
2945ea8dc4b6Seschrock 		break;
2946ea8dc4b6Seschrock 
2947eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_OLDER:
2948eaca9bbdSeschrock 		(void) printf(gettext("status: The pool is formatted using an "
2949eaca9bbdSeschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
2950eaca9bbdSeschrock 		    "some features are unavailable.\n"));
2951eaca9bbdSeschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
2952eaca9bbdSeschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
2953eaca9bbdSeschrock 		    "be accessible on older software versions.\n"));
2954eaca9bbdSeschrock 		break;
2955eaca9bbdSeschrock 
2956eaca9bbdSeschrock 	case ZPOOL_STATUS_VERSION_NEWER:
2957eaca9bbdSeschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
2958eaca9bbdSeschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
2959eaca9bbdSeschrock 		    "be accessed on this system.\n"));
2960eaca9bbdSeschrock 		(void) printf(gettext("action: Access the pool from a system "
2961eaca9bbdSeschrock 		    "running more recent software, or\n\trestore the pool from "
2962eaca9bbdSeschrock 		    "backup.\n"));
2963eaca9bbdSeschrock 		break;
2964eaca9bbdSeschrock 
29653d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
29663d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
29673d7072f8Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
29683d7072f8Seschrock 		    "replicas exist for the pool to continue functioning "
29693d7072f8Seschrock 		    "in a\n\tdegraded state.\n"));
29703d7072f8Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
29713d7072f8Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
29723d7072f8Seschrock 		break;
29733d7072f8Seschrock 
29743d7072f8Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
29753d7072f8Seschrock 		(void) printf(gettext("status: One or more devices are "
29763d7072f8Seschrock 		    "faulted in response to persistent errors.  There are "
29773d7072f8Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
29783d7072f8Seschrock 		    "functioning.\n"));
29793d7072f8Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
29803d7072f8Seschrock 		    "from a backup source.  Manually marking the device\n"
29813d7072f8Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
29823d7072f8Seschrock 		    "to be recovered.\n"));
29833d7072f8Seschrock 		break;
29843d7072f8Seschrock 
2985fa9e4066Sahrens 	default:
2986fa9e4066Sahrens 		/*
2987fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
2988fa9e4066Sahrens 		 */
2989fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
2990fa9e4066Sahrens 	}
2991fa9e4066Sahrens 
2992fa9e4066Sahrens 	if (msgid != NULL)
2993fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
2994fa9e4066Sahrens 		    msgid);
2995fa9e4066Sahrens 
2996fa9e4066Sahrens 	if (config != NULL) {
2997fa9e4066Sahrens 		int namewidth;
2998ea8dc4b6Seschrock 		uint64_t nerr;
299999653d4eSeschrock 		nvlist_t **spares;
300099653d4eSeschrock 		uint_t nspares;
3001fa9e4066Sahrens 
3002fa9e4066Sahrens 
3003fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
3004fa9e4066Sahrens 		print_scrub_status(nvroot);
3005fa9e4066Sahrens 
3006c67d9675Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3007fa9e4066Sahrens 		if (namewidth < 10)
3008fa9e4066Sahrens 			namewidth = 10;
3009fa9e4066Sahrens 
3010fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
3011fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3012fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3013c67d9675Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
30148654d025Sperrin 		    namewidth, 0, B_FALSE, B_FALSE);
30158654d025Sperrin 		if (num_logs(nvroot) > 0)
30168654d025Sperrin 			print_status_config(zhp, "logs", nvroot, namewidth, 0,
30178654d025Sperrin 			    B_FALSE, B_TRUE);
301899653d4eSeschrock 
301999653d4eSeschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
302099653d4eSeschrock 		    &spares, &nspares) == 0)
302199653d4eSeschrock 			print_spares(zhp, spares, nspares, namewidth);
3022ea8dc4b6Seschrock 
3023ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3024ea8dc4b6Seschrock 		    &nerr) == 0) {
302555434c77Sek110237 			nvlist_t *nverrlist = NULL;
302655434c77Sek110237 
3027ea8dc4b6Seschrock 			/*
3028ea8dc4b6Seschrock 			 * If the approximate error count is small, get a
3029ea8dc4b6Seschrock 			 * precise count by fetching the entire log and
3030ea8dc4b6Seschrock 			 * uniquifying the results.
3031ea8dc4b6Seschrock 			 */
303275519f38Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
303355434c77Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
303455434c77Sek110237 				nvpair_t *elem;
303555434c77Sek110237 
303655434c77Sek110237 				elem = NULL;
303755434c77Sek110237 				nerr = 0;
303855434c77Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
303955434c77Sek110237 				    elem)) != NULL) {
304055434c77Sek110237 					nerr++;
304155434c77Sek110237 				}
304255434c77Sek110237 			}
304355434c77Sek110237 			nvlist_free(nverrlist);
3044ea8dc4b6Seschrock 
3045ea8dc4b6Seschrock 			(void) printf("\n");
304699653d4eSeschrock 
3047ea8dc4b6Seschrock 			if (nerr == 0)
3048ea8dc4b6Seschrock 				(void) printf(gettext("errors: No known data "
3049ea8dc4b6Seschrock 				    "errors\n"));
3050ea8dc4b6Seschrock 			else if (!cbp->cb_verbose)
3051e9dbad6fSeschrock 				(void) printf(gettext("errors: %llu data "
30525ad82045Snd150628 				    "errors, use '-v' for a list\n"),
30535ad82045Snd150628 				    (u_longlong_t)nerr);
3054ea8dc4b6Seschrock 			else
3055ea8dc4b6Seschrock 				print_error_log(zhp);
3056ea8dc4b6Seschrock 		}
3057fa9e4066Sahrens 	} else {
3058fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3059fa9e4066Sahrens 		    "determined.\n"));
3060fa9e4066Sahrens 	}
3061fa9e4066Sahrens 
3062fa9e4066Sahrens 	return (0);
3063fa9e4066Sahrens }
3064fa9e4066Sahrens 
3065fa9e4066Sahrens /*
3066fa9e4066Sahrens  * zpool status [-vx] [pool] ...
3067fa9e4066Sahrens  *
3068fa9e4066Sahrens  *	-v	Display complete error logs
3069fa9e4066Sahrens  *	-x	Display only pools with potential problems
3070fa9e4066Sahrens  *
3071fa9e4066Sahrens  * Describes the health status of all pools or some subset.
3072fa9e4066Sahrens  */
3073fa9e4066Sahrens int
3074fa9e4066Sahrens zpool_do_status(int argc, char **argv)
3075fa9e4066Sahrens {
3076fa9e4066Sahrens 	int c;
3077fa9e4066Sahrens 	int ret;
3078fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
3079fa9e4066Sahrens 
3080fa9e4066Sahrens 	/* check options */
3081fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
3082fa9e4066Sahrens 		switch (c) {
3083fa9e4066Sahrens 		case 'v':
308499653d4eSeschrock 			cb.cb_verbose = B_TRUE;
3085fa9e4066Sahrens 			break;
3086fa9e4066Sahrens 		case 'x':
308799653d4eSeschrock 			cb.cb_explain = B_TRUE;
3088fa9e4066Sahrens 			break;
3089fa9e4066Sahrens 		case '?':
3090fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3091fa9e4066Sahrens 			    optopt);
309299653d4eSeschrock 			usage(B_FALSE);
3093fa9e4066Sahrens 		}
3094fa9e4066Sahrens 	}
3095fa9e4066Sahrens 
3096fa9e4066Sahrens 	argc -= optind;
3097fa9e4066Sahrens 	argv += optind;
3098fa9e4066Sahrens 
309999653d4eSeschrock 	cb.cb_first = B_TRUE;
3100fa9e4066Sahrens 
3101e9dbad6fSeschrock 	if (argc == 0)
3102e9dbad6fSeschrock 		cb.cb_allpools = B_TRUE;
3103e9dbad6fSeschrock 
3104b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3105fa9e4066Sahrens 
3106fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
3107fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
3108e9dbad6fSeschrock 	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3109fa9e4066Sahrens 		(void) printf(gettext("all pools are healthy\n"));
3110fa9e4066Sahrens 
3111fa9e4066Sahrens 	return (ret);
3112fa9e4066Sahrens }
3113fa9e4066Sahrens 
3114eaca9bbdSeschrock typedef struct upgrade_cbdata {
3115eaca9bbdSeschrock 	int	cb_all;
3116eaca9bbdSeschrock 	int	cb_first;
3117eaca9bbdSeschrock 	int	cb_newer;
311806eeb2adSek110237 	int	cb_argc;
3119990b4856Slling 	uint64_t cb_version;
312006eeb2adSek110237 	char	**cb_argv;
3121eaca9bbdSeschrock } upgrade_cbdata_t;
3122eaca9bbdSeschrock 
3123eaca9bbdSeschrock static int
3124eaca9bbdSeschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
3125eaca9bbdSeschrock {
3126eaca9bbdSeschrock 	upgrade_cbdata_t *cbp = arg;
3127eaca9bbdSeschrock 	nvlist_t *config;
3128eaca9bbdSeschrock 	uint64_t version;
3129eaca9bbdSeschrock 	int ret = 0;
3130eaca9bbdSeschrock 
3131eaca9bbdSeschrock 	config = zpool_get_config(zhp, NULL);
3132eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3133eaca9bbdSeschrock 	    &version) == 0);
3134eaca9bbdSeschrock 
3135e7437265Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
3136eaca9bbdSeschrock 		if (!cbp->cb_all) {
3137eaca9bbdSeschrock 			if (cbp->cb_first) {
3138eaca9bbdSeschrock 				(void) printf(gettext("The following pools are "
3139eaca9bbdSeschrock 				    "out of date, and can be upgraded.  After "
3140eaca9bbdSeschrock 				    "being\nupgraded, these pools will no "
3141eaca9bbdSeschrock 				    "longer be accessible by older software "
3142eaca9bbdSeschrock 				    "versions.\n\n"));
3143eaca9bbdSeschrock 				(void) printf(gettext("VER  POOL\n"));
3144eaca9bbdSeschrock 				(void) printf(gettext("---  ------------\n"));
314599653d4eSeschrock 				cbp->cb_first = B_FALSE;
3146eaca9bbdSeschrock 			}
3147eaca9bbdSeschrock 
31485ad82045Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3149eaca9bbdSeschrock 			    zpool_get_name(zhp));
3150eaca9bbdSeschrock 		} else {
315199653d4eSeschrock 			cbp->cb_first = B_FALSE;
3152990b4856Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
315306eeb2adSek110237 			if (!ret) {
3154eaca9bbdSeschrock 				(void) printf(gettext("Successfully upgraded "
3155990b4856Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
3156eaca9bbdSeschrock 			}
315706eeb2adSek110237 		}
3158e7437265Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
3159eaca9bbdSeschrock 		assert(!cbp->cb_all);
3160eaca9bbdSeschrock 
3161eaca9bbdSeschrock 		if (cbp->cb_first) {
3162eaca9bbdSeschrock 			(void) printf(gettext("The following pools are "
3163eaca9bbdSeschrock 			    "formatted using a newer software version and\n"
3164eaca9bbdSeschrock 			    "cannot be accessed on the current system.\n\n"));
3165eaca9bbdSeschrock 			(void) printf(gettext("VER  POOL\n"));
3166eaca9bbdSeschrock 			(void) printf(gettext("---  ------------\n"));
316799653d4eSeschrock 			cbp->cb_first = B_FALSE;
3168eaca9bbdSeschrock 		}
3169eaca9bbdSeschrock 
31705ad82045Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3171eaca9bbdSeschrock 		    zpool_get_name(zhp));
3172eaca9bbdSeschrock 	}
3173eaca9bbdSeschrock 
3174eaca9bbdSeschrock 	zpool_close(zhp);
3175eaca9bbdSeschrock 	return (ret);
3176eaca9bbdSeschrock }
3177eaca9bbdSeschrock 
3178eaca9bbdSeschrock /* ARGSUSED */
3179eaca9bbdSeschrock static int
318006eeb2adSek110237 upgrade_one(zpool_handle_t *zhp, void *data)
3181eaca9bbdSeschrock {
3182990b4856Slling 	upgrade_cbdata_t *cbp = data;
3183990b4856Slling 	uint64_t cur_version;
3184eaca9bbdSeschrock 	int ret;
3185eaca9bbdSeschrock 
31868654d025Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
31878654d025Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
31888654d025Sperrin 		    "Pool 'log' must be renamed using export and import"
31898654d025Sperrin 		    " to upgrade.\n"));
31908654d025Sperrin 		return (1);
31918654d025Sperrin 	}
3192990b4856Slling 
3193990b4856Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3194990b4856Slling 	if (cur_version >= cbp->cb_version) {
3195eaca9bbdSeschrock 		(void) printf(gettext("Pool '%s' is already formatted "
3196990b4856Slling 		    "using more current version '%d'.\n"), zpool_get_name(zhp),
3197990b4856Slling 		    cur_version);
3198eaca9bbdSeschrock 		return (0);
3199eaca9bbdSeschrock 	}
3200eaca9bbdSeschrock 
3201990b4856Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
320206eeb2adSek110237 
320306eeb2adSek110237 	if (!ret) {
320444cd46caSbillm 		(void) printf(gettext("Successfully upgraded '%s' "
3205990b4856Slling 		    "from version %llu to version %llu\n\n"),
3206990b4856Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3207990b4856Slling 		    (u_longlong_t)cbp->cb_version);
320806eeb2adSek110237 	}
3209eaca9bbdSeschrock 
3210eaca9bbdSeschrock 	return (ret != 0);
3211eaca9bbdSeschrock }
3212eaca9bbdSeschrock 
3213eaca9bbdSeschrock /*
3214eaca9bbdSeschrock  * zpool upgrade
3215eaca9bbdSeschrock  * zpool upgrade -v
3216990b4856Slling  * zpool upgrade [-V version] <-a | pool ...>
3217eaca9bbdSeschrock  *
3218eaca9bbdSeschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
3219eaca9bbdSeschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
3220eaca9bbdSeschrock  * upgrade all pools.
3221eaca9bbdSeschrock  */
3222eaca9bbdSeschrock int
3223eaca9bbdSeschrock zpool_do_upgrade(int argc, char **argv)
3224eaca9bbdSeschrock {
3225eaca9bbdSeschrock 	int c;
3226eaca9bbdSeschrock 	upgrade_cbdata_t cb = { 0 };
3227eaca9bbdSeschrock 	int ret = 0;
3228eaca9bbdSeschrock 	boolean_t showversions = B_FALSE;
3229990b4856Slling 	char *end;
3230990b4856Slling 
3231eaca9bbdSeschrock 
3232eaca9bbdSeschrock 	/* check options */
3233990b4856Slling 	while ((c = getopt(argc, argv, "avV:")) != -1) {
3234eaca9bbdSeschrock 		switch (c) {
3235eaca9bbdSeschrock 		case 'a':
323699653d4eSeschrock 			cb.cb_all = B_TRUE;
3237eaca9bbdSeschrock 			break;
3238eaca9bbdSeschrock 		case 'v':
3239eaca9bbdSeschrock 			showversions = B_TRUE;
3240eaca9bbdSeschrock 			break;
3241990b4856Slling 		case 'V':
3242990b4856Slling 			cb.cb_version = strtoll(optarg, &end, 10);
3243351420b3Slling 			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
3244351420b3Slling 			    cb.cb_version < SPA_VERSION_1) {
3245990b4856Slling 				(void) fprintf(stderr,
3246990b4856Slling 				    gettext("invalid version '%s'\n"), optarg);
3247990b4856Slling 				usage(B_FALSE);
3248990b4856Slling 			}
3249990b4856Slling 			break;
3250eaca9bbdSeschrock 		case '?':
3251eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3252eaca9bbdSeschrock 			    optopt);
325399653d4eSeschrock 			usage(B_FALSE);
3254eaca9bbdSeschrock 		}
3255eaca9bbdSeschrock 	}
3256eaca9bbdSeschrock 
325706eeb2adSek110237 	cb.cb_argc = argc;
325806eeb2adSek110237 	cb.cb_argv = argv;
3259eaca9bbdSeschrock 	argc -= optind;
3260eaca9bbdSeschrock 	argv += optind;
3261eaca9bbdSeschrock 
3262351420b3Slling 	if (cb.cb_version == 0) {
3263351420b3Slling 		cb.cb_version = SPA_VERSION;
3264351420b3Slling 	} else if (!cb.cb_all && argc == 0) {
3265351420b3Slling 		(void) fprintf(stderr, gettext("-V option is "
3266351420b3Slling 		    "incompatible with other arguments\n"));
3267351420b3Slling 		usage(B_FALSE);
3268351420b3Slling 	}
3269351420b3Slling 
3270eaca9bbdSeschrock 	if (showversions) {
3271eaca9bbdSeschrock 		if (cb.cb_all || argc != 0) {
3272eaca9bbdSeschrock 			(void) fprintf(stderr, gettext("-v option is "
3273eaca9bbdSeschrock 			    "incompatible with other arguments\n"));
327499653d4eSeschrock 			usage(B_FALSE);
3275eaca9bbdSeschrock 		}
3276eaca9bbdSeschrock 	} else if (cb.cb_all) {
3277eaca9bbdSeschrock 		if (argc != 0) {
3278351420b3Slling 			(void) fprintf(stderr, gettext("-a option should not "
3279351420b3Slling 			    "be used along with a pool name\n"));
328099653d4eSeschrock 			usage(B_FALSE);
3281eaca9bbdSeschrock 		}
3282eaca9bbdSeschrock 	}
3283eaca9bbdSeschrock 
3284e7437265Sahrens 	(void) printf(gettext("This system is currently running "
3285e7437265Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
328699653d4eSeschrock 	cb.cb_first = B_TRUE;
3287eaca9bbdSeschrock 	if (showversions) {
3288eaca9bbdSeschrock 		(void) printf(gettext("The following versions are "
3289d7d4af51Smmusante 		    "supported:\n\n"));
3290eaca9bbdSeschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
3291eaca9bbdSeschrock 		(void) printf("---  -----------------------------------------"
3292eaca9bbdSeschrock 		    "---------------\n");
329399653d4eSeschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
329444cd46caSbillm 		(void) printf(gettext(" 2   Ditto blocks "
329544cd46caSbillm 		    "(replicated metadata)\n"));
329699653d4eSeschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
329799653d4eSeschrock 		    "RAID-Z\n"));
3298d7306b64Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
3299c9431fa1Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
3300c9431fa1Sahl 		    "algorithm\n"));
3301990b4856Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
33028654d025Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
3303ecd6cf80Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
3304*a9799022Sck153898 		(void) printf(gettext(" 9  refquota and refreservation "
3305*a9799022Sck153898 		    "properties\n"));
33068654d025Sperrin 		(void) printf(gettext("For more information on a particular "
3307eaca9bbdSeschrock 		    "version, including supported releases, see:\n\n"));
3308eaca9bbdSeschrock 		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3309eaca9bbdSeschrock 		    "version/N\n\n");
3310eaca9bbdSeschrock 		(void) printf(gettext("Where 'N' is the version number.\n"));
3311eaca9bbdSeschrock 	} else if (argc == 0) {
3312eaca9bbdSeschrock 		int notfound;
3313eaca9bbdSeschrock 
331499653d4eSeschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3315eaca9bbdSeschrock 		notfound = cb.cb_first;
3316eaca9bbdSeschrock 
3317eaca9bbdSeschrock 		if (!cb.cb_all && ret == 0) {
3318eaca9bbdSeschrock 			if (!cb.cb_first)
3319eaca9bbdSeschrock 				(void) printf("\n");
3320eaca9bbdSeschrock 			cb.cb_first = B_TRUE;
3321eaca9bbdSeschrock 			cb.cb_newer = B_TRUE;
332299653d4eSeschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3323eaca9bbdSeschrock 			if (!cb.cb_first) {
3324eaca9bbdSeschrock 				notfound = B_FALSE;
3325eaca9bbdSeschrock 				(void) printf("\n");
3326eaca9bbdSeschrock 			}
3327eaca9bbdSeschrock 		}
3328eaca9bbdSeschrock 
3329eaca9bbdSeschrock 		if (ret == 0) {
3330eaca9bbdSeschrock 			if (notfound)
3331eaca9bbdSeschrock 				(void) printf(gettext("All pools are formatted "
3332eaca9bbdSeschrock 				    "using this version.\n"));
3333eaca9bbdSeschrock 			else if (!cb.cb_all)
3334eaca9bbdSeschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
3335eaca9bbdSeschrock 				    "for a list of available versions and "
3336eaca9bbdSeschrock 				    "their associated\nfeatures.\n"));
3337eaca9bbdSeschrock 		}
3338eaca9bbdSeschrock 	} else {
3339b1b8ab34Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3340b1b8ab34Slling 		    upgrade_one, &cb);
334106eeb2adSek110237 	}
334206eeb2adSek110237 
334306eeb2adSek110237 	return (ret);
334406eeb2adSek110237 }
334506eeb2adSek110237 
3346ecd6cf80Smarks typedef struct hist_cbdata {
3347ecd6cf80Smarks 	boolean_t first;
3348ecd6cf80Smarks 	int longfmt;
3349ecd6cf80Smarks 	int internal;
3350ecd6cf80Smarks } hist_cbdata_t;
3351ecd6cf80Smarks 
3352ecd6cf80Smarks char *hist_event_table[LOG_END] = {
3353ecd6cf80Smarks 	"invalid event",
3354ecd6cf80Smarks 	"pool create",
3355ecd6cf80Smarks 	"vdev add",
3356ecd6cf80Smarks 	"pool remove",
3357ecd6cf80Smarks 	"pool destroy",
3358ecd6cf80Smarks 	"pool export",
3359ecd6cf80Smarks 	"pool import",
3360ecd6cf80Smarks 	"vdev attach",
3361ecd6cf80Smarks 	"vdev replace",
3362ecd6cf80Smarks 	"vdev detach",
3363ecd6cf80Smarks 	"vdev online",
3364ecd6cf80Smarks 	"vdev offline",
3365ecd6cf80Smarks 	"vdev upgrade",
3366ecd6cf80Smarks 	"pool clear",
3367ecd6cf80Smarks 	"pool scrub",
3368ecd6cf80Smarks 	"pool property set",
3369ecd6cf80Smarks 	"create",
3370ecd6cf80Smarks 	"clone",
3371ecd6cf80Smarks 	"destroy",
3372ecd6cf80Smarks 	"destroy_begin_sync",
3373ecd6cf80Smarks 	"inherit",
3374ecd6cf80Smarks 	"property set",
3375ecd6cf80Smarks 	"quota set",
3376ecd6cf80Smarks 	"permission update",
3377ecd6cf80Smarks 	"permission remove",
3378ecd6cf80Smarks 	"permission who remove",
3379ecd6cf80Smarks 	"promote",
3380ecd6cf80Smarks 	"receive",
3381ecd6cf80Smarks 	"rename",
3382ecd6cf80Smarks 	"reservation set",
3383ecd6cf80Smarks 	"replay_inc_sync",
3384ecd6cf80Smarks 	"replay_full_sync",
3385ecd6cf80Smarks 	"rollback",
3386ecd6cf80Smarks 	"snapshot",
3387e7437265Sahrens 	"filesystem version upgrade",
3388*a9799022Sck153898 	"refquota set",
3389*a9799022Sck153898 	"refreservation set",
3390ecd6cf80Smarks };
3391ecd6cf80Smarks 
339206eeb2adSek110237 /*
339306eeb2adSek110237  * Print out the command history for a specific pool.
339406eeb2adSek110237  */
339506eeb2adSek110237 static int
339606eeb2adSek110237 get_history_one(zpool_handle_t *zhp, void *data)
339706eeb2adSek110237 {
339806eeb2adSek110237 	nvlist_t *nvhis;
339906eeb2adSek110237 	nvlist_t **records;
340006eeb2adSek110237 	uint_t numrecords;
340106eeb2adSek110237 	char *cmdstr;
3402ecd6cf80Smarks 	char *pathstr;
340306eeb2adSek110237 	uint64_t dst_time;
340406eeb2adSek110237 	time_t tsec;
340506eeb2adSek110237 	struct tm t;
340606eeb2adSek110237 	char tbuf[30];
340706eeb2adSek110237 	int ret, i;
3408ecd6cf80Smarks 	uint64_t who;
3409ecd6cf80Smarks 	struct passwd *pwd;
3410ecd6cf80Smarks 	char *hostname;
3411ecd6cf80Smarks 	char *zonename;
3412ecd6cf80Smarks 	char internalstr[MAXPATHLEN];
3413ecd6cf80Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3414ecd6cf80Smarks 	uint64_t txg;
3415ecd6cf80Smarks 	uint64_t ievent;
341606eeb2adSek110237 
3417ecd6cf80Smarks 	cb->first = B_FALSE;
341806eeb2adSek110237 
341906eeb2adSek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
342006eeb2adSek110237 
342106eeb2adSek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
342206eeb2adSek110237 		return (ret);
342306eeb2adSek110237 
342406eeb2adSek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
342506eeb2adSek110237 	    &records, &numrecords) == 0);
342606eeb2adSek110237 	for (i = 0; i < numrecords; i++) {
342706eeb2adSek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3428ecd6cf80Smarks 		    &dst_time) != 0)
3429ecd6cf80Smarks 			continue;
3430ecd6cf80Smarks 
3431ecd6cf80Smarks 		/* is it an internal event or a standard event? */
3432ecd6cf80Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3433ecd6cf80Smarks 		    &cmdstr) != 0) {
3434ecd6cf80Smarks 			if (cb->internal == 0)
3435ecd6cf80Smarks 				continue;
3436ecd6cf80Smarks 
3437ecd6cf80Smarks 			if (nvlist_lookup_uint64(records[i],
3438ecd6cf80Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3439ecd6cf80Smarks 				continue;
3440ecd6cf80Smarks 			verify(nvlist_lookup_uint64(records[i],
3441ecd6cf80Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
3442ecd6cf80Smarks 			verify(nvlist_lookup_string(records[i],
3443ecd6cf80Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3444ecd6cf80Smarks 			if (ievent > LOG_END)
3445ecd6cf80Smarks 				continue;
3446ecd6cf80Smarks 			(void) snprintf(internalstr,
3447ecd6cf80Smarks 			    sizeof (internalstr),
3448ecd6cf80Smarks 			    "[internal %s txg:%lld] %s",
3449ecd6cf80Smarks 			    hist_event_table[ievent], txg,
3450ecd6cf80Smarks 			    pathstr);
3451ecd6cf80Smarks 			cmdstr = internalstr;
3452ecd6cf80Smarks 		}
345306eeb2adSek110237 		tsec = dst_time;
345406eeb2adSek110237 		(void) localtime_r(&tsec, &t);
345506eeb2adSek110237 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3456ecd6cf80Smarks 		(void) printf("%s %s", tbuf, cmdstr);
3457ecd6cf80Smarks 
3458ecd6cf80Smarks 		if (!cb->longfmt) {
3459ecd6cf80Smarks 			(void) printf("\n");
3460ecd6cf80Smarks 			continue;
346106eeb2adSek110237 		}
3462ecd6cf80Smarks 		(void) printf(" [");
3463ecd6cf80Smarks 		if (nvlist_lookup_uint64(records[i],
3464ecd6cf80Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
3465ecd6cf80Smarks 			pwd = getpwuid((uid_t)who);
3466ecd6cf80Smarks 			if (pwd)
3467ecd6cf80Smarks 				(void) printf("user %s on",
3468ecd6cf80Smarks 				    pwd->pw_name);
3469ecd6cf80Smarks 			else
3470ecd6cf80Smarks 				(void) printf("user %d on",
3471ecd6cf80Smarks 				    (int)who);
3472ecd6cf80Smarks 		} else {
3473ecd6cf80Smarks 			(void) printf(gettext("no info]\n"));
3474ecd6cf80Smarks 			continue;
3475ecd6cf80Smarks 		}
3476ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3477ecd6cf80Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
3478ecd6cf80Smarks 			(void) printf(" %s", hostname);
3479ecd6cf80Smarks 		}
3480ecd6cf80Smarks 		if (nvlist_lookup_string(records[i],
3481ecd6cf80Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3482ecd6cf80Smarks 			(void) printf(":%s", zonename);
3483ecd6cf80Smarks 		}
3484ecd6cf80Smarks 
3485ecd6cf80Smarks 		(void) printf("]");
3486ecd6cf80Smarks 		(void) printf("\n");
348706eeb2adSek110237 	}
348806eeb2adSek110237 	(void) printf("\n");
348906eeb2adSek110237 	nvlist_free(nvhis);
349006eeb2adSek110237 
349106eeb2adSek110237 	return (ret);
349206eeb2adSek110237 }
349306eeb2adSek110237 
349406eeb2adSek110237 /*
349506eeb2adSek110237  * zpool history <pool>
349606eeb2adSek110237  *
349706eeb2adSek110237  * Displays the history of commands that modified pools.
349806eeb2adSek110237  */
3499ecd6cf80Smarks 
3500ecd6cf80Smarks 
350106eeb2adSek110237 int
350206eeb2adSek110237 zpool_do_history(int argc, char **argv)
350306eeb2adSek110237 {
3504ecd6cf80Smarks 	hist_cbdata_t cbdata = { 0 };
350506eeb2adSek110237 	int ret;
3506ecd6cf80Smarks 	int c;
350706eeb2adSek110237 
3508ecd6cf80Smarks 	cbdata.first = B_TRUE;
3509ecd6cf80Smarks 	/* check options */
3510ecd6cf80Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
3511ecd6cf80Smarks 		switch (c) {
3512ecd6cf80Smarks 		case 'l':
3513ecd6cf80Smarks 			cbdata.longfmt = 1;
3514ecd6cf80Smarks 			break;
3515ecd6cf80Smarks 		case 'i':
3516ecd6cf80Smarks 			cbdata.internal = 1;
3517ecd6cf80Smarks 			break;
3518ecd6cf80Smarks 		case '?':
3519ecd6cf80Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3520ecd6cf80Smarks 			    optopt);
3521ecd6cf80Smarks 			usage(B_FALSE);
3522ecd6cf80Smarks 		}
3523ecd6cf80Smarks 	}
352406eeb2adSek110237 	argc -= optind;
352506eeb2adSek110237 	argv += optind;
352606eeb2adSek110237 
3527b1b8ab34Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3528ecd6cf80Smarks 	    &cbdata);
352906eeb2adSek110237 
3530ecd6cf80Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
353106eeb2adSek110237 		(void) printf(gettext("no pools available\n"));
353206eeb2adSek110237 		return (0);
3533eaca9bbdSeschrock 	}
3534eaca9bbdSeschrock 
3535eaca9bbdSeschrock 	return (ret);
3536eaca9bbdSeschrock }
3537eaca9bbdSeschrock 
3538b1b8ab34Slling static int
3539b1b8ab34Slling get_callback(zpool_handle_t *zhp, void *data)
3540b1b8ab34Slling {
3541990b4856Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3542b1b8ab34Slling 	char value[MAXNAMELEN];
3543990b4856Slling 	zprop_source_t srctype;
3544990b4856Slling 	zprop_list_t *pl;
3545b1b8ab34Slling 
3546b1b8ab34Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3547b1b8ab34Slling 
3548b1b8ab34Slling 		/*
3549990b4856Slling 		 * Skip the special fake placeholder. This will also skip
3550990b4856Slling 		 * over the name property when 'all' is specified.
3551b1b8ab34Slling 		 */
3552990b4856Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3553b1b8ab34Slling 		    pl == cbp->cb_proplist)
3554b1b8ab34Slling 			continue;
3555b1b8ab34Slling 
3556b1b8ab34Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
3557b1b8ab34Slling 		    value, sizeof (value), &srctype) != 0)
3558b1b8ab34Slling 			continue;
3559b1b8ab34Slling 
3560990b4856Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
3561b1b8ab34Slling 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3562b1b8ab34Slling 	}
3563b1b8ab34Slling 	return (0);
3564b1b8ab34Slling }
3565b1b8ab34Slling 
3566b1b8ab34Slling int
3567b1b8ab34Slling zpool_do_get(int argc, char **argv)
3568b1b8ab34Slling {
3569990b4856Slling 	zprop_get_cbdata_t cb = { 0 };
3570990b4856Slling 	zprop_list_t fake_name = { 0 };
3571b1b8ab34Slling 	int ret;
3572b1b8ab34Slling 
3573b1b8ab34Slling 	if (argc < 3)
3574b1b8ab34Slling 		usage(B_FALSE);
3575b1b8ab34Slling 
3576b1b8ab34Slling 	cb.cb_first = B_TRUE;
3577990b4856Slling 	cb.cb_sources = ZPROP_SRC_ALL;
3578b1b8ab34Slling 	cb.cb_columns[0] = GET_COL_NAME;
3579b1b8ab34Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
3580b1b8ab34Slling 	cb.cb_columns[2] = GET_COL_VALUE;
3581b1b8ab34Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
3582990b4856Slling 	cb.cb_type = ZFS_TYPE_POOL;
3583b1b8ab34Slling 
3584990b4856Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3585990b4856Slling 	    ZFS_TYPE_POOL) != 0)
3586b1b8ab34Slling 		usage(B_FALSE);
3587b1b8ab34Slling 
3588b1b8ab34Slling 	if (cb.cb_proplist != NULL) {
3589990b4856Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
3590b1b8ab34Slling 		fake_name.pl_width = strlen(gettext("NAME"));
3591b1b8ab34Slling 		fake_name.pl_next = cb.cb_proplist;
3592b1b8ab34Slling 		cb.cb_proplist = &fake_name;
3593b1b8ab34Slling 	}
3594b1b8ab34Slling 
3595b1b8ab34Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3596b1b8ab34Slling 	    get_callback, &cb);
3597b1b8ab34Slling 
3598b1b8ab34Slling 	if (cb.cb_proplist == &fake_name)
3599990b4856Slling 		zprop_free_list(fake_name.pl_next);
3600b1b8ab34Slling 	else
3601990b4856Slling 		zprop_free_list(cb.cb_proplist);
3602b1b8ab34Slling 
3603b1b8ab34Slling 	return (ret);
3604b1b8ab34Slling }
3605b1b8ab34Slling 
3606b1b8ab34Slling typedef struct set_cbdata {
3607b1b8ab34Slling 	char *cb_propname;
3608b1b8ab34Slling 	char *cb_value;
3609b1b8ab34Slling 	boolean_t cb_any_successful;
3610b1b8ab34Slling } set_cbdata_t;
3611b1b8ab34Slling 
3612b1b8ab34Slling int
3613b1b8ab34Slling set_callback(zpool_handle_t *zhp, void *data)
3614b1b8ab34Slling {
3615b1b8ab34Slling 	int error;
3616b1b8ab34Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
3617b1b8ab34Slling 
3618b1b8ab34Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3619b1b8ab34Slling 
3620b1b8ab34Slling 	if (!error)
3621b1b8ab34Slling 		cb->cb_any_successful = B_TRUE;
3622b1b8ab34Slling 
3623b1b8ab34Slling 	return (error);
3624b1b8ab34Slling }
3625b1b8ab34Slling 
3626b1b8ab34Slling int
3627b1b8ab34Slling zpool_do_set(int argc, char **argv)
3628b1b8ab34Slling {
3629b1b8ab34Slling 	set_cbdata_t cb = { 0 };
3630b1b8ab34Slling 	int error;
3631b1b8ab34Slling 
3632b1b8ab34Slling 	if (argc > 1 && argv[1][0] == '-') {
3633b1b8ab34Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3634b1b8ab34Slling 		    argv[1][1]);
3635b1b8ab34Slling 		usage(B_FALSE);
3636b1b8ab34Slling 	}
3637b1b8ab34Slling 
3638b1b8ab34Slling 	if (argc < 2) {
3639b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing property=value "
3640b1b8ab34Slling 		    "argument\n"));
3641b1b8ab34Slling 		usage(B_FALSE);
3642b1b8ab34Slling 	}
3643b1b8ab34Slling 
3644b1b8ab34Slling 	if (argc < 3) {
3645b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
3646b1b8ab34Slling 		usage(B_FALSE);
3647b1b8ab34Slling 	}
3648b1b8ab34Slling 
3649b1b8ab34Slling 	if (argc > 3) {
3650b1b8ab34Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
3651b1b8ab34Slling 		usage(B_FALSE);
3652b1b8ab34Slling 	}
3653b1b8ab34Slling 
3654b1b8ab34Slling 	cb.cb_propname = argv[1];
3655b1b8ab34Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
3656b1b8ab34Slling 	if (cb.cb_value == NULL) {
3657b1b8ab34Slling 		(void) fprintf(stderr, gettext("missing value in "
3658b1b8ab34Slling 		    "property=value argument\n"));
3659b1b8ab34Slling 		usage(B_FALSE);
3660b1b8ab34Slling 	}
3661b1b8ab34Slling 
3662b1b8ab34Slling 	*(cb.cb_value) = '\0';
3663b1b8ab34Slling 	cb.cb_value++;
3664b1b8ab34Slling 
3665b1b8ab34Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3666b1b8ab34Slling 	    set_callback, &cb);
3667b1b8ab34Slling 
3668b1b8ab34Slling 	return (error);
3669b1b8ab34Slling }
3670b1b8ab34Slling 
3671b1b8ab34Slling static int
3672b1b8ab34Slling find_command_idx(char *command, int *idx)
3673b1b8ab34Slling {
3674b1b8ab34Slling 	int i;
3675b1b8ab34Slling 
3676b1b8ab34Slling 	for (i = 0; i < NCOMMAND; i++) {
3677b1b8ab34Slling 		if (command_table[i].name == NULL)
3678b1b8ab34Slling 			continue;
3679b1b8ab34Slling 
3680b1b8ab34Slling 		if (strcmp(command, command_table[i].name) == 0) {
3681b1b8ab34Slling 			*idx = i;
3682b1b8ab34Slling 			return (0);
3683b1b8ab34Slling 		}
3684b1b8ab34Slling 	}
3685b1b8ab34Slling 	return (1);
3686b1b8ab34Slling }
3687b1b8ab34Slling 
3688fa9e4066Sahrens int
3689fa9e4066Sahrens main(int argc, char **argv)
3690fa9e4066Sahrens {
3691fa9e4066Sahrens 	int ret;
3692fa9e4066Sahrens 	int i;
3693fa9e4066Sahrens 	char *cmdname;
3694fa9e4066Sahrens 
3695fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
3696fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
3697fa9e4066Sahrens 
369899653d4eSeschrock 	if ((g_zfs = libzfs_init()) == NULL) {
369999653d4eSeschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
3700203a47d8Snd150628 		    "initialize ZFS library\n"));
370199653d4eSeschrock 		return (1);
370299653d4eSeschrock 	}
370399653d4eSeschrock 
370499653d4eSeschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
370599653d4eSeschrock 
3706fa9e4066Sahrens 	opterr = 0;
3707fa9e4066Sahrens 
3708fa9e4066Sahrens 	/*
3709fa9e4066Sahrens 	 * Make sure the user has specified some command.
3710fa9e4066Sahrens 	 */
3711fa9e4066Sahrens 	if (argc < 2) {
3712fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
371399653d4eSeschrock 		usage(B_FALSE);
3714fa9e4066Sahrens 	}
3715fa9e4066Sahrens 
3716fa9e4066Sahrens 	cmdname = argv[1];
3717fa9e4066Sahrens 
3718fa9e4066Sahrens 	/*
3719fa9e4066Sahrens 	 * Special case '-?'
3720fa9e4066Sahrens 	 */
3721fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
372299653d4eSeschrock 		usage(B_TRUE);
3723fa9e4066Sahrens 
37242a6b87f0Sek110237 	zpool_set_history_str("zpool", argc, argv, history_str);
37252a6b87f0Sek110237 	verify(zpool_stage_history(g_zfs, history_str) == 0);
37262a6b87f0Sek110237 
3727fa9e4066Sahrens 	/*
3728fa9e4066Sahrens 	 * Run the appropriate command.
3729fa9e4066Sahrens 	 */
3730b1b8ab34Slling 	if (find_command_idx(cmdname, &i) == 0) {
3731fa9e4066Sahrens 		current_command = &command_table[i];
3732fa9e4066Sahrens 		ret = command_table[i].func(argc - 1, argv + 1);
373391ebeef5Sahrens 	} else if (strchr(cmdname, '=')) {
373491ebeef5Sahrens 		verify(find_command_idx("set", &i) == 0);
373591ebeef5Sahrens 		current_command = &command_table[i];
373691ebeef5Sahrens 		ret = command_table[i].func(argc, argv);
373791ebeef5Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
3738fa9e4066Sahrens 		/*
373991ebeef5Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
374091ebeef5Sahrens 		 * it as such.
3741fa9e4066Sahrens 		 */
3742ea8dc4b6Seschrock 		char buf[16384];
3743ea8dc4b6Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
3744fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
3745fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
374691ebeef5Sahrens 	} else {
3747fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
3748fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
374999653d4eSeschrock 		usage(B_FALSE);
3750fa9e4066Sahrens 	}
3751fa9e4066Sahrens 
375299653d4eSeschrock 	libzfs_fini(g_zfs);
375399653d4eSeschrock 
3754fa9e4066Sahrens 	/*
3755fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3756fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
3757fa9e4066Sahrens 	 */
3758fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
3759fa9e4066Sahrens 		(void) printf("dumping core by request\n");
3760fa9e4066Sahrens 		abort();
3761fa9e4066Sahrens 	}
3762fa9e4066Sahrens 
3763fa9e4066Sahrens 	return (ret);
3764fa9e4066Sahrens }
3765