xref: /onnv-gate/usr/src/cmd/zpool/zpool_main.c (revision 13099:186dcc2a6f67)
1789Sahrens /*
2789Sahrens  * CDDL HEADER START
3789Sahrens  *
4789Sahrens  * The contents of this file are subject to the terms of the
51485Slling  * Common Development and Distribution License (the "License").
61485Slling  * You may not use this file except in compliance with the License.
7789Sahrens  *
8789Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9789Sahrens  * or http://www.opensolaris.org/os/licensing.
10789Sahrens  * See the License for the specific language governing permissions
11789Sahrens  * and limitations under the License.
12789Sahrens  *
13789Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14789Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15789Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16789Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17789Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18789Sahrens  *
19789Sahrens  * CDDL HEADER END
20789Sahrens  */
212082Seschrock 
22789Sahrens /*
2312296SLin.Ling@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24789Sahrens  */
25789Sahrens 
26789Sahrens #include <assert.h>
27789Sahrens #include <ctype.h>
28789Sahrens #include <dirent.h>
29789Sahrens #include <errno.h>
30789Sahrens #include <fcntl.h>
31789Sahrens #include <libgen.h>
32789Sahrens #include <libintl.h>
33789Sahrens #include <libuutil.h>
34789Sahrens #include <locale.h>
35789Sahrens #include <stdio.h>
36789Sahrens #include <stdlib.h>
37789Sahrens #include <string.h>
38789Sahrens #include <strings.h>
39789Sahrens #include <unistd.h>
40789Sahrens #include <priv.h>
414543Smarks #include <pwd.h>
424543Smarks #include <zone.h>
433912Slling #include <sys/fs/zfs.h>
44789Sahrens #include <sys/stat.h>
45789Sahrens 
46789Sahrens #include <libzfs.h>
47789Sahrens 
48789Sahrens #include "zpool_util.h"
495913Sperrin #include "zfs_comutil.h"
50789Sahrens 
5110265SKrishnendu.Sadhukhan@Sun.COM #include "statcommon.h"
5210265SKrishnendu.Sadhukhan@Sun.COM 
53789Sahrens static int zpool_do_create(int, char **);
54789Sahrens static int zpool_do_destroy(int, char **);
55789Sahrens 
56789Sahrens static int zpool_do_add(int, char **);
572082Seschrock static int zpool_do_remove(int, char **);
58789Sahrens 
59789Sahrens static int zpool_do_list(int, char **);
60789Sahrens static int zpool_do_iostat(int, char **);
61789Sahrens static int zpool_do_status(int, char **);
62789Sahrens 
63789Sahrens static int zpool_do_online(int, char **);
64789Sahrens static int zpool_do_offline(int, char **);
651544Seschrock static int zpool_do_clear(int, char **);
66789Sahrens 
67789Sahrens static int zpool_do_attach(int, char **);
68789Sahrens static int zpool_do_detach(int, char **);
69789Sahrens static int zpool_do_replace(int, char **);
7011422SMark.Musante@Sun.COM static int zpool_do_split(int, char **);
71789Sahrens 
72789Sahrens static int zpool_do_scrub(int, char **);
73789Sahrens 
74789Sahrens static int zpool_do_import(int, char **);
75789Sahrens static int zpool_do_export(int, char **);
76789Sahrens 
771760Seschrock static int zpool_do_upgrade(int, char **);
781760Seschrock 
792926Sek110237 static int zpool_do_history(int, char **);
802926Sek110237 
813912Slling static int zpool_do_get(int, char **);
823912Slling static int zpool_do_set(int, char **);
833912Slling 
84789Sahrens /*
85789Sahrens  * These libumem hooks provide a reasonable set of defaults for the allocator's
86789Sahrens  * debugging facilities.
87789Sahrens  */
886865Srm160521 
896865Srm160521 #ifdef DEBUG
90789Sahrens const char *
_umem_debug_init(void)912082Seschrock _umem_debug_init(void)
92789Sahrens {
93789Sahrens 	return ("default,verbose"); /* $UMEM_DEBUG setting */
94789Sahrens }
95789Sahrens 
96789Sahrens const char *
_umem_logging_init(void)97789Sahrens _umem_logging_init(void)
98789Sahrens {
99789Sahrens 	return ("fail,contents"); /* $UMEM_LOGGING setting */
100789Sahrens }
1016865Srm160521 #endif
102789Sahrens 
1031387Seschrock typedef enum {
1041387Seschrock 	HELP_ADD,
1051387Seschrock 	HELP_ATTACH,
1061544Seschrock 	HELP_CLEAR,
1071387Seschrock 	HELP_CREATE,
1081387Seschrock 	HELP_DESTROY,
1091387Seschrock 	HELP_DETACH,
1101387Seschrock 	HELP_EXPORT,
1112926Sek110237 	HELP_HISTORY,
1121387Seschrock 	HELP_IMPORT,
1131387Seschrock 	HELP_IOSTAT,
1141387Seschrock 	HELP_LIST,
1151387Seschrock 	HELP_OFFLINE,
1161387Seschrock 	HELP_ONLINE,
1171387Seschrock 	HELP_REPLACE,
1182082Seschrock 	HELP_REMOVE,
1191387Seschrock 	HELP_SCRUB,
1201760Seschrock 	HELP_STATUS,
1213912Slling 	HELP_UPGRADE,
1223912Slling 	HELP_GET,
12311422SMark.Musante@Sun.COM 	HELP_SET,
12411422SMark.Musante@Sun.COM 	HELP_SPLIT
1251387Seschrock } zpool_help_t;
1261387Seschrock 
1271387Seschrock 
128789Sahrens typedef struct zpool_command {
129789Sahrens 	const char	*name;
130789Sahrens 	int		(*func)(int, char **);
1311387Seschrock 	zpool_help_t	usage;
132789Sahrens } zpool_command_t;
133789Sahrens 
134789Sahrens /*
135789Sahrens  * Master command table.  Each ZFS command has a name, associated function, and
1361544Seschrock  * usage message.  The usage messages need to be internationalized, so we have
1371544Seschrock  * to have a function to return the usage message based on a command index.
1381387Seschrock  *
1391387Seschrock  * These commands are organized according to how they are displayed in the usage
1401387Seschrock  * message.  An empty command (one with a NULL name) indicates an empty line in
1411387Seschrock  * the generic usage message.
142789Sahrens  */
143789Sahrens static zpool_command_t command_table[] = {
1441387Seschrock 	{ "create",	zpool_do_create,	HELP_CREATE		},
1451387Seschrock 	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
146789Sahrens 	{ NULL },
1471387Seschrock 	{ "add",	zpool_do_add,		HELP_ADD		},
1482082Seschrock 	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
149789Sahrens 	{ NULL },
1501387Seschrock 	{ "list",	zpool_do_list,		HELP_LIST		},
1511387Seschrock 	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
1521387Seschrock 	{ "status",	zpool_do_status,	HELP_STATUS		},
153789Sahrens 	{ NULL },
1541387Seschrock 	{ "online",	zpool_do_online,	HELP_ONLINE		},
1551387Seschrock 	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
1561544Seschrock 	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
157789Sahrens 	{ NULL },
1581387Seschrock 	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
1591387Seschrock 	{ "detach",	zpool_do_detach,	HELP_DETACH		},
1601387Seschrock 	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
16111422SMark.Musante@Sun.COM 	{ "split",	zpool_do_split,		HELP_SPLIT		},
162789Sahrens 	{ NULL },
1631387Seschrock 	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
1641387Seschrock 	{ NULL },
1651387Seschrock 	{ "import",	zpool_do_import,	HELP_IMPORT		},
1661387Seschrock 	{ "export",	zpool_do_export,	HELP_EXPORT		},
1672926Sek110237 	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
1682926Sek110237 	{ NULL },
1693912Slling 	{ "history",	zpool_do_history,	HELP_HISTORY		},
1703912Slling 	{ "get",	zpool_do_get,		HELP_GET		},
1713912Slling 	{ "set",	zpool_do_set,		HELP_SET		},
172789Sahrens };
173789Sahrens 
174789Sahrens #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
175789Sahrens 
176789Sahrens zpool_command_t *current_command;
1774988Sek110237 static char history_str[HIS_MAX_RECORD_LEN];
178789Sahrens 
17910265SKrishnendu.Sadhukhan@Sun.COM static uint_t timestamp_fmt = NODATE;
18010265SKrishnendu.Sadhukhan@Sun.COM 
1811387Seschrock static const char *
get_usage(zpool_help_t idx)1821387Seschrock get_usage(zpool_help_t idx) {
1831387Seschrock 	switch (idx) {
1841387Seschrock 	case HELP_ADD:
1851387Seschrock 		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
1861387Seschrock 	case HELP_ATTACH:
1871387Seschrock 		return (gettext("\tattach [-f] <pool> <device> "
1884849Sahrens 		    "<new-device>\n"));
1891544Seschrock 	case HELP_CLEAR:
19010921STim.Haley@Sun.COM 		return (gettext("\tclear [-nF] <pool> [device]\n"));
1911387Seschrock 	case HELP_CREATE:
1925094Slling 		return (gettext("\tcreate [-fn] [-o property=value] ... \n"
1937184Stimh 		    "\t    [-O file-system-property=value] ... \n"
1945094Slling 		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
1951387Seschrock 	case HELP_DESTROY:
1961387Seschrock 		return (gettext("\tdestroy [-f] <pool>\n"));
1971387Seschrock 	case HELP_DETACH:
1981387Seschrock 		return (gettext("\tdetach <pool> <device>\n"));
1991387Seschrock 	case HELP_EXPORT:
2001387Seschrock 		return (gettext("\texport [-f] <pool> ...\n"));
2012926Sek110237 	case HELP_HISTORY:
2024543Smarks 		return (gettext("\thistory [-il] [<pool>] ...\n"));
2031387Seschrock 	case HELP_IMPORT:
2041631Sdarrenm 		return (gettext("\timport [-d dir] [-D]\n"
20513049SGeorge.Wilson@Sun.COM 		    "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n"
2065363Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
20713049SGeorge.Wilson@Sun.COM 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
20813049SGeorge.Wilson@Sun.COM 		    "[-R root] [-F [-n]] -a\n"
2095363Seschrock 		    "\timport [-o mntopts] [-o property=value] ... \n"
21013049SGeorge.Wilson@Sun.COM 		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
21113049SGeorge.Wilson@Sun.COM 		    "[-R root] [-F [-n]]\n"
21213049SGeorge.Wilson@Sun.COM 		    "\t    <pool | id> [newpool]\n"));
2131387Seschrock 	case HELP_IOSTAT:
21410265SKrishnendu.Sadhukhan@Sun.COM 		return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
2151387Seschrock 		    "[count]]\n"));
2161387Seschrock 	case HELP_LIST:
2175094Slling 		return (gettext("\tlist [-H] [-o property[,...]] "
21812296SLin.Ling@Sun.COM 		    "[-T d|u] [pool] ... [interval [count]]\n"));
2191387Seschrock 	case HELP_OFFLINE:
2201485Slling 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
2211387Seschrock 	case HELP_ONLINE:
2221485Slling 		return (gettext("\tonline <pool> <device> ...\n"));
2231387Seschrock 	case HELP_REPLACE:
2241387Seschrock 		return (gettext("\treplace [-f] <pool> <device> "
2254849Sahrens 		    "[new-device]\n"));
2262082Seschrock 	case HELP_REMOVE:
2275450Sbrendan 		return (gettext("\tremove <pool> <device> ...\n"));
2281387Seschrock 	case HELP_SCRUB:
2291387Seschrock 		return (gettext("\tscrub [-s] <pool> ...\n"));
2301387Seschrock 	case HELP_STATUS:
23112296SLin.Ling@Sun.COM 		return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
23212296SLin.Ling@Sun.COM 		    "[count]]\n"));
2331760Seschrock 	case HELP_UPGRADE:
2341760Seschrock 		return (gettext("\tupgrade\n"
2351760Seschrock 		    "\tupgrade -v\n"
2365094Slling 		    "\tupgrade [-V version] <-a | pool ...>\n"));
2373912Slling 	case HELP_GET:
2384849Sahrens 		return (gettext("\tget <\"all\" | property[,...]> "
2393912Slling 		    "<pool> ...\n"));
2403912Slling 	case HELP_SET:
2413912Slling 		return (gettext("\tset <property=value> <pool> \n"));
24211422SMark.Musante@Sun.COM 	case HELP_SPLIT:
24311422SMark.Musante@Sun.COM 		return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
24411422SMark.Musante@Sun.COM 		    "\t    [-o property=value] <pool> <newpool> "
24511422SMark.Musante@Sun.COM 		    "[<device> ...]\n"));
2461387Seschrock 	}
2471387Seschrock 
2481387Seschrock 	abort();
2491387Seschrock 	/* NOTREACHED */
2501387Seschrock }
2511387Seschrock 
252789Sahrens 
253789Sahrens /*
2543912Slling  * Callback routine that will print out a pool property value.
2553912Slling  */
2565094Slling static int
print_prop_cb(int prop,void * cb)2575094Slling print_prop_cb(int prop, void *cb)
2583912Slling {
2593912Slling 	FILE *fp = cb;
2603912Slling 
26110922SJeff.Bonwick@Sun.COM 	(void) fprintf(fp, "\t%-15s  ", zpool_prop_to_name(prop));
2623912Slling 
2635094Slling 	if (zpool_prop_readonly(prop))
2645094Slling 		(void) fprintf(fp, "  NO   ");
2655094Slling 	else
26610922SJeff.Bonwick@Sun.COM 		(void) fprintf(fp, " YES   ");
2675094Slling 
2683912Slling 	if (zpool_prop_values(prop) == NULL)
2693912Slling 		(void) fprintf(fp, "-\n");
2703912Slling 	else
2713912Slling 		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
2723912Slling 
2735094Slling 	return (ZPROP_CONT);
2743912Slling }
2753912Slling 
2763912Slling /*
277789Sahrens  * Display usage message.  If we're inside a command, display only the usage for
278789Sahrens  * that command.  Otherwise, iterate over the entire command table and display
279789Sahrens  * a complete usage message.
280789Sahrens  */
281789Sahrens void
usage(boolean_t requested)2822082Seschrock usage(boolean_t requested)
283789Sahrens {
284789Sahrens 	FILE *fp = requested ? stdout : stderr;
285789Sahrens 
286789Sahrens 	if (current_command == NULL) {
287789Sahrens 		int i;
288789Sahrens 
289789Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
290789Sahrens 		(void) fprintf(fp,
291789Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
292789Sahrens 
293789Sahrens 		for (i = 0; i < NCOMMAND; i++) {
294789Sahrens 			if (command_table[i].name == NULL)
295789Sahrens 				(void) fprintf(fp, "\n");
296789Sahrens 			else
297789Sahrens 				(void) fprintf(fp, "%s",
2981387Seschrock 				    get_usage(command_table[i].usage));
299789Sahrens 		}
300789Sahrens 	} else {
301789Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
3021387Seschrock 		(void) fprintf(fp, "%s", get_usage(current_command->usage));
303789Sahrens 	}
304789Sahrens 
3053912Slling 	if (current_command != NULL &&
3063912Slling 	    ((strcmp(current_command->name, "set") == 0) ||
3075094Slling 	    (strcmp(current_command->name, "get") == 0) ||
3085094Slling 	    (strcmp(current_command->name, "list") == 0))) {
3093912Slling 
3103912Slling 		(void) fprintf(fp,
3113912Slling 		    gettext("\nthe following properties are supported:\n"));
3123912Slling 
31310922SJeff.Bonwick@Sun.COM 		(void) fprintf(fp, "\n\t%-15s  %s   %s\n\n",
3145094Slling 		    "PROPERTY", "EDIT", "VALUES");
3153912Slling 
3163912Slling 		/* Iterate over all properties */
3175094Slling 		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
3185094Slling 		    ZFS_TYPE_POOL);
3193912Slling 	}
3203912Slling 
3212676Seschrock 	/*
3222676Seschrock 	 * See comments at end of main().
3232676Seschrock 	 */
3242676Seschrock 	if (getenv("ZFS_ABORT") != NULL) {
3252676Seschrock 		(void) printf("dumping core by request\n");
3262676Seschrock 		abort();
3272676Seschrock 	}
3282676Seschrock 
329789Sahrens 	exit(requested ? 0 : 2);
330789Sahrens }
331789Sahrens 
332789Sahrens void
print_vdev_tree(zpool_handle_t * zhp,const char * name,nvlist_t * nv,int indent,boolean_t print_logs)3334527Sperrin print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
3344527Sperrin     boolean_t print_logs)
335789Sahrens {
336789Sahrens 	nvlist_t **child;
337789Sahrens 	uint_t c, children;
3381171Seschrock 	char *vname;
339789Sahrens 
340789Sahrens 	if (name != NULL)
341789Sahrens 		(void) printf("\t%*s%s\n", indent, "", name);
342789Sahrens 
343789Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
344789Sahrens 	    &child, &children) != 0)
345789Sahrens 		return;
346789Sahrens 
3471171Seschrock 	for (c = 0; c < children; c++) {
3484527Sperrin 		uint64_t is_log = B_FALSE;
3494527Sperrin 
3504527Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3514527Sperrin 		    &is_log);
3524527Sperrin 		if ((is_log && !print_logs) || (!is_log && print_logs))
3534527Sperrin 			continue;
3544527Sperrin 
35510594SGeorge.Wilson@Sun.COM 		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
3564527Sperrin 		print_vdev_tree(zhp, vname, child[c], indent + 2,
3574527Sperrin 		    B_FALSE);
3581171Seschrock 		free(vname);
3591171Seschrock 	}
360789Sahrens }
361789Sahrens 
362789Sahrens /*
3635094Slling  * Add a property pair (name, string-value) into a property nvlist.
3645094Slling  */
3655094Slling static int
add_prop_list(const char * propname,char * propval,nvlist_t ** props,boolean_t poolprop)3667184Stimh add_prop_list(const char *propname, char *propval, nvlist_t **props,
3677184Stimh     boolean_t poolprop)
3685094Slling {
3697184Stimh 	zpool_prop_t prop = ZPROP_INVAL;
3707184Stimh 	zfs_prop_t fprop;
3717184Stimh 	nvlist_t *proplist;
3727184Stimh 	const char *normnm;
3735094Slling 	char *strval;
3745094Slling 
3755094Slling 	if (*props == NULL &&
3765094Slling 	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
3775094Slling 		(void) fprintf(stderr,
3785094Slling 		    gettext("internal error: out of memory\n"));
3795094Slling 		return (1);
3805094Slling 	}
3815094Slling 
3825094Slling 	proplist = *props;
3835094Slling 
3847184Stimh 	if (poolprop) {
3857184Stimh 		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
3867184Stimh 			(void) fprintf(stderr, gettext("property '%s' is "
3877184Stimh 			    "not a valid pool property\n"), propname);
3887184Stimh 			return (2);
3897184Stimh 		}
3907184Stimh 		normnm = zpool_prop_to_name(prop);
3917184Stimh 	} else {
3929396SMatthew.Ahrens@Sun.COM 		if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
3939396SMatthew.Ahrens@Sun.COM 			normnm = zfs_prop_to_name(fprop);
3949396SMatthew.Ahrens@Sun.COM 		} else {
3959396SMatthew.Ahrens@Sun.COM 			normnm = propname;
3967184Stimh 		}
3975094Slling 	}
3985094Slling 
3997184Stimh 	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
4007184Stimh 	    prop != ZPOOL_PROP_CACHEFILE) {
4015094Slling 		(void) fprintf(stderr, gettext("property '%s' "
4025094Slling 		    "specified multiple times\n"), propname);
4035094Slling 		return (2);
4045094Slling 	}
4055094Slling 
4067184Stimh 	if (nvlist_add_string(proplist, normnm, propval) != 0) {
4075094Slling 		(void) fprintf(stderr, gettext("internal "
4085094Slling 		    "error: out of memory\n"));
4095094Slling 		return (1);
4105094Slling 	}
4115094Slling 
4125094Slling 	return (0);
4135094Slling }
4145094Slling 
4155094Slling /*
416789Sahrens  * zpool add [-fn] <pool> <vdev> ...
417789Sahrens  *
418789Sahrens  *	-f	Force addition of devices, even if they appear in use
419789Sahrens  *	-n	Do not add the devices, but display the resulting layout if
420789Sahrens  *		they were to be added.
421789Sahrens  *
422789Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
423789Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
424789Sahrens  * libzfs.
425789Sahrens  */
426789Sahrens int
zpool_do_add(int argc,char ** argv)427789Sahrens zpool_do_add(int argc, char **argv)
428789Sahrens {
4292082Seschrock 	boolean_t force = B_FALSE;
4302082Seschrock 	boolean_t dryrun = B_FALSE;
431789Sahrens 	int c;
432789Sahrens 	nvlist_t *nvroot;
433789Sahrens 	char *poolname;
434789Sahrens 	int ret;
435789Sahrens 	zpool_handle_t *zhp;
436789Sahrens 	nvlist_t *config;
437789Sahrens 
438789Sahrens 	/* check options */
439789Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
440789Sahrens 		switch (c) {
441789Sahrens 		case 'f':
4422082Seschrock 			force = B_TRUE;
443789Sahrens 			break;
444789Sahrens 		case 'n':
4452082Seschrock 			dryrun = B_TRUE;
446789Sahrens 			break;
447789Sahrens 		case '?':
448789Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
449789Sahrens 			    optopt);
4502082Seschrock 			usage(B_FALSE);
451789Sahrens 		}
452789Sahrens 	}
453789Sahrens 
454789Sahrens 	argc -= optind;
455789Sahrens 	argv += optind;
456789Sahrens 
457789Sahrens 	/* get pool name and check number of arguments */
458789Sahrens 	if (argc < 1) {
459789Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
4602082Seschrock 		usage(B_FALSE);
461789Sahrens 	}
462789Sahrens 	if (argc < 2) {
463789Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
4642082Seschrock 		usage(B_FALSE);
465789Sahrens 	}
466789Sahrens 
467789Sahrens 	poolname = argv[0];
468789Sahrens 
469789Sahrens 	argc--;
470789Sahrens 	argv++;
471789Sahrens 
4722082Seschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
473789Sahrens 		return (1);
474789Sahrens 
475952Seschrock 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
476789Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
477789Sahrens 		    poolname);
478789Sahrens 		zpool_close(zhp);
479789Sahrens 		return (1);
480789Sahrens 	}
481789Sahrens 
482789Sahrens 	/* pass off to get_vdev_spec for processing */
4837343SEric.Taylor@Sun.COM 	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
4847343SEric.Taylor@Sun.COM 	    argc, argv);
485789Sahrens 	if (nvroot == NULL) {
486789Sahrens 		zpool_close(zhp);
487789Sahrens 		return (1);
488789Sahrens 	}
489789Sahrens 
490789Sahrens 	if (dryrun) {
491789Sahrens 		nvlist_t *poolnvroot;
492789Sahrens 
493789Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
494789Sahrens 		    &poolnvroot) == 0);
495789Sahrens 
496789Sahrens 		(void) printf(gettext("would update '%s' to the following "
497789Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
498789Sahrens 
4994527Sperrin 		/* print original main pool and new tree */
5004527Sperrin 		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
5014527Sperrin 		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
5024527Sperrin 
5034527Sperrin 		/* Do the same for the logs */
5044527Sperrin 		if (num_logs(poolnvroot) > 0) {
5054527Sperrin 			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
5064527Sperrin 			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
5074527Sperrin 		} else if (num_logs(nvroot) > 0) {
5084527Sperrin 			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
5094527Sperrin 		}
510789Sahrens 
511789Sahrens 		ret = 0;
512789Sahrens 	} else {
513789Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
514789Sahrens 	}
515789Sahrens 
5162082Seschrock 	nvlist_free(nvroot);
5172082Seschrock 	zpool_close(zhp);
5182082Seschrock 
5192082Seschrock 	return (ret);
5202082Seschrock }
5212082Seschrock 
5222082Seschrock /*
52312296SLin.Ling@Sun.COM  * zpool remove  <pool> <vdev> ...
5242082Seschrock  *
52512296SLin.Ling@Sun.COM  * Removes the given vdev from the pool.  Currently, this supports removing
52612296SLin.Ling@Sun.COM  * spares, cache, and log devices from the pool.
5272082Seschrock  */
5282082Seschrock int
zpool_do_remove(int argc,char ** argv)5292082Seschrock zpool_do_remove(int argc, char **argv)
5302082Seschrock {
5312082Seschrock 	char *poolname;
5325450Sbrendan 	int i, ret = 0;
5332082Seschrock 	zpool_handle_t *zhp;
5342082Seschrock 
5352082Seschrock 	argc--;
5362082Seschrock 	argv++;
5372082Seschrock 
5382082Seschrock 	/* get pool name and check number of arguments */
5392082Seschrock 	if (argc < 1) {
5402082Seschrock 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
5412082Seschrock 		usage(B_FALSE);
5422082Seschrock 	}
5432082Seschrock 	if (argc < 2) {
5442082Seschrock 		(void) fprintf(stderr, gettext("missing device\n"));
5452082Seschrock 		usage(B_FALSE);
5462082Seschrock 	}
5472082Seschrock 
5482082Seschrock 	poolname = argv[0];
5492082Seschrock 
5502082Seschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
5512082Seschrock 		return (1);
5522082Seschrock 
5535450Sbrendan 	for (i = 1; i < argc; i++) {
5545450Sbrendan 		if (zpool_vdev_remove(zhp, argv[i]) != 0)
5555450Sbrendan 			ret = 1;
5565450Sbrendan 	}
5572082Seschrock 
558789Sahrens 	return (ret);
559789Sahrens }
560789Sahrens 
561789Sahrens /*
5627184Stimh  * zpool create [-fn] [-o property=value] ...
5637184Stimh  *		[-O file-system-property=value] ...
5647184Stimh  *		[-R root] [-m mountpoint] <pool> <dev> ...
565789Sahrens  *
566789Sahrens  *	-f	Force creation, even if devices appear in use
567789Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
568789Sahrens  *		were to be created.
569789Sahrens  *      -R	Create a pool under an alternate root
570789Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
571789Sahrens  *      	'/<pool>'
5725094Slling  *	-o	Set property=value.
5737184Stimh  *	-O	Set fsproperty=value in the pool's root file system
574789Sahrens  *
5753912Slling  * Creates the named pool according to the given vdev specification.  The
576789Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
577789Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
578789Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
579789Sahrens  */
580789Sahrens int
zpool_do_create(int argc,char ** argv)581789Sahrens zpool_do_create(int argc, char **argv)
582789Sahrens {
5832082Seschrock 	boolean_t force = B_FALSE;
5842082Seschrock 	boolean_t dryrun = B_FALSE;
585789Sahrens 	int c;
5865094Slling 	nvlist_t *nvroot = NULL;
587789Sahrens 	char *poolname;
5885094Slling 	int ret = 1;
589789Sahrens 	char *altroot = NULL;
590789Sahrens 	char *mountpoint = NULL;
5917184Stimh 	nvlist_t *fsprops = NULL;
5925094Slling 	nvlist_t *props = NULL;
5935363Seschrock 	char *propval;
594789Sahrens 
595789Sahrens 	/* check options */
5967184Stimh 	while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) {
597789Sahrens 		switch (c) {
598789Sahrens 		case 'f':
5992082Seschrock 			force = B_TRUE;
600789Sahrens 			break;
601789Sahrens 		case 'n':
6022082Seschrock 			dryrun = B_TRUE;
603789Sahrens 			break;
604789Sahrens 		case 'R':
605789Sahrens 			altroot = optarg;
6065094Slling 			if (add_prop_list(zpool_prop_to_name(
6077184Stimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
6085094Slling 				goto errout;
6095363Seschrock 			if (nvlist_lookup_string(props,
6105363Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
6115363Seschrock 			    &propval) == 0)
6125363Seschrock 				break;
6135094Slling 			if (add_prop_list(zpool_prop_to_name(
6147184Stimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
6155094Slling 				goto errout;
616789Sahrens 			break;
617789Sahrens 		case 'm':
618789Sahrens 			mountpoint = optarg;
619789Sahrens 			break;
6205094Slling 		case 'o':
6215094Slling 			if ((propval = strchr(optarg, '=')) == NULL) {
6225094Slling 				(void) fprintf(stderr, gettext("missing "
6235094Slling 				    "'=' for -o option\n"));
6245094Slling 				goto errout;
6255094Slling 			}
6265094Slling 			*propval = '\0';
6275094Slling 			propval++;
6285094Slling 
6297184Stimh 			if (add_prop_list(optarg, propval, &props, B_TRUE))
6307184Stimh 				goto errout;
6317184Stimh 			break;
6327184Stimh 		case 'O':
6337184Stimh 			if ((propval = strchr(optarg, '=')) == NULL) {
6347184Stimh 				(void) fprintf(stderr, gettext("missing "
6357184Stimh 				    "'=' for -O option\n"));
6367184Stimh 				goto errout;
6377184Stimh 			}
6387184Stimh 			*propval = '\0';
6397184Stimh 			propval++;
6407184Stimh 
6417184Stimh 			if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
6425094Slling 				goto errout;
6435094Slling 			break;
644789Sahrens 		case ':':
645789Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
646789Sahrens 			    "'%c' option\n"), optopt);
6475094Slling 			goto badusage;
648789Sahrens 		case '?':
649789Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
650789Sahrens 			    optopt);
6515094Slling 			goto badusage;
652789Sahrens 		}
653789Sahrens 	}
654789Sahrens 
655789Sahrens 	argc -= optind;
656789Sahrens 	argv += optind;
657789Sahrens 
658789Sahrens 	/* get pool name and check number of arguments */
659789Sahrens 	if (argc < 1) {
660789Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
6615094Slling 		goto badusage;
662789Sahrens 	}
663789Sahrens 	if (argc < 2) {
664789Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
6655094Slling 		goto badusage;
666789Sahrens 	}
667789Sahrens 
668789Sahrens 	poolname = argv[0];
669789Sahrens 
670789Sahrens 	/*
671789Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
672789Sahrens 	 * user to use 'zfs create' instead.
673789Sahrens 	 */
674789Sahrens 	if (strchr(poolname, '/') != NULL) {
675789Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
676789Sahrens 		    "character '/' in pool name\n"), poolname);
677789Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
678789Sahrens 		    "create a dataset\n"));
6795094Slling 		goto errout;
680789Sahrens 	}
681789Sahrens 
682789Sahrens 	/* pass off to get_vdev_spec for bulk processing */
6837343SEric.Taylor@Sun.COM 	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
6847343SEric.Taylor@Sun.COM 	    argc - 1, argv + 1);
685789Sahrens 	if (nvroot == NULL)
6867184Stimh 		goto errout;
687789Sahrens 
6882082Seschrock 	/* make_root_vdev() allows 0 toplevel children if there are spares */
6895913Sperrin 	if (!zfs_allocatable_devs(nvroot)) {
6902082Seschrock 		(void) fprintf(stderr, gettext("invalid vdev "
6912082Seschrock 		    "specification: at least one toplevel vdev must be "
6922082Seschrock 		    "specified\n"));
6935094Slling 		goto errout;
6942082Seschrock 	}
6952082Seschrock 
6962082Seschrock 
697789Sahrens 	if (altroot != NULL && altroot[0] != '/') {
698789Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
6992676Seschrock 		    "must be an absolute path\n"), altroot);
7005094Slling 		goto errout;
701789Sahrens 	}
702789Sahrens 
703789Sahrens 	/*
704789Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
705789Sahrens 	 * '-m' mountpoint option if it looks like its in use.
706789Sahrens 	 */
707789Sahrens 	if (mountpoint == NULL ||
708789Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
709789Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
710789Sahrens 		char buf[MAXPATHLEN];
7115904Stimh 		DIR *dirp;
712789Sahrens 
713789Sahrens 		if (mountpoint && mountpoint[0] != '/') {
714789Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
715789Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
716789Sahrens 			    "'none'\n"), mountpoint);
7175094Slling 			goto errout;
718789Sahrens 		}
719789Sahrens 
720789Sahrens 		if (mountpoint == NULL) {
721789Sahrens 			if (altroot != NULL)
722789Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
723789Sahrens 				    altroot, poolname);
724789Sahrens 			else
725789Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
726789Sahrens 				    poolname);
727789Sahrens 		} else {
728789Sahrens 			if (altroot != NULL)
729789Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
730789Sahrens 				    altroot, mountpoint);
731789Sahrens 			else
732789Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
733789Sahrens 				    mountpoint);
734789Sahrens 		}
735789Sahrens 
7365904Stimh 		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
7375904Stimh 			(void) fprintf(stderr, gettext("mountpoint '%s' : "
7385904Stimh 			    "%s\n"), buf, strerror(errno));
739789Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
740789Sahrens 			    "option to provide a different default\n"));
7415094Slling 			goto errout;
7425904Stimh 		} else if (dirp) {
7435904Stimh 			int count = 0;
7445904Stimh 
7455904Stimh 			while (count < 3 && readdir(dirp) != NULL)
7465904Stimh 				count++;
7475904Stimh 			(void) closedir(dirp);
7485904Stimh 
7495904Stimh 			if (count > 2) {
7505904Stimh 				(void) fprintf(stderr, gettext("mountpoint "
7515904Stimh 				    "'%s' exists and is not empty\n"), buf);
7525904Stimh 				(void) fprintf(stderr, gettext("use '-m' "
7535904Stimh 				    "option to provide a "
7545904Stimh 				    "different default\n"));
7555904Stimh 				goto errout;
7565904Stimh 			}
757789Sahrens 		}
758789Sahrens 	}
759789Sahrens 
760789Sahrens 	if (dryrun) {
761789Sahrens 		/*
762789Sahrens 		 * For a dry run invocation, print out a basic message and run
763789Sahrens 		 * through all the vdevs in the list and print out in an
764789Sahrens 		 * appropriate hierarchy.
765789Sahrens 		 */
766789Sahrens 		(void) printf(gettext("would create '%s' with the "
767789Sahrens 		    "following layout:\n\n"), poolname);
768789Sahrens 
7694527Sperrin 		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
7704527Sperrin 		if (num_logs(nvroot) > 0)
7714527Sperrin 			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
772789Sahrens 
773789Sahrens 		ret = 0;
774789Sahrens 	} else {
775789Sahrens 		/*
776789Sahrens 		 * Hand off to libzfs.
777789Sahrens 		 */
7787184Stimh 		if (zpool_create(g_zfs, poolname,
7797184Stimh 		    nvroot, props, fsprops) == 0) {
7802082Seschrock 			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
781789Sahrens 			    ZFS_TYPE_FILESYSTEM);
782789Sahrens 			if (pool != NULL) {
783789Sahrens 				if (mountpoint != NULL)
784789Sahrens 					verify(zfs_prop_set(pool,
7852676Seschrock 					    zfs_prop_to_name(
7862676Seschrock 					    ZFS_PROP_MOUNTPOINT),
787789Sahrens 					    mountpoint) == 0);
788789Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
7895331Samw 					ret = zfs_shareall(pool);
790789Sahrens 				zfs_close(pool);
791789Sahrens 			}
7922082Seschrock 		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
7932082Seschrock 			(void) fprintf(stderr, gettext("pool name may have "
7942082Seschrock 			    "been omitted\n"));
795789Sahrens 		}
796789Sahrens 	}
797789Sahrens 
7985094Slling errout:
7995363Seschrock 	nvlist_free(nvroot);
8007184Stimh 	nvlist_free(fsprops);
8015363Seschrock 	nvlist_free(props);
802789Sahrens 	return (ret);
8035094Slling badusage:
8047184Stimh 	nvlist_free(fsprops);
8055094Slling 	nvlist_free(props);
8065094Slling 	usage(B_FALSE);
8075094Slling 	return (2);
808789Sahrens }
809789Sahrens 
810789Sahrens /*
811789Sahrens  * zpool destroy <pool>
812789Sahrens  *
813789Sahrens  * 	-f	Forcefully unmount any datasets
814789Sahrens  *
815789Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
816789Sahrens  */
817789Sahrens int
zpool_do_destroy(int argc,char ** argv)818789Sahrens zpool_do_destroy(int argc, char **argv)
819789Sahrens {
8202082Seschrock 	boolean_t force = B_FALSE;
821789Sahrens 	int c;
822789Sahrens 	char *pool;
823789Sahrens 	zpool_handle_t *zhp;
824789Sahrens 	int ret;
825789Sahrens 
826789Sahrens 	/* check options */
827789Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
828789Sahrens 		switch (c) {
829789Sahrens 		case 'f':
8302082Seschrock 			force = B_TRUE;
831789Sahrens 			break;
832789Sahrens 		case '?':
833789Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
834789Sahrens 			    optopt);
8352082Seschrock 			usage(B_FALSE);
836789Sahrens 		}
837789Sahrens 	}
838789Sahrens 
839789Sahrens 	argc -= optind;
840789Sahrens 	argv += optind;
841789Sahrens 
842789Sahrens 	/* check arguments */
843789Sahrens 	if (argc < 1) {
844789Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
8452082Seschrock 		usage(B_FALSE);
846789Sahrens 	}
847789Sahrens 	if (argc > 1) {
848789Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
8492082Seschrock 		usage(B_FALSE);
850789Sahrens 	}
851789Sahrens 
852789Sahrens 	pool = argv[0];
853789Sahrens 
8542082Seschrock 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
855789Sahrens 		/*
856789Sahrens 		 * As a special case, check for use of '/' in the name, and
857789Sahrens 		 * direct the user to use 'zfs destroy' instead.
858789Sahrens 		 */
859789Sahrens 		if (strchr(pool, '/') != NULL)
860789Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
861789Sahrens 			    "destroy a dataset\n"));
862789Sahrens 		return (1);
863789Sahrens 	}
864789Sahrens 
8653126Sahl 	if (zpool_disable_datasets(zhp, force) != 0) {
866789Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
867789Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
868789Sahrens 		return (1);
869789Sahrens 	}
870789Sahrens 
871789Sahrens 	ret = (zpool_destroy(zhp) != 0);
872789Sahrens 
873789Sahrens 	zpool_close(zhp);
874789Sahrens 
875789Sahrens 	return (ret);
876789Sahrens }
877789Sahrens 
878789Sahrens /*
879789Sahrens  * zpool export [-f] <pool> ...
880789Sahrens  *
881789Sahrens  *	-f	Forcefully unmount datasets
882789Sahrens  *
8833912Slling  * Export the given pools.  By default, the command will attempt to cleanly
884789Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
885789Sahrens  * then the datasets will be forcefully unmounted.
886789Sahrens  */
887789Sahrens int
zpool_do_export(int argc,char ** argv)888789Sahrens zpool_do_export(int argc, char **argv)
889789Sahrens {
8902082Seschrock 	boolean_t force = B_FALSE;
8918211SGeorge.Wilson@Sun.COM 	boolean_t hardforce = B_FALSE;
892789Sahrens 	int c;
893789Sahrens 	zpool_handle_t *zhp;
894789Sahrens 	int ret;
895789Sahrens 	int i;
896789Sahrens 
897789Sahrens 	/* check options */
8988211SGeorge.Wilson@Sun.COM 	while ((c = getopt(argc, argv, "fF")) != -1) {
899789Sahrens 		switch (c) {
900789Sahrens 		case 'f':
9012082Seschrock 			force = B_TRUE;
902789Sahrens 			break;
9038211SGeorge.Wilson@Sun.COM 		case 'F':
9048211SGeorge.Wilson@Sun.COM 			hardforce = B_TRUE;
9058211SGeorge.Wilson@Sun.COM 			break;
906789Sahrens 		case '?':
907789Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
908789Sahrens 			    optopt);
9092082Seschrock 			usage(B_FALSE);
910789Sahrens 		}
911789Sahrens 	}
912789Sahrens 
913789Sahrens 	argc -= optind;
914789Sahrens 	argv += optind;
915789Sahrens 
916789Sahrens 	/* check arguments */
917789Sahrens 	if (argc < 1) {
918789Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
9192082Seschrock 		usage(B_FALSE);
920789Sahrens 	}
921789Sahrens 
922789Sahrens 	ret = 0;
923789Sahrens 	for (i = 0; i < argc; i++) {
9242082Seschrock 		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
925789Sahrens 			ret = 1;
926789Sahrens 			continue;
927789Sahrens 		}
928789Sahrens 
9293126Sahl 		if (zpool_disable_datasets(zhp, force) != 0) {
930789Sahrens 			ret = 1;
931789Sahrens 			zpool_close(zhp);
932789Sahrens 			continue;
933789Sahrens 		}
934789Sahrens 
9358211SGeorge.Wilson@Sun.COM 		if (hardforce) {
9368211SGeorge.Wilson@Sun.COM 			if (zpool_export_force(zhp) != 0)
9378211SGeorge.Wilson@Sun.COM 				ret = 1;
9388211SGeorge.Wilson@Sun.COM 		} else if (zpool_export(zhp, force) != 0) {
939789Sahrens 			ret = 1;
9408211SGeorge.Wilson@Sun.COM 		}
941789Sahrens 
942789Sahrens 		zpool_close(zhp);
943789Sahrens 	}
944789Sahrens 
945789Sahrens 	return (ret);
946789Sahrens }
947789Sahrens 
948789Sahrens /*
949789Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
950789Sahrens  * name column.
951789Sahrens  */
952789Sahrens static int
max_width(zpool_handle_t * zhp,nvlist_t * nv,int depth,int max)9531354Seschrock max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
954789Sahrens {
95510594SGeorge.Wilson@Sun.COM 	char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
956789Sahrens 	nvlist_t **child;
957789Sahrens 	uint_t c, children;
958789Sahrens 	int ret;
959789Sahrens 
960789Sahrens 	if (strlen(name) + depth > max)
961789Sahrens 		max = strlen(name) + depth;
962789Sahrens 
9631171Seschrock 	free(name);
9641171Seschrock 
9652082Seschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
9662082Seschrock 	    &child, &children) == 0) {
9672082Seschrock 		for (c = 0; c < children; c++)
9682082Seschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
9692082Seschrock 			    max)) > max)
9702082Seschrock 				max = ret;
9712082Seschrock 	}
9722082Seschrock 
9735450Sbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
9745450Sbrendan 	    &child, &children) == 0) {
9755450Sbrendan 		for (c = 0; c < children; c++)
9765450Sbrendan 			if ((ret = max_width(zhp, child[c], depth + 2,
9775450Sbrendan 			    max)) > max)
9785450Sbrendan 				max = ret;
9795450Sbrendan 	}
9805450Sbrendan 
981789Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
9822082Seschrock 	    &child, &children) == 0) {
9832082Seschrock 		for (c = 0; c < children; c++)
9842082Seschrock 			if ((ret = max_width(zhp, child[c], depth + 2,
9852082Seschrock 			    max)) > max)
9862082Seschrock 				max = ret;
9872082Seschrock 	}
9882082Seschrock 
989789Sahrens 
990789Sahrens 	return (max);
991789Sahrens }
992789Sahrens 
9939701SGeorge.Wilson@Sun.COM typedef struct spare_cbdata {
9949701SGeorge.Wilson@Sun.COM 	uint64_t	cb_guid;
9959701SGeorge.Wilson@Sun.COM 	zpool_handle_t	*cb_zhp;
9969701SGeorge.Wilson@Sun.COM } spare_cbdata_t;
9979701SGeorge.Wilson@Sun.COM 
9989701SGeorge.Wilson@Sun.COM static boolean_t
find_vdev(nvlist_t * nv,uint64_t search)9999701SGeorge.Wilson@Sun.COM find_vdev(nvlist_t *nv, uint64_t search)
10009701SGeorge.Wilson@Sun.COM {
10019701SGeorge.Wilson@Sun.COM 	uint64_t guid;
10029701SGeorge.Wilson@Sun.COM 	nvlist_t **child;
10039701SGeorge.Wilson@Sun.COM 	uint_t c, children;
10049701SGeorge.Wilson@Sun.COM 
10059701SGeorge.Wilson@Sun.COM 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
10069701SGeorge.Wilson@Sun.COM 	    search == guid)
10079701SGeorge.Wilson@Sun.COM 		return (B_TRUE);
10089701SGeorge.Wilson@Sun.COM 
10099701SGeorge.Wilson@Sun.COM 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
10109701SGeorge.Wilson@Sun.COM 	    &child, &children) == 0) {
10119701SGeorge.Wilson@Sun.COM 		for (c = 0; c < children; c++)
10129701SGeorge.Wilson@Sun.COM 			if (find_vdev(child[c], search))
10139701SGeorge.Wilson@Sun.COM 				return (B_TRUE);
10149701SGeorge.Wilson@Sun.COM 	}
10159701SGeorge.Wilson@Sun.COM 
10169701SGeorge.Wilson@Sun.COM 	return (B_FALSE);
10179701SGeorge.Wilson@Sun.COM }
10189701SGeorge.Wilson@Sun.COM 
10199701SGeorge.Wilson@Sun.COM static int
find_spare(zpool_handle_t * zhp,void * data)10209701SGeorge.Wilson@Sun.COM find_spare(zpool_handle_t *zhp, void *data)
10219701SGeorge.Wilson@Sun.COM {
10229701SGeorge.Wilson@Sun.COM 	spare_cbdata_t *cbp = data;
10239701SGeorge.Wilson@Sun.COM 	nvlist_t *config, *nvroot;
10249701SGeorge.Wilson@Sun.COM 
10259701SGeorge.Wilson@Sun.COM 	config = zpool_get_config(zhp, NULL);
10269701SGeorge.Wilson@Sun.COM 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
10279701SGeorge.Wilson@Sun.COM 	    &nvroot) == 0);
10289701SGeorge.Wilson@Sun.COM 
10299701SGeorge.Wilson@Sun.COM 	if (find_vdev(nvroot, cbp->cb_guid)) {
10309701SGeorge.Wilson@Sun.COM 		cbp->cb_zhp = zhp;
10319701SGeorge.Wilson@Sun.COM 		return (1);
10329701SGeorge.Wilson@Sun.COM 	}
10339701SGeorge.Wilson@Sun.COM 
10349701SGeorge.Wilson@Sun.COM 	zpool_close(zhp);
10359701SGeorge.Wilson@Sun.COM 	return (0);
10369701SGeorge.Wilson@Sun.COM }
10379701SGeorge.Wilson@Sun.COM 
10389701SGeorge.Wilson@Sun.COM /*
10399701SGeorge.Wilson@Sun.COM  * Print out configuration state as requested by status_callback.
10409701SGeorge.Wilson@Sun.COM  */
10419701SGeorge.Wilson@Sun.COM void
print_status_config(zpool_handle_t * zhp,const char * name,nvlist_t * nv,int namewidth,int depth,boolean_t isspare)10429701SGeorge.Wilson@Sun.COM print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
10439701SGeorge.Wilson@Sun.COM     int namewidth, int depth, boolean_t isspare)
10449701SGeorge.Wilson@Sun.COM {
10459701SGeorge.Wilson@Sun.COM 	nvlist_t **child;
10469701SGeorge.Wilson@Sun.COM 	uint_t c, children;
104712296SLin.Ling@Sun.COM 	pool_scan_stat_t *ps = NULL;
10489701SGeorge.Wilson@Sun.COM 	vdev_stat_t *vs;
104912296SLin.Ling@Sun.COM 	char rbuf[6], wbuf[6], cbuf[6];
10509701SGeorge.Wilson@Sun.COM 	char *vname;
10519701SGeorge.Wilson@Sun.COM 	uint64_t notpresent;
10529701SGeorge.Wilson@Sun.COM 	spare_cbdata_t cb;
10539701SGeorge.Wilson@Sun.COM 	char *state;
10549701SGeorge.Wilson@Sun.COM 
10559701SGeorge.Wilson@Sun.COM 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
10569701SGeorge.Wilson@Sun.COM 	    &child, &children) != 0)
10579701SGeorge.Wilson@Sun.COM 		children = 0;
10589701SGeorge.Wilson@Sun.COM 
105912296SLin.Ling@Sun.COM 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
106012296SLin.Ling@Sun.COM 	    (uint64_t **)&vs, &c) == 0);
106112296SLin.Ling@Sun.COM 
10629701SGeorge.Wilson@Sun.COM 	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
10639701SGeorge.Wilson@Sun.COM 	if (isspare) {
10649701SGeorge.Wilson@Sun.COM 		/*
10659701SGeorge.Wilson@Sun.COM 		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
10669701SGeorge.Wilson@Sun.COM 		 * online drives.
10679701SGeorge.Wilson@Sun.COM 		 */
10689701SGeorge.Wilson@Sun.COM 		if (vs->vs_aux == VDEV_AUX_SPARED)
10699701SGeorge.Wilson@Sun.COM 			state = "INUSE";
10709701SGeorge.Wilson@Sun.COM 		else if (vs->vs_state == VDEV_STATE_HEALTHY)
10719701SGeorge.Wilson@Sun.COM 			state = "AVAIL";
10729701SGeorge.Wilson@Sun.COM 	}
10739701SGeorge.Wilson@Sun.COM 
10749701SGeorge.Wilson@Sun.COM 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
10759701SGeorge.Wilson@Sun.COM 	    name, state);
10769701SGeorge.Wilson@Sun.COM 
10779701SGeorge.Wilson@Sun.COM 	if (!isspare) {
10789701SGeorge.Wilson@Sun.COM 		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
10799701SGeorge.Wilson@Sun.COM 		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
10809701SGeorge.Wilson@Sun.COM 		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
10819701SGeorge.Wilson@Sun.COM 		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
10829701SGeorge.Wilson@Sun.COM 	}
10839701SGeorge.Wilson@Sun.COM 
10849701SGeorge.Wilson@Sun.COM 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
10859701SGeorge.Wilson@Sun.COM 	    &notpresent) == 0) {
10869701SGeorge.Wilson@Sun.COM 		char *path;
10879701SGeorge.Wilson@Sun.COM 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
10889701SGeorge.Wilson@Sun.COM 		(void) printf("  was %s", path);
10899701SGeorge.Wilson@Sun.COM 	} else if (vs->vs_aux != 0) {
10909701SGeorge.Wilson@Sun.COM 		(void) printf("  ");
10919701SGeorge.Wilson@Sun.COM 
10929701SGeorge.Wilson@Sun.COM 		switch (vs->vs_aux) {
10939701SGeorge.Wilson@Sun.COM 		case VDEV_AUX_OPEN_FAILED:
10949701SGeorge.Wilson@Sun.COM 			(void) printf(gettext("cannot open"));
10959701SGeorge.Wilson@Sun.COM 			break;
10969701SGeorge.Wilson@Sun.COM 
10979701SGeorge.Wilson@Sun.COM 		case VDEV_AUX_BAD_GUID_SUM:
10989701SGeorge.Wilson@Sun.COM 			(void) printf(gettext("missing device"));
10999701SGeorge.Wilson@Sun.COM 			break;
11009701SGeorge.Wilson@Sun.COM 
11019701SGeorge.Wilson@Sun.COM 		case VDEV_AUX_NO_REPLICAS:
11029701SGeorge.Wilson@Sun.COM 			(void) printf(gettext("insufficient replicas"));
11039701SGeorge.Wilson@Sun.COM 			break;
11049701SGeorge.Wilson@Sun.COM 
11059701SGeorge.Wilson@Sun.COM 		case VDEV_AUX_VERSION_NEWER:
11069701SGeorge.Wilson@Sun.COM 			(void) printf(gettext("newer version"));
11079701SGeorge.Wilson@Sun.COM 			break;
11089701SGeorge.Wilson@Sun.COM 
11099701SGeorge.Wilson@Sun.COM 		case VDEV_AUX_SPARED:
11109701SGeorge.Wilson@Sun.COM 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
11119701SGeorge.Wilson@Sun.COM 			    &cb.cb_guid) == 0);
11129701SGeorge.Wilson@Sun.COM 			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
11139701SGeorge.Wilson@Sun.COM 				if (strcmp(zpool_get_name(cb.cb_zhp),
11149701SGeorge.Wilson@Sun.COM 				    zpool_get_name(zhp)) == 0)
11159701SGeorge.Wilson@Sun.COM 					(void) printf(gettext("currently in "
11169701SGeorge.Wilson@Sun.COM 					    "use"));
11179701SGeorge.Wilson@Sun.COM 				else
11189701SGeorge.Wilson@Sun.COM 					(void) printf(gettext("in use by "
11199701SGeorge.Wilson@Sun.COM 					    "pool '%s'"),
11209701SGeorge.Wilson@Sun.COM 					    zpool_get_name(cb.cb_zhp));
11219701SGeorge.Wilson@Sun.COM 				zpool_close(cb.cb_zhp);
11229701SGeorge.Wilson@Sun.COM 			} else {
11239701SGeorge.Wilson@Sun.COM 				(void) printf(gettext("currently in use"));
11249701SGeorge.Wilson@Sun.COM 			}
11259701SGeorge.Wilson@Sun.COM 			break;
11269701SGeorge.Wilson@Sun.COM 
11279701SGeorge.Wilson@Sun.COM 		case VDEV_AUX_ERR_EXCEEDED:
11289701SGeorge.Wilson@Sun.COM 			(void) printf(gettext("too many errors"));
11299701SGeorge.Wilson@Sun.COM 			break;
11309701SGeorge.Wilson@Sun.COM 
11319701SGeorge.Wilson@Sun.COM 		case VDEV_AUX_IO_FAILURE:
11329701SGeorge.Wilson@Sun.COM 			(void) printf(gettext("experienced I/O failures"));
11339701SGeorge.Wilson@Sun.COM 			break;
11349701SGeorge.Wilson@Sun.COM 
11359701SGeorge.Wilson@Sun.COM 		case VDEV_AUX_BAD_LOG:
11369701SGeorge.Wilson@Sun.COM 			(void) printf(gettext("bad intent log"));
11379701SGeorge.Wilson@Sun.COM 			break;
11389701SGeorge.Wilson@Sun.COM 
113910817SEric.Schrock@Sun.COM 		case VDEV_AUX_EXTERNAL:
114010817SEric.Schrock@Sun.COM 			(void) printf(gettext("external device fault"));
114110817SEric.Schrock@Sun.COM 			break;
114210817SEric.Schrock@Sun.COM 
114311422SMark.Musante@Sun.COM 		case VDEV_AUX_SPLIT_POOL:
114411422SMark.Musante@Sun.COM 			(void) printf(gettext("split into new pool"));
114511422SMark.Musante@Sun.COM 			break;
114611422SMark.Musante@Sun.COM 
11479701SGeorge.Wilson@Sun.COM 		default:
11489701SGeorge.Wilson@Sun.COM 			(void) printf(gettext("corrupted data"));
11499701SGeorge.Wilson@Sun.COM 			break;
11509701SGeorge.Wilson@Sun.COM 		}
115112296SLin.Ling@Sun.COM 	}
115212296SLin.Ling@Sun.COM 
115312296SLin.Ling@Sun.COM 	(void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS,
115412296SLin.Ling@Sun.COM 	    (uint64_t **)&ps, &c);
115512296SLin.Ling@Sun.COM 
115612296SLin.Ling@Sun.COM 	if (ps && ps->pss_state == DSS_SCANNING &&
115712296SLin.Ling@Sun.COM 	    vs->vs_scan_processed != 0 && children == 0) {
115812296SLin.Ling@Sun.COM 		(void) printf(gettext("  (%s)"),
115912296SLin.Ling@Sun.COM 		    (ps->pss_func == POOL_SCAN_RESILVER) ?
116012296SLin.Ling@Sun.COM 		    "resilvering" : "repairing");
11619701SGeorge.Wilson@Sun.COM 	}
11629701SGeorge.Wilson@Sun.COM 
11639701SGeorge.Wilson@Sun.COM 	(void) printf("\n");
11649701SGeorge.Wilson@Sun.COM 
11659701SGeorge.Wilson@Sun.COM 	for (c = 0; c < children; c++) {
116610594SGeorge.Wilson@Sun.COM 		uint64_t islog = B_FALSE, ishole = B_FALSE;
116710594SGeorge.Wilson@Sun.COM 
116810594SGeorge.Wilson@Sun.COM 		/* Don't print logs or holes here */
11699701SGeorge.Wilson@Sun.COM 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
117010594SGeorge.Wilson@Sun.COM 		    &islog);
117110594SGeorge.Wilson@Sun.COM 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
117210594SGeorge.Wilson@Sun.COM 		    &ishole);
117310594SGeorge.Wilson@Sun.COM 		if (islog || ishole)
11749701SGeorge.Wilson@Sun.COM 			continue;
117510594SGeorge.Wilson@Sun.COM 		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
11769701SGeorge.Wilson@Sun.COM 		print_status_config(zhp, vname, child[c],
11779701SGeorge.Wilson@Sun.COM 		    namewidth, depth + 2, isspare);
11789701SGeorge.Wilson@Sun.COM 		free(vname);
11799701SGeorge.Wilson@Sun.COM 	}
11809701SGeorge.Wilson@Sun.COM }
11819701SGeorge.Wilson@Sun.COM 
1182789Sahrens 
1183789Sahrens /*
1184789Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
1185789Sahrens  * pool, printing out the name and status for each one.
1186789Sahrens  */
1187789Sahrens void
print_import_config(const char * name,nvlist_t * nv,int namewidth,int depth)11889701SGeorge.Wilson@Sun.COM print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
1189789Sahrens {
1190789Sahrens 	nvlist_t **child;
1191789Sahrens 	uint_t c, children;
1192789Sahrens 	vdev_stat_t *vs;
11931171Seschrock 	char *type, *vname;
1194789Sahrens 
1195789Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
119610594SGeorge.Wilson@Sun.COM 	if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
119710594SGeorge.Wilson@Sun.COM 	    strcmp(type, VDEV_TYPE_HOLE) == 0)
1198789Sahrens 		return;
1199789Sahrens 
120012296SLin.Ling@Sun.COM 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1201789Sahrens 	    (uint64_t **)&vs, &c) == 0);
1202789Sahrens 
1203789Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
12045094Slling 	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1205789Sahrens 
1206789Sahrens 	if (vs->vs_aux != 0) {
12074451Seschrock 		(void) printf("  ");
1208789Sahrens 
1209789Sahrens 		switch (vs->vs_aux) {
1210789Sahrens 		case VDEV_AUX_OPEN_FAILED:
1211789Sahrens 			(void) printf(gettext("cannot open"));
1212789Sahrens 			break;
1213789Sahrens 
1214789Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
1215789Sahrens 			(void) printf(gettext("missing device"));
1216789Sahrens 			break;
1217789Sahrens 
1218789Sahrens 		case VDEV_AUX_NO_REPLICAS:
1219789Sahrens 			(void) printf(gettext("insufficient replicas"));
1220789Sahrens 			break;
1221789Sahrens 
12221760Seschrock 		case VDEV_AUX_VERSION_NEWER:
12231760Seschrock 			(void) printf(gettext("newer version"));
12241760Seschrock 			break;
12251760Seschrock 
12264451Seschrock 		case VDEV_AUX_ERR_EXCEEDED:
12274451Seschrock 			(void) printf(gettext("too many errors"));
12284451Seschrock 			break;
12294451Seschrock 
1230789Sahrens 		default:
1231789Sahrens 			(void) printf(gettext("corrupted data"));
1232789Sahrens 			break;
1233789Sahrens 		}
1234789Sahrens 	}
1235789Sahrens 	(void) printf("\n");
1236789Sahrens 
1237789Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1238789Sahrens 	    &child, &children) != 0)
1239789Sahrens 		return;
1240789Sahrens 
12411171Seschrock 	for (c = 0; c < children; c++) {
12424527Sperrin 		uint64_t is_log = B_FALSE;
12434527Sperrin 
12444527Sperrin 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
12454527Sperrin 		    &is_log);
12469701SGeorge.Wilson@Sun.COM 		if (is_log)
12474527Sperrin 			continue;
12484527Sperrin 
124910594SGeorge.Wilson@Sun.COM 		vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
12509701SGeorge.Wilson@Sun.COM 		print_import_config(vname, child[c], namewidth, depth + 2);
12511171Seschrock 		free(vname);
12521171Seschrock 	}
12532082Seschrock 
12545450Sbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
12555450Sbrendan 	    &child, &children) == 0) {
12565450Sbrendan 		(void) printf(gettext("\tcache\n"));
12575450Sbrendan 		for (c = 0; c < children; c++) {
125810594SGeorge.Wilson@Sun.COM 			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
12595450Sbrendan 			(void) printf("\t  %s\n", vname);
12605450Sbrendan 			free(vname);
12615450Sbrendan 		}
12625450Sbrendan 	}
12635450Sbrendan 
12642082Seschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
12655450Sbrendan 	    &child, &children) == 0) {
12665450Sbrendan 		(void) printf(gettext("\tspares\n"));
12675450Sbrendan 		for (c = 0; c < children; c++) {
126810594SGeorge.Wilson@Sun.COM 			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
12695450Sbrendan 			(void) printf("\t  %s\n", vname);
12705450Sbrendan 			free(vname);
12715450Sbrendan 		}
12722082Seschrock 	}
1273789Sahrens }
1274789Sahrens 
1275789Sahrens /*
12769701SGeorge.Wilson@Sun.COM  * Print log vdevs.
12779701SGeorge.Wilson@Sun.COM  * Logs are recorded as top level vdevs in the main pool child array
12789701SGeorge.Wilson@Sun.COM  * but with "is_log" set to 1. We use either print_status_config() or
12799701SGeorge.Wilson@Sun.COM  * print_import_config() to print the top level logs then any log
12809701SGeorge.Wilson@Sun.COM  * children (eg mirrored slogs) are printed recursively - which
12819701SGeorge.Wilson@Sun.COM  * works because only the top level vdev is marked "is_log"
12829701SGeorge.Wilson@Sun.COM  */
12839701SGeorge.Wilson@Sun.COM static void
print_logs(zpool_handle_t * zhp,nvlist_t * nv,int namewidth,boolean_t verbose)12849701SGeorge.Wilson@Sun.COM print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
12859701SGeorge.Wilson@Sun.COM {
12869701SGeorge.Wilson@Sun.COM 	uint_t c, children;
12879701SGeorge.Wilson@Sun.COM 	nvlist_t **child;
12889701SGeorge.Wilson@Sun.COM 
12899701SGeorge.Wilson@Sun.COM 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
12909701SGeorge.Wilson@Sun.COM 	    &children) != 0)
12919701SGeorge.Wilson@Sun.COM 		return;
12929701SGeorge.Wilson@Sun.COM 
12939701SGeorge.Wilson@Sun.COM 	(void) printf(gettext("\tlogs\n"));
12949701SGeorge.Wilson@Sun.COM 
12959701SGeorge.Wilson@Sun.COM 	for (c = 0; c < children; c++) {
12969701SGeorge.Wilson@Sun.COM 		uint64_t is_log = B_FALSE;
12979701SGeorge.Wilson@Sun.COM 		char *name;
12989701SGeorge.Wilson@Sun.COM 
12999701SGeorge.Wilson@Sun.COM 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
13009701SGeorge.Wilson@Sun.COM 		    &is_log);
13019701SGeorge.Wilson@Sun.COM 		if (!is_log)
13029701SGeorge.Wilson@Sun.COM 			continue;
130310594SGeorge.Wilson@Sun.COM 		name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
13049701SGeorge.Wilson@Sun.COM 		if (verbose)
13059701SGeorge.Wilson@Sun.COM 			print_status_config(zhp, name, child[c], namewidth,
13069701SGeorge.Wilson@Sun.COM 			    2, B_FALSE);
13079701SGeorge.Wilson@Sun.COM 		else
13089701SGeorge.Wilson@Sun.COM 			print_import_config(name, child[c], namewidth, 2);
13099701SGeorge.Wilson@Sun.COM 		free(name);
13109701SGeorge.Wilson@Sun.COM 	}
13119701SGeorge.Wilson@Sun.COM }
131210921STim.Haley@Sun.COM 
13139701SGeorge.Wilson@Sun.COM /*
1314789Sahrens  * Display the status for the given pool.
1315789Sahrens  */
1316789Sahrens static void
show_import(nvlist_t * config)1317789Sahrens show_import(nvlist_t *config)
1318789Sahrens {
1319789Sahrens 	uint64_t pool_state;
1320789Sahrens 	vdev_stat_t *vs;
1321789Sahrens 	char *name;
1322789Sahrens 	uint64_t guid;
1323789Sahrens 	char *msgid;
1324789Sahrens 	nvlist_t *nvroot;
1325789Sahrens 	int reason;
13263741Smmusante 	const char *health;
1327789Sahrens 	uint_t vsc;
1328789Sahrens 	int namewidth;
1329789Sahrens 
1330789Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1331789Sahrens 	    &name) == 0);
1332789Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1333789Sahrens 	    &guid) == 0);
1334789Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1335789Sahrens 	    &pool_state) == 0);
1336789Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1337789Sahrens 	    &nvroot) == 0);
1338789Sahrens 
133912296SLin.Ling@Sun.COM 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
1340789Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
13415094Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1342789Sahrens 
1343789Sahrens 	reason = zpool_import_status(config, &msgid);
1344789Sahrens 
13453741Smmusante 	(void) printf(gettext("  pool: %s\n"), name);
13463741Smmusante 	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
13473741Smmusante 	(void) printf(gettext(" state: %s"), health);
13481631Sdarrenm 	if (pool_state == POOL_STATE_DESTROYED)
13493912Slling 		(void) printf(gettext(" (DESTROYED)"));
13501631Sdarrenm 	(void) printf("\n");
1351789Sahrens 
1352789Sahrens 	switch (reason) {
1353789Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
1354789Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
1355789Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
1356789Sahrens 		(void) printf(gettext("status: One or more devices are missing "
1357789Sahrens 		    "from the system.\n"));
1358789Sahrens 		break;
1359789Sahrens 
1360789Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1361789Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1362789Sahrens 		(void) printf(gettext("status: One or more devices contains "
1363789Sahrens 		    "corrupted data.\n"));
1364789Sahrens 		break;
1365789Sahrens 
1366789Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
1367789Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
1368789Sahrens 		break;
1369789Sahrens 
13701485Slling 	case ZPOOL_STATUS_OFFLINE_DEV:
13711485Slling 		(void) printf(gettext("status: One or more devices "
13721485Slling 		    "are offlined.\n"));
13731485Slling 		break;
13741485Slling 
13751544Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
13761544Seschrock 		(void) printf(gettext("status: The pool metadata is "
13771544Seschrock 		    "corrupted.\n"));
13781544Seschrock 		break;
13791544Seschrock 
13801760Seschrock 	case ZPOOL_STATUS_VERSION_OLDER:
13811760Seschrock 		(void) printf(gettext("status: The pool is formatted using an "
13821760Seschrock 		    "older on-disk version.\n"));
13831760Seschrock 		break;
13841760Seschrock 
13851760Seschrock 	case ZPOOL_STATUS_VERSION_NEWER:
13861760Seschrock 		(void) printf(gettext("status: The pool is formatted using an "
13871760Seschrock 		    "incompatible version.\n"));
13881760Seschrock 		break;
13897294Sperrin 
13903975Sek110237 	case ZPOOL_STATUS_HOSTID_MISMATCH:
13913975Sek110237 		(void) printf(gettext("status: The pool was last accessed by "
13923975Sek110237 		    "another system.\n"));
13933975Sek110237 		break;
13947294Sperrin 
13954451Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
13964451Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
13974451Seschrock 		(void) printf(gettext("status: One or more devices are "
13984451Seschrock 		    "faulted.\n"));
13994451Seschrock 		break;
14004451Seschrock 
14017294Sperrin 	case ZPOOL_STATUS_BAD_LOG:
14027294Sperrin 		(void) printf(gettext("status: An intent log record cannot be "
14037294Sperrin 		    "read.\n"));
14047294Sperrin 		break;
14057294Sperrin 
140612296SLin.Ling@Sun.COM 	case ZPOOL_STATUS_RESILVERING:
140712296SLin.Ling@Sun.COM 		(void) printf(gettext("status: One or more devices were being "
140812296SLin.Ling@Sun.COM 		    "resilvered.\n"));
140912296SLin.Ling@Sun.COM 		break;
141012296SLin.Ling@Sun.COM 
1411789Sahrens 	default:
1412789Sahrens 		/*
1413789Sahrens 		 * No other status can be seen when importing pools.
1414789Sahrens 		 */
1415789Sahrens 		assert(reason == ZPOOL_STATUS_OK);
1416789Sahrens 	}
1417789Sahrens 
1418789Sahrens 	/*
1419789Sahrens 	 * Print out an action according to the overall state of the pool.
1420789Sahrens 	 */
14213741Smmusante 	if (vs->vs_state == VDEV_STATE_HEALTHY) {
14221760Seschrock 		if (reason == ZPOOL_STATUS_VERSION_OLDER)
14231760Seschrock 			(void) printf(gettext("action: The pool can be "
14241760Seschrock 			    "imported using its name or numeric identifier, "
14251760Seschrock 			    "though\n\tsome features will not be available "
14261760Seschrock 			    "without an explicit 'zpool upgrade'.\n"));
14273975Sek110237 		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
14283975Sek110237 			(void) printf(gettext("action: The pool can be "
14293975Sek110237 			    "imported using its name or numeric "
14303975Sek110237 			    "identifier and\n\tthe '-f' flag.\n"));
1431789Sahrens 		else
14321760Seschrock 			(void) printf(gettext("action: The pool can be "
14331760Seschrock 			    "imported using its name or numeric "
14341760Seschrock 			    "identifier.\n"));
14353741Smmusante 	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1436789Sahrens 		(void) printf(gettext("action: The pool can be imported "
1437789Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
14381760Seschrock 		    "tolerance of the pool may be compromised if imported.\n"));
1439789Sahrens 	} else {
14401760Seschrock 		switch (reason) {
14411760Seschrock 		case ZPOOL_STATUS_VERSION_NEWER:
14421760Seschrock 			(void) printf(gettext("action: The pool cannot be "
14431760Seschrock 			    "imported.  Access the pool on a system running "
14441760Seschrock 			    "newer\n\tsoftware, or recreate the pool from "
14451760Seschrock 			    "backup.\n"));
14461760Seschrock 			break;
14471760Seschrock 		case ZPOOL_STATUS_MISSING_DEV_R:
14481760Seschrock 		case ZPOOL_STATUS_MISSING_DEV_NR:
14491760Seschrock 		case ZPOOL_STATUS_BAD_GUID_SUM:
1450789Sahrens 			(void) printf(gettext("action: The pool cannot be "
1451789Sahrens 			    "imported. Attach the missing\n\tdevices and try "
1452789Sahrens 			    "again.\n"));
14531760Seschrock 			break;
14541760Seschrock 		default:
1455789Sahrens 			(void) printf(gettext("action: The pool cannot be "
1456789Sahrens 			    "imported due to damaged devices or data.\n"));
14571760Seschrock 		}
14581760Seschrock 	}
14591760Seschrock 
14603741Smmusante 	/*
14613741Smmusante 	 * If the state is "closed" or "can't open", and the aux state
14623741Smmusante 	 * is "corrupt data":
14633741Smmusante 	 */
14643741Smmusante 	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
14653741Smmusante 	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
14663741Smmusante 	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
14671760Seschrock 		if (pool_state == POOL_STATE_DESTROYED)
14681760Seschrock 			(void) printf(gettext("\tThe pool was destroyed, "
14691760Seschrock 			    "but can be imported using the '-Df' flags.\n"));
14701760Seschrock 		else if (pool_state != POOL_STATE_EXPORTED)
14711760Seschrock 			(void) printf(gettext("\tThe pool may be active on "
14725853Sek110237 			    "another system, but can be imported using\n\t"
14731760Seschrock 			    "the '-f' flag.\n"));
1474789Sahrens 	}
1475789Sahrens 
1476789Sahrens 	if (msgid != NULL)
1477789Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1478789Sahrens 		    msgid);
1479789Sahrens 
1480789Sahrens 	(void) printf(gettext("config:\n\n"));
1481789Sahrens 
14821354Seschrock 	namewidth = max_width(NULL, nvroot, 0, 0);
1483789Sahrens 	if (namewidth < 10)
1484789Sahrens 		namewidth = 10;
14854527Sperrin 
14869701SGeorge.Wilson@Sun.COM 	print_import_config(name, nvroot, namewidth, 0);
14879701SGeorge.Wilson@Sun.COM 	if (num_logs(nvroot) > 0)
14889701SGeorge.Wilson@Sun.COM 		print_logs(NULL, nvroot, namewidth, B_FALSE);
1489789Sahrens 
1490789Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
14913741Smmusante 		(void) printf(gettext("\n\tAdditional devices are known to "
1492789Sahrens 		    "be part of this pool, though their\n\texact "
14933741Smmusante 		    "configuration cannot be determined.\n"));
1494789Sahrens 	}
1495789Sahrens }
1496789Sahrens 
1497789Sahrens /*
1498789Sahrens  * Perform the import for the given configuration.  This passes the heavy
14995094Slling  * lifting off to zpool_import_props(), and then mounts the datasets contained
15005094Slling  * within the pool.
1501789Sahrens  */
1502789Sahrens static int
do_import(nvlist_t * config,const char * newname,const char * mntopts,nvlist_t * props,int flags)1503789Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
150412949SGeorge.Wilson@Sun.COM     nvlist_t *props, int flags)
1505789Sahrens {
1506789Sahrens 	zpool_handle_t *zhp;
1507789Sahrens 	char *name;
1508789Sahrens 	uint64_t state;
15091760Seschrock 	uint64_t version;
1510789Sahrens 
1511789Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1512789Sahrens 	    &name) == 0);
1513789Sahrens 
1514789Sahrens 	verify(nvlist_lookup_uint64(config,
1515789Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
15161760Seschrock 	verify(nvlist_lookup_uint64(config,
15171760Seschrock 	    ZPOOL_CONFIG_VERSION, &version) == 0);
15184577Sahrens 	if (version > SPA_VERSION) {
15191760Seschrock 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
15201760Seschrock 		    "is formatted using a newer ZFS version\n"), name);
15211760Seschrock 		return (1);
152212949SGeorge.Wilson@Sun.COM 	} else if (state != POOL_STATE_EXPORTED &&
152312949SGeorge.Wilson@Sun.COM 	    !(flags & ZFS_IMPORT_ANY_HOST)) {
15243975Sek110237 		uint64_t hostid;
15253975Sek110237 
15263975Sek110237 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
15273975Sek110237 		    &hostid) == 0) {
15283975Sek110237 			if ((unsigned long)hostid != gethostid()) {
15293975Sek110237 				char *hostname;
15303975Sek110237 				uint64_t timestamp;
15313975Sek110237 				time_t t;
15323975Sek110237 
15333975Sek110237 				verify(nvlist_lookup_string(config,
15343975Sek110237 				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
15353975Sek110237 				verify(nvlist_lookup_uint64(config,
15363975Sek110237 				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
15373975Sek110237 				t = timestamp;
15383975Sek110237 				(void) fprintf(stderr, gettext("cannot import "
15393975Sek110237 				    "'%s': pool may be in use from other "
15403975Sek110237 				    "system, it was last accessed by %s "
15413975Sek110237 				    "(hostid: 0x%lx) on %s"), name, hostname,
15423975Sek110237 				    (unsigned long)hostid,
15433975Sek110237 				    asctime(localtime(&t)));
15443975Sek110237 				(void) fprintf(stderr, gettext("use '-f' to "
15453975Sek110237 				    "import anyway\n"));
15463975Sek110237 				return (1);
15473975Sek110237 			}
15483975Sek110237 		} else {
15493975Sek110237 			(void) fprintf(stderr, gettext("cannot import '%s': "
15503975Sek110237 			    "pool may be in use from other system\n"), name);
15513975Sek110237 			(void) fprintf(stderr, gettext("use '-f' to import "
15523975Sek110237 			    "anyway\n"));
15533975Sek110237 			return (1);
15543975Sek110237 		}
1555789Sahrens 	}
1556789Sahrens 
155712949SGeorge.Wilson@Sun.COM 	if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
1558789Sahrens 		return (1);
1559789Sahrens 
1560789Sahrens 	if (newname != NULL)
1561789Sahrens 		name = (char *)newname;
1562789Sahrens 
156310000SVictor.Latushkin@Sun.COM 	if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
156410000SVictor.Latushkin@Sun.COM 		return (1);
1565789Sahrens 
15668525SEric.Schrock@Sun.COM 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
156713049SGeorge.Wilson@Sun.COM 	    !(flags & ZFS_IMPORT_ONLY) &&
15688525SEric.Schrock@Sun.COM 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1569789Sahrens 		zpool_close(zhp);
1570789Sahrens 		return (1);
1571789Sahrens 	}
1572789Sahrens 
1573789Sahrens 	zpool_close(zhp);
157410921STim.Haley@Sun.COM 	return (0);
1575789Sahrens }
1576789Sahrens 
1577789Sahrens /*
15781631Sdarrenm  * zpool import [-d dir] [-D]
15795363Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
15805363Seschrock  *              [-d dir | -c cachefile] [-f] -a
15815363Seschrock  *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
158210921STim.Haley@Sun.COM  *              [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool]
15835363Seschrock  *
15845363Seschrock  *	 -c	Read pool information from a cachefile instead of searching
15855363Seschrock  *		devices.
1586789Sahrens  *
1587789Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1588789Sahrens  *		one directory can be specified using multiple '-d' options.
1589789Sahrens  *
15901631Sdarrenm  *       -D     Scan for previously destroyed pools or import all or only
15911631Sdarrenm  *              specified destroyed pools.
15921631Sdarrenm  *
1593789Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
1594789Sahrens  *		the given root.  The pool will remain exported when the machine
1595789Sahrens  *		is rebooted.
1596789Sahrens  *
159710921STim.Haley@Sun.COM  *       -V	Import even in the presence of faulted vdevs.  This is an
15986643Seschrock  *       	intentionally undocumented option for testing purposes, and
15996643Seschrock  *       	treats the pool configuration as complete, leaving any bad
160010000SVictor.Latushkin@Sun.COM  *		vdevs in the FAULTED state. In other words, it does verbatim
160110000SVictor.Latushkin@Sun.COM  *		import.
16026643Seschrock  *
160310921STim.Haley@Sun.COM  *       -f	Force import, even if it appears that the pool is active.
160410921STim.Haley@Sun.COM  *
160510921STim.Haley@Sun.COM  *       -F     Attempt rewind if necessary.
160610921STim.Haley@Sun.COM  *
160710921STim.Haley@Sun.COM  *       -n     See if rewind would work, but don't actually rewind.
160810921STim.Haley@Sun.COM  *
160913049SGeorge.Wilson@Sun.COM  *       -N     Import the pool but don't mount datasets.
161013049SGeorge.Wilson@Sun.COM  *
161113049SGeorge.Wilson@Sun.COM  *       -T     Specify a starting txg to use for import. This option is
161213049SGeorge.Wilson@Sun.COM  *       	intentionally undocumented option for testing purposes.
161313049SGeorge.Wilson@Sun.COM  *
1614789Sahrens  *       -a	Import all pools found.
1615789Sahrens  *
16165094Slling  *       -o	Set property=value and/or temporary mount options (without '=').
16174543Smarks  *
1618789Sahrens  * The import command scans for pools to import, and import pools based on pool
1619789Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
1620789Sahrens  */
1621789Sahrens int
zpool_do_import(int argc,char ** argv)1622789Sahrens zpool_do_import(int argc, char **argv)
1623789Sahrens {
1624789Sahrens 	char **searchdirs = NULL;
1625789Sahrens 	int nsearch = 0;
1626789Sahrens 	int c;
162711497SMark.Musante@Sun.COM 	int err = 0;
16285363Seschrock 	nvlist_t *pools = NULL;
16292082Seschrock 	boolean_t do_all = B_FALSE;
16302082Seschrock 	boolean_t do_destroyed = B_FALSE;
1631789Sahrens 	char *mntopts = NULL;
1632789Sahrens 	nvpair_t *elem;
1633789Sahrens 	nvlist_t *config;
16346807Sck153898 	uint64_t searchguid = 0;
16356807Sck153898 	char *searchname = NULL;
16365094Slling 	char *propval;
1637789Sahrens 	nvlist_t *found_config;
163810921STim.Haley@Sun.COM 	nvlist_t *policy = NULL;
16394543Smarks 	nvlist_t *props = NULL;
16402082Seschrock 	boolean_t first;
164112949SGeorge.Wilson@Sun.COM 	int flags = ZFS_IMPORT_NORMAL;
164210921STim.Haley@Sun.COM 	uint32_t rewind_policy = ZPOOL_NO_REWIND;
164310921STim.Haley@Sun.COM 	boolean_t dryrun = B_FALSE;
164410921STim.Haley@Sun.COM 	boolean_t do_rewind = B_FALSE;
164510921STim.Haley@Sun.COM 	boolean_t xtreme_rewind = B_FALSE;
164613049SGeorge.Wilson@Sun.COM 	uint64_t pool_state, txg = -1ULL;
16475363Seschrock 	char *cachefile = NULL;
164811497SMark.Musante@Sun.COM 	importargs_t idata = { 0 };
164913049SGeorge.Wilson@Sun.COM 	char *endptr;
1650789Sahrens 
1651789Sahrens 	/* check options */
165213049SGeorge.Wilson@Sun.COM 	while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) {
1653789Sahrens 		switch (c) {
1654789Sahrens 		case 'a':
16552082Seschrock 			do_all = B_TRUE;
1656789Sahrens 			break;
16575363Seschrock 		case 'c':
16585363Seschrock 			cachefile = optarg;
16595363Seschrock 			break;
1660789Sahrens 		case 'd':
1661789Sahrens 			if (searchdirs == NULL) {
1662789Sahrens 				searchdirs = safe_malloc(sizeof (char *));
1663789Sahrens 			} else {
1664789Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
1665789Sahrens 				    sizeof (char *));
1666789Sahrens 				bcopy(searchdirs, tmp, nsearch *
1667789Sahrens 				    sizeof (char *));
1668789Sahrens 				free(searchdirs);
1669789Sahrens 				searchdirs = tmp;
1670789Sahrens 			}
1671789Sahrens 			searchdirs[nsearch++] = optarg;
1672789Sahrens 			break;
16731631Sdarrenm 		case 'D':
16742082Seschrock 			do_destroyed = B_TRUE;
16751631Sdarrenm 			break;
1676789Sahrens 		case 'f':
167712949SGeorge.Wilson@Sun.COM 			flags |= ZFS_IMPORT_ANY_HOST;
1678789Sahrens 			break;
16796643Seschrock 		case 'F':
168010921STim.Haley@Sun.COM 			do_rewind = B_TRUE;
168110921STim.Haley@Sun.COM 			break;
168212949SGeorge.Wilson@Sun.COM 		case 'm':
168312949SGeorge.Wilson@Sun.COM 			flags |= ZFS_IMPORT_MISSING_LOG;
168412949SGeorge.Wilson@Sun.COM 			break;
168510921STim.Haley@Sun.COM 		case 'n':
168610921STim.Haley@Sun.COM 			dryrun = B_TRUE;
16876643Seschrock 			break;
168813049SGeorge.Wilson@Sun.COM 		case 'N':
168913049SGeorge.Wilson@Sun.COM 			flags |= ZFS_IMPORT_ONLY;
169013049SGeorge.Wilson@Sun.COM 			break;
1691789Sahrens 		case 'o':
16925094Slling 			if ((propval = strchr(optarg, '=')) != NULL) {
16935094Slling 				*propval = '\0';
16945094Slling 				propval++;
16957184Stimh 				if (add_prop_list(optarg, propval,
16967184Stimh 				    &props, B_TRUE))
16975094Slling 					goto error;
16985094Slling 			} else {
16995094Slling 				mntopts = optarg;
17005094Slling 			}
1701789Sahrens 			break;
1702789Sahrens 		case 'R':
17035094Slling 			if (add_prop_list(zpool_prop_to_name(
17047184Stimh 			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
17055094Slling 				goto error;
17065363Seschrock 			if (nvlist_lookup_string(props,
17075363Seschrock 			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
17085363Seschrock 			    &propval) == 0)
17095363Seschrock 				break;
17105094Slling 			if (add_prop_list(zpool_prop_to_name(
17117184Stimh 			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
17125094Slling 				goto error;
1713789Sahrens 			break;
171413049SGeorge.Wilson@Sun.COM 		case 'T':
171513049SGeorge.Wilson@Sun.COM 			errno = 0;
171613049SGeorge.Wilson@Sun.COM 			txg = strtoull(optarg, &endptr, 10);
171713049SGeorge.Wilson@Sun.COM 			if (errno != 0 || *endptr != '\0') {
171813049SGeorge.Wilson@Sun.COM 				(void) fprintf(stderr,
171913049SGeorge.Wilson@Sun.COM 				    gettext("invalid txg value\n"));
172013049SGeorge.Wilson@Sun.COM 				usage(B_FALSE);
172113049SGeorge.Wilson@Sun.COM 			}
172213049SGeorge.Wilson@Sun.COM 			rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
172313049SGeorge.Wilson@Sun.COM 			break;
172410921STim.Haley@Sun.COM 		case 'V':
172512949SGeorge.Wilson@Sun.COM 			flags |= ZFS_IMPORT_VERBATIM;
172610921STim.Haley@Sun.COM 			break;
172710921STim.Haley@Sun.COM 		case 'X':
172810921STim.Haley@Sun.COM 			xtreme_rewind = B_TRUE;
172910921STim.Haley@Sun.COM 			break;
1730789Sahrens 		case ':':
1731789Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1732789Sahrens 			    "'%c' option\n"), optopt);
17332082Seschrock 			usage(B_FALSE);
1734789Sahrens 			break;
1735789Sahrens 		case '?':
1736789Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1737789Sahrens 			    optopt);
17382082Seschrock 			usage(B_FALSE);
1739789Sahrens 		}
1740789Sahrens 	}
1741789Sahrens 
1742789Sahrens 	argc -= optind;
1743789Sahrens 	argv += optind;
1744789Sahrens 
17455363Seschrock 	if (cachefile && nsearch != 0) {
17465363Seschrock 		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
17475363Seschrock 		usage(B_FALSE);
17485363Seschrock 	}
17495363Seschrock 
175010921STim.Haley@Sun.COM 	if ((dryrun || xtreme_rewind) && !do_rewind) {
175110921STim.Haley@Sun.COM 		(void) fprintf(stderr,
175210921STim.Haley@Sun.COM 		    gettext("-n or -X only meaningful with -F\n"));
175310921STim.Haley@Sun.COM 		usage(B_FALSE);
175410921STim.Haley@Sun.COM 	}
175510921STim.Haley@Sun.COM 	if (dryrun)
175610921STim.Haley@Sun.COM 		rewind_policy = ZPOOL_TRY_REWIND;
175710921STim.Haley@Sun.COM 	else if (do_rewind)
175810921STim.Haley@Sun.COM 		rewind_policy = ZPOOL_DO_REWIND;
175910921STim.Haley@Sun.COM 	if (xtreme_rewind)
176010921STim.Haley@Sun.COM 		rewind_policy |= ZPOOL_EXTREME_REWIND;
176110921STim.Haley@Sun.COM 
176210921STim.Haley@Sun.COM 	/* In the future, we can capture further policy and include it here */
176310921STim.Haley@Sun.COM 	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
176413049SGeorge.Wilson@Sun.COM 	    nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 ||
176510921STim.Haley@Sun.COM 	    nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
176610921STim.Haley@Sun.COM 		goto error;
176710921STim.Haley@Sun.COM 
1768789Sahrens 	if (searchdirs == NULL) {
1769789Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1770789Sahrens 		searchdirs[0] = "/dev/dsk";
1771789Sahrens 		nsearch = 1;
1772789Sahrens 	}
1773789Sahrens 
1774789Sahrens 	/* check argument count */
1775789Sahrens 	if (do_all) {
1776789Sahrens 		if (argc != 0) {
1777789Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
17782082Seschrock 			usage(B_FALSE);
1779789Sahrens 		}
1780789Sahrens 	} else {
1781789Sahrens 		if (argc > 2) {
1782789Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
17832082Seschrock 			usage(B_FALSE);
1784789Sahrens 		}
1785789Sahrens 
1786789Sahrens 		/*
1787789Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1788789Sahrens 		 * here because otherwise any attempt to discover pools will
1789789Sahrens 		 * silently fail.
1790789Sahrens 		 */
1791789Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1792789Sahrens 			(void) fprintf(stderr, gettext("cannot "
1793789Sahrens 			    "discover pools: permission denied\n"));
17942082Seschrock 			free(searchdirs);
179510921STim.Haley@Sun.COM 			nvlist_free(policy);
1796789Sahrens 			return (1);
1797789Sahrens 		}
1798789Sahrens 	}
1799789Sahrens 
1800789Sahrens 	/*
1801789Sahrens 	 * Depending on the arguments given, we do one of the following:
1802789Sahrens 	 *
1803789Sahrens 	 *	<none>	Iterate through all pools and display information about
1804789Sahrens 	 *		each one.
1805789Sahrens 	 *
1806789Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1807789Sahrens 	 *
1808789Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1809789Sahrens 	 *		name and import that one.
18101631Sdarrenm 	 *
18111631Sdarrenm 	 *	-D	Above options applies only to destroyed pools.
1812789Sahrens 	 */
1813789Sahrens 	if (argc != 0) {
1814789Sahrens 		char *endptr;
1815789Sahrens 
1816789Sahrens 		errno = 0;
1817789Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1818789Sahrens 		if (errno != 0 || *endptr != '\0')
1819789Sahrens 			searchname = argv[0];
1820789Sahrens 		found_config = NULL;
182111497SMark.Musante@Sun.COM 
182211497SMark.Musante@Sun.COM 		/*
182311497SMark.Musante@Sun.COM 		 * User specified a name or guid.  Ensure it's unique.
182411497SMark.Musante@Sun.COM 		 */
182511497SMark.Musante@Sun.COM 		idata.unique = B_TRUE;
1826789Sahrens 	}
1827789Sahrens 
182811497SMark.Musante@Sun.COM 
182911497SMark.Musante@Sun.COM 	idata.path = searchdirs;
183011497SMark.Musante@Sun.COM 	idata.paths = nsearch;
183111497SMark.Musante@Sun.COM 	idata.poolname = searchname;
183211497SMark.Musante@Sun.COM 	idata.guid = searchguid;
183311497SMark.Musante@Sun.COM 	idata.cachefile = cachefile;
183411497SMark.Musante@Sun.COM 
183511497SMark.Musante@Sun.COM 	pools = zpool_search_import(g_zfs, &idata);
183611497SMark.Musante@Sun.COM 
183711497SMark.Musante@Sun.COM 	if (pools != NULL && idata.exists &&
183811497SMark.Musante@Sun.COM 	    (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
183911497SMark.Musante@Sun.COM 		(void) fprintf(stderr, gettext("cannot import '%s': "
184011497SMark.Musante@Sun.COM 		    "a pool with that name already exists\n"),
184111497SMark.Musante@Sun.COM 		    argv[0]);
184211497SMark.Musante@Sun.COM 		(void) fprintf(stderr, gettext("use the form '%s "
184311497SMark.Musante@Sun.COM 		    "<pool | id> <newpool>' to give it a new name\n"),
184411497SMark.Musante@Sun.COM 		    "zpool import");
184511497SMark.Musante@Sun.COM 		err = 1;
184611497SMark.Musante@Sun.COM 	} else if (pools == NULL && idata.exists) {
184711497SMark.Musante@Sun.COM 		(void) fprintf(stderr, gettext("cannot import '%s': "
184811497SMark.Musante@Sun.COM 		    "a pool with that name is already created/imported,\n"),
184911497SMark.Musante@Sun.COM 		    argv[0]);
185011497SMark.Musante@Sun.COM 		(void) fprintf(stderr, gettext("and no additional pools "
185111497SMark.Musante@Sun.COM 		    "with that name were found\n"));
185211497SMark.Musante@Sun.COM 		err = 1;
185311497SMark.Musante@Sun.COM 	} else if (pools == NULL) {
18546807Sck153898 		if (argc != 0) {
18556807Sck153898 			(void) fprintf(stderr, gettext("cannot import '%s': "
18566807Sck153898 			    "no such pool available\n"), argv[0]);
18576807Sck153898 		}
185811497SMark.Musante@Sun.COM 		err = 1;
185911497SMark.Musante@Sun.COM 	}
186011497SMark.Musante@Sun.COM 
186111497SMark.Musante@Sun.COM 	if (err == 1) {
18626807Sck153898 		free(searchdirs);
186310921STim.Haley@Sun.COM 		nvlist_free(policy);
18646807Sck153898 		return (1);
18656807Sck153898 	}
18666807Sck153898 
18676807Sck153898 	/*
18686807Sck153898 	 * At this point we have a list of import candidate configs. Even if
18696807Sck153898 	 * we were searching by pool name or guid, we still need to
18706807Sck153898 	 * post-process the list to deal with pool state and possible
18716807Sck153898 	 * duplicate names.
18726807Sck153898 	 */
1873789Sahrens 	err = 0;
1874789Sahrens 	elem = NULL;
18752082Seschrock 	first = B_TRUE;
1876789Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1877789Sahrens 
1878789Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1879789Sahrens 
18801631Sdarrenm 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
18811631Sdarrenm 		    &pool_state) == 0);
18821631Sdarrenm 		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
18831631Sdarrenm 			continue;
18841631Sdarrenm 		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
18851631Sdarrenm 			continue;
18861631Sdarrenm 
188710921STim.Haley@Sun.COM 		verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY,
188810921STim.Haley@Sun.COM 		    policy) == 0);
188910921STim.Haley@Sun.COM 
1890789Sahrens 		if (argc == 0) {
1891789Sahrens 			if (first)
18922082Seschrock 				first = B_FALSE;
18932474Seschrock 			else if (!do_all)
1894789Sahrens 				(void) printf("\n");
1895789Sahrens 
189610921STim.Haley@Sun.COM 			if (do_all) {
1897789Sahrens 				err |= do_import(config, NULL, mntopts,
189812949SGeorge.Wilson@Sun.COM 				    props, flags);
189910921STim.Haley@Sun.COM 			} else {
1900789Sahrens 				show_import(config);
190110921STim.Haley@Sun.COM 			}
1902789Sahrens 		} else if (searchname != NULL) {
1903789Sahrens 			char *name;
1904789Sahrens 
1905789Sahrens 			/*
1906789Sahrens 			 * We are searching for a pool based on name.
1907789Sahrens 			 */
1908789Sahrens 			verify(nvlist_lookup_string(config,
1909789Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1910789Sahrens 
1911789Sahrens 			if (strcmp(name, searchname) == 0) {
1912789Sahrens 				if (found_config != NULL) {
1913789Sahrens 					(void) fprintf(stderr, gettext(
1914789Sahrens 					    "cannot import '%s': more than "
1915789Sahrens 					    "one matching pool\n"), searchname);
1916789Sahrens 					(void) fprintf(stderr, gettext(
1917789Sahrens 					    "import by numeric ID instead\n"));
19182082Seschrock 					err = B_TRUE;
1919789Sahrens 				}
1920789Sahrens 				found_config = config;
1921789Sahrens 			}
1922789Sahrens 		} else {
1923789Sahrens 			uint64_t guid;
1924789Sahrens 
1925789Sahrens 			/*
1926789Sahrens 			 * Search for a pool by guid.
1927789Sahrens 			 */
1928789Sahrens 			verify(nvlist_lookup_uint64(config,
1929789Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1930789Sahrens 
1931789Sahrens 			if (guid == searchguid)
1932789Sahrens 				found_config = config;
1933789Sahrens 		}
1934789Sahrens 	}
1935789Sahrens 
1936789Sahrens 	/*
1937789Sahrens 	 * If we were searching for a specific pool, verify that we found a
1938789Sahrens 	 * pool, and then do the import.
1939789Sahrens 	 */
1940789Sahrens 	if (argc != 0 && err == 0) {
1941789Sahrens 		if (found_config == NULL) {
1942789Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1943789Sahrens 			    "no such pool available\n"), argv[0]);
19442082Seschrock 			err = B_TRUE;
1945789Sahrens 		} else {
1946789Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
194712949SGeorge.Wilson@Sun.COM 			    argv[1], mntopts, props, flags);
1948789Sahrens 		}
1949789Sahrens 	}
1950789Sahrens 
1951789Sahrens 	/*
1952789Sahrens 	 * If we were just looking for pools, report an error if none were
1953789Sahrens 	 * found.
1954789Sahrens 	 */
1955789Sahrens 	if (argc == 0 && first)
1956789Sahrens 		(void) fprintf(stderr,
1957789Sahrens 		    gettext("no pools available to import\n"));
1958789Sahrens 
19594543Smarks error:
19605363Seschrock 	nvlist_free(props);
1961789Sahrens 	nvlist_free(pools);
196210921STim.Haley@Sun.COM 	nvlist_free(policy);
19632082Seschrock 	free(searchdirs);
1964789Sahrens 
1965789Sahrens 	return (err ? 1 : 0);
1966789Sahrens }
1967789Sahrens 
1968789Sahrens typedef struct iostat_cbdata {
1969789Sahrens 	zpool_list_t *cb_list;
1970789Sahrens 	int cb_verbose;
1971789Sahrens 	int cb_iteration;
1972789Sahrens 	int cb_namewidth;
1973789Sahrens } iostat_cbdata_t;
1974789Sahrens 
1975789Sahrens static void
print_iostat_separator(iostat_cbdata_t * cb)1976789Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1977789Sahrens {
1978789Sahrens 	int i = 0;
1979789Sahrens 
1980789Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1981789Sahrens 		(void) printf("-");
1982789Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1983789Sahrens }
1984789Sahrens 
1985789Sahrens static void
print_iostat_header(iostat_cbdata_t * cb)1986789Sahrens print_iostat_header(iostat_cbdata_t *cb)
1987789Sahrens {
1988789Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1989789Sahrens 	    cb->cb_namewidth, "");
199010956SGeorge.Wilson@Sun.COM 	(void) printf("%-*s  alloc   free   read  write   read  write\n",
1991789Sahrens 	    cb->cb_namewidth, "pool");
1992789Sahrens 	print_iostat_separator(cb);
1993789Sahrens }
1994789Sahrens 
1995789Sahrens /*
1996789Sahrens  * Display a single statistic.
1997789Sahrens  */
19985094Slling static void
print_one_stat(uint64_t value)1999789Sahrens print_one_stat(uint64_t value)
2000789Sahrens {
2001789Sahrens 	char buf[64];
2002789Sahrens 
2003789Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
2004789Sahrens 	(void) printf("  %5s", buf);
2005789Sahrens }
2006789Sahrens 
2007789Sahrens /*
2008789Sahrens  * Print out all the statistics for the given vdev.  This can either be the
2009789Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
2010789Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
2011789Sahrens  */
2012789Sahrens void
print_vdev_stats(zpool_handle_t * zhp,const char * name,nvlist_t * oldnv,nvlist_t * newnv,iostat_cbdata_t * cb,int depth)20131354Seschrock print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
20141354Seschrock     nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
2015789Sahrens {
2016789Sahrens 	nvlist_t **oldchild, **newchild;
2017789Sahrens 	uint_t c, children;
2018789Sahrens 	vdev_stat_t *oldvs, *newvs;
2019789Sahrens 	vdev_stat_t zerovs = { 0 };
2020789Sahrens 	uint64_t tdelta;
2021789Sahrens 	double scale;
20221171Seschrock 	char *vname;
2023789Sahrens 
2024789Sahrens 	if (oldnv != NULL) {
202512296SLin.Ling@Sun.COM 		verify(nvlist_lookup_uint64_array(oldnv,
202612296SLin.Ling@Sun.COM 		    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
2027789Sahrens 	} else {
2028789Sahrens 		oldvs = &zerovs;
2029789Sahrens 	}
2030789Sahrens 
203112296SLin.Ling@Sun.COM 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
2032789Sahrens 	    (uint64_t **)&newvs, &c) == 0);
2033789Sahrens 
2034789Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
2035789Sahrens 		(void) printf("%*s%s", depth, "", name);
2036789Sahrens 	else
2037789Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
2038789Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
2039789Sahrens 
2040789Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
2041789Sahrens 
2042789Sahrens 	if (tdelta == 0)
2043789Sahrens 		scale = 1.0;
2044789Sahrens 	else
2045789Sahrens 		scale = (double)NANOSEC / tdelta;
2046789Sahrens 
2047789Sahrens 	/* only toplevel vdevs have capacity stats */
2048789Sahrens 	if (newvs->vs_space == 0) {
2049789Sahrens 		(void) printf("      -      -");
2050789Sahrens 	} else {
2051789Sahrens 		print_one_stat(newvs->vs_alloc);
2052789Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
2053789Sahrens 	}
2054789Sahrens 
2055789Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
2056789Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
2057789Sahrens 
2058789Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
2059789Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
2060789Sahrens 
2061789Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
2062789Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
2063789Sahrens 
2064789Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
2065789Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
2066789Sahrens 
2067789Sahrens 	(void) printf("\n");
2068789Sahrens 
2069789Sahrens 	if (!cb->cb_verbose)
2070789Sahrens 		return;
2071789Sahrens 
2072789Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
2073789Sahrens 	    &newchild, &children) != 0)
2074789Sahrens 		return;
2075789Sahrens 
2076789Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
2077789Sahrens 	    &oldchild, &c) != 0)
2078789Sahrens 		return;
2079789Sahrens 
20801171Seschrock 	for (c = 0; c < children; c++) {
208112296SLin.Ling@Sun.COM 		uint64_t ishole = B_FALSE;
208212296SLin.Ling@Sun.COM 
208312296SLin.Ling@Sun.COM 		if (nvlist_lookup_uint64(newchild[c],
208412296SLin.Ling@Sun.COM 		    ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
208512296SLin.Ling@Sun.COM 			continue;
208612296SLin.Ling@Sun.COM 
208710594SGeorge.Wilson@Sun.COM 		vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
20881354Seschrock 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
20891171Seschrock 		    newchild[c], cb, depth + 2);
20901171Seschrock 		free(vname);
20911171Seschrock 	}
20925450Sbrendan 
20935450Sbrendan 	/*
20945450Sbrendan 	 * Include level 2 ARC devices in iostat output
20955450Sbrendan 	 */
20965450Sbrendan 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
20975450Sbrendan 	    &newchild, &children) != 0)
20985450Sbrendan 		return;
20995450Sbrendan 
21005450Sbrendan 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
21015450Sbrendan 	    &oldchild, &c) != 0)
21025450Sbrendan 		return;
21035450Sbrendan 
21045450Sbrendan 	if (children > 0) {
21055450Sbrendan 		(void) printf("%-*s      -      -      -      -      -      "
21065450Sbrendan 		    "-\n", cb->cb_namewidth, "cache");
21075450Sbrendan 		for (c = 0; c < children; c++) {
210810594SGeorge.Wilson@Sun.COM 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
210910594SGeorge.Wilson@Sun.COM 			    B_FALSE);
21105450Sbrendan 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
21115450Sbrendan 			    newchild[c], cb, depth + 2);
21125450Sbrendan 			free(vname);
21135450Sbrendan 		}
21145450Sbrendan 	}
2115789Sahrens }
2116789Sahrens 
2117952Seschrock static int
refresh_iostat(zpool_handle_t * zhp,void * data)2118952Seschrock refresh_iostat(zpool_handle_t *zhp, void *data)
2119952Seschrock {
2120952Seschrock 	iostat_cbdata_t *cb = data;
21212142Seschrock 	boolean_t missing;
2122952Seschrock 
2123952Seschrock 	/*
2124952Seschrock 	 * If the pool has disappeared, remove it from the list and continue.
2125952Seschrock 	 */
21262142Seschrock 	if (zpool_refresh_stats(zhp, &missing) != 0)
21272142Seschrock 		return (-1);
21282142Seschrock 
21292142Seschrock 	if (missing)
2130952Seschrock 		pool_list_remove(cb->cb_list, zhp);
2131952Seschrock 
2132952Seschrock 	return (0);
2133952Seschrock }
2134952Seschrock 
2135789Sahrens /*
2136789Sahrens  * Callback to print out the iostats for the given pool.
2137789Sahrens  */
2138789Sahrens int
print_iostat(zpool_handle_t * zhp,void * data)2139789Sahrens print_iostat(zpool_handle_t *zhp, void *data)
2140789Sahrens {
2141789Sahrens 	iostat_cbdata_t *cb = data;
2142789Sahrens 	nvlist_t *oldconfig, *newconfig;
2143789Sahrens 	nvlist_t *oldnvroot, *newnvroot;
2144952Seschrock 
2145952Seschrock 	newconfig = zpool_get_config(zhp, &oldconfig);
2146789Sahrens 
2147952Seschrock 	if (cb->cb_iteration == 1)
2148952Seschrock 		oldconfig = NULL;
2149789Sahrens 
2150789Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
2151789Sahrens 	    &newnvroot) == 0);
2152789Sahrens 
2153952Seschrock 	if (oldconfig == NULL)
2154789Sahrens 		oldnvroot = NULL;
2155952Seschrock 	else
2156952Seschrock 		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
2157952Seschrock 		    &oldnvroot) == 0);
2158789Sahrens 
2159789Sahrens 	/*
2160789Sahrens 	 * Print out the statistics for the pool.
2161789Sahrens 	 */
21621354Seschrock 	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
2163789Sahrens 
2164789Sahrens 	if (cb->cb_verbose)
2165789Sahrens 		print_iostat_separator(cb);
2166789Sahrens 
2167789Sahrens 	return (0);
2168789Sahrens }
2169789Sahrens 
2170789Sahrens int
get_namewidth(zpool_handle_t * zhp,void * data)2171789Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
2172789Sahrens {
2173789Sahrens 	iostat_cbdata_t *cb = data;
2174789Sahrens 	nvlist_t *config, *nvroot;
2175789Sahrens 
2176952Seschrock 	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
2177789Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2178789Sahrens 		    &nvroot) == 0);
2179789Sahrens 		if (!cb->cb_verbose)
2180789Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
2181789Sahrens 		else
21821354Seschrock 			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
2183789Sahrens 	}
2184789Sahrens 
2185789Sahrens 	/*
2186789Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
2187789Sahrens 	 * maximum we can have and still fit in 80 columns.
2188789Sahrens 	 */
2189789Sahrens 	if (cb->cb_namewidth < 10)
2190789Sahrens 		cb->cb_namewidth = 10;
2191789Sahrens 	if (cb->cb_namewidth > 38)
2192789Sahrens 		cb->cb_namewidth = 38;
2193789Sahrens 
2194789Sahrens 	return (0);
2195789Sahrens }
2196789Sahrens 
2197789Sahrens /*
219812296SLin.Ling@Sun.COM  * Parse the input string, get the 'interval' and 'count' value if there is one.
2199789Sahrens  */
220012296SLin.Ling@Sun.COM static void
get_interval_count(int * argcp,char ** argv,unsigned long * iv,unsigned long * cnt)220112296SLin.Ling@Sun.COM get_interval_count(int *argcp, char **argv, unsigned long *iv,
220212296SLin.Ling@Sun.COM     unsigned long *cnt)
2203789Sahrens {
2204789Sahrens 	unsigned long interval = 0, count = 0;
220512296SLin.Ling@Sun.COM 	int argc = *argcp, errno;
2206789Sahrens 
2207789Sahrens 	/*
2208789Sahrens 	 * Determine if the last argument is an integer or a pool name
2209789Sahrens 	 */
2210789Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2211789Sahrens 		char *end;
2212789Sahrens 
2213789Sahrens 		errno = 0;
2214789Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
2215789Sahrens 
2216789Sahrens 		if (*end == '\0' && errno == 0) {
2217789Sahrens 			if (interval == 0) {
2218789Sahrens 				(void) fprintf(stderr, gettext("interval "
2219789Sahrens 				    "cannot be zero\n"));
22202082Seschrock 				usage(B_FALSE);
2221789Sahrens 			}
2222789Sahrens 			/*
2223789Sahrens 			 * Ignore the last parameter
2224789Sahrens 			 */
2225789Sahrens 			argc--;
2226789Sahrens 		} else {
2227789Sahrens 			/*
2228789Sahrens 			 * If this is not a valid number, just plow on.  The
2229789Sahrens 			 * user will get a more informative error message later
2230789Sahrens 			 * on.
2231789Sahrens 			 */
2232789Sahrens 			interval = 0;
2233789Sahrens 		}
2234789Sahrens 	}
2235789Sahrens 
2236789Sahrens 	/*
2237789Sahrens 	 * If the last argument is also an integer, then we have both a count
223812296SLin.Ling@Sun.COM 	 * and an interval.
2239789Sahrens 	 */
2240789Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2241789Sahrens 		char *end;
2242789Sahrens 
2243789Sahrens 		errno = 0;
2244789Sahrens 		count = interval;
2245789Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
2246789Sahrens 
2247789Sahrens 		if (*end == '\0' && errno == 0) {
2248789Sahrens 			if (interval == 0) {
2249789Sahrens 				(void) fprintf(stderr, gettext("interval "
2250789Sahrens 				    "cannot be zero\n"));
22512082Seschrock 				usage(B_FALSE);
2252789Sahrens 			}
2253789Sahrens 
2254789Sahrens 			/*
2255789Sahrens 			 * Ignore the last parameter
2256789Sahrens 			 */
2257789Sahrens 			argc--;
2258789Sahrens 		} else {
2259789Sahrens 			interval = 0;
2260789Sahrens 		}
2261789Sahrens 	}
2262789Sahrens 
226312296SLin.Ling@Sun.COM 	*iv = interval;
226412296SLin.Ling@Sun.COM 	*cnt = count;
226512296SLin.Ling@Sun.COM 	*argcp = argc;
226612296SLin.Ling@Sun.COM }
226712296SLin.Ling@Sun.COM 
226812296SLin.Ling@Sun.COM static void
get_timestamp_arg(char c)226912296SLin.Ling@Sun.COM get_timestamp_arg(char c)
227012296SLin.Ling@Sun.COM {
227112296SLin.Ling@Sun.COM 	if (c == 'u')
227212296SLin.Ling@Sun.COM 		timestamp_fmt = UDATE;
227312296SLin.Ling@Sun.COM 	else if (c == 'd')
227412296SLin.Ling@Sun.COM 		timestamp_fmt = DDATE;
227512296SLin.Ling@Sun.COM 	else
227612296SLin.Ling@Sun.COM 		usage(B_FALSE);
227712296SLin.Ling@Sun.COM }
227812296SLin.Ling@Sun.COM 
227912296SLin.Ling@Sun.COM /*
228012296SLin.Ling@Sun.COM  * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]]
228112296SLin.Ling@Sun.COM  *
228212296SLin.Ling@Sun.COM  *	-v	Display statistics for individual vdevs
228312296SLin.Ling@Sun.COM  *	-T	Display a timestamp in date(1) or Unix format
228412296SLin.Ling@Sun.COM  *
228512296SLin.Ling@Sun.COM  * This command can be tricky because we want to be able to deal with pool
228612296SLin.Ling@Sun.COM  * creation/destruction as well as vdev configuration changes.  The bulk of this
228712296SLin.Ling@Sun.COM  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
228812296SLin.Ling@Sun.COM  * on pool_list_update() to detect the addition of new pools.  Configuration
228912296SLin.Ling@Sun.COM  * changes are all handled within libzfs.
229012296SLin.Ling@Sun.COM  */
229112296SLin.Ling@Sun.COM int
zpool_do_iostat(int argc,char ** argv)229212296SLin.Ling@Sun.COM zpool_do_iostat(int argc, char **argv)
229312296SLin.Ling@Sun.COM {
229412296SLin.Ling@Sun.COM 	int c;
229512296SLin.Ling@Sun.COM 	int ret;
229612296SLin.Ling@Sun.COM 	int npools;
229712296SLin.Ling@Sun.COM 	unsigned long interval = 0, count = 0;
229812296SLin.Ling@Sun.COM 	zpool_list_t *list;
229912296SLin.Ling@Sun.COM 	boolean_t verbose = B_FALSE;
230012296SLin.Ling@Sun.COM 	iostat_cbdata_t cb;
230112296SLin.Ling@Sun.COM 
230212296SLin.Ling@Sun.COM 	/* check options */
230312296SLin.Ling@Sun.COM 	while ((c = getopt(argc, argv, "T:v")) != -1) {
230412296SLin.Ling@Sun.COM 		switch (c) {
230512296SLin.Ling@Sun.COM 		case 'T':
230612296SLin.Ling@Sun.COM 			get_timestamp_arg(*optarg);
230712296SLin.Ling@Sun.COM 			break;
230812296SLin.Ling@Sun.COM 		case 'v':
230912296SLin.Ling@Sun.COM 			verbose = B_TRUE;
231012296SLin.Ling@Sun.COM 			break;
231112296SLin.Ling@Sun.COM 		case '?':
231212296SLin.Ling@Sun.COM 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
231312296SLin.Ling@Sun.COM 			    optopt);
231412296SLin.Ling@Sun.COM 			usage(B_FALSE);
231512296SLin.Ling@Sun.COM 		}
231612296SLin.Ling@Sun.COM 	}
231712296SLin.Ling@Sun.COM 
231812296SLin.Ling@Sun.COM 	argc -= optind;
231912296SLin.Ling@Sun.COM 	argv += optind;
232012296SLin.Ling@Sun.COM 
232112296SLin.Ling@Sun.COM 	get_interval_count(&argc, argv, &interval, &count);
232212296SLin.Ling@Sun.COM 
2323789Sahrens 	/*
2324789Sahrens 	 * Construct the list of all interesting pools.
2325789Sahrens 	 */
2326789Sahrens 	ret = 0;
23273912Slling 	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
2328789Sahrens 		return (1);
2329789Sahrens 
23302082Seschrock 	if (pool_list_count(list) == 0 && argc != 0) {
23312082Seschrock 		pool_list_free(list);
2332789Sahrens 		return (1);
23332082Seschrock 	}
2334789Sahrens 
2335789Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
23362082Seschrock 		pool_list_free(list);
2337789Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
2338789Sahrens 		return (1);
2339789Sahrens 	}
2340789Sahrens 
2341789Sahrens 	/*
2342789Sahrens 	 * Enter the main iostat loop.
2343789Sahrens 	 */
2344789Sahrens 	cb.cb_list = list;
2345789Sahrens 	cb.cb_verbose = verbose;
2346789Sahrens 	cb.cb_iteration = 0;
2347789Sahrens 	cb.cb_namewidth = 0;
2348789Sahrens 
2349789Sahrens 	for (;;) {
2350789Sahrens 		pool_list_update(list);
2351789Sahrens 
2352789Sahrens 		if ((npools = pool_list_count(list)) == 0)
2353789Sahrens 			break;
2354789Sahrens 
2355789Sahrens 		/*
2356952Seschrock 		 * Refresh all statistics.  This is done as an explicit step
2357952Seschrock 		 * before calculating the maximum name width, so that any
2358952Seschrock 		 * configuration changes are properly accounted for.
2359952Seschrock 		 */
23602082Seschrock 		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
2361952Seschrock 
2362952Seschrock 		/*
2363789Sahrens 		 * Iterate over all pools to determine the maximum width
2364789Sahrens 		 * for the pool / device name column across all pools.
2365789Sahrens 		 */
2366789Sahrens 		cb.cb_namewidth = 0;
23672082Seschrock 		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2368789Sahrens 
236910265SKrishnendu.Sadhukhan@Sun.COM 		if (timestamp_fmt != NODATE)
237010265SKrishnendu.Sadhukhan@Sun.COM 			print_timestamp(timestamp_fmt);
237110265SKrishnendu.Sadhukhan@Sun.COM 
2372789Sahrens 		/*
2373789Sahrens 		 * If it's the first time, or verbose mode, print the header.
2374789Sahrens 		 */
2375789Sahrens 		if (++cb.cb_iteration == 1 || verbose)
2376789Sahrens 			print_iostat_header(&cb);
2377789Sahrens 
23782082Seschrock 		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2379789Sahrens 
2380789Sahrens 		/*
2381789Sahrens 		 * If there's more than one pool, and we're not in verbose mode
2382789Sahrens 		 * (which prints a separator for us), then print a separator.
2383789Sahrens 		 */
2384789Sahrens 		if (npools > 1 && !verbose)
2385789Sahrens 			print_iostat_separator(&cb);
2386789Sahrens 
2387789Sahrens 		if (verbose)
2388789Sahrens 			(void) printf("\n");
2389789Sahrens 
23903377Seschrock 		/*
23913377Seschrock 		 * Flush the output so that redirection to a file isn't buffered
23923377Seschrock 		 * indefinitely.
23933377Seschrock 		 */
23943377Seschrock 		(void) fflush(stdout);
23953377Seschrock 
2396789Sahrens 		if (interval == 0)
2397789Sahrens 			break;
2398789Sahrens 
2399789Sahrens 		if (count != 0 && --count == 0)
2400789Sahrens 			break;
2401789Sahrens 
2402789Sahrens 		(void) sleep(interval);
2403789Sahrens 	}
2404789Sahrens 
2405789Sahrens 	pool_list_free(list);
2406789Sahrens 
2407789Sahrens 	return (ret);
2408789Sahrens }
2409789Sahrens 
2410789Sahrens typedef struct list_cbdata {
24112082Seschrock 	boolean_t	cb_scripted;
24122082Seschrock 	boolean_t	cb_first;
24135094Slling 	zprop_list_t	*cb_proplist;
2414789Sahrens } list_cbdata_t;
2415789Sahrens 
2416789Sahrens /*
2417789Sahrens  * Given a list of columns to display, output appropriate headers for each one.
2418789Sahrens  */
24195094Slling static void
print_header(zprop_list_t * pl)24205094Slling print_header(zprop_list_t *pl)
2421789Sahrens {
24225094Slling 	const char *header;
24235094Slling 	boolean_t first = B_TRUE;
24245094Slling 	boolean_t right_justify;
24255094Slling 
24265094Slling 	for (; pl != NULL; pl = pl->pl_next) {
24275094Slling 		if (pl->pl_prop == ZPROP_INVAL)
24285094Slling 			continue;
24295094Slling 
24305094Slling 		if (!first)
2431789Sahrens 			(void) printf("  ");
2432789Sahrens 		else
24335094Slling 			first = B_FALSE;
24345094Slling 
24355094Slling 		header = zpool_prop_column_name(pl->pl_prop);
24365094Slling 		right_justify = zpool_prop_align_right(pl->pl_prop);
24375094Slling 
24385094Slling 		if (pl->pl_next == NULL && !right_justify)
24395094Slling 			(void) printf("%s", header);
24405094Slling 		else if (right_justify)
24415094Slling 			(void) printf("%*s", pl->pl_width, header);
24425094Slling 		else
24435094Slling 			(void) printf("%-*s", pl->pl_width, header);
2444789Sahrens 	}
2445789Sahrens 
2446789Sahrens 	(void) printf("\n");
2447789Sahrens }
2448789Sahrens 
24495094Slling /*
24505094Slling  * Given a pool and a list of properties, print out all the properties according
24515094Slling  * to the described layout.
24525094Slling  */
24535094Slling static void
print_pool(zpool_handle_t * zhp,zprop_list_t * pl,int scripted)24545094Slling print_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
24555094Slling {
24565094Slling 	boolean_t first = B_TRUE;
24575094Slling 	char property[ZPOOL_MAXPROPLEN];
24585094Slling 	char *propstr;
24595094Slling 	boolean_t right_justify;
24605094Slling 	int width;
24615094Slling 
24625094Slling 	for (; pl != NULL; pl = pl->pl_next) {
24635094Slling 		if (!first) {
24645094Slling 			if (scripted)
24655094Slling 				(void) printf("\t");
24665094Slling 			else
24675094Slling 				(void) printf("  ");
24685094Slling 		} else {
24695094Slling 			first = B_FALSE;
24705094Slling 		}
24715094Slling 
24725094Slling 		right_justify = B_FALSE;
24735094Slling 		if (pl->pl_prop != ZPROP_INVAL) {
24745094Slling 			if (zpool_get_prop(zhp, pl->pl_prop, property,
24755094Slling 			    sizeof (property), NULL) != 0)
24765094Slling 				propstr = "-";
24775094Slling 			else
24785094Slling 				propstr = property;
24795094Slling 
24805094Slling 			right_justify = zpool_prop_align_right(pl->pl_prop);
24815094Slling 		} else {
24825094Slling 			propstr = "-";
24835094Slling 		}
24845094Slling 
24855094Slling 		width = pl->pl_width;
24865094Slling 
24875094Slling 		/*
24885094Slling 		 * If this is being called in scripted mode, or if this is the
24895094Slling 		 * last column and it is left-justified, don't include a width
24905094Slling 		 * format specifier.
24915094Slling 		 */
24925094Slling 		if (scripted || (pl->pl_next == NULL && !right_justify))
24935094Slling 			(void) printf("%s", propstr);
24945094Slling 		else if (right_justify)
24955094Slling 			(void) printf("%*s", width, propstr);
24965094Slling 		else
24975094Slling 			(void) printf("%-*s", width, propstr);
24985094Slling 	}
24995094Slling 
25005094Slling 	(void) printf("\n");
25015094Slling }
25025094Slling 
25035094Slling /*
25045094Slling  * Generic callback function to list a pool.
25055094Slling  */
2506789Sahrens int
list_callback(zpool_handle_t * zhp,void * data)2507789Sahrens list_callback(zpool_handle_t *zhp, void *data)
2508789Sahrens {
2509789Sahrens 	list_cbdata_t *cbp = data;
2510789Sahrens 
2511789Sahrens 	if (cbp->cb_first) {
2512789Sahrens 		if (!cbp->cb_scripted)
25135094Slling 			print_header(cbp->cb_proplist);
25142082Seschrock 		cbp->cb_first = B_FALSE;
2515789Sahrens 	}
2516789Sahrens 
25175094Slling 	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2518789Sahrens 
2519789Sahrens 	return (0);
2520789Sahrens }
2521789Sahrens 
2522789Sahrens /*
252312296SLin.Ling@Sun.COM  * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
2524789Sahrens  *
25255094Slling  *	-H	Scripted mode.  Don't display headers, and separate properties
25265094Slling  *		by a single tab.
25275094Slling  *	-o	List of properties to display.  Defaults to
252810956SGeorge.Wilson@Sun.COM  *		"name,size,allocated,free,capacity,health,altroot"
252912296SLin.Ling@Sun.COM  *	-T	Display a timestamp in date(1) or Unix format
2530789Sahrens  *
2531789Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
2532789Sahrens  * statistics for each one, as well as health status summary.
2533789Sahrens  */
2534789Sahrens int
zpool_do_list(int argc,char ** argv)2535789Sahrens zpool_do_list(int argc, char **argv)
2536789Sahrens {
2537789Sahrens 	int c;
2538789Sahrens 	int ret;
2539789Sahrens 	list_cbdata_t cb = { 0 };
25405094Slling 	static char default_props[] =
254110956SGeorge.Wilson@Sun.COM 	    "name,size,allocated,free,capacity,dedupratio,health,altroot";
25425094Slling 	char *props = default_props;
254312296SLin.Ling@Sun.COM 	unsigned long interval = 0, count = 0;
2544789Sahrens 
2545789Sahrens 	/* check options */
254612296SLin.Ling@Sun.COM 	while ((c = getopt(argc, argv, ":Ho:T:")) != -1) {
2547789Sahrens 		switch (c) {
2548789Sahrens 		case 'H':
25492082Seschrock 			cb.cb_scripted = B_TRUE;
2550789Sahrens 			break;
2551789Sahrens 		case 'o':
25525094Slling 			props = optarg;
2553789Sahrens 			break;
255412296SLin.Ling@Sun.COM 		case 'T':
255512296SLin.Ling@Sun.COM 			get_timestamp_arg(*optarg);
255612296SLin.Ling@Sun.COM 			break;
2557789Sahrens 		case ':':
2558789Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
2559789Sahrens 			    "'%c' option\n"), optopt);
25602082Seschrock 			usage(B_FALSE);
2561789Sahrens 			break;
2562789Sahrens 		case '?':
2563789Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2564789Sahrens 			    optopt);
25652082Seschrock 			usage(B_FALSE);
2566789Sahrens 		}
2567789Sahrens 	}
2568789Sahrens 
2569789Sahrens 	argc -= optind;
2570789Sahrens 	argv += optind;
2571789Sahrens 
257212296SLin.Ling@Sun.COM 	get_interval_count(&argc, argv, &interval, &count);
257312296SLin.Ling@Sun.COM 
25745094Slling 	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
25755094Slling 		usage(B_FALSE);
2576789Sahrens 
25772082Seschrock 	cb.cb_first = B_TRUE;
25782082Seschrock 
257912296SLin.Ling@Sun.COM 	for (;;) {
258012296SLin.Ling@Sun.COM 
258112296SLin.Ling@Sun.COM 		if (timestamp_fmt != NODATE)
258212296SLin.Ling@Sun.COM 			print_timestamp(timestamp_fmt);
258312296SLin.Ling@Sun.COM 
258412296SLin.Ling@Sun.COM 		ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
258512296SLin.Ling@Sun.COM 		    list_callback, &cb);
258612296SLin.Ling@Sun.COM 
258712296SLin.Ling@Sun.COM 		if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
258812296SLin.Ling@Sun.COM 			(void) printf(gettext("no pools available\n"));
258912296SLin.Ling@Sun.COM 			zprop_free_list(cb.cb_proplist);
259012296SLin.Ling@Sun.COM 			return (0);
259112296SLin.Ling@Sun.COM 		}
259212296SLin.Ling@Sun.COM 
259312296SLin.Ling@Sun.COM 		if (interval == 0)
259412296SLin.Ling@Sun.COM 			break;
259512296SLin.Ling@Sun.COM 
259612296SLin.Ling@Sun.COM 		if (count != 0 && --count == 0)
259712296SLin.Ling@Sun.COM 			break;
259812296SLin.Ling@Sun.COM 
259912296SLin.Ling@Sun.COM 		(void) sleep(interval);
260012296SLin.Ling@Sun.COM 	}
26015094Slling 
26025094Slling 	zprop_free_list(cb.cb_proplist);
2603789Sahrens 	return (ret);
2604789Sahrens }
2605789Sahrens 
2606789Sahrens static nvlist_t *
zpool_get_vdev_by_name(nvlist_t * nv,char * name)2607789Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
2608789Sahrens {
2609789Sahrens 	nvlist_t **child;
2610789Sahrens 	uint_t c, children;
2611789Sahrens 	nvlist_t *match;
2612789Sahrens 	char *path;
2613789Sahrens 
2614789Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2615789Sahrens 	    &child, &children) != 0) {
2616789Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2617789Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
2618789Sahrens 			name += 9;
2619789Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2620789Sahrens 			path += 9;
2621789Sahrens 		if (strcmp(name, path) == 0)
2622789Sahrens 			return (nv);
2623789Sahrens 		return (NULL);
2624789Sahrens 	}
2625789Sahrens 
2626789Sahrens 	for (c = 0; c < children; c++)
2627789Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2628789Sahrens 			return (match);
2629789Sahrens 
2630789Sahrens 	return (NULL);
2631789Sahrens }
2632789Sahrens 
2633789Sahrens static int
zpool_do_attach_or_replace(int argc,char ** argv,int replacing)2634789Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
2635789Sahrens {
26362082Seschrock 	boolean_t force = B_FALSE;
2637789Sahrens 	int c;
2638789Sahrens 	nvlist_t *nvroot;
2639789Sahrens 	char *poolname, *old_disk, *new_disk;
2640789Sahrens 	zpool_handle_t *zhp;
26412082Seschrock 	int ret;
2642789Sahrens 
2643789Sahrens 	/* check options */
2644789Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2645789Sahrens 		switch (c) {
2646789Sahrens 		case 'f':
26472082Seschrock 			force = B_TRUE;
2648789Sahrens 			break;
2649789Sahrens 		case '?':
2650789Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2651789Sahrens 			    optopt);
26522082Seschrock 			usage(B_FALSE);
2653789Sahrens 		}
2654789Sahrens 	}
2655789Sahrens 
2656789Sahrens 	argc -= optind;
2657789Sahrens 	argv += optind;
2658789Sahrens 
2659789Sahrens 	/* get pool name and check number of arguments */
2660789Sahrens 	if (argc < 1) {
2661789Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
26622082Seschrock 		usage(B_FALSE);
2663789Sahrens 	}
2664789Sahrens 
2665789Sahrens 	poolname = argv[0];
2666789Sahrens 
2667789Sahrens 	if (argc < 2) {
2668789Sahrens 		(void) fprintf(stderr,
2669789Sahrens 		    gettext("missing <device> specification\n"));
26702082Seschrock 		usage(B_FALSE);
2671789Sahrens 	}
2672789Sahrens 
2673789Sahrens 	old_disk = argv[1];
2674789Sahrens 
2675789Sahrens 	if (argc < 3) {
2676789Sahrens 		if (!replacing) {
2677789Sahrens 			(void) fprintf(stderr,
2678789Sahrens 			    gettext("missing <new_device> specification\n"));
26792082Seschrock 			usage(B_FALSE);
2680789Sahrens 		}
2681789Sahrens 		new_disk = old_disk;
2682789Sahrens 		argc -= 1;
2683789Sahrens 		argv += 1;
2684789Sahrens 	} else {
2685789Sahrens 		new_disk = argv[2];
2686789Sahrens 		argc -= 2;
2687789Sahrens 		argv += 2;
2688789Sahrens 	}
2689789Sahrens 
2690789Sahrens 	if (argc > 1) {
2691789Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
26922082Seschrock 		usage(B_FALSE);
2693789Sahrens 	}
2694789Sahrens 
26952082Seschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2696789Sahrens 		return (1);
2697789Sahrens 
26984276Staylor 	if (zpool_get_config(zhp, NULL) == NULL) {
2699789Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2700789Sahrens 		    poolname);
2701789Sahrens 		zpool_close(zhp);
2702789Sahrens 		return (1);
2703789Sahrens 	}
2704789Sahrens 
27057343SEric.Taylor@Sun.COM 	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
27067343SEric.Taylor@Sun.COM 	    argc, argv);
2707789Sahrens 	if (nvroot == NULL) {
2708789Sahrens 		zpool_close(zhp);
2709789Sahrens 		return (1);
2710789Sahrens 	}
2711789Sahrens 
27122082Seschrock 	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
27132082Seschrock 
27142082Seschrock 	nvlist_free(nvroot);
27152082Seschrock 	zpool_close(zhp);
27162082Seschrock 
27172082Seschrock 	return (ret);
2718789Sahrens }
2719789Sahrens 
2720789Sahrens /*
2721789Sahrens  * zpool replace [-f] <pool> <device> <new_device>
2722789Sahrens  *
2723789Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2724789Sahrens  *
2725789Sahrens  * Replace <device> with <new_device>.
2726789Sahrens  */
2727789Sahrens /* ARGSUSED */
2728789Sahrens int
zpool_do_replace(int argc,char ** argv)2729789Sahrens zpool_do_replace(int argc, char **argv)
2730789Sahrens {
2731789Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2732789Sahrens }
2733789Sahrens 
2734789Sahrens /*
2735789Sahrens  * zpool attach [-f] <pool> <device> <new_device>
2736789Sahrens  *
2737789Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
2738789Sahrens  *
2739789Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
2740789Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
2741789Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
2742789Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
2743789Sahrens  */
2744789Sahrens int
zpool_do_attach(int argc,char ** argv)2745789Sahrens zpool_do_attach(int argc, char **argv)
2746789Sahrens {
2747789Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2748789Sahrens }
2749789Sahrens 
2750789Sahrens /*
2751789Sahrens  * zpool detach [-f] <pool> <device>
2752789Sahrens  *
2753789Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
2754789Sahrens  *		(not supported yet)
2755789Sahrens  *
2756789Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
2757789Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
2758789Sahrens  * has the only valid copy of some data.
2759789Sahrens  */
2760789Sahrens /* ARGSUSED */
2761789Sahrens int
zpool_do_detach(int argc,char ** argv)2762789Sahrens zpool_do_detach(int argc, char **argv)
2763789Sahrens {
2764789Sahrens 	int c;
2765789Sahrens 	char *poolname, *path;
2766789Sahrens 	zpool_handle_t *zhp;
27672082Seschrock 	int ret;
2768789Sahrens 
2769789Sahrens 	/* check options */
2770789Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
2771789Sahrens 		switch (c) {
2772789Sahrens 		case 'f':
2773789Sahrens 		case '?':
2774789Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2775789Sahrens 			    optopt);
27762082Seschrock 			usage(B_FALSE);
2777789Sahrens 		}
2778789Sahrens 	}
2779789Sahrens 
2780789Sahrens 	argc -= optind;
2781789Sahrens 	argv += optind;
2782789Sahrens 
2783789Sahrens 	/* get pool name and check number of arguments */
2784789Sahrens 	if (argc < 1) {
2785789Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
27862082Seschrock 		usage(B_FALSE);
2787789Sahrens 	}
2788789Sahrens 
2789789Sahrens 	if (argc < 2) {
2790789Sahrens 		(void) fprintf(stderr,
2791789Sahrens 		    gettext("missing <device> specification\n"));
27922082Seschrock 		usage(B_FALSE);
2793789Sahrens 	}
2794789Sahrens 
2795789Sahrens 	poolname = argv[0];
2796789Sahrens 	path = argv[1];
2797789Sahrens 
27982082Seschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2799789Sahrens 		return (1);
2800789Sahrens 
28012082Seschrock 	ret = zpool_vdev_detach(zhp, path);
28022082Seschrock 
28032082Seschrock 	zpool_close(zhp);
28042082Seschrock 
28052082Seschrock 	return (ret);
2806789Sahrens }
2807789Sahrens 
2808789Sahrens /*
280911422SMark.Musante@Sun.COM  * zpool split [-n] [-o prop=val] ...
281011422SMark.Musante@Sun.COM  *		[-o mntopt] ...
281111422SMark.Musante@Sun.COM  *		[-R altroot] <pool> <newpool> [<device> ...]
281211422SMark.Musante@Sun.COM  *
281311422SMark.Musante@Sun.COM  *	-n	Do not split the pool, but display the resulting layout if
281411422SMark.Musante@Sun.COM  *		it were to be split.
281511422SMark.Musante@Sun.COM  *	-o	Set property=value, or set mount options.
281611422SMark.Musante@Sun.COM  *	-R	Mount the split-off pool under an alternate root.
281711422SMark.Musante@Sun.COM  *
281811422SMark.Musante@Sun.COM  * Splits the named pool and gives it the new pool name.  Devices to be split
281911422SMark.Musante@Sun.COM  * off may be listed, provided that no more than one device is specified
282011422SMark.Musante@Sun.COM  * per top-level vdev mirror.  The newly split pool is left in an exported
282111422SMark.Musante@Sun.COM  * state unless -R is specified.
282211422SMark.Musante@Sun.COM  *
282311422SMark.Musante@Sun.COM  * Restrictions: the top-level of the pool pool must only be made up of
282411422SMark.Musante@Sun.COM  * mirrors; all devices in the pool must be healthy; no device may be
282511422SMark.Musante@Sun.COM  * undergoing a resilvering operation.
282611422SMark.Musante@Sun.COM  */
282711422SMark.Musante@Sun.COM int
zpool_do_split(int argc,char ** argv)282811422SMark.Musante@Sun.COM zpool_do_split(int argc, char **argv)
282911422SMark.Musante@Sun.COM {
283011422SMark.Musante@Sun.COM 	char *srcpool, *newpool, *propval;
283111422SMark.Musante@Sun.COM 	char *mntopts = NULL;
283211422SMark.Musante@Sun.COM 	splitflags_t flags;
283311422SMark.Musante@Sun.COM 	int c, ret = 0;
283411422SMark.Musante@Sun.COM 	zpool_handle_t *zhp;
283511422SMark.Musante@Sun.COM 	nvlist_t *config, *props = NULL;
283611422SMark.Musante@Sun.COM 
283711422SMark.Musante@Sun.COM 	flags.dryrun = B_FALSE;
283811422SMark.Musante@Sun.COM 	flags.import = B_FALSE;
283911422SMark.Musante@Sun.COM 
284011422SMark.Musante@Sun.COM 	/* check options */
284111422SMark.Musante@Sun.COM 	while ((c = getopt(argc, argv, ":R:no:")) != -1) {
284211422SMark.Musante@Sun.COM 		switch (c) {
284311422SMark.Musante@Sun.COM 		case 'R':
284411422SMark.Musante@Sun.COM 			flags.import = B_TRUE;
284511422SMark.Musante@Sun.COM 			if (add_prop_list(
284611422SMark.Musante@Sun.COM 			    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
284711422SMark.Musante@Sun.COM 			    &props, B_TRUE) != 0) {
284811422SMark.Musante@Sun.COM 				if (props)
284911422SMark.Musante@Sun.COM 					nvlist_free(props);
285011422SMark.Musante@Sun.COM 				usage(B_FALSE);
285111422SMark.Musante@Sun.COM 			}
285211422SMark.Musante@Sun.COM 			break;
285311422SMark.Musante@Sun.COM 		case 'n':
285411422SMark.Musante@Sun.COM 			flags.dryrun = B_TRUE;
285511422SMark.Musante@Sun.COM 			break;
285611422SMark.Musante@Sun.COM 		case 'o':
285711422SMark.Musante@Sun.COM 			if ((propval = strchr(optarg, '=')) != NULL) {
285811422SMark.Musante@Sun.COM 				*propval = '\0';
285911422SMark.Musante@Sun.COM 				propval++;
286011422SMark.Musante@Sun.COM 				if (add_prop_list(optarg, propval,
286111422SMark.Musante@Sun.COM 				    &props, B_TRUE) != 0) {
286211422SMark.Musante@Sun.COM 					if (props)
286311422SMark.Musante@Sun.COM 						nvlist_free(props);
286411422SMark.Musante@Sun.COM 					usage(B_FALSE);
286511422SMark.Musante@Sun.COM 				}
286611422SMark.Musante@Sun.COM 			} else {
286711422SMark.Musante@Sun.COM 				mntopts = optarg;
286811422SMark.Musante@Sun.COM 			}
286911422SMark.Musante@Sun.COM 			break;
287011422SMark.Musante@Sun.COM 		case ':':
287111422SMark.Musante@Sun.COM 			(void) fprintf(stderr, gettext("missing argument for "
287211422SMark.Musante@Sun.COM 			    "'%c' option\n"), optopt);
287311422SMark.Musante@Sun.COM 			usage(B_FALSE);
287411422SMark.Musante@Sun.COM 			break;
287511422SMark.Musante@Sun.COM 		case '?':
287611422SMark.Musante@Sun.COM 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
287711422SMark.Musante@Sun.COM 			    optopt);
287811422SMark.Musante@Sun.COM 			usage(B_FALSE);
287911422SMark.Musante@Sun.COM 			break;
288011422SMark.Musante@Sun.COM 		}
288111422SMark.Musante@Sun.COM 	}
288211422SMark.Musante@Sun.COM 
288311422SMark.Musante@Sun.COM 	if (!flags.import && mntopts != NULL) {
288411422SMark.Musante@Sun.COM 		(void) fprintf(stderr, gettext("setting mntopts is only "
288511422SMark.Musante@Sun.COM 		    "valid when importing the pool\n"));
288611422SMark.Musante@Sun.COM 		usage(B_FALSE);
288711422SMark.Musante@Sun.COM 	}
288811422SMark.Musante@Sun.COM 
288911422SMark.Musante@Sun.COM 	argc -= optind;
289011422SMark.Musante@Sun.COM 	argv += optind;
289111422SMark.Musante@Sun.COM 
289211422SMark.Musante@Sun.COM 	if (argc < 1) {
289311422SMark.Musante@Sun.COM 		(void) fprintf(stderr, gettext("Missing pool name\n"));
289411422SMark.Musante@Sun.COM 		usage(B_FALSE);
289511422SMark.Musante@Sun.COM 	}
289611422SMark.Musante@Sun.COM 	if (argc < 2) {
289711422SMark.Musante@Sun.COM 		(void) fprintf(stderr, gettext("Missing new pool name\n"));
289811422SMark.Musante@Sun.COM 		usage(B_FALSE);
289911422SMark.Musante@Sun.COM 	}
290011422SMark.Musante@Sun.COM 
290111422SMark.Musante@Sun.COM 	srcpool = argv[0];
290211422SMark.Musante@Sun.COM 	newpool = argv[1];
290311422SMark.Musante@Sun.COM 
290411422SMark.Musante@Sun.COM 	argc -= 2;
290511422SMark.Musante@Sun.COM 	argv += 2;
290611422SMark.Musante@Sun.COM 
290711422SMark.Musante@Sun.COM 	if ((zhp = zpool_open(g_zfs, srcpool)) == NULL)
290811422SMark.Musante@Sun.COM 		return (1);
290911422SMark.Musante@Sun.COM 
291011422SMark.Musante@Sun.COM 	config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
291111422SMark.Musante@Sun.COM 	if (config == NULL) {
291211422SMark.Musante@Sun.COM 		ret = 1;
291311422SMark.Musante@Sun.COM 	} else {
291411422SMark.Musante@Sun.COM 		if (flags.dryrun) {
291511422SMark.Musante@Sun.COM 			(void) printf(gettext("would create '%s' with the "
291611422SMark.Musante@Sun.COM 			    "following layout:\n\n"), newpool);
291711422SMark.Musante@Sun.COM 			print_vdev_tree(NULL, newpool, config, 0, B_FALSE);
291811422SMark.Musante@Sun.COM 		}
291911422SMark.Musante@Sun.COM 		nvlist_free(config);
292011422SMark.Musante@Sun.COM 	}
292111422SMark.Musante@Sun.COM 
292211422SMark.Musante@Sun.COM 	zpool_close(zhp);
292311422SMark.Musante@Sun.COM 
292411422SMark.Musante@Sun.COM 	if (ret != 0 || flags.dryrun || !flags.import)
292511422SMark.Musante@Sun.COM 		return (ret);
292611422SMark.Musante@Sun.COM 
292711422SMark.Musante@Sun.COM 	/*
292811422SMark.Musante@Sun.COM 	 * The split was successful. Now we need to open the new
292911422SMark.Musante@Sun.COM 	 * pool and import it.
293011422SMark.Musante@Sun.COM 	 */
293111422SMark.Musante@Sun.COM 	if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
293211422SMark.Musante@Sun.COM 		return (1);
293311422SMark.Musante@Sun.COM 	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
293411422SMark.Musante@Sun.COM 	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
293511422SMark.Musante@Sun.COM 		ret = 1;
293611422SMark.Musante@Sun.COM 		(void) fprintf(stderr, gettext("Split was succssful, but "
293711422SMark.Musante@Sun.COM 		    "the datasets could not all be mounted\n"));
293811422SMark.Musante@Sun.COM 		(void) fprintf(stderr, gettext("Try doing '%s' with a "
293911422SMark.Musante@Sun.COM 		    "different altroot\n"), "zpool import");
294011422SMark.Musante@Sun.COM 	}
294111422SMark.Musante@Sun.COM 	zpool_close(zhp);
294211422SMark.Musante@Sun.COM 
294311422SMark.Musante@Sun.COM 	return (ret);
294411422SMark.Musante@Sun.COM }
294511422SMark.Musante@Sun.COM 
294611422SMark.Musante@Sun.COM 
294711422SMark.Musante@Sun.COM 
294811422SMark.Musante@Sun.COM /*
29491485Slling  * zpool online <pool> <device> ...
2950789Sahrens  */
2951789Sahrens int
zpool_do_online(int argc,char ** argv)2952789Sahrens zpool_do_online(int argc, char **argv)
2953789Sahrens {
2954789Sahrens 	int c, i;
2955789Sahrens 	char *poolname;
2956789Sahrens 	zpool_handle_t *zhp;
2957789Sahrens 	int ret = 0;
29584451Seschrock 	vdev_state_t newstate;
29599816SGeorge.Wilson@Sun.COM 	int flags = 0;
2960789Sahrens 
2961789Sahrens 	/* check options */
29629816SGeorge.Wilson@Sun.COM 	while ((c = getopt(argc, argv, "et")) != -1) {
2963789Sahrens 		switch (c) {
29649816SGeorge.Wilson@Sun.COM 		case 'e':
29659816SGeorge.Wilson@Sun.COM 			flags |= ZFS_ONLINE_EXPAND;
29669816SGeorge.Wilson@Sun.COM 			break;
2967789Sahrens 		case 't':
2968789Sahrens 		case '?':
2969789Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2970789Sahrens 			    optopt);
29712082Seschrock 			usage(B_FALSE);
2972789Sahrens 		}
2973789Sahrens 	}
2974789Sahrens 
2975789Sahrens 	argc -= optind;
2976789Sahrens 	argv += optind;
2977789Sahrens 
2978789Sahrens 	/* get pool name and check number of arguments */
2979789Sahrens 	if (argc < 1) {
2980789Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
29812082Seschrock 		usage(B_FALSE);
2982789Sahrens 	}
2983789Sahrens 	if (argc < 2) {
2984789Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
29852082Seschrock 		usage(B_FALSE);
2986789Sahrens 	}
2987789Sahrens 
2988789Sahrens 	poolname = argv[0];
2989789Sahrens 
29902082Seschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2991789Sahrens 		return (1);
2992789Sahrens 
29934451Seschrock 	for (i = 1; i < argc; i++) {
29949816SGeorge.Wilson@Sun.COM 		if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
29954451Seschrock 			if (newstate != VDEV_STATE_HEALTHY) {
29964451Seschrock 				(void) printf(gettext("warning: device '%s' "
29974451Seschrock 				    "onlined, but remains in faulted state\n"),
29984451Seschrock 				    argv[i]);
29994451Seschrock 				if (newstate == VDEV_STATE_FAULTED)
30004451Seschrock 					(void) printf(gettext("use 'zpool "
30014451Seschrock 					    "clear' to restore a faulted "
30024451Seschrock 					    "device\n"));
30034451Seschrock 				else
30044451Seschrock 					(void) printf(gettext("use 'zpool "
30054451Seschrock 					    "replace' to replace devices "
30064451Seschrock 					    "that are no longer present\n"));
30074451Seschrock 			}
30084451Seschrock 		} else {
3009789Sahrens 			ret = 1;
30104451Seschrock 		}
30114451Seschrock 	}
3012789Sahrens 
30132082Seschrock 	zpool_close(zhp);
30142082Seschrock 
3015789Sahrens 	return (ret);
3016789Sahrens }
3017789Sahrens 
3018789Sahrens /*
30191485Slling  * zpool offline [-ft] <pool> <device> ...
3020789Sahrens  *
3021789Sahrens  *	-f	Force the device into the offline state, even if doing
3022789Sahrens  *		so would appear to compromise pool availability.
3023789Sahrens  *		(not supported yet)
3024789Sahrens  *
3025789Sahrens  *	-t	Only take the device off-line temporarily.  The offline
3026789Sahrens  *		state will not be persistent across reboots.
3027789Sahrens  */
3028789Sahrens /* ARGSUSED */
3029789Sahrens int
zpool_do_offline(int argc,char ** argv)3030789Sahrens zpool_do_offline(int argc, char **argv)
3031789Sahrens {
3032789Sahrens 	int c, i;
3033789Sahrens 	char *poolname;
3034789Sahrens 	zpool_handle_t *zhp;
30352082Seschrock 	int ret = 0;
30362082Seschrock 	boolean_t istmp = B_FALSE;
3037789Sahrens 
3038789Sahrens 	/* check options */
3039789Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
3040789Sahrens 		switch (c) {
30411485Slling 		case 't':
30422082Seschrock 			istmp = B_TRUE;
30431485Slling 			break;
3044789Sahrens 		case 'f':
3045789Sahrens 		case '?':
3046789Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3047789Sahrens 			    optopt);
30482082Seschrock 			usage(B_FALSE);
3049789Sahrens 		}
3050789Sahrens 	}
3051789Sahrens 
3052789Sahrens 	argc -= optind;
3053789Sahrens 	argv += optind;
3054789Sahrens 
3055789Sahrens 	/* get pool name and check number of arguments */
3056789Sahrens 	if (argc < 1) {
3057789Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
30582082Seschrock 		usage(B_FALSE);
3059789Sahrens 	}
3060789Sahrens 	if (argc < 2) {
3061789Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
30622082Seschrock 		usage(B_FALSE);
3063789Sahrens 	}
3064789Sahrens 
3065789Sahrens 	poolname = argv[0];
3066789Sahrens 
30672082Seschrock 	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3068789Sahrens 		return (1);
3069789Sahrens 
30704451Seschrock 	for (i = 1; i < argc; i++) {
30714451Seschrock 		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
3072789Sahrens 			ret = 1;
30734451Seschrock 	}
3074789Sahrens 
30752082Seschrock 	zpool_close(zhp);
30762082Seschrock 
3077789Sahrens 	return (ret);
3078789Sahrens }
3079789Sahrens 
30801544Seschrock /*
30811544Seschrock  * zpool clear <pool> [device]
30821544Seschrock  *
30831544Seschrock  * Clear all errors associated with a pool or a particular device.
30841544Seschrock  */
30851544Seschrock int
zpool_do_clear(int argc,char ** argv)30861544Seschrock zpool_do_clear(int argc, char **argv)
30871544Seschrock {
308810921STim.Haley@Sun.COM 	int c;
30891544Seschrock 	int ret = 0;
309010921STim.Haley@Sun.COM 	boolean_t dryrun = B_FALSE;
309110921STim.Haley@Sun.COM 	boolean_t do_rewind = B_FALSE;
309210921STim.Haley@Sun.COM 	boolean_t xtreme_rewind = B_FALSE;
309310921STim.Haley@Sun.COM 	uint32_t rewind_policy = ZPOOL_NO_REWIND;
309410921STim.Haley@Sun.COM 	nvlist_t *policy = NULL;
30951544Seschrock 	zpool_handle_t *zhp;
30961544Seschrock 	char *pool, *device;
30971544Seschrock 
309810921STim.Haley@Sun.COM 	/* check options */
309910921STim.Haley@Sun.COM 	while ((c = getopt(argc, argv, "FnX")) != -1) {
310010921STim.Haley@Sun.COM 		switch (c) {
310110921STim.Haley@Sun.COM 		case 'F':
310210921STim.Haley@Sun.COM 			do_rewind = B_TRUE;
310310921STim.Haley@Sun.COM 			break;
310410921STim.Haley@Sun.COM 		case 'n':
310510921STim.Haley@Sun.COM 			dryrun = B_TRUE;
310610921STim.Haley@Sun.COM 			break;
310710921STim.Haley@Sun.COM 		case 'X':
310810921STim.Haley@Sun.COM 			xtreme_rewind = B_TRUE;
310910921STim.Haley@Sun.COM 			break;
311010921STim.Haley@Sun.COM 		case '?':
311110921STim.Haley@Sun.COM 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
311210921STim.Haley@Sun.COM 			    optopt);
311310921STim.Haley@Sun.COM 			usage(B_FALSE);
311410921STim.Haley@Sun.COM 		}
311510921STim.Haley@Sun.COM 	}
311610921STim.Haley@Sun.COM 
311710921STim.Haley@Sun.COM 	argc -= optind;
311810921STim.Haley@Sun.COM 	argv += optind;
311910921STim.Haley@Sun.COM 
312010921STim.Haley@Sun.COM 	if (argc < 1) {
31211544Seschrock 		(void) fprintf(stderr, gettext("missing pool name\n"));
31222082Seschrock 		usage(B_FALSE);
31231544Seschrock 	}
31241544Seschrock 
312510921STim.Haley@Sun.COM 	if (argc > 2) {
31261544Seschrock 		(void) fprintf(stderr, gettext("too many arguments\n"));
31272082Seschrock 		usage(B_FALSE);
31281544Seschrock 	}
31291544Seschrock 
313010921STim.Haley@Sun.COM 	if ((dryrun || xtreme_rewind) && !do_rewind) {
313110921STim.Haley@Sun.COM 		(void) fprintf(stderr,
313210921STim.Haley@Sun.COM 		    gettext("-n or -X only meaningful with -F\n"));
313310921STim.Haley@Sun.COM 		usage(B_FALSE);
313410921STim.Haley@Sun.COM 	}
313510921STim.Haley@Sun.COM 	if (dryrun)
313610921STim.Haley@Sun.COM 		rewind_policy = ZPOOL_TRY_REWIND;
313710921STim.Haley@Sun.COM 	else if (do_rewind)
313810921STim.Haley@Sun.COM 		rewind_policy = ZPOOL_DO_REWIND;
313910921STim.Haley@Sun.COM 	if (xtreme_rewind)
314010921STim.Haley@Sun.COM 		rewind_policy |= ZPOOL_EXTREME_REWIND;
314110921STim.Haley@Sun.COM 
314210921STim.Haley@Sun.COM 	/* In future, further rewind policy choices can be passed along here */
314310921STim.Haley@Sun.COM 	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
314410921STim.Haley@Sun.COM 	    nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
31451544Seschrock 		return (1);
31461544Seschrock 
314710921STim.Haley@Sun.COM 	pool = argv[0];
314810921STim.Haley@Sun.COM 	device = argc == 2 ? argv[1] : NULL;
314910921STim.Haley@Sun.COM 
315010921STim.Haley@Sun.COM 	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
315110921STim.Haley@Sun.COM 		nvlist_free(policy);
315210921STim.Haley@Sun.COM 		return (1);
315310921STim.Haley@Sun.COM 	}
315410921STim.Haley@Sun.COM 
315510921STim.Haley@Sun.COM 	if (zpool_clear(zhp, device, policy) != 0)
31561544Seschrock 		ret = 1;
31571544Seschrock 
31581544Seschrock 	zpool_close(zhp);
31591544Seschrock 
316010921STim.Haley@Sun.COM 	nvlist_free(policy);
316110921STim.Haley@Sun.COM 
31621544Seschrock 	return (ret);
31631544Seschrock }
31641544Seschrock 
3165789Sahrens typedef struct scrub_cbdata {
3166789Sahrens 	int	cb_type;
31672926Sek110237 	int	cb_argc;
31682926Sek110237 	char	**cb_argv;
3169789Sahrens } scrub_cbdata_t;
3170789Sahrens 
3171789Sahrens int
scrub_callback(zpool_handle_t * zhp,void * data)3172789Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
3173789Sahrens {
3174789Sahrens 	scrub_cbdata_t *cb = data;
31752926Sek110237 	int err;
3176789Sahrens 
31771544Seschrock 	/*
31781544Seschrock 	 * Ignore faulted pools.
31791544Seschrock 	 */
31801544Seschrock 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
31811544Seschrock 		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
31821544Seschrock 		    "currently unavailable\n"), zpool_get_name(zhp));
31831544Seschrock 		return (1);
31841544Seschrock 	}
31851544Seschrock 
318612296SLin.Ling@Sun.COM 	err = zpool_scan(zhp, cb->cb_type);
31872926Sek110237 
31882926Sek110237 	return (err != 0);
3189789Sahrens }
3190789Sahrens 
3191789Sahrens /*
3192789Sahrens  * zpool scrub [-s] <pool> ...
3193789Sahrens  *
3194789Sahrens  *	-s	Stop.  Stops any in-progress scrub.
3195789Sahrens  */
3196789Sahrens int
zpool_do_scrub(int argc,char ** argv)3197789Sahrens zpool_do_scrub(int argc, char **argv)
3198789Sahrens {
3199789Sahrens 	int c;
3200789Sahrens 	scrub_cbdata_t cb;
3201789Sahrens 
320212296SLin.Ling@Sun.COM 	cb.cb_type = POOL_SCAN_SCRUB;
3203789Sahrens 
3204789Sahrens 	/* check options */
3205789Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
3206789Sahrens 		switch (c) {
3207789Sahrens 		case 's':
320812296SLin.Ling@Sun.COM 			cb.cb_type = POOL_SCAN_NONE;
3209789Sahrens 			break;
3210789Sahrens 		case '?':
3211789Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3212789Sahrens 			    optopt);
32132082Seschrock 			usage(B_FALSE);
3214789Sahrens 		}
3215789Sahrens 	}
3216789Sahrens 
32172926Sek110237 	cb.cb_argc = argc;
32182926Sek110237 	cb.cb_argv = argv;
3219789Sahrens 	argc -= optind;
3220789Sahrens 	argv += optind;
3221789Sahrens 
3222789Sahrens 	if (argc < 1) {
3223789Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
32242082Seschrock 		usage(B_FALSE);
3225789Sahrens 	}
3226789Sahrens 
32273912Slling 	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
3228789Sahrens }
3229789Sahrens 
3230789Sahrens typedef struct status_cbdata {
32312082Seschrock 	int		cb_count;
32322676Seschrock 	boolean_t	cb_allpools;
32332082Seschrock 	boolean_t	cb_verbose;
32342082Seschrock 	boolean_t	cb_explain;
32352082Seschrock 	boolean_t	cb_first;
323611149SGeorge.Wilson@Sun.COM 	boolean_t	cb_dedup_stats;
3237789Sahrens } status_cbdata_t;
3238789Sahrens 
3239789Sahrens /*
3240789Sahrens  * Print out detailed scrub status.
3241789Sahrens  */
3242789Sahrens void
print_scan_status(pool_scan_stat_t * ps)324312296SLin.Ling@Sun.COM print_scan_status(pool_scan_stat_t *ps)
3244789Sahrens {
324512296SLin.Ling@Sun.COM 	time_t start, end;
3246*13099SLin.Ling@Sun.COM 	uint64_t elapsed, mins_left, hours_left;
324712296SLin.Ling@Sun.COM 	uint64_t pass_exam, examined, total;
324812296SLin.Ling@Sun.COM 	uint_t rate;
3249789Sahrens 	double fraction_done;
325012296SLin.Ling@Sun.COM 	char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
325112296SLin.Ling@Sun.COM 
325212296SLin.Ling@Sun.COM 	(void) printf(gettext(" scan: "));
325312296SLin.Ling@Sun.COM 
325412296SLin.Ling@Sun.COM 	/* If there's never been a scan, there's not much to say. */
325512296SLin.Ling@Sun.COM 	if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
325612296SLin.Ling@Sun.COM 	    ps->pss_func >= POOL_SCAN_FUNCS) {
3257789Sahrens 		(void) printf(gettext("none requested\n"));
3258789Sahrens 		return;
3259789Sahrens 	}
3260789Sahrens 
326112296SLin.Ling@Sun.COM 	start = ps->pss_start_time;
326212296SLin.Ling@Sun.COM 	end = ps->pss_end_time;
326312296SLin.Ling@Sun.COM 	zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
326412296SLin.Ling@Sun.COM 
326512296SLin.Ling@Sun.COM 	assert(ps->pss_func == POOL_SCAN_SCRUB ||
326612296SLin.Ling@Sun.COM 	    ps->pss_func == POOL_SCAN_RESILVER);
326712296SLin.Ling@Sun.COM 	/*
326812296SLin.Ling@Sun.COM 	 * Scan is finished or canceled.
326912296SLin.Ling@Sun.COM 	 */
327012296SLin.Ling@Sun.COM 	if (ps->pss_state == DSS_FINISHED) {
327112296SLin.Ling@Sun.COM 		uint64_t minutes_taken = (end - start) / 60;
327212296SLin.Ling@Sun.COM 		char *fmt;
327312296SLin.Ling@Sun.COM 
327412296SLin.Ling@Sun.COM 		if (ps->pss_func == POOL_SCAN_SCRUB) {
327512296SLin.Ling@Sun.COM 			fmt = gettext("scrub repaired %s in %lluh%um with "
327612296SLin.Ling@Sun.COM 			    "%llu errors on %s");
327712296SLin.Ling@Sun.COM 		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
327812296SLin.Ling@Sun.COM 			fmt = gettext("resilvered %s in %lluh%um with "
327912296SLin.Ling@Sun.COM 			    "%llu errors on %s");
328012296SLin.Ling@Sun.COM 		}
328112296SLin.Ling@Sun.COM 		/* LINTED */
328212296SLin.Ling@Sun.COM 		(void) printf(fmt, processed_buf,
32835853Sek110237 		    (u_longlong_t)(minutes_taken / 60),
32845853Sek110237 		    (uint_t)(minutes_taken % 60),
328512296SLin.Ling@Sun.COM 		    (u_longlong_t)ps->pss_errors,
328612296SLin.Ling@Sun.COM 		    ctime((time_t *)&end));
328712296SLin.Ling@Sun.COM 		return;
328812296SLin.Ling@Sun.COM 	} else if (ps->pss_state == DSS_CANCELED) {
328912296SLin.Ling@Sun.COM 		if (ps->pss_func == POOL_SCAN_SCRUB) {
329012296SLin.Ling@Sun.COM 			(void) printf(gettext("scrub canceled on %s"),
329112296SLin.Ling@Sun.COM 			    ctime(&end));
329212296SLin.Ling@Sun.COM 		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
329312296SLin.Ling@Sun.COM 			(void) printf(gettext("resilver canceled on %s"),
329412296SLin.Ling@Sun.COM 			    ctime(&end));
329512296SLin.Ling@Sun.COM 		}
3296789Sahrens 		return;
3297789Sahrens 	}
3298789Sahrens 
329912296SLin.Ling@Sun.COM 	assert(ps->pss_state == DSS_SCANNING);
330012296SLin.Ling@Sun.COM 
330112296SLin.Ling@Sun.COM 	/*
330212296SLin.Ling@Sun.COM 	 * Scan is in progress.
330312296SLin.Ling@Sun.COM 	 */
330412296SLin.Ling@Sun.COM 	if (ps->pss_func == POOL_SCAN_SCRUB) {
330512296SLin.Ling@Sun.COM 		(void) printf(gettext("scrub in progress since %s"),
330612296SLin.Ling@Sun.COM 		    ctime(&start));
330712296SLin.Ling@Sun.COM 	} else if (ps->pss_func == POOL_SCAN_RESILVER) {
330812296SLin.Ling@Sun.COM 		(void) printf(gettext("resilver in progress since %s"),
330912296SLin.Ling@Sun.COM 		    ctime(&start));
331012296SLin.Ling@Sun.COM 	}
331112296SLin.Ling@Sun.COM 
331212296SLin.Ling@Sun.COM 	examined = ps->pss_examined ? ps->pss_examined : 1;
331312296SLin.Ling@Sun.COM 	total = ps->pss_to_examine;
3314789Sahrens 	fraction_done = (double)examined / total;
331512296SLin.Ling@Sun.COM 
331612296SLin.Ling@Sun.COM 	/* elapsed time for this pass */
331712296SLin.Ling@Sun.COM 	elapsed = time(NULL) - ps->pss_pass_start;
331812296SLin.Ling@Sun.COM 	elapsed = elapsed ? elapsed : 1;
331912296SLin.Ling@Sun.COM 	pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1;
332012296SLin.Ling@Sun.COM 	rate = pass_exam / elapsed;
332112296SLin.Ling@Sun.COM 	rate = rate ? rate : 1;
332212296SLin.Ling@Sun.COM 	mins_left = ((total - examined) / rate) / 60;
3323*13099SLin.Ling@Sun.COM 	hours_left = mins_left / 60;
332412296SLin.Ling@Sun.COM 
332512296SLin.Ling@Sun.COM 	zfs_nicenum(examined, examined_buf, sizeof (examined_buf));
332612296SLin.Ling@Sun.COM 	zfs_nicenum(total, total_buf, sizeof (total_buf));
332712296SLin.Ling@Sun.COM 	zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
332812296SLin.Ling@Sun.COM 
3329*13099SLin.Ling@Sun.COM 	/*
3330*13099SLin.Ling@Sun.COM 	 * do not print estimated time if hours_left is more than 30 days
3331*13099SLin.Ling@Sun.COM 	 */
3332*13099SLin.Ling@Sun.COM 	(void) printf(gettext("    %s scanned out of %s at %s/s"),
3333*13099SLin.Ling@Sun.COM 	    examined_buf, total_buf, rate_buf);
3334*13099SLin.Ling@Sun.COM 	if (hours_left < (30 * 24)) {
3335*13099SLin.Ling@Sun.COM 		(void) printf(gettext(", %lluh%um to go\n"),
3336*13099SLin.Ling@Sun.COM 		    (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
3337*13099SLin.Ling@Sun.COM 	} else {
3338*13099SLin.Ling@Sun.COM 		(void) printf(gettext(
3339*13099SLin.Ling@Sun.COM 		    ", (scan is slow, no estimated time)\n"));
3340*13099SLin.Ling@Sun.COM 	}
334112296SLin.Ling@Sun.COM 
334212296SLin.Ling@Sun.COM 	if (ps->pss_func == POOL_SCAN_RESILVER) {
334312296SLin.Ling@Sun.COM 		(void) printf(gettext("    %s resilvered, %.2f%% done\n"),
334412296SLin.Ling@Sun.COM 		    processed_buf, 100 * fraction_done);
334512296SLin.Ling@Sun.COM 	} else if (ps->pss_func == POOL_SCAN_SCRUB) {
334612296SLin.Ling@Sun.COM 		(void) printf(gettext("    %s repaired, %.2f%% done\n"),
334712296SLin.Ling@Sun.COM 		    processed_buf, 100 * fraction_done);
334812296SLin.Ling@Sun.COM 	}
3349789Sahrens }
3350789Sahrens 
33511544Seschrock static void
print_error_log(zpool_handle_t * zhp)33521544Seschrock print_error_log(zpool_handle_t *zhp)
33531544Seschrock {
33544820Sek110237 	nvlist_t *nverrlist = NULL;
33553444Sek110237 	nvpair_t *elem;
33563444Sek110237 	char *pathname;
33573444Sek110237 	size_t len = MAXPATHLEN * 2;
33583444Sek110237 
33593444Sek110237 	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
33601544Seschrock 		(void) printf("errors: List of errors unavailable "
33611544Seschrock 		    "(insufficient privileges)\n");
33621544Seschrock 		return;
33631544Seschrock 	}
33641544Seschrock 
33653444Sek110237 	(void) printf("errors: Permanent errors have been "
33663444Sek110237 	    "detected in the following files:\n\n");
33673444Sek110237 
33683444Sek110237 	pathname = safe_malloc(len);
33693444Sek110237 	elem = NULL;
33703444Sek110237 	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
33713444Sek110237 		nvlist_t *nv;
33723444Sek110237 		uint64_t dsobj, obj;
33733444Sek110237 
33743444Sek110237 		verify(nvpair_value_nvlist(elem, &nv) == 0);
33753444Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
33763444Sek110237 		    &dsobj) == 0);
33773444Sek110237 		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
33783444Sek110237 		    &obj) == 0);
33793444Sek110237 		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
33803444Sek110237 		(void) printf("%7s %s\n", "", pathname);
33811544Seschrock 	}
33823444Sek110237 	free(pathname);
33833444Sek110237 	nvlist_free(nverrlist);
33841544Seschrock }
33851544Seschrock 
33862082Seschrock static void
print_spares(zpool_handle_t * zhp,nvlist_t ** spares,uint_t nspares,int namewidth)33872082Seschrock print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
33882082Seschrock     int namewidth)
33892082Seschrock {
33902082Seschrock 	uint_t i;
33912082Seschrock 	char *name;
33922082Seschrock 
33932082Seschrock 	if (nspares == 0)
33942082Seschrock 		return;
33952082Seschrock 
33962082Seschrock 	(void) printf(gettext("\tspares\n"));
33972082Seschrock 
33982082Seschrock 	for (i = 0; i < nspares; i++) {
339910594SGeorge.Wilson@Sun.COM 		name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE);
34002082Seschrock 		print_status_config(zhp, name, spares[i],
34019391SNeil.Perrin@Sun.COM 		    namewidth, 2, B_TRUE);
34022082Seschrock 		free(name);
34032082Seschrock 	}
34042082Seschrock }
34052082Seschrock 
34065450Sbrendan static void
print_l2cache(zpool_handle_t * zhp,nvlist_t ** l2cache,uint_t nl2cache,int namewidth)34075450Sbrendan print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
34085450Sbrendan     int namewidth)
34095450Sbrendan {
34105450Sbrendan 	uint_t i;
34115450Sbrendan 	char *name;
34125450Sbrendan 
34135450Sbrendan 	if (nl2cache == 0)
34145450Sbrendan 		return;
34155450Sbrendan 
34165450Sbrendan 	(void) printf(gettext("\tcache\n"));
34175450Sbrendan 
34185450Sbrendan 	for (i = 0; i < nl2cache; i++) {
341910594SGeorge.Wilson@Sun.COM 		name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE);
34205450Sbrendan 		print_status_config(zhp, name, l2cache[i],
34219391SNeil.Perrin@Sun.COM 		    namewidth, 2, B_FALSE);
34229391SNeil.Perrin@Sun.COM 		free(name);
34239391SNeil.Perrin@Sun.COM 	}
34249391SNeil.Perrin@Sun.COM }
34259391SNeil.Perrin@Sun.COM 
342611149SGeorge.Wilson@Sun.COM static void
print_dedup_stats(nvlist_t * config)342711149SGeorge.Wilson@Sun.COM print_dedup_stats(nvlist_t *config)
342811149SGeorge.Wilson@Sun.COM {
342911149SGeorge.Wilson@Sun.COM 	ddt_histogram_t *ddh;
343011149SGeorge.Wilson@Sun.COM 	ddt_stat_t *dds;
343111149SGeorge.Wilson@Sun.COM 	ddt_object_t *ddo;
343211149SGeorge.Wilson@Sun.COM 	uint_t c;
343311149SGeorge.Wilson@Sun.COM 
343411149SGeorge.Wilson@Sun.COM 	/*
343511149SGeorge.Wilson@Sun.COM 	 * If the pool was faulted then we may not have been able to
343611149SGeorge.Wilson@Sun.COM 	 * obtain the config. Otherwise, if have anything in the dedup
343711149SGeorge.Wilson@Sun.COM 	 * table continue processing the stats.
343811149SGeorge.Wilson@Sun.COM 	 */
343911149SGeorge.Wilson@Sun.COM 	if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
344011149SGeorge.Wilson@Sun.COM 	    (uint64_t **)&ddo, &c) != 0 || ddo->ddo_count == 0)
344111149SGeorge.Wilson@Sun.COM 		return;
344211149SGeorge.Wilson@Sun.COM 
344311149SGeorge.Wilson@Sun.COM 	(void) printf("\n");
344411149SGeorge.Wilson@Sun.COM 	(void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
344511149SGeorge.Wilson@Sun.COM 	    (u_longlong_t)ddo->ddo_count,
344611149SGeorge.Wilson@Sun.COM 	    (u_longlong_t)ddo->ddo_dspace,
344711149SGeorge.Wilson@Sun.COM 	    (u_longlong_t)ddo->ddo_mspace);
344811149SGeorge.Wilson@Sun.COM 
344911149SGeorge.Wilson@Sun.COM 	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
345011149SGeorge.Wilson@Sun.COM 	    (uint64_t **)&dds, &c) == 0);
345111149SGeorge.Wilson@Sun.COM 	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
345211149SGeorge.Wilson@Sun.COM 	    (uint64_t **)&ddh, &c) == 0);
345311149SGeorge.Wilson@Sun.COM 	zpool_dump_ddt(dds, ddh);
345411149SGeorge.Wilson@Sun.COM }
345511149SGeorge.Wilson@Sun.COM 
34569391SNeil.Perrin@Sun.COM /*
3457789Sahrens  * Display a summary of pool status.  Displays a summary such as:
3458789Sahrens  *
3459789Sahrens  *        pool: tank
3460789Sahrens  *	status: DEGRADED
3461789Sahrens  *	reason: One or more devices ...
3462789Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
3463789Sahrens  *	config:
3464789Sahrens  *		mirror		DEGRADED
3465789Sahrens  *                c1t0d0	OK
34661544Seschrock  *                c2t0d0	UNAVAIL
3467789Sahrens  *
3468789Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
3469789Sahrens  * option is specified, then we print out error rate information as well.
3470789Sahrens  */
3471789Sahrens int
status_callback(zpool_handle_t * zhp,void * data)3472789Sahrens status_callback(zpool_handle_t *zhp, void *data)
3473789Sahrens {
3474789Sahrens 	status_cbdata_t *cbp = data;
3475789Sahrens 	nvlist_t *config, *nvroot;
3476789Sahrens 	char *msgid;
3477789Sahrens 	int reason;
34783741Smmusante 	const char *health;
34793741Smmusante 	uint_t c;
34803741Smmusante 	vdev_stat_t *vs;
3481789Sahrens 
3482952Seschrock 	config = zpool_get_config(zhp, NULL);
3483789Sahrens 	reason = zpool_get_status(zhp, &msgid);
3484789Sahrens 
3485789Sahrens 	cbp->cb_count++;
3486789Sahrens 
3487789Sahrens 	/*
3488789Sahrens 	 * If we were given 'zpool status -x', only report those pools with
3489789Sahrens 	 * problems.
3490789Sahrens 	 */
34912676Seschrock 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
34922676Seschrock 		if (!cbp->cb_allpools) {
34932676Seschrock 			(void) printf(gettext("pool '%s' is healthy\n"),
34942676Seschrock 			    zpool_get_name(zhp));
34952676Seschrock 			if (cbp->cb_first)
34962676Seschrock 				cbp->cb_first = B_FALSE;
34972676Seschrock 		}
3498789Sahrens 		return (0);
34992676Seschrock 	}
3500789Sahrens 
3501789Sahrens 	if (cbp->cb_first)
35022082Seschrock 		cbp->cb_first = B_FALSE;
3503789Sahrens 	else
3504789Sahrens 		(void) printf("\n");
3505789Sahrens 
35063741Smmusante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
35073741Smmusante 	    &nvroot) == 0);
350812296SLin.Ling@Sun.COM 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
35093741Smmusante 	    (uint64_t **)&vs, &c) == 0);
35105094Slling 	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3511789Sahrens 
3512789Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
3513789Sahrens 	(void) printf(gettext(" state: %s\n"), health);
3514789Sahrens 
3515789Sahrens 	switch (reason) {
3516789Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
3517789Sahrens 		(void) printf(gettext("status: One or more devices could not "
3518789Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
3519789Sahrens 		    "continue functioning in a degraded state.\n"));
3520789Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3521789Sahrens 		    "online it using 'zpool online'.\n"));
3522789Sahrens 		break;
3523789Sahrens 
3524789Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
3525789Sahrens 		(void) printf(gettext("status: One or more devices could not "
3526789Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
3527789Sahrens 		    "pool to continue functioning.\n"));
3528789Sahrens 		(void) printf(gettext("action: Attach the missing device and "
3529789Sahrens 		    "online it using 'zpool online'.\n"));
3530789Sahrens 		break;
3531789Sahrens 
3532789Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
3533789Sahrens 		(void) printf(gettext("status: One or more devices could not "
3534789Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
3535789Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
3536789Sahrens 		    "functioning in a degraded state.\n"));
3537789Sahrens 		(void) printf(gettext("action: Replace the device using "
3538789Sahrens 		    "'zpool replace'.\n"));
3539789Sahrens 		break;
3540789Sahrens 
3541789Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3542789Sahrens 		(void) printf(gettext("status: One or more devices could not "
35433912Slling 		    "be used because the label is missing \n\tor invalid.  "
3544789Sahrens 		    "There are insufficient replicas for the pool to "
3545789Sahrens 		    "continue\n\tfunctioning.\n"));
354610921STim.Haley@Sun.COM 		zpool_explain_recover(zpool_get_handle(zhp),
354710921STim.Haley@Sun.COM 		    zpool_get_name(zhp), reason, config);
3548789Sahrens 		break;
3549789Sahrens 
3550789Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
3551789Sahrens 		(void) printf(gettext("status: One or more devices has "
3552789Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
3553789Sahrens 		    "made to correct the error.  Applications are "
3554789Sahrens 		    "unaffected.\n"));
3555789Sahrens 		(void) printf(gettext("action: Determine if the device needs "
3556789Sahrens 		    "to be replaced, and clear the errors\n\tusing "
35571544Seschrock 		    "'zpool clear' or replace the device with 'zpool "
3558789Sahrens 		    "replace'.\n"));
3559789Sahrens 		break;
3560789Sahrens 
3561789Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
3562789Sahrens 		(void) printf(gettext("status: One or more devices has "
35633413Smmusante 		    "been taken offline by the administrator.\n\tSufficient "
3564789Sahrens 		    "replicas exist for the pool to continue functioning in "
3565789Sahrens 		    "a\n\tdegraded state.\n"));
3566789Sahrens 		(void) printf(gettext("action: Online the device using "
3567789Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
3568789Sahrens 		    "replace'.\n"));
3569789Sahrens 		break;
3570789Sahrens 
357110151SGeorge.Wilson@Sun.COM 	case ZPOOL_STATUS_REMOVED_DEV:
357210151SGeorge.Wilson@Sun.COM 		(void) printf(gettext("status: One or more devices has "
357310151SGeorge.Wilson@Sun.COM 		    "been removed by the administrator.\n\tSufficient "
357410151SGeorge.Wilson@Sun.COM 		    "replicas exist for the pool to continue functioning in "
357510151SGeorge.Wilson@Sun.COM 		    "a\n\tdegraded state.\n"));
357610151SGeorge.Wilson@Sun.COM 		(void) printf(gettext("action: Online the device using "
357710151SGeorge.Wilson@Sun.COM 		    "'zpool online' or replace the device with\n\t'zpool "
357810151SGeorge.Wilson@Sun.COM 		    "replace'.\n"));
357910151SGeorge.Wilson@Sun.COM 		break;
358010151SGeorge.Wilson@Sun.COM 
3581789Sahrens 	case ZPOOL_STATUS_RESILVERING:
3582789Sahrens 		(void) printf(gettext("status: One or more devices is "
3583789Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
3584789Sahrens 		    "to function, possibly in a degraded state.\n"));
3585789Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
3586789Sahrens 		    "complete.\n"));
3587789Sahrens 		break;
3588789Sahrens 
35891544Seschrock 	case ZPOOL_STATUS_CORRUPT_DATA:
35901544Seschrock 		(void) printf(gettext("status: One or more devices has "
35911544Seschrock 		    "experienced an error resulting in data\n\tcorruption.  "
35921544Seschrock 		    "Applications may be affected.\n"));
35931544Seschrock 		(void) printf(gettext("action: Restore the file in question "
35941544Seschrock 		    "if possible.  Otherwise restore the\n\tentire pool from "
35951544Seschrock 		    "backup.\n"));
35961544Seschrock 		break;
35971544Seschrock 
35981544Seschrock 	case ZPOOL_STATUS_CORRUPT_POOL:
35991544Seschrock 		(void) printf(gettext("status: The pool metadata is corrupted "
36001544Seschrock 		    "and the pool cannot be opened.\n"));
360110921STim.Haley@Sun.COM 		zpool_explain_recover(zpool_get_handle(zhp),
360210921STim.Haley@Sun.COM 		    zpool_get_name(zhp), reason, config);
36031544Seschrock 		break;
36041544Seschrock 
36051760Seschrock 	case ZPOOL_STATUS_VERSION_OLDER:
36061760Seschrock 		(void) printf(gettext("status: The pool is formatted using an "
36071760Seschrock 		    "older on-disk format.  The pool can\n\tstill be used, but "
36081760Seschrock 		    "some features are unavailable.\n"));
36091760Seschrock 		(void) printf(gettext("action: Upgrade the pool using 'zpool "
36101760Seschrock 		    "upgrade'.  Once this is done, the\n\tpool will no longer "
36111760Seschrock 		    "be accessible on older software versions.\n"));
36121760Seschrock 		break;
36131760Seschrock 
36141760Seschrock 	case ZPOOL_STATUS_VERSION_NEWER:
36151760Seschrock 		(void) printf(gettext("status: The pool has been upgraded to a "
36161760Seschrock 		    "newer, incompatible on-disk version.\n\tThe pool cannot "
36171760Seschrock 		    "be accessed on this system.\n"));
36181760Seschrock 		(void) printf(gettext("action: Access the pool from a system "
36191760Seschrock 		    "running more recent software, or\n\trestore the pool from "
36201760Seschrock 		    "backup.\n"));
36211760Seschrock 		break;
36221760Seschrock 
36234451Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_R:
36244451Seschrock 		(void) printf(gettext("status: One or more devices are "
36254451Seschrock 		    "faulted in response to persistent errors.\n\tSufficient "
36264451Seschrock 		    "replicas exist for the pool to continue functioning "
36274451Seschrock 		    "in a\n\tdegraded state.\n"));
36284451Seschrock 		(void) printf(gettext("action: Replace the faulted device, "
36294451Seschrock 		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
36304451Seschrock 		break;
36314451Seschrock 
36324451Seschrock 	case ZPOOL_STATUS_FAULTED_DEV_NR:
36334451Seschrock 		(void) printf(gettext("status: One or more devices are "
36344451Seschrock 		    "faulted in response to persistent errors.  There are "
36354451Seschrock 		    "insufficient replicas for the pool to\n\tcontinue "
36364451Seschrock 		    "functioning.\n"));
36374451Seschrock 		(void) printf(gettext("action: Destroy and re-create the pool "
36384451Seschrock 		    "from a backup source.  Manually marking the device\n"
36394451Seschrock 		    "\trepaired using 'zpool clear' may allow some data "
36404451Seschrock 		    "to be recovered.\n"));
36414451Seschrock 		break;
36424451Seschrock 
36436523Sek110237 	case ZPOOL_STATUS_IO_FAILURE_WAIT:
36446523Sek110237 	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
36456523Sek110237 		(void) printf(gettext("status: One or more devices are "
36466959Sek110237 		    "faulted in response to IO failures.\n"));
36476523Sek110237 		(void) printf(gettext("action: Make sure the affected devices "
36486523Sek110237 		    "are connected, then run 'zpool clear'.\n"));
36496523Sek110237 		break;
36506523Sek110237 
36517294Sperrin 	case ZPOOL_STATUS_BAD_LOG:
36527294Sperrin 		(void) printf(gettext("status: An intent log record "
36537294Sperrin 		    "could not be read.\n"
36547294Sperrin 		    "\tWaiting for adminstrator intervention to fix the "
36557294Sperrin 		    "faulted pool.\n"));
36567294Sperrin 		(void) printf(gettext("action: Either restore the affected "
36577294Sperrin 		    "device(s) and run 'zpool online',\n"
36587294Sperrin 		    "\tor ignore the intent log records by running "
36597294Sperrin 		    "'zpool clear'.\n"));
36607294Sperrin 		break;
36617294Sperrin 
3662789Sahrens 	default:
3663789Sahrens 		/*
3664789Sahrens 		 * The remaining errors can't actually be generated, yet.
3665789Sahrens 		 */
3666789Sahrens 		assert(reason == ZPOOL_STATUS_OK);
3667789Sahrens 	}
3668789Sahrens 
3669789Sahrens 	if (msgid != NULL)
3670789Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3671789Sahrens 		    msgid);
3672789Sahrens 
3673789Sahrens 	if (config != NULL) {
3674789Sahrens 		int namewidth;
36751544Seschrock 		uint64_t nerr;
36765450Sbrendan 		nvlist_t **spares, **l2cache;
36775450Sbrendan 		uint_t nspares, nl2cache;
367812296SLin.Ling@Sun.COM 		pool_scan_stat_t *ps = NULL;
367912296SLin.Ling@Sun.COM 
368012296SLin.Ling@Sun.COM 		(void) nvlist_lookup_uint64_array(nvroot,
368112296SLin.Ling@Sun.COM 		    ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
368212296SLin.Ling@Sun.COM 		print_scan_status(ps);
3683789Sahrens 
36841354Seschrock 		namewidth = max_width(zhp, nvroot, 0, 0);
3685789Sahrens 		if (namewidth < 10)
3686789Sahrens 			namewidth = 10;
3687789Sahrens 
3688789Sahrens 		(void) printf(gettext("config:\n\n"));
3689789Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3690789Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
36911354Seschrock 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
36929391SNeil.Perrin@Sun.COM 		    namewidth, 0, B_FALSE);
36939391SNeil.Perrin@Sun.COM 
36949466SNeil.Perrin@Sun.COM 		if (num_logs(nvroot) > 0)
36959701SGeorge.Wilson@Sun.COM 			print_logs(zhp, nvroot, namewidth, B_TRUE);
36965450Sbrendan 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
36975450Sbrendan 		    &l2cache, &nl2cache) == 0)
36985450Sbrendan 			print_l2cache(zhp, l2cache, nl2cache, namewidth);
36995450Sbrendan 
37002082Seschrock 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
37012082Seschrock 		    &spares, &nspares) == 0)
37022082Seschrock 			print_spares(zhp, spares, nspares, namewidth);
37031544Seschrock 
37041544Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
37051544Seschrock 		    &nerr) == 0) {
37063444Sek110237 			nvlist_t *nverrlist = NULL;
37073444Sek110237 
37081544Seschrock 			/*
37091544Seschrock 			 * If the approximate error count is small, get a
37101544Seschrock 			 * precise count by fetching the entire log and
37111544Seschrock 			 * uniquifying the results.
37121544Seschrock 			 */
37134820Sek110237 			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
37143444Sek110237 			    zpool_get_errlog(zhp, &nverrlist) == 0) {
37153444Sek110237 				nvpair_t *elem;
37163444Sek110237 
37173444Sek110237 				elem = NULL;
37183444Sek110237 				nerr = 0;
37193444Sek110237 				while ((elem = nvlist_next_nvpair(nverrlist,
37203444Sek110237 				    elem)) != NULL) {
37213444Sek110237 					nerr++;
37223444Sek110237 				}
37233444Sek110237 			}
37243444Sek110237 			nvlist_free(nverrlist);
37251544Seschrock 
37261544Seschrock 			(void) printf("\n");
37272082Seschrock 
37281544Seschrock 			if (nerr == 0)
37291544Seschrock 				(void) printf(gettext("errors: No known data "
37301544Seschrock 				    "errors\n"));
37311544Seschrock 			else if (!cbp->cb_verbose)
37322676Seschrock 				(void) printf(gettext("errors: %llu data "
37332856Snd150628 				    "errors, use '-v' for a list\n"),
37342856Snd150628 				    (u_longlong_t)nerr);
37351544Seschrock 			else
37361544Seschrock 				print_error_log(zhp);
37371544Seschrock 		}
373811149SGeorge.Wilson@Sun.COM 
373911149SGeorge.Wilson@Sun.COM 		if (cbp->cb_dedup_stats)
374011149SGeorge.Wilson@Sun.COM 			print_dedup_stats(config);
3741789Sahrens 	} else {
3742789Sahrens 		(void) printf(gettext("config: The configuration cannot be "
3743789Sahrens 		    "determined.\n"));
3744789Sahrens 	}
3745789Sahrens 
3746789Sahrens 	return (0);
3747789Sahrens }
3748789Sahrens 
3749789Sahrens /*
375012296SLin.Ling@Sun.COM  * zpool status [-vx] [-T d|u] [pool] ... [interval [count]]
3751789Sahrens  *
3752789Sahrens  *	-v	Display complete error logs
3753789Sahrens  *	-x	Display only pools with potential problems
375411149SGeorge.Wilson@Sun.COM  *	-D	Display dedup status (undocumented)
375512296SLin.Ling@Sun.COM  *	-T	Display a timestamp in date(1) or Unix format
3756789Sahrens  *
3757789Sahrens  * Describes the health status of all pools or some subset.
3758789Sahrens  */
3759789Sahrens int
zpool_do_status(int argc,char ** argv)3760789Sahrens zpool_do_status(int argc, char **argv)
3761789Sahrens {
3762789Sahrens 	int c;
3763789Sahrens 	int ret;
376412296SLin.Ling@Sun.COM 	unsigned long interval = 0, count = 0;
3765789Sahrens 	status_cbdata_t cb = { 0 };
3766789Sahrens 
3767789Sahrens 	/* check options */
376812296SLin.Ling@Sun.COM 	while ((c = getopt(argc, argv, "vxDT:")) != -1) {
3769789Sahrens 		switch (c) {
3770789Sahrens 		case 'v':
37712082Seschrock 			cb.cb_verbose = B_TRUE;
3772789Sahrens 			break;
3773789Sahrens 		case 'x':
37742082Seschrock 			cb.cb_explain = B_TRUE;
3775789Sahrens 			break;
377611149SGeorge.Wilson@Sun.COM 		case 'D':
377711149SGeorge.Wilson@Sun.COM 			cb.cb_dedup_stats = B_TRUE;
377811149SGeorge.Wilson@Sun.COM 			break;
377912296SLin.Ling@Sun.COM 		case 'T':
378012296SLin.Ling@Sun.COM 			get_timestamp_arg(*optarg);
378112296SLin.Ling@Sun.COM 			break;
3782789Sahrens 		case '?':
3783789Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3784789Sahrens 			    optopt);
37852082Seschrock 			usage(B_FALSE);
3786789Sahrens 		}
3787789Sahrens 	}
3788789Sahrens 
3789789Sahrens 	argc -= optind;
3790789Sahrens 	argv += optind;
3791789Sahrens 
379212296SLin.Ling@Sun.COM 	get_interval_count(&argc, argv, &interval, &count);
37932082Seschrock 
37942676Seschrock 	if (argc == 0)
37952676Seschrock 		cb.cb_allpools = B_TRUE;
37962676Seschrock 
379712296SLin.Ling@Sun.COM 	cb.cb_first = B_TRUE;
379812296SLin.Ling@Sun.COM 
379912296SLin.Ling@Sun.COM 	for (;;) {
380012296SLin.Ling@Sun.COM 		if (timestamp_fmt != NODATE)
380112296SLin.Ling@Sun.COM 			print_timestamp(timestamp_fmt);
380212296SLin.Ling@Sun.COM 
380312296SLin.Ling@Sun.COM 		ret = for_each_pool(argc, argv, B_TRUE, NULL,
380412296SLin.Ling@Sun.COM 		    status_callback, &cb);
380512296SLin.Ling@Sun.COM 
380612296SLin.Ling@Sun.COM 		if (argc == 0 && cb.cb_count == 0)
380712296SLin.Ling@Sun.COM 			(void) printf(gettext("no pools available\n"));
380812296SLin.Ling@Sun.COM 		else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
380912296SLin.Ling@Sun.COM 			(void) printf(gettext("all pools are healthy\n"));
381012296SLin.Ling@Sun.COM 
381112296SLin.Ling@Sun.COM 		if (ret != 0)
381212296SLin.Ling@Sun.COM 			return (ret);
381312296SLin.Ling@Sun.COM 
381412296SLin.Ling@Sun.COM 		if (interval == 0)
381512296SLin.Ling@Sun.COM 			break;
381612296SLin.Ling@Sun.COM 
381712296SLin.Ling@Sun.COM 		if (count != 0 && --count == 0)
381812296SLin.Ling@Sun.COM 			break;
381912296SLin.Ling@Sun.COM 
382012296SLin.Ling@Sun.COM 		(void) sleep(interval);
382112296SLin.Ling@Sun.COM 	}
382212296SLin.Ling@Sun.COM 
382312296SLin.Ling@Sun.COM 	return (0);
3824789Sahrens }
3825789Sahrens 
38261760Seschrock typedef struct upgrade_cbdata {
38271760Seschrock 	int	cb_all;
38281760Seschrock 	int	cb_first;
38291760Seschrock 	int	cb_newer;
38302926Sek110237 	int	cb_argc;
38315094Slling 	uint64_t cb_version;
38322926Sek110237 	char	**cb_argv;
38331760Seschrock } upgrade_cbdata_t;
38341760Seschrock 
38351760Seschrock static int
upgrade_cb(zpool_handle_t * zhp,void * arg)38361760Seschrock upgrade_cb(zpool_handle_t *zhp, void *arg)
38371760Seschrock {
38381760Seschrock 	upgrade_cbdata_t *cbp = arg;
38391760Seschrock 	nvlist_t *config;
38401760Seschrock 	uint64_t version;
38411760Seschrock 	int ret = 0;
38421760Seschrock 
38431760Seschrock 	config = zpool_get_config(zhp, NULL);
38441760Seschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
38451760Seschrock 	    &version) == 0);
38461760Seschrock 
38474577Sahrens 	if (!cbp->cb_newer && version < SPA_VERSION) {
38481760Seschrock 		if (!cbp->cb_all) {
38491760Seschrock 			if (cbp->cb_first) {
38501760Seschrock 				(void) printf(gettext("The following pools are "
38511760Seschrock 				    "out of date, and can be upgraded.  After "
38521760Seschrock 				    "being\nupgraded, these pools will no "
38531760Seschrock 				    "longer be accessible by older software "
38541760Seschrock 				    "versions.\n\n"));
38551760Seschrock 				(void) printf(gettext("VER  POOL\n"));
38561760Seschrock 				(void) printf(gettext("---  ------------\n"));
38572082Seschrock 				cbp->cb_first = B_FALSE;
38581760Seschrock 			}
38591760Seschrock 
38602856Snd150628 			(void) printf("%2llu   %s\n", (u_longlong_t)version,
38611760Seschrock 			    zpool_get_name(zhp));
38621760Seschrock 		} else {
38632082Seschrock 			cbp->cb_first = B_FALSE;
38645094Slling 			ret = zpool_upgrade(zhp, cbp->cb_version);
38652926Sek110237 			if (!ret) {
38661760Seschrock 				(void) printf(gettext("Successfully upgraded "
38675094Slling 				    "'%s'\n\n"), zpool_get_name(zhp));
38682926Sek110237 			}
38691760Seschrock 		}
38704577Sahrens 	} else if (cbp->cb_newer && version > SPA_VERSION) {
38711760Seschrock 		assert(!cbp->cb_all);
38721760Seschrock 
38731760Seschrock 		if (cbp->cb_first) {
38741760Seschrock 			(void) printf(gettext("The following pools are "
38751760Seschrock 			    "formatted using a newer software version and\n"
38761760Seschrock 			    "cannot be accessed on the current system.\n\n"));
38771760Seschrock 			(void) printf(gettext("VER  POOL\n"));
38781760Seschrock 			(void) printf(gettext("---  ------------\n"));
38792082Seschrock 			cbp->cb_first = B_FALSE;
38801760Seschrock 		}
38811760Seschrock 
38822856Snd150628 		(void) printf("%2llu   %s\n", (u_longlong_t)version,
38831760Seschrock 		    zpool_get_name(zhp));
38841760Seschrock 	}
38851760Seschrock 
38861760Seschrock 	zpool_close(zhp);
38871760Seschrock 	return (ret);
38881760Seschrock }
38891760Seschrock 
38901760Seschrock /* ARGSUSED */
38911760Seschrock static int
upgrade_one(zpool_handle_t * zhp,void * data)38922926Sek110237 upgrade_one(zpool_handle_t *zhp, void *data)
38931760Seschrock {
38945094Slling 	upgrade_cbdata_t *cbp = data;
38955094Slling 	uint64_t cur_version;
38961760Seschrock 	int ret;
38971760Seschrock 
38984527Sperrin 	if (strcmp("log", zpool_get_name(zhp)) == 0) {
38994527Sperrin 		(void) printf(gettext("'log' is now a reserved word\n"
39004527Sperrin 		    "Pool 'log' must be renamed using export and import"
39014527Sperrin 		    " to upgrade.\n"));
39024527Sperrin 		return (1);
39034527Sperrin 	}
39045094Slling 
39055094Slling 	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
39066018Sbrendan 	if (cur_version > cbp->cb_version) {
39071760Seschrock 		(void) printf(gettext("Pool '%s' is already formatted "
39086018Sbrendan 		    "using more current version '%llu'.\n"),
39096018Sbrendan 		    zpool_get_name(zhp), cur_version);
39106018Sbrendan 		return (0);
39116018Sbrendan 	}
39126018Sbrendan 	if (cur_version == cbp->cb_version) {
39136018Sbrendan 		(void) printf(gettext("Pool '%s' is already formatted "
39146018Sbrendan 		    "using the current version.\n"), zpool_get_name(zhp));
39151760Seschrock 		return (0);
39161760Seschrock 	}
39171760Seschrock 
39185094Slling 	ret = zpool_upgrade(zhp, cbp->cb_version);
39192926Sek110237 
39202926Sek110237 	if (!ret) {
39211775Sbillm 		(void) printf(gettext("Successfully upgraded '%s' "
39225094Slling 		    "from version %llu to version %llu\n\n"),
39235094Slling 		    zpool_get_name(zhp), (u_longlong_t)cur_version,
39245094Slling 		    (u_longlong_t)cbp->cb_version);
39252926Sek110237 	}
39261760Seschrock 
39271760Seschrock 	return (ret != 0);
39281760Seschrock }
39291760Seschrock 
39301760Seschrock /*
39311760Seschrock  * zpool upgrade
39321760Seschrock  * zpool upgrade -v
39335094Slling  * zpool upgrade [-V version] <-a | pool ...>
39341760Seschrock  *
39351760Seschrock  * With no arguments, display downrev'd ZFS pool available for upgrade.
39361760Seschrock  * Individual pools can be upgraded by specifying the pool, and '-a' will
39371760Seschrock  * upgrade all pools.
39381760Seschrock  */
39391760Seschrock int
zpool_do_upgrade(int argc,char ** argv)39401760Seschrock zpool_do_upgrade(int argc, char **argv)
39411760Seschrock {
39421760Seschrock 	int c;
39431760Seschrock 	upgrade_cbdata_t cb = { 0 };
39441760Seschrock 	int ret = 0;
39451760Seschrock 	boolean_t showversions = B_FALSE;
39465094Slling 	char *end;
39475094Slling 
39481760Seschrock 
39491760Seschrock 	/* check options */
39509643SEric.Taylor@Sun.COM 	while ((c = getopt(argc, argv, ":avV:")) != -1) {
39511760Seschrock 		switch (c) {
39521760Seschrock 		case 'a':
39532082Seschrock 			cb.cb_all = B_TRUE;
39541760Seschrock 			break;
39551760Seschrock 		case 'v':
39561760Seschrock 			showversions = B_TRUE;
39571760Seschrock 			break;
39585094Slling 		case 'V':
39595094Slling 			cb.cb_version = strtoll(optarg, &end, 10);
39605320Slling 			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
39615320Slling 			    cb.cb_version < SPA_VERSION_1) {
39625094Slling 				(void) fprintf(stderr,
39635094Slling 				    gettext("invalid version '%s'\n"), optarg);
39645094Slling 				usage(B_FALSE);
39655094Slling 			}
39665094Slling 			break;
39679643SEric.Taylor@Sun.COM 		case ':':
39689643SEric.Taylor@Sun.COM 			(void) fprintf(stderr, gettext("missing argument for "
39699643SEric.Taylor@Sun.COM 			    "'%c' option\n"), optopt);
39709643SEric.Taylor@Sun.COM 			usage(B_FALSE);
39719643SEric.Taylor@Sun.COM 			break;
39721760Seschrock 		case '?':
39731760Seschrock 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
39741760Seschrock 			    optopt);
39752082Seschrock 			usage(B_FALSE);
39761760Seschrock 		}
39771760Seschrock 	}
39781760Seschrock 
39792926Sek110237 	cb.cb_argc = argc;
39802926Sek110237 	cb.cb_argv = argv;
39811760Seschrock 	argc -= optind;
39821760Seschrock 	argv += optind;
39831760Seschrock 
39845320Slling 	if (cb.cb_version == 0) {
39855320Slling 		cb.cb_version = SPA_VERSION;
39865320Slling 	} else if (!cb.cb_all && argc == 0) {
39875320Slling 		(void) fprintf(stderr, gettext("-V option is "
39885320Slling 		    "incompatible with other arguments\n"));
39895320Slling 		usage(B_FALSE);
39905320Slling 	}
39915320Slling 
39921760Seschrock 	if (showversions) {
39931760Seschrock 		if (cb.cb_all || argc != 0) {
39941760Seschrock 			(void) fprintf(stderr, gettext("-v option is "
39951760Seschrock 			    "incompatible with other arguments\n"));
39962082Seschrock 			usage(B_FALSE);
39971760Seschrock 		}
39981760Seschrock 	} else if (cb.cb_all) {
39991760Seschrock 		if (argc != 0) {
40005320Slling 			(void) fprintf(stderr, gettext("-a option should not "
40015320Slling 			    "be used along with a pool name\n"));
40022082Seschrock 			usage(B_FALSE);
40031760Seschrock 		}
40041760Seschrock 	}
40051760Seschrock 
40064577Sahrens 	(void) printf(gettext("This system is currently running "
40074577Sahrens 	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
40082082Seschrock 	cb.cb_first = B_TRUE;
40091760Seschrock 	if (showversions) {
40101760Seschrock 		(void) printf(gettext("The following versions are "
40113413Smmusante 		    "supported:\n\n"));
40121760Seschrock 		(void) printf(gettext("VER  DESCRIPTION\n"));
40131760Seschrock 		(void) printf("---  -----------------------------------------"
40141760Seschrock 		    "---------------\n");
40152082Seschrock 		(void) printf(gettext(" 1   Initial ZFS version\n"));
40161775Sbillm 		(void) printf(gettext(" 2   Ditto blocks "
40171775Sbillm 		    "(replicated metadata)\n"));
40182082Seschrock 		(void) printf(gettext(" 3   Hot spares and double parity "
40192082Seschrock 		    "RAID-Z\n"));
40203863Sek110237 		(void) printf(gettext(" 4   zpool history\n"));
40213886Sahl 		(void) printf(gettext(" 5   Compression using the gzip "
40223886Sahl 		    "algorithm\n"));
40235094Slling 		(void) printf(gettext(" 6   bootfs pool property\n"));
40244527Sperrin 		(void) printf(gettext(" 7   Separate intent log devices\n"));
40254543Smarks 		(void) printf(gettext(" 8   Delegated administration\n"));
40265390Sck153898 		(void) printf(gettext(" 9   refquota and refreservation "
40275378Sck153898 		    "properties\n"));
40285450Sbrendan 		(void) printf(gettext(" 10  Cache devices\n"));
40297046Sahrens 		(void) printf(gettext(" 11  Improved scrub performance\n"));
40307265Sahrens 		(void) printf(gettext(" 12  Snapshot properties\n"));
40317390SMatthew.Ahrens@Sun.COM 		(void) printf(gettext(" 13  snapused property\n"));
40329396SMatthew.Ahrens@Sun.COM 		(void) printf(gettext(" 14  passthrough-x aclinherit\n"));
40339396SMatthew.Ahrens@Sun.COM 		(void) printf(gettext(" 15  user/group space accounting\n"));
40349643SEric.Taylor@Sun.COM 		(void) printf(gettext(" 16  stmf property support\n"));
403510117Sadam.leventhal@sun.com 		(void) printf(gettext(" 17  Triple-parity RAID-Z\n"));
403610922SJeff.Bonwick@Sun.COM 		(void) printf(gettext(" 18  Snapshot user holds\n"));
403710594SGeorge.Wilson@Sun.COM 		(void) printf(gettext(" 19  Log device removal\n"));
403810922SJeff.Bonwick@Sun.COM 		(void) printf(gettext(" 20  Compression using zle "
403910922SJeff.Bonwick@Sun.COM 		    "(zero-length encoding)\n"));
404010922SJeff.Bonwick@Sun.COM 		(void) printf(gettext(" 21  Deduplication\n"));
404111022STom.Erickson@Sun.COM 		(void) printf(gettext(" 22  Received properties\n"));
404211670SNeil.Perrin@Sun.COM 		(void) printf(gettext(" 23  Slim ZIL\n"));
404311935SMark.Shellenbaum@Sun.COM 		(void) printf(gettext(" 24  System attributes\n"));
404412296SLin.Ling@Sun.COM 		(void) printf(gettext(" 25  Improved scrub stats\n"));
404512470SMatthew.Ahrens@Sun.COM 		(void) printf(gettext(" 26  Improved snapshot deletion "
404612470SMatthew.Ahrens@Sun.COM 		    "performance\n"));
404712827SMatthew.Ahrens@Sun.COM 		(void) printf(gettext(" 27  Improved snapshot creation "
404812827SMatthew.Ahrens@Sun.COM 		    "performance\n"));
404913037SMark.Musante@Sun.COM 		(void) printf(gettext(" 28  Multiple vdev replacements\n"));
405010922SJeff.Bonwick@Sun.COM 		(void) printf(gettext("\nFor more information on a particular "
405112321SStephanie.Scheffler@Sun.COM 		    "version, including supported releases,\n"));
405212321SStephanie.Scheffler@Sun.COM 		(void) printf(gettext("see the ZFS Administration Guide.\n\n"));
40531760Seschrock 	} else if (argc == 0) {
40541760Seschrock 		int notfound;
40551760Seschrock 
40562082Seschrock 		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
40571760Seschrock 		notfound = cb.cb_first;
40581760Seschrock 
40591760Seschrock 		if (!cb.cb_all && ret == 0) {
40601760Seschrock 			if (!cb.cb_first)
40611760Seschrock 				(void) printf("\n");
40621760Seschrock 			cb.cb_first = B_TRUE;
40631760Seschrock 			cb.cb_newer = B_TRUE;
40642082Seschrock 			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
40651760Seschrock 			if (!cb.cb_first) {
40661760Seschrock 				notfound = B_FALSE;
40671760Seschrock 				(void) printf("\n");
40681760Seschrock 			}
40691760Seschrock 		}
40701760Seschrock 
40711760Seschrock 		if (ret == 0) {
40721760Seschrock 			if (notfound)
40731760Seschrock 				(void) printf(gettext("All pools are formatted "
40741760Seschrock 				    "using this version.\n"));
40751760Seschrock 			else if (!cb.cb_all)
40761760Seschrock 				(void) printf(gettext("Use 'zpool upgrade -v' "
40771760Seschrock 				    "for a list of available versions and "
40781760Seschrock 				    "their associated\nfeatures.\n"));
40791760Seschrock 		}
40801760Seschrock 	} else {
40813912Slling 		ret = for_each_pool(argc, argv, B_FALSE, NULL,
40823912Slling 		    upgrade_one, &cb);
40832926Sek110237 	}
40842926Sek110237 
40852926Sek110237 	return (ret);
40862926Sek110237 }
40872926Sek110237 
40884543Smarks typedef struct hist_cbdata {
40894543Smarks 	boolean_t first;
40904543Smarks 	int longfmt;
40914543Smarks 	int internal;
40924543Smarks } hist_cbdata_t;
40934543Smarks 
40942926Sek110237 /*
40952926Sek110237  * Print out the command history for a specific pool.
40962926Sek110237  */
40972926Sek110237 static int
get_history_one(zpool_handle_t * zhp,void * data)40982926Sek110237 get_history_one(zpool_handle_t *zhp, void *data)
40992926Sek110237 {
41002926Sek110237 	nvlist_t *nvhis;
41012926Sek110237 	nvlist_t **records;
41022926Sek110237 	uint_t numrecords;
41032926Sek110237 	char *cmdstr;
41044543Smarks 	char *pathstr;
41052926Sek110237 	uint64_t dst_time;
41062926Sek110237 	time_t tsec;
41072926Sek110237 	struct tm t;
41082926Sek110237 	char tbuf[30];
41092926Sek110237 	int ret, i;
41104543Smarks 	uint64_t who;
41114543Smarks 	struct passwd *pwd;
41124543Smarks 	char *hostname;
41134543Smarks 	char *zonename;
41144543Smarks 	char internalstr[MAXPATHLEN];
41154543Smarks 	hist_cbdata_t *cb = (hist_cbdata_t *)data;
41164543Smarks 	uint64_t txg;
41174543Smarks 	uint64_t ievent;
41184543Smarks 
41194543Smarks 	cb->first = B_FALSE;
41202926Sek110237 
41212926Sek110237 	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
41222926Sek110237 
41232926Sek110237 	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
41242926Sek110237 		return (ret);
41252926Sek110237 
41262926Sek110237 	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
41272926Sek110237 	    &records, &numrecords) == 0);
41282926Sek110237 	for (i = 0; i < numrecords; i++) {
41292926Sek110237 		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
41304543Smarks 		    &dst_time) != 0)
41314543Smarks 			continue;
41324543Smarks 
41334543Smarks 		/* is it an internal event or a standard event? */
41344543Smarks 		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
41354543Smarks 		    &cmdstr) != 0) {
41364543Smarks 			if (cb->internal == 0)
41374543Smarks 				continue;
41384543Smarks 
41394543Smarks 			if (nvlist_lookup_uint64(records[i],
41404543Smarks 			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
41414543Smarks 				continue;
41424543Smarks 			verify(nvlist_lookup_uint64(records[i],
41434543Smarks 			    ZPOOL_HIST_TXG, &txg) == 0);
41444543Smarks 			verify(nvlist_lookup_string(records[i],
41454543Smarks 			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
41467046Sahrens 			if (ievent >= LOG_END)
41474543Smarks 				continue;
41484543Smarks 			(void) snprintf(internalstr,
41494543Smarks 			    sizeof (internalstr),
41504543Smarks 			    "[internal %s txg:%lld] %s",
415112296SLin.Ling@Sun.COM 			    zfs_history_event_names[ievent], txg,
41524543Smarks 			    pathstr);
41534543Smarks 			cmdstr = internalstr;
41542926Sek110237 		}
41554543Smarks 		tsec = dst_time;
41564543Smarks 		(void) localtime_r(&tsec, &t);
41574543Smarks 		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
41584543Smarks 		(void) printf("%s %s", tbuf, cmdstr);
41594543Smarks 
41604543Smarks 		if (!cb->longfmt) {
41614543Smarks 			(void) printf("\n");
41624543Smarks 			continue;
41634543Smarks 		}
41644543Smarks 		(void) printf(" [");
41654543Smarks 		if (nvlist_lookup_uint64(records[i],
41664543Smarks 		    ZPOOL_HIST_WHO, &who) == 0) {
41674543Smarks 			pwd = getpwuid((uid_t)who);
41684543Smarks 			if (pwd)
41694543Smarks 				(void) printf("user %s on",
41704543Smarks 				    pwd->pw_name);
41714543Smarks 			else
41724543Smarks 				(void) printf("user %d on",
41734543Smarks 				    (int)who);
41744543Smarks 		} else {
41754543Smarks 			(void) printf(gettext("no info]\n"));
41764543Smarks 			continue;
41774543Smarks 		}
41784543Smarks 		if (nvlist_lookup_string(records[i],
41794543Smarks 		    ZPOOL_HIST_HOST, &hostname) == 0) {
41804543Smarks 			(void) printf(" %s", hostname);
41814543Smarks 		}
41824543Smarks 		if (nvlist_lookup_string(records[i],
41834543Smarks 		    ZPOOL_HIST_ZONE, &zonename) == 0) {
41844543Smarks 			(void) printf(":%s", zonename);
41854543Smarks 		}
41864543Smarks 
41874543Smarks 		(void) printf("]");
41884543Smarks 		(void) printf("\n");
41892926Sek110237 	}
41902926Sek110237 	(void) printf("\n");
41912926Sek110237 	nvlist_free(nvhis);
41922926Sek110237 
41932926Sek110237 	return (ret);
41942926Sek110237 }
41952926Sek110237 
41962926Sek110237 /*
41972926Sek110237  * zpool history <pool>
41982926Sek110237  *
41992926Sek110237  * Displays the history of commands that modified pools.
42002926Sek110237  */
42014543Smarks 
42024543Smarks 
42032926Sek110237 int
zpool_do_history(int argc,char ** argv)42042926Sek110237 zpool_do_history(int argc, char **argv)
42052926Sek110237 {
42064543Smarks 	hist_cbdata_t cbdata = { 0 };
42072926Sek110237 	int ret;
42084543Smarks 	int c;
42094543Smarks 
42104543Smarks 	cbdata.first = B_TRUE;
42114543Smarks 	/* check options */
42124543Smarks 	while ((c = getopt(argc, argv, "li")) != -1) {
42134543Smarks 		switch (c) {
42144543Smarks 		case 'l':
42154543Smarks 			cbdata.longfmt = 1;
42164543Smarks 			break;
42174543Smarks 		case 'i':
42184543Smarks 			cbdata.internal = 1;
42194543Smarks 			break;
42204543Smarks 		case '?':
42214543Smarks 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
42224543Smarks 			    optopt);
42234543Smarks 			usage(B_FALSE);
42244543Smarks 		}
42254543Smarks 	}
42262926Sek110237 	argc -= optind;
42272926Sek110237 	argv += optind;
42282926Sek110237 
42293912Slling 	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
42304543Smarks 	    &cbdata);
42314543Smarks 
42324543Smarks 	if (argc == 0 && cbdata.first == B_TRUE) {
42332926Sek110237 		(void) printf(gettext("no pools available\n"));
42342926Sek110237 		return (0);
42351760Seschrock 	}
42361760Seschrock 
42371760Seschrock 	return (ret);
42381760Seschrock }
42391760Seschrock 
42403912Slling static int
get_callback(zpool_handle_t * zhp,void * data)42413912Slling get_callback(zpool_handle_t *zhp, void *data)
42423912Slling {
42435094Slling 	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
42443912Slling 	char value[MAXNAMELEN];
42455094Slling 	zprop_source_t srctype;
42465094Slling 	zprop_list_t *pl;
42473912Slling 
42483912Slling 	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
42493912Slling 
42503912Slling 		/*
42515094Slling 		 * Skip the special fake placeholder. This will also skip
42525094Slling 		 * over the name property when 'all' is specified.
42533912Slling 		 */
42545094Slling 		if (pl->pl_prop == ZPOOL_PROP_NAME &&
42553912Slling 		    pl == cbp->cb_proplist)
42563912Slling 			continue;
42573912Slling 
42583912Slling 		if (zpool_get_prop(zhp, pl->pl_prop,
42593912Slling 		    value, sizeof (value), &srctype) != 0)
42603912Slling 			continue;
42613912Slling 
42625094Slling 		zprop_print_one_property(zpool_get_name(zhp), cbp,
426311022STom.Erickson@Sun.COM 		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL,
426411022STom.Erickson@Sun.COM 		    NULL);
42653912Slling 	}
42663912Slling 	return (0);
42673912Slling }
42683912Slling 
42693912Slling int
zpool_do_get(int argc,char ** argv)42703912Slling zpool_do_get(int argc, char **argv)
42713912Slling {
42725094Slling 	zprop_get_cbdata_t cb = { 0 };
42735094Slling 	zprop_list_t fake_name = { 0 };
42743912Slling 	int ret;
42753912Slling 
42763912Slling 	if (argc < 3)
42773912Slling 		usage(B_FALSE);
42783912Slling 
42793912Slling 	cb.cb_first = B_TRUE;
42805094Slling 	cb.cb_sources = ZPROP_SRC_ALL;
42813912Slling 	cb.cb_columns[0] = GET_COL_NAME;
42823912Slling 	cb.cb_columns[1] = GET_COL_PROPERTY;
42833912Slling 	cb.cb_columns[2] = GET_COL_VALUE;
42843912Slling 	cb.cb_columns[3] = GET_COL_SOURCE;
42855094Slling 	cb.cb_type = ZFS_TYPE_POOL;
42865094Slling 
42875094Slling 	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
42885094Slling 	    ZFS_TYPE_POOL) != 0)
42893912Slling 		usage(B_FALSE);
42903912Slling 
42913912Slling 	if (cb.cb_proplist != NULL) {
42925094Slling 		fake_name.pl_prop = ZPOOL_PROP_NAME;
42933912Slling 		fake_name.pl_width = strlen(gettext("NAME"));
42943912Slling 		fake_name.pl_next = cb.cb_proplist;
42953912Slling 		cb.cb_proplist = &fake_name;
42963912Slling 	}
42973912Slling 
42983912Slling 	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
42993912Slling 	    get_callback, &cb);
43003912Slling 
43013912Slling 	if (cb.cb_proplist == &fake_name)
43025094Slling 		zprop_free_list(fake_name.pl_next);
43033912Slling 	else
43045094Slling 		zprop_free_list(cb.cb_proplist);
43053912Slling 
43063912Slling 	return (ret);
43073912Slling }
43083912Slling 
43093912Slling typedef struct set_cbdata {
43103912Slling 	char *cb_propname;
43113912Slling 	char *cb_value;
43123912Slling 	boolean_t cb_any_successful;
43133912Slling } set_cbdata_t;
43143912Slling 
43153912Slling int
set_callback(zpool_handle_t * zhp,void * data)43163912Slling set_callback(zpool_handle_t *zhp, void *data)
43173912Slling {
43183912Slling 	int error;
43193912Slling 	set_cbdata_t *cb = (set_cbdata_t *)data;
43203912Slling 
43213912Slling 	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
43223912Slling 
43233912Slling 	if (!error)
43243912Slling 		cb->cb_any_successful = B_TRUE;
43253912Slling 
43263912Slling 	return (error);
43273912Slling }
43283912Slling 
43293912Slling int
zpool_do_set(int argc,char ** argv)43303912Slling zpool_do_set(int argc, char **argv)
43313912Slling {
43323912Slling 	set_cbdata_t cb = { 0 };
43333912Slling 	int error;
43343912Slling 
43353912Slling 	if (argc > 1 && argv[1][0] == '-') {
43363912Slling 		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
43373912Slling 		    argv[1][1]);
43383912Slling 		usage(B_FALSE);
43393912Slling 	}
43403912Slling 
43413912Slling 	if (argc < 2) {
43423912Slling 		(void) fprintf(stderr, gettext("missing property=value "
43433912Slling 		    "argument\n"));
43443912Slling 		usage(B_FALSE);
43453912Slling 	}
43463912Slling 
43473912Slling 	if (argc < 3) {
43483912Slling 		(void) fprintf(stderr, gettext("missing pool name\n"));
43493912Slling 		usage(B_FALSE);
43503912Slling 	}
43513912Slling 
43523912Slling 	if (argc > 3) {
43533912Slling 		(void) fprintf(stderr, gettext("too many pool names\n"));
43543912Slling 		usage(B_FALSE);
43553912Slling 	}
43563912Slling 
43573912Slling 	cb.cb_propname = argv[1];
43583912Slling 	cb.cb_value = strchr(cb.cb_propname, '=');
43593912Slling 	if (cb.cb_value == NULL) {
43603912Slling 		(void) fprintf(stderr, gettext("missing value in "
43613912Slling 		    "property=value argument\n"));
43623912Slling 		usage(B_FALSE);
43633912Slling 	}
43643912Slling 
43653912Slling 	*(cb.cb_value) = '\0';
43663912Slling 	cb.cb_value++;
43673912Slling 
43683912Slling 	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
43693912Slling 	    set_callback, &cb);
43703912Slling 
43713912Slling 	return (error);
43723912Slling }
43733912Slling 
43743912Slling static int
find_command_idx(char * command,int * idx)43753912Slling find_command_idx(char *command, int *idx)
43763912Slling {
43773912Slling 	int i;
43783912Slling 
43793912Slling 	for (i = 0; i < NCOMMAND; i++) {
43803912Slling 		if (command_table[i].name == NULL)
43813912Slling 			continue;
43823912Slling 
43833912Slling 		if (strcmp(command, command_table[i].name) == 0) {
43843912Slling 			*idx = i;
43853912Slling 			return (0);
43863912Slling 		}
43873912Slling 	}
43883912Slling 	return (1);
43893912Slling }
43903912Slling 
4391789Sahrens int
main(int argc,char ** argv)4392789Sahrens main(int argc, char **argv)
4393789Sahrens {
4394789Sahrens 	int ret;
4395789Sahrens 	int i;
4396789Sahrens 	char *cmdname;
4397789Sahrens 
4398789Sahrens 	(void) setlocale(LC_ALL, "");
4399789Sahrens 	(void) textdomain(TEXT_DOMAIN);
4400789Sahrens 
44012082Seschrock 	if ((g_zfs = libzfs_init()) == NULL) {
44022082Seschrock 		(void) fprintf(stderr, gettext("internal error: failed to "
44032731Snd150628 		    "initialize ZFS library\n"));
44042082Seschrock 		return (1);
44052082Seschrock 	}
44062082Seschrock 
44072082Seschrock 	libzfs_print_on_error(g_zfs, B_TRUE);
44082082Seschrock 
4409789Sahrens 	opterr = 0;
4410789Sahrens 
4411789Sahrens 	/*
4412789Sahrens 	 * Make sure the user has specified some command.
4413789Sahrens 	 */
4414789Sahrens 	if (argc < 2) {
4415789Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
44162082Seschrock 		usage(B_FALSE);
4417789Sahrens 	}
4418789Sahrens 
4419789Sahrens 	cmdname = argv[1];
4420789Sahrens 
4421789Sahrens 	/*
4422789Sahrens 	 * Special case '-?'
4423789Sahrens 	 */
4424789Sahrens 	if (strcmp(cmdname, "-?") == 0)
44252082Seschrock 		usage(B_TRUE);
4426789Sahrens 
44274988Sek110237 	zpool_set_history_str("zpool", argc, argv, history_str);
44284988Sek110237 	verify(zpool_stage_history(g_zfs, history_str) == 0);
44294988Sek110237 
4430789Sahrens 	/*
4431789Sahrens 	 * Run the appropriate command.
4432789Sahrens 	 */
44333912Slling 	if (find_command_idx(cmdname, &i) == 0) {
44343912Slling 		current_command = &command_table[i];
44353912Slling 		ret = command_table[i].func(argc - 1, argv + 1);
44364787Sahrens 	} else if (strchr(cmdname, '=')) {
44374787Sahrens 		verify(find_command_idx("set", &i) == 0);
44384787Sahrens 		current_command = &command_table[i];
44394787Sahrens 		ret = command_table[i].func(argc, argv);
44404787Sahrens 	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
44414787Sahrens 		/*
44424787Sahrens 		 * 'freeze' is a vile debugging abomination, so we treat
44434787Sahrens 		 * it as such.
44444787Sahrens 		 */
44451544Seschrock 		char buf[16384];
44461544Seschrock 		int fd = open(ZFS_DEV, O_RDWR);
4447789Sahrens 		(void) strcpy((void *)buf, argv[2]);
4448789Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
44494787Sahrens 	} else {
4450789Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
4451789Sahrens 		    "command '%s'\n"), cmdname);
44522082Seschrock 		usage(B_FALSE);
4453789Sahrens 	}
4454789Sahrens 
44552082Seschrock 	libzfs_fini(g_zfs);
44562082Seschrock 
4457789Sahrens 	/*
4458789Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
4459789Sahrens 	 * for the purposes of running ::findleaks.
4460789Sahrens 	 */
4461789Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
4462789Sahrens 		(void) printf("dumping core by request\n");
4463789Sahrens 		abort();
4464789Sahrens 	}
4465789Sahrens 
4466789Sahrens 	return (ret);
4467789Sahrens }
4468