xref: /titanic_53/usr/src/cmd/zpool/zpool_main.c (revision fa9e4066f08beec538e775443c5be79dd423fcab)
1*fa9e4066Sahrens /*
2*fa9e4066Sahrens  * CDDL HEADER START
3*fa9e4066Sahrens  *
4*fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5*fa9e4066Sahrens  * Common Development and Distribution License, Version 1.0 only
6*fa9e4066Sahrens  * (the "License").  You may not use this file except in compliance
7*fa9e4066Sahrens  * with the License.
8*fa9e4066Sahrens  *
9*fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
11*fa9e4066Sahrens  * See the License for the specific language governing permissions
12*fa9e4066Sahrens  * and limitations under the License.
13*fa9e4066Sahrens  *
14*fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
15*fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
17*fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
18*fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
19*fa9e4066Sahrens  *
20*fa9e4066Sahrens  * CDDL HEADER END
21*fa9e4066Sahrens  */
22*fa9e4066Sahrens /*
23*fa9e4066Sahrens  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*fa9e4066Sahrens  * Use is subject to license terms.
25*fa9e4066Sahrens  */
26*fa9e4066Sahrens 
27*fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*fa9e4066Sahrens 
29*fa9e4066Sahrens #include <assert.h>
30*fa9e4066Sahrens #include <ctype.h>
31*fa9e4066Sahrens #include <dirent.h>
32*fa9e4066Sahrens #include <errno.h>
33*fa9e4066Sahrens #include <fcntl.h>
34*fa9e4066Sahrens #include <libgen.h>
35*fa9e4066Sahrens #include <libintl.h>
36*fa9e4066Sahrens #include <libuutil.h>
37*fa9e4066Sahrens #include <locale.h>
38*fa9e4066Sahrens #include <stdio.h>
39*fa9e4066Sahrens #include <stdlib.h>
40*fa9e4066Sahrens #include <string.h>
41*fa9e4066Sahrens #include <strings.h>
42*fa9e4066Sahrens #include <unistd.h>
43*fa9e4066Sahrens #include <priv.h>
44*fa9e4066Sahrens 
45*fa9e4066Sahrens #include <sys/stat.h>
46*fa9e4066Sahrens 
47*fa9e4066Sahrens #include <libzfs.h>
48*fa9e4066Sahrens 
49*fa9e4066Sahrens #include "zpool_util.h"
50*fa9e4066Sahrens 
51*fa9e4066Sahrens static int zpool_do_create(int, char **);
52*fa9e4066Sahrens static int zpool_do_destroy(int, char **);
53*fa9e4066Sahrens 
54*fa9e4066Sahrens static int zpool_do_add(int, char **);
55*fa9e4066Sahrens 
56*fa9e4066Sahrens static int zpool_do_list(int, char **);
57*fa9e4066Sahrens static int zpool_do_iostat(int, char **);
58*fa9e4066Sahrens static int zpool_do_status(int, char **);
59*fa9e4066Sahrens 
60*fa9e4066Sahrens static int zpool_do_online(int, char **);
61*fa9e4066Sahrens static int zpool_do_offline(int, char **);
62*fa9e4066Sahrens 
63*fa9e4066Sahrens static int zpool_do_attach(int, char **);
64*fa9e4066Sahrens static int zpool_do_detach(int, char **);
65*fa9e4066Sahrens static int zpool_do_replace(int, char **);
66*fa9e4066Sahrens 
67*fa9e4066Sahrens static int zpool_do_scrub(int, char **);
68*fa9e4066Sahrens 
69*fa9e4066Sahrens static int zpool_do_import(int, char **);
70*fa9e4066Sahrens static int zpool_do_export(int, char **);
71*fa9e4066Sahrens 
72*fa9e4066Sahrens /*
73*fa9e4066Sahrens  * These libumem hooks provide a reasonable set of defaults for the allocator's
74*fa9e4066Sahrens  * debugging facilities.
75*fa9e4066Sahrens  */
76*fa9e4066Sahrens const char *
77*fa9e4066Sahrens _umem_debug_init()
78*fa9e4066Sahrens {
79*fa9e4066Sahrens 	return ("default,verbose"); /* $UMEM_DEBUG setting */
80*fa9e4066Sahrens }
81*fa9e4066Sahrens 
82*fa9e4066Sahrens const char *
83*fa9e4066Sahrens _umem_logging_init(void)
84*fa9e4066Sahrens {
85*fa9e4066Sahrens 	return ("fail,contents"); /* $UMEM_LOGGING setting */
86*fa9e4066Sahrens }
87*fa9e4066Sahrens 
88*fa9e4066Sahrens typedef struct zpool_command {
89*fa9e4066Sahrens 	const char	*name;
90*fa9e4066Sahrens 	int		(*func)(int, char **);
91*fa9e4066Sahrens 	const char	*usage;
92*fa9e4066Sahrens } zpool_command_t;
93*fa9e4066Sahrens 
94*fa9e4066Sahrens /*
95*fa9e4066Sahrens  * Master command table.  Each ZFS command has a name, associated function, and
96*fa9e4066Sahrens  * usage message.  These commands are organized according to how they are
97*fa9e4066Sahrens  * displayed in the usage message.  An empty command (one with a NULL name)
98*fa9e4066Sahrens  * indicates an empty line in the generic usage message.
99*fa9e4066Sahrens  */
100*fa9e4066Sahrens static zpool_command_t command_table[] = {
101*fa9e4066Sahrens 	{ "create",	zpool_do_create,
102*fa9e4066Sahrens 	    "\tcreate  [-fn] [-R root] [-m mountpoint] <pool> <vdev> ...\n" },
103*fa9e4066Sahrens 	{ "destroy",	zpool_do_destroy,
104*fa9e4066Sahrens 	    "\tdestroy [-f] <pool>\n"					},
105*fa9e4066Sahrens 
106*fa9e4066Sahrens 
107*fa9e4066Sahrens 	{ NULL },
108*fa9e4066Sahrens 
109*fa9e4066Sahrens 	{ "add",	zpool_do_add,
110*fa9e4066Sahrens 	    "\tadd [-fn] <pool> <vdev> ...\n"				},
111*fa9e4066Sahrens 
112*fa9e4066Sahrens 	{ NULL },
113*fa9e4066Sahrens 
114*fa9e4066Sahrens 	{ "list",	zpool_do_list,
115*fa9e4066Sahrens 	    "\tlist [-H] [-o field[,field]*] [pool] ...\n"		},
116*fa9e4066Sahrens 	{ "iostat",	zpool_do_iostat,
117*fa9e4066Sahrens 	    "\tiostat [-v] [pool] ... [interval [count]]\n"		},
118*fa9e4066Sahrens 	{ "status",	zpool_do_status,
119*fa9e4066Sahrens 	    "\tstatus [-vx] [pool] ...\n"				},
120*fa9e4066Sahrens 
121*fa9e4066Sahrens 	{ NULL },
122*fa9e4066Sahrens 
123*fa9e4066Sahrens 	{ "online",	zpool_do_online,
124*fa9e4066Sahrens 	    "\tonline <pool> <device>\n"				},
125*fa9e4066Sahrens 	{ "offline",	zpool_do_offline,
126*fa9e4066Sahrens 	    "\toffline <pool> <device>\n"				},
127*fa9e4066Sahrens 
128*fa9e4066Sahrens 	{ NULL },
129*fa9e4066Sahrens 
130*fa9e4066Sahrens 	{ "attach",	zpool_do_attach,
131*fa9e4066Sahrens 	    "\tattach [-f] <pool> <device> <new_device>\n"		},
132*fa9e4066Sahrens 	{ "detach",	zpool_do_detach,
133*fa9e4066Sahrens 	    "\tdetach <pool> <device>\n"				},
134*fa9e4066Sahrens 	{ "replace",	zpool_do_replace,
135*fa9e4066Sahrens 	    "\treplace [-f] <pool> <device> [new_device]\n"		},
136*fa9e4066Sahrens 
137*fa9e4066Sahrens 	{ NULL },
138*fa9e4066Sahrens 
139*fa9e4066Sahrens 	{ "scrub",	zpool_do_scrub,
140*fa9e4066Sahrens 	    "\tscrub [-s] <pool> ...\n"					},
141*fa9e4066Sahrens 
142*fa9e4066Sahrens 	{ NULL },
143*fa9e4066Sahrens 
144*fa9e4066Sahrens 	{ "import",	zpool_do_import,
145*fa9e4066Sahrens 	    "\timport [-d dir]\n"
146*fa9e4066Sahrens 	    "\timport [-d dir] [-f] [-o opts] [-R root] -a\n"
147*fa9e4066Sahrens 	    "\timport [-d dir] [-f] [-o opts] [-R root ]<pool | id> "
148*fa9e4066Sahrens 	    "[newpool]\n"						},
149*fa9e4066Sahrens 	{ "export",	zpool_do_export,
150*fa9e4066Sahrens 	    "\texport [-f] <pool> ...\n"				},
151*fa9e4066Sahrens 
152*fa9e4066Sahrens 	{ NULL }
153*fa9e4066Sahrens };
154*fa9e4066Sahrens 
155*fa9e4066Sahrens #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
156*fa9e4066Sahrens 
157*fa9e4066Sahrens zpool_command_t *current_command;
158*fa9e4066Sahrens 
159*fa9e4066Sahrens /*
160*fa9e4066Sahrens  * Fields available for 'zpool list'.
161*fa9e4066Sahrens  */
162*fa9e4066Sahrens typedef enum {
163*fa9e4066Sahrens 	ZPOOL_FIELD_NAME,
164*fa9e4066Sahrens 	ZPOOL_FIELD_SIZE,
165*fa9e4066Sahrens 	ZPOOL_FIELD_USED,
166*fa9e4066Sahrens 	ZPOOL_FIELD_AVAILABLE,
167*fa9e4066Sahrens 	ZPOOL_FIELD_CAPACITY,
168*fa9e4066Sahrens 	ZPOOL_FIELD_HEALTH,
169*fa9e4066Sahrens 	ZPOOL_FIELD_ROOT
170*fa9e4066Sahrens } zpool_field_t;
171*fa9e4066Sahrens 
172*fa9e4066Sahrens #define	MAX_FIELDS	10
173*fa9e4066Sahrens 
174*fa9e4066Sahrens typedef struct column_def {
175*fa9e4066Sahrens 	const char	*cd_title;
176*fa9e4066Sahrens 	size_t		cd_width;
177*fa9e4066Sahrens 	enum {
178*fa9e4066Sahrens 		left_justify,
179*fa9e4066Sahrens 		right_justify
180*fa9e4066Sahrens 	}		cd_justify;
181*fa9e4066Sahrens } column_def_t;
182*fa9e4066Sahrens 
183*fa9e4066Sahrens static column_def_t column_table[] = {
184*fa9e4066Sahrens 	{ "NAME",	20,	left_justify	},
185*fa9e4066Sahrens 	{ "SIZE",	6,	right_justify	},
186*fa9e4066Sahrens 	{ "USED",	6,	right_justify	},
187*fa9e4066Sahrens 	{ "AVAIL",	6,	right_justify	},
188*fa9e4066Sahrens 	{ "CAP",	5,	right_justify	},
189*fa9e4066Sahrens 	{ "HEALTH",	9,	left_justify	},
190*fa9e4066Sahrens 	{ "ALTROOT",	15,	left_justify	}
191*fa9e4066Sahrens };
192*fa9e4066Sahrens 
193*fa9e4066Sahrens static char *column_subopts[] = {
194*fa9e4066Sahrens 	"name",
195*fa9e4066Sahrens 	"size",
196*fa9e4066Sahrens 	"used",
197*fa9e4066Sahrens 	"available",
198*fa9e4066Sahrens 	"capacity",
199*fa9e4066Sahrens 	"health",
200*fa9e4066Sahrens 	"root",
201*fa9e4066Sahrens 	NULL
202*fa9e4066Sahrens };
203*fa9e4066Sahrens 
204*fa9e4066Sahrens /*
205*fa9e4066Sahrens  * Display usage message.  If we're inside a command, display only the usage for
206*fa9e4066Sahrens  * that command.  Otherwise, iterate over the entire command table and display
207*fa9e4066Sahrens  * a complete usage message.
208*fa9e4066Sahrens  */
209*fa9e4066Sahrens void
210*fa9e4066Sahrens usage(int requested)
211*fa9e4066Sahrens {
212*fa9e4066Sahrens 	int i;
213*fa9e4066Sahrens 	FILE *fp = requested ? stdout : stderr;
214*fa9e4066Sahrens 
215*fa9e4066Sahrens 	if (current_command == NULL) {
216*fa9e4066Sahrens 		int i;
217*fa9e4066Sahrens 
218*fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
219*fa9e4066Sahrens 		(void) fprintf(fp,
220*fa9e4066Sahrens 		    gettext("where 'command' is one of the following:\n\n"));
221*fa9e4066Sahrens 
222*fa9e4066Sahrens 		for (i = 0; i < NCOMMAND; i++) {
223*fa9e4066Sahrens 			if (command_table[i].name == NULL)
224*fa9e4066Sahrens 				(void) fprintf(fp, "\n");
225*fa9e4066Sahrens 			else
226*fa9e4066Sahrens 				(void) fprintf(fp, "%s",
227*fa9e4066Sahrens 				    command_table[i].usage);
228*fa9e4066Sahrens 		}
229*fa9e4066Sahrens 	} else {
230*fa9e4066Sahrens 		(void) fprintf(fp, gettext("usage:\n"));
231*fa9e4066Sahrens 		(void) fprintf(fp, current_command->usage);
232*fa9e4066Sahrens 
233*fa9e4066Sahrens 		if (strcmp(current_command->name, "list") == 0) {
234*fa9e4066Sahrens 			(void) fprintf(fp, gettext("\nwhere 'field' is one "
235*fa9e4066Sahrens 			    "of the following:\n\n"));
236*fa9e4066Sahrens 
237*fa9e4066Sahrens 			for (i = 0; column_subopts[i] != NULL; i++)
238*fa9e4066Sahrens 				(void) fprintf(fp, "\t%s\n", column_subopts[i]);
239*fa9e4066Sahrens 		}
240*fa9e4066Sahrens 	}
241*fa9e4066Sahrens 
242*fa9e4066Sahrens 	exit(requested ? 0 : 2);
243*fa9e4066Sahrens }
244*fa9e4066Sahrens 
245*fa9e4066Sahrens const char *
246*fa9e4066Sahrens state_to_name(int state)
247*fa9e4066Sahrens {
248*fa9e4066Sahrens 	switch (state) {
249*fa9e4066Sahrens 	case VDEV_STATE_CLOSED:
250*fa9e4066Sahrens 	case VDEV_STATE_CANT_OPEN:
251*fa9e4066Sahrens 		return (gettext("FAULTED"));
252*fa9e4066Sahrens 	case VDEV_STATE_OFFLINE:
253*fa9e4066Sahrens 		return (gettext("OFFLINE"));
254*fa9e4066Sahrens 	case VDEV_STATE_DEGRADED:
255*fa9e4066Sahrens 		return (gettext("DEGRADED"));
256*fa9e4066Sahrens 	case VDEV_STATE_HEALTHY:
257*fa9e4066Sahrens 		return (gettext("ONLINE"));
258*fa9e4066Sahrens 	}
259*fa9e4066Sahrens 
260*fa9e4066Sahrens 	return (gettext("UNKNOWN"));
261*fa9e4066Sahrens }
262*fa9e4066Sahrens 
263*fa9e4066Sahrens void
264*fa9e4066Sahrens print_vdev_tree(const char *name, nvlist_t *nv, int indent)
265*fa9e4066Sahrens {
266*fa9e4066Sahrens 	nvlist_t **child;
267*fa9e4066Sahrens 	uint_t c, children;
268*fa9e4066Sahrens 
269*fa9e4066Sahrens 	if (name != NULL)
270*fa9e4066Sahrens 		(void) printf("\t%*s%s\n", indent, "", name);
271*fa9e4066Sahrens 
272*fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
273*fa9e4066Sahrens 	    &child, &children) != 0)
274*fa9e4066Sahrens 		return;
275*fa9e4066Sahrens 
276*fa9e4066Sahrens 	for (c = 0; c < children; c++)
277*fa9e4066Sahrens 		print_vdev_tree(vdev_get_name(child[c]), child[c], indent + 2);
278*fa9e4066Sahrens }
279*fa9e4066Sahrens 
280*fa9e4066Sahrens /*
281*fa9e4066Sahrens  * zpool add [-fn] <pool> <vdev> ...
282*fa9e4066Sahrens  *
283*fa9e4066Sahrens  *	-f	Force addition of devices, even if they appear in use
284*fa9e4066Sahrens  *	-n	Do not add the devices, but display the resulting layout if
285*fa9e4066Sahrens  *		they were to be added.
286*fa9e4066Sahrens  *
287*fa9e4066Sahrens  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
288*fa9e4066Sahrens  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
289*fa9e4066Sahrens  * libzfs.
290*fa9e4066Sahrens  */
291*fa9e4066Sahrens int
292*fa9e4066Sahrens zpool_do_add(int argc, char **argv)
293*fa9e4066Sahrens {
294*fa9e4066Sahrens 	int force = FALSE;
295*fa9e4066Sahrens 	int dryrun = FALSE;
296*fa9e4066Sahrens 	int c;
297*fa9e4066Sahrens 	nvlist_t *nvroot;
298*fa9e4066Sahrens 	char *poolname;
299*fa9e4066Sahrens 	int ret;
300*fa9e4066Sahrens 	zpool_handle_t *zhp;
301*fa9e4066Sahrens 	nvlist_t *config;
302*fa9e4066Sahrens 
303*fa9e4066Sahrens 	/* check options */
304*fa9e4066Sahrens 	while ((c = getopt(argc, argv, "fn")) != -1) {
305*fa9e4066Sahrens 		switch (c) {
306*fa9e4066Sahrens 		case 'f':
307*fa9e4066Sahrens 			force = TRUE;
308*fa9e4066Sahrens 			break;
309*fa9e4066Sahrens 		case 'n':
310*fa9e4066Sahrens 			dryrun = TRUE;
311*fa9e4066Sahrens 			break;
312*fa9e4066Sahrens 		case '?':
313*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
314*fa9e4066Sahrens 			    optopt);
315*fa9e4066Sahrens 			usage(FALSE);
316*fa9e4066Sahrens 		}
317*fa9e4066Sahrens 	}
318*fa9e4066Sahrens 
319*fa9e4066Sahrens 	argc -= optind;
320*fa9e4066Sahrens 	argv += optind;
321*fa9e4066Sahrens 
322*fa9e4066Sahrens 	/* get pool name and check number of arguments */
323*fa9e4066Sahrens 	if (argc < 1) {
324*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
325*fa9e4066Sahrens 		usage(FALSE);
326*fa9e4066Sahrens 	}
327*fa9e4066Sahrens 	if (argc < 2) {
328*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
329*fa9e4066Sahrens 		usage(FALSE);
330*fa9e4066Sahrens 	}
331*fa9e4066Sahrens 
332*fa9e4066Sahrens 	poolname = argv[0];
333*fa9e4066Sahrens 
334*fa9e4066Sahrens 	argc--;
335*fa9e4066Sahrens 	argv++;
336*fa9e4066Sahrens 
337*fa9e4066Sahrens 	if ((zhp = zpool_open(poolname)) == NULL)
338*fa9e4066Sahrens 		return (1);
339*fa9e4066Sahrens 
340*fa9e4066Sahrens 	if ((config = zpool_get_config(zhp)) == NULL) {
341*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
342*fa9e4066Sahrens 		    poolname);
343*fa9e4066Sahrens 		zpool_close(zhp);
344*fa9e4066Sahrens 		return (1);
345*fa9e4066Sahrens 	}
346*fa9e4066Sahrens 
347*fa9e4066Sahrens 	/* pass off to get_vdev_spec for processing */
348*fa9e4066Sahrens 	nvroot = make_root_vdev(config, force, !force, argc, argv);
349*fa9e4066Sahrens 	if (nvroot == NULL) {
350*fa9e4066Sahrens 		zpool_close(zhp);
351*fa9e4066Sahrens 		return (1);
352*fa9e4066Sahrens 	}
353*fa9e4066Sahrens 
354*fa9e4066Sahrens 	if (dryrun) {
355*fa9e4066Sahrens 		nvlist_t *poolnvroot;
356*fa9e4066Sahrens 
357*fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
358*fa9e4066Sahrens 		    &poolnvroot) == 0);
359*fa9e4066Sahrens 
360*fa9e4066Sahrens 		(void) printf(gettext("would update '%s' to the following "
361*fa9e4066Sahrens 		    "configuration:\n"), zpool_get_name(zhp));
362*fa9e4066Sahrens 
363*fa9e4066Sahrens 		print_vdev_tree(poolname, poolnvroot, 0);
364*fa9e4066Sahrens 		print_vdev_tree(NULL, nvroot, 0);
365*fa9e4066Sahrens 
366*fa9e4066Sahrens 		ret = 0;
367*fa9e4066Sahrens 	} else {
368*fa9e4066Sahrens 		ret = (zpool_add(zhp, nvroot) != 0);
369*fa9e4066Sahrens 	}
370*fa9e4066Sahrens 
371*fa9e4066Sahrens 	return (ret);
372*fa9e4066Sahrens }
373*fa9e4066Sahrens 
374*fa9e4066Sahrens /*
375*fa9e4066Sahrens  * zpool create [-fn] [-R root] [-m mountpoint] <pool> <dev> ...
376*fa9e4066Sahrens  *
377*fa9e4066Sahrens  *	-f	Force creation, even if devices appear in use
378*fa9e4066Sahrens  *	-n	Do not create the pool, but display the resulting layout if it
379*fa9e4066Sahrens  *		were to be created.
380*fa9e4066Sahrens  *      -R	Create a pool under an alternate root
381*fa9e4066Sahrens  *      -m	Set default mountpoint for the root dataset.  By default it's
382*fa9e4066Sahrens  *      	'/<pool>'
383*fa9e4066Sahrens  *
384*fa9e4066Sahrens  * Creates the the named pool according to the given vdev specification.  The
385*fa9e4066Sahrens  * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
386*fa9e4066Sahrens  * we get the nvlist back from get_vdev_spec(), we either print out the contents
387*fa9e4066Sahrens  * (if '-n' was specified), or pass it to libzfs to do the creation.
388*fa9e4066Sahrens  */
389*fa9e4066Sahrens int
390*fa9e4066Sahrens zpool_do_create(int argc, char **argv)
391*fa9e4066Sahrens {
392*fa9e4066Sahrens 	int force = FALSE;
393*fa9e4066Sahrens 	int dryrun = FALSE;
394*fa9e4066Sahrens 	int c;
395*fa9e4066Sahrens 	nvlist_t *nvroot;
396*fa9e4066Sahrens 	char *poolname;
397*fa9e4066Sahrens 	int ret;
398*fa9e4066Sahrens 	char *altroot = NULL;
399*fa9e4066Sahrens 	char *mountpoint = NULL;
400*fa9e4066Sahrens 
401*fa9e4066Sahrens 	/* check options */
402*fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":fnR:m:")) != -1) {
403*fa9e4066Sahrens 		switch (c) {
404*fa9e4066Sahrens 		case 'f':
405*fa9e4066Sahrens 			force = TRUE;
406*fa9e4066Sahrens 			break;
407*fa9e4066Sahrens 		case 'n':
408*fa9e4066Sahrens 			dryrun = TRUE;
409*fa9e4066Sahrens 			break;
410*fa9e4066Sahrens 		case 'R':
411*fa9e4066Sahrens 			altroot = optarg;
412*fa9e4066Sahrens 			break;
413*fa9e4066Sahrens 		case 'm':
414*fa9e4066Sahrens 			mountpoint = optarg;
415*fa9e4066Sahrens 			break;
416*fa9e4066Sahrens 		case ':':
417*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
418*fa9e4066Sahrens 			    "'%c' option\n"), optopt);
419*fa9e4066Sahrens 			usage(FALSE);
420*fa9e4066Sahrens 			break;
421*fa9e4066Sahrens 		case '?':
422*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
423*fa9e4066Sahrens 			    optopt);
424*fa9e4066Sahrens 			usage(FALSE);
425*fa9e4066Sahrens 		}
426*fa9e4066Sahrens 	}
427*fa9e4066Sahrens 
428*fa9e4066Sahrens 	argc -= optind;
429*fa9e4066Sahrens 	argv += optind;
430*fa9e4066Sahrens 
431*fa9e4066Sahrens 	/* get pool name and check number of arguments */
432*fa9e4066Sahrens 	if (argc < 1) {
433*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
434*fa9e4066Sahrens 		usage(FALSE);
435*fa9e4066Sahrens 	}
436*fa9e4066Sahrens 	if (argc < 2) {
437*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing vdev specification\n"));
438*fa9e4066Sahrens 		usage(FALSE);
439*fa9e4066Sahrens 	}
440*fa9e4066Sahrens 
441*fa9e4066Sahrens 	poolname = argv[0];
442*fa9e4066Sahrens 
443*fa9e4066Sahrens 	/*
444*fa9e4066Sahrens 	 * As a special case, check for use of '/' in the name, and direct the
445*fa9e4066Sahrens 	 * user to use 'zfs create' instead.
446*fa9e4066Sahrens 	 */
447*fa9e4066Sahrens 	if (strchr(poolname, '/') != NULL) {
448*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
449*fa9e4066Sahrens 		    "character '/' in pool name\n"), poolname);
450*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use 'zfs create' to "
451*fa9e4066Sahrens 		    "create a dataset\n"));
452*fa9e4066Sahrens 		return (1);
453*fa9e4066Sahrens 	}
454*fa9e4066Sahrens 
455*fa9e4066Sahrens 	/* pass off to get_vdev_spec for bulk processing */
456*fa9e4066Sahrens 	nvroot = make_root_vdev(NULL, force, !force, argc - 1, argv + 1);
457*fa9e4066Sahrens 	if (nvroot == NULL)
458*fa9e4066Sahrens 		return (1);
459*fa9e4066Sahrens 
460*fa9e4066Sahrens 	if (altroot != NULL && altroot[0] != '/') {
461*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
462*fa9e4066Sahrens 		    "must be an absolute path\n"));
463*fa9e4066Sahrens 		return (1);
464*fa9e4066Sahrens 	}
465*fa9e4066Sahrens 
466*fa9e4066Sahrens 	/*
467*fa9e4066Sahrens 	 * Check the validity of the mountpoint and direct the user to use the
468*fa9e4066Sahrens 	 * '-m' mountpoint option if it looks like its in use.
469*fa9e4066Sahrens 	 */
470*fa9e4066Sahrens 	if (mountpoint == NULL ||
471*fa9e4066Sahrens 	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
472*fa9e4066Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
473*fa9e4066Sahrens 		char buf[MAXPATHLEN];
474*fa9e4066Sahrens 		struct stat64 statbuf;
475*fa9e4066Sahrens 
476*fa9e4066Sahrens 		if (mountpoint && mountpoint[0] != '/') {
477*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid mountpoint "
478*fa9e4066Sahrens 			    "'%s': must be an absolute path, 'legacy', or "
479*fa9e4066Sahrens 			    "'none'\n"), mountpoint);
480*fa9e4066Sahrens 			return (1);
481*fa9e4066Sahrens 		}
482*fa9e4066Sahrens 
483*fa9e4066Sahrens 		if (mountpoint == NULL) {
484*fa9e4066Sahrens 			if (altroot != NULL)
485*fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s/%s",
486*fa9e4066Sahrens 				    altroot, poolname);
487*fa9e4066Sahrens 			else
488*fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "/%s",
489*fa9e4066Sahrens 				    poolname);
490*fa9e4066Sahrens 		} else {
491*fa9e4066Sahrens 			if (altroot != NULL)
492*fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s%s",
493*fa9e4066Sahrens 				    altroot, mountpoint);
494*fa9e4066Sahrens 			else
495*fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%s",
496*fa9e4066Sahrens 				    mountpoint);
497*fa9e4066Sahrens 		}
498*fa9e4066Sahrens 
499*fa9e4066Sahrens 		if (stat64(buf, &statbuf) == 0 &&
500*fa9e4066Sahrens 		    statbuf.st_nlink != 2) {
501*fa9e4066Sahrens 			if (mountpoint == NULL)
502*fa9e4066Sahrens 				(void) fprintf(stderr, gettext("default "
503*fa9e4066Sahrens 				    "mountpoint '%s' exists and is not "
504*fa9e4066Sahrens 				    "empty\n"), buf);
505*fa9e4066Sahrens 			else
506*fa9e4066Sahrens 				(void) fprintf(stderr, gettext("mountpoint "
507*fa9e4066Sahrens 				    "'%s' exists and is not empty\n"), buf);
508*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use '-m' "
509*fa9e4066Sahrens 			    "option to provide a different default\n"));
510*fa9e4066Sahrens 			return (1);
511*fa9e4066Sahrens 		}
512*fa9e4066Sahrens 	}
513*fa9e4066Sahrens 
514*fa9e4066Sahrens 
515*fa9e4066Sahrens 	if (dryrun) {
516*fa9e4066Sahrens 		/*
517*fa9e4066Sahrens 		 * For a dry run invocation, print out a basic message and run
518*fa9e4066Sahrens 		 * through all the vdevs in the list and print out in an
519*fa9e4066Sahrens 		 * appropriate hierarchy.
520*fa9e4066Sahrens 		 *
521*fa9e4066Sahrens 		 * XXZFS find out of we can create the pool?
522*fa9e4066Sahrens 		 */
523*fa9e4066Sahrens 		(void) printf(gettext("would create '%s' with the "
524*fa9e4066Sahrens 		    "following layout:\n\n"), poolname);
525*fa9e4066Sahrens 
526*fa9e4066Sahrens 		print_vdev_tree(poolname, nvroot, 0);
527*fa9e4066Sahrens 
528*fa9e4066Sahrens 		ret = 0;
529*fa9e4066Sahrens 	} else {
530*fa9e4066Sahrens 		ret = 1;
531*fa9e4066Sahrens 		/*
532*fa9e4066Sahrens 		 * Hand off to libzfs.
533*fa9e4066Sahrens 		 */
534*fa9e4066Sahrens 		if (zpool_create(poolname, nvroot, altroot) == 0) {
535*fa9e4066Sahrens 			zfs_handle_t *pool = zfs_open(poolname,
536*fa9e4066Sahrens 			    ZFS_TYPE_FILESYSTEM);
537*fa9e4066Sahrens 			if (pool != NULL) {
538*fa9e4066Sahrens 				if (mountpoint != NULL)
539*fa9e4066Sahrens 					verify(zfs_prop_set(pool,
540*fa9e4066Sahrens 					    ZFS_PROP_MOUNTPOINT,
541*fa9e4066Sahrens 					    mountpoint) == 0);
542*fa9e4066Sahrens 				if (zfs_mount(pool, NULL, 0) == 0)
543*fa9e4066Sahrens 					ret = zfs_share(pool);
544*fa9e4066Sahrens 				zfs_close(pool);
545*fa9e4066Sahrens 			}
546*fa9e4066Sahrens 		}
547*fa9e4066Sahrens 
548*fa9e4066Sahrens 	}
549*fa9e4066Sahrens 
550*fa9e4066Sahrens 	nvlist_free(nvroot);
551*fa9e4066Sahrens 
552*fa9e4066Sahrens 	return (ret);
553*fa9e4066Sahrens }
554*fa9e4066Sahrens 
555*fa9e4066Sahrens /*
556*fa9e4066Sahrens  * zpool destroy <pool>
557*fa9e4066Sahrens  *
558*fa9e4066Sahrens  * 	-f	Forcefully unmount any datasets
559*fa9e4066Sahrens  *
560*fa9e4066Sahrens  * Destroy the given pool.  Automatically unmounts any datasets in the pool.
561*fa9e4066Sahrens  */
562*fa9e4066Sahrens int
563*fa9e4066Sahrens zpool_do_destroy(int argc, char **argv)
564*fa9e4066Sahrens {
565*fa9e4066Sahrens 	int force = FALSE;
566*fa9e4066Sahrens 	int c;
567*fa9e4066Sahrens 	char *pool;
568*fa9e4066Sahrens 	zpool_handle_t *zhp;
569*fa9e4066Sahrens 	int ret;
570*fa9e4066Sahrens 
571*fa9e4066Sahrens 	/* check options */
572*fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
573*fa9e4066Sahrens 		switch (c) {
574*fa9e4066Sahrens 		case 'f':
575*fa9e4066Sahrens 			force = TRUE;
576*fa9e4066Sahrens 			break;
577*fa9e4066Sahrens 		case '?':
578*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
579*fa9e4066Sahrens 			    optopt);
580*fa9e4066Sahrens 			usage(FALSE);
581*fa9e4066Sahrens 		}
582*fa9e4066Sahrens 	}
583*fa9e4066Sahrens 
584*fa9e4066Sahrens 	argc -= optind;
585*fa9e4066Sahrens 	argv += optind;
586*fa9e4066Sahrens 
587*fa9e4066Sahrens 	/* check arguments */
588*fa9e4066Sahrens 	if (argc < 1) {
589*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
590*fa9e4066Sahrens 		usage(FALSE);
591*fa9e4066Sahrens 	}
592*fa9e4066Sahrens 	if (argc > 1) {
593*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
594*fa9e4066Sahrens 		usage(FALSE);
595*fa9e4066Sahrens 	}
596*fa9e4066Sahrens 
597*fa9e4066Sahrens 	pool = argv[0];
598*fa9e4066Sahrens 
599*fa9e4066Sahrens 	if ((zhp = zpool_open_canfail(pool)) == NULL) {
600*fa9e4066Sahrens 		/*
601*fa9e4066Sahrens 		 * As a special case, check for use of '/' in the name, and
602*fa9e4066Sahrens 		 * direct the user to use 'zfs destroy' instead.
603*fa9e4066Sahrens 		 */
604*fa9e4066Sahrens 		if (strchr(pool, '/') != NULL)
605*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
606*fa9e4066Sahrens 			    "destroy a dataset\n"));
607*fa9e4066Sahrens 		return (1);
608*fa9e4066Sahrens 	}
609*fa9e4066Sahrens 
610*fa9e4066Sahrens 	if (unmount_datasets(zhp, force) != 0) {
611*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("could not destroy '%s': "
612*fa9e4066Sahrens 		    "could not unmount datasets\n"), zpool_get_name(zhp));
613*fa9e4066Sahrens 		return (1);
614*fa9e4066Sahrens 	}
615*fa9e4066Sahrens 
616*fa9e4066Sahrens 	ret = (zpool_destroy(zhp) != 0);
617*fa9e4066Sahrens 
618*fa9e4066Sahrens 	zpool_close(zhp);
619*fa9e4066Sahrens 
620*fa9e4066Sahrens 	return (ret);
621*fa9e4066Sahrens }
622*fa9e4066Sahrens 
623*fa9e4066Sahrens /*
624*fa9e4066Sahrens  * zpool export [-f] <pool> ...
625*fa9e4066Sahrens  *
626*fa9e4066Sahrens  *	-f	Forcefully unmount datasets
627*fa9e4066Sahrens  *
628*fa9e4066Sahrens  * Export the the given pools.  By default, the command will attempt to cleanly
629*fa9e4066Sahrens  * unmount any active datasets within the pool.  If the '-f' flag is specified,
630*fa9e4066Sahrens  * then the datasets will be forcefully unmounted.
631*fa9e4066Sahrens  */
632*fa9e4066Sahrens int
633*fa9e4066Sahrens zpool_do_export(int argc, char **argv)
634*fa9e4066Sahrens {
635*fa9e4066Sahrens 	int force = FALSE;
636*fa9e4066Sahrens 	int c;
637*fa9e4066Sahrens 	zpool_handle_t *zhp;
638*fa9e4066Sahrens 	int ret;
639*fa9e4066Sahrens 	int i;
640*fa9e4066Sahrens 
641*fa9e4066Sahrens 	/* check options */
642*fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
643*fa9e4066Sahrens 		switch (c) {
644*fa9e4066Sahrens 		case 'f':
645*fa9e4066Sahrens 			force = TRUE;
646*fa9e4066Sahrens 			break;
647*fa9e4066Sahrens 		case '?':
648*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
649*fa9e4066Sahrens 			    optopt);
650*fa9e4066Sahrens 			usage(FALSE);
651*fa9e4066Sahrens 		}
652*fa9e4066Sahrens 	}
653*fa9e4066Sahrens 
654*fa9e4066Sahrens 	argc -= optind;
655*fa9e4066Sahrens 	argv += optind;
656*fa9e4066Sahrens 
657*fa9e4066Sahrens 	/* check arguments */
658*fa9e4066Sahrens 	if (argc < 1) {
659*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool argument\n"));
660*fa9e4066Sahrens 		usage(FALSE);
661*fa9e4066Sahrens 	}
662*fa9e4066Sahrens 
663*fa9e4066Sahrens 	ret = 0;
664*fa9e4066Sahrens 	for (i = 0; i < argc; i++) {
665*fa9e4066Sahrens 		if ((zhp = zpool_open_canfail(argv[i])) == NULL) {
666*fa9e4066Sahrens 			ret = 1;
667*fa9e4066Sahrens 			continue;
668*fa9e4066Sahrens 		}
669*fa9e4066Sahrens 
670*fa9e4066Sahrens 		if (unmount_datasets(zhp, force) != 0) {
671*fa9e4066Sahrens 			ret = 1;
672*fa9e4066Sahrens 			zpool_close(zhp);
673*fa9e4066Sahrens 			continue;
674*fa9e4066Sahrens 		}
675*fa9e4066Sahrens 
676*fa9e4066Sahrens 		if (zpool_export(zhp) != 0)
677*fa9e4066Sahrens 			ret = 1;
678*fa9e4066Sahrens 
679*fa9e4066Sahrens 		zpool_close(zhp);
680*fa9e4066Sahrens 	}
681*fa9e4066Sahrens 
682*fa9e4066Sahrens 	return (ret);
683*fa9e4066Sahrens }
684*fa9e4066Sahrens 
685*fa9e4066Sahrens /*
686*fa9e4066Sahrens  * Given a vdev configuration, determine the maximum width needed for the device
687*fa9e4066Sahrens  * name column.
688*fa9e4066Sahrens  */
689*fa9e4066Sahrens static int
690*fa9e4066Sahrens max_width(nvlist_t *nv, int depth, int max)
691*fa9e4066Sahrens {
692*fa9e4066Sahrens 	const char *name = vdev_get_name(nv);
693*fa9e4066Sahrens 	nvlist_t **child;
694*fa9e4066Sahrens 	uint_t c, children;
695*fa9e4066Sahrens 	int ret;
696*fa9e4066Sahrens 
697*fa9e4066Sahrens 	if (strlen(name) + depth > max)
698*fa9e4066Sahrens 		max = strlen(name) + depth;
699*fa9e4066Sahrens 
700*fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
701*fa9e4066Sahrens 	    &child, &children) != 0)
702*fa9e4066Sahrens 		return (max);
703*fa9e4066Sahrens 
704*fa9e4066Sahrens 	for (c = 0; c < children; c++)
705*fa9e4066Sahrens 		if ((ret = max_width(child[c], depth + 2, max)) > max)
706*fa9e4066Sahrens 			max = ret;
707*fa9e4066Sahrens 
708*fa9e4066Sahrens 	return (max);
709*fa9e4066Sahrens }
710*fa9e4066Sahrens 
711*fa9e4066Sahrens 
712*fa9e4066Sahrens /*
713*fa9e4066Sahrens  * Print the configuration of an exported pool.  Iterate over all vdevs in the
714*fa9e4066Sahrens  * pool, printing out the name and status for each one.
715*fa9e4066Sahrens  */
716*fa9e4066Sahrens void
717*fa9e4066Sahrens print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
718*fa9e4066Sahrens {
719*fa9e4066Sahrens 	nvlist_t **child;
720*fa9e4066Sahrens 	uint_t c, children;
721*fa9e4066Sahrens 	vdev_stat_t *vs;
722*fa9e4066Sahrens 	char *type;
723*fa9e4066Sahrens 
724*fa9e4066Sahrens 	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
725*fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
726*fa9e4066Sahrens 		return;
727*fa9e4066Sahrens 
728*fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
729*fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
730*fa9e4066Sahrens 
731*fa9e4066Sahrens 	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
732*fa9e4066Sahrens 
733*fa9e4066Sahrens 	if (vs->vs_aux != 0) {
734*fa9e4066Sahrens 		(void) printf("  %-8s  ", state_to_name(vs->vs_state));
735*fa9e4066Sahrens 
736*fa9e4066Sahrens 		switch (vs->vs_aux) {
737*fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
738*fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
739*fa9e4066Sahrens 			break;
740*fa9e4066Sahrens 
741*fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
742*fa9e4066Sahrens 			(void) printf(gettext("missing device"));
743*fa9e4066Sahrens 			break;
744*fa9e4066Sahrens 
745*fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
746*fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
747*fa9e4066Sahrens 			break;
748*fa9e4066Sahrens 
749*fa9e4066Sahrens 		default:
750*fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
751*fa9e4066Sahrens 			break;
752*fa9e4066Sahrens 		}
753*fa9e4066Sahrens 	} else {
754*fa9e4066Sahrens 		(void) printf("  %s", state_to_name(vs->vs_state));
755*fa9e4066Sahrens 	}
756*fa9e4066Sahrens 	(void) printf("\n");
757*fa9e4066Sahrens 
758*fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
759*fa9e4066Sahrens 	    &child, &children) != 0)
760*fa9e4066Sahrens 		return;
761*fa9e4066Sahrens 
762*fa9e4066Sahrens 	for (c = 0; c < children; c++)
763*fa9e4066Sahrens 		print_import_config(vdev_get_name(child[c]), child[c],
764*fa9e4066Sahrens 		    namewidth, depth + 2);
765*fa9e4066Sahrens }
766*fa9e4066Sahrens 
767*fa9e4066Sahrens /*
768*fa9e4066Sahrens  * Display the status for the given pool.
769*fa9e4066Sahrens  */
770*fa9e4066Sahrens static void
771*fa9e4066Sahrens show_import(nvlist_t *config)
772*fa9e4066Sahrens {
773*fa9e4066Sahrens 	uint64_t pool_state;
774*fa9e4066Sahrens 	vdev_stat_t *vs;
775*fa9e4066Sahrens 	char *name;
776*fa9e4066Sahrens 	uint64_t guid;
777*fa9e4066Sahrens 	char *msgid;
778*fa9e4066Sahrens 	nvlist_t *nvroot;
779*fa9e4066Sahrens 	int reason;
780*fa9e4066Sahrens 	char *health;
781*fa9e4066Sahrens 	uint_t vsc;
782*fa9e4066Sahrens 	int namewidth;
783*fa9e4066Sahrens 
784*fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
785*fa9e4066Sahrens 	    &name) == 0);
786*fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
787*fa9e4066Sahrens 	    &guid) == 0);
788*fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
789*fa9e4066Sahrens 	    &pool_state) == 0);
790*fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_HEALTH,
791*fa9e4066Sahrens 	    &health) == 0);
792*fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
793*fa9e4066Sahrens 	    &nvroot) == 0);
794*fa9e4066Sahrens 
795*fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
796*fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
797*fa9e4066Sahrens 
798*fa9e4066Sahrens 	reason = zpool_import_status(config, &msgid);
799*fa9e4066Sahrens 
800*fa9e4066Sahrens 	(void) printf("  pool: %s\n", name);
801*fa9e4066Sahrens 	(void) printf("    id: %llu\n", guid);
802*fa9e4066Sahrens 	(void) printf(" state: %s\n", health);
803*fa9e4066Sahrens 
804*fa9e4066Sahrens 	switch (reason) {
805*fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
806*fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
807*fa9e4066Sahrens 	case ZPOOL_STATUS_BAD_GUID_SUM:
808*fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices are missing "
809*fa9e4066Sahrens 		    "from the system.\n"));
810*fa9e4066Sahrens 		break;
811*fa9e4066Sahrens 
812*fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
813*fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
814*fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices contains "
815*fa9e4066Sahrens 		    "corrupted data.\n"));
816*fa9e4066Sahrens 		break;
817*fa9e4066Sahrens 
818*fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_DATA:
819*fa9e4066Sahrens 		(void) printf(gettext("status: The pool data is corrupted.\n"));
820*fa9e4066Sahrens 		break;
821*fa9e4066Sahrens 
822*fa9e4066Sahrens 	default:
823*fa9e4066Sahrens 		/*
824*fa9e4066Sahrens 		 * No other status can be seen when importing pools.
825*fa9e4066Sahrens 		 */
826*fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
827*fa9e4066Sahrens 	}
828*fa9e4066Sahrens 
829*fa9e4066Sahrens 	/*
830*fa9e4066Sahrens 	 * Print out an action according to the overall state of the pool.
831*fa9e4066Sahrens 	 */
832*fa9e4066Sahrens 	if (strcmp(health, gettext("ONLINE")) == 0) {
833*fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported"
834*fa9e4066Sahrens 		    " using its name or numeric identifier."));
835*fa9e4066Sahrens 		if (pool_state != POOL_STATE_EXPORTED)
836*fa9e4066Sahrens 			(void) printf(gettext("  The\n\tpool may be active on "
837*fa9e4066Sahrens 			    "on another system, but can be imported using\n\t"
838*fa9e4066Sahrens 			    "the '-f' flag.\n"));
839*fa9e4066Sahrens 		else
840*fa9e4066Sahrens 			(void) printf("\n");
841*fa9e4066Sahrens 	} else if (strcmp(health, gettext("DEGRADED")) == 0) {
842*fa9e4066Sahrens 		(void) printf(gettext("action: The pool can be imported "
843*fa9e4066Sahrens 		    "despite missing or damaged devices.  The\n\tfault "
844*fa9e4066Sahrens 		    "tolerance of the pool may be compromised if imported."));
845*fa9e4066Sahrens 		if (pool_state != POOL_STATE_EXPORTED)
846*fa9e4066Sahrens 			(void) printf(gettext("  The\n\tpool may be active on "
847*fa9e4066Sahrens 			    "on another system, but can be imported using\n\t"
848*fa9e4066Sahrens 			    "the '-f' flag.\n"));
849*fa9e4066Sahrens 		else
850*fa9e4066Sahrens 			(void) printf("\n");
851*fa9e4066Sahrens 	} else {
852*fa9e4066Sahrens 		if (reason == ZPOOL_STATUS_MISSING_DEV_R ||
853*fa9e4066Sahrens 		    reason == ZPOOL_STATUS_MISSING_DEV_NR ||
854*fa9e4066Sahrens 		    reason == ZPOOL_STATUS_BAD_GUID_SUM)
855*fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
856*fa9e4066Sahrens 			    "imported. Attach the missing\n\tdevices and try "
857*fa9e4066Sahrens 			    "again.\n"));
858*fa9e4066Sahrens 		else
859*fa9e4066Sahrens 			(void) printf(gettext("action: The pool cannot be "
860*fa9e4066Sahrens 			    "imported due to damaged devices or data.\n"));
861*fa9e4066Sahrens 	}
862*fa9e4066Sahrens 
863*fa9e4066Sahrens 	if (msgid != NULL)
864*fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
865*fa9e4066Sahrens 		    msgid);
866*fa9e4066Sahrens 
867*fa9e4066Sahrens 	(void) printf(gettext("config:\n\n"));
868*fa9e4066Sahrens 
869*fa9e4066Sahrens 	namewidth = max_width(nvroot, 0, 0);
870*fa9e4066Sahrens 	if (namewidth < 10)
871*fa9e4066Sahrens 		namewidth = 10;
872*fa9e4066Sahrens 	print_import_config(name, nvroot, namewidth, 0);
873*fa9e4066Sahrens 
874*fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
875*fa9e4066Sahrens 		(void) printf("\n\tAdditional devices are known to "
876*fa9e4066Sahrens 		    "be part of this pool, though their\n\texact "
877*fa9e4066Sahrens 		    "configuration cannot be determined.\n");
878*fa9e4066Sahrens 	}
879*fa9e4066Sahrens }
880*fa9e4066Sahrens 
881*fa9e4066Sahrens /*
882*fa9e4066Sahrens  * Perform the import for the given configuration.  This passes the heavy
883*fa9e4066Sahrens  * lifting off to zpool_import(), and then mounts the datasets contained within
884*fa9e4066Sahrens  * the pool.
885*fa9e4066Sahrens  */
886*fa9e4066Sahrens static int
887*fa9e4066Sahrens do_import(nvlist_t *config, const char *newname, const char *mntopts,
888*fa9e4066Sahrens     const char *altroot, int force)
889*fa9e4066Sahrens {
890*fa9e4066Sahrens 	zpool_handle_t *zhp;
891*fa9e4066Sahrens 	char *name;
892*fa9e4066Sahrens 	uint64_t state;
893*fa9e4066Sahrens 
894*fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
895*fa9e4066Sahrens 	    &name) == 0);
896*fa9e4066Sahrens 
897*fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config,
898*fa9e4066Sahrens 	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
899*fa9e4066Sahrens 	if (state != POOL_STATE_EXPORTED && !force) {
900*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("cannot import '%s': pool "
901*fa9e4066Sahrens 		    "may be in use from other system\n"), name);
902*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("use '-f' to import anyway\n"));
903*fa9e4066Sahrens 		return (1);
904*fa9e4066Sahrens 	}
905*fa9e4066Sahrens 
906*fa9e4066Sahrens 	if (zpool_import(config, newname, altroot) != 0)
907*fa9e4066Sahrens 		return (1);
908*fa9e4066Sahrens 
909*fa9e4066Sahrens 	if (newname != NULL)
910*fa9e4066Sahrens 		name = (char *)newname;
911*fa9e4066Sahrens 
912*fa9e4066Sahrens 	verify((zhp = zpool_open(name)) != NULL);
913*fa9e4066Sahrens 
914*fa9e4066Sahrens 	if (mount_datasets(zhp, mntopts) != 0) {
915*fa9e4066Sahrens 		zpool_close(zhp);
916*fa9e4066Sahrens 		return (1);
917*fa9e4066Sahrens 	}
918*fa9e4066Sahrens 
919*fa9e4066Sahrens 	zpool_close(zhp);
920*fa9e4066Sahrens 	return (0);
921*fa9e4066Sahrens }
922*fa9e4066Sahrens 
923*fa9e4066Sahrens /*
924*fa9e4066Sahrens  * zpool import [-d dir]
925*fa9e4066Sahrens  *       import [-R root] [-d dir] [-f] -a
926*fa9e4066Sahrens  *       import [-R root] [-d dir] [-f] <pool | id> [newpool]
927*fa9e4066Sahrens  *
928*fa9e4066Sahrens  *       -d	Scan in a specific directory, other than /dev/dsk.  More than
929*fa9e4066Sahrens  *		one directory can be specified using multiple '-d' options.
930*fa9e4066Sahrens  *
931*fa9e4066Sahrens  *       -R	Temporarily import the pool, with all mountpoints relative to
932*fa9e4066Sahrens  *		the given root.  The pool will remain exported when the machine
933*fa9e4066Sahrens  *		is rebooted.
934*fa9e4066Sahrens  *
935*fa9e4066Sahrens  *       -f	Force import, even if it appears that the pool is active.
936*fa9e4066Sahrens  *
937*fa9e4066Sahrens  *       -a	Import all pools found.
938*fa9e4066Sahrens  *
939*fa9e4066Sahrens  * The import command scans for pools to import, and import pools based on pool
940*fa9e4066Sahrens  * name and GUID.  The pool can also be renamed as part of the import process.
941*fa9e4066Sahrens  */
942*fa9e4066Sahrens int
943*fa9e4066Sahrens zpool_do_import(int argc, char **argv)
944*fa9e4066Sahrens {
945*fa9e4066Sahrens 	char **searchdirs = NULL;
946*fa9e4066Sahrens 	int nsearch = 0;
947*fa9e4066Sahrens 	int c;
948*fa9e4066Sahrens 	int err;
949*fa9e4066Sahrens 	nvlist_t *pools;
950*fa9e4066Sahrens 	int do_all = FALSE;
951*fa9e4066Sahrens 	char *altroot = NULL;
952*fa9e4066Sahrens 	char *mntopts = NULL;
953*fa9e4066Sahrens 	int do_force = FALSE;
954*fa9e4066Sahrens 	nvpair_t *elem;
955*fa9e4066Sahrens 	nvlist_t *config;
956*fa9e4066Sahrens 	uint64_t searchguid;
957*fa9e4066Sahrens 	char *searchname;
958*fa9e4066Sahrens 	nvlist_t *found_config;
959*fa9e4066Sahrens 	int first;
960*fa9e4066Sahrens 
961*fa9e4066Sahrens 	/* check options */
962*fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":fd:R:ao:")) != -1) {
963*fa9e4066Sahrens 		switch (c) {
964*fa9e4066Sahrens 		case 'a':
965*fa9e4066Sahrens 			do_all = TRUE;
966*fa9e4066Sahrens 			break;
967*fa9e4066Sahrens 		case 'd':
968*fa9e4066Sahrens 			if (searchdirs == NULL) {
969*fa9e4066Sahrens 				searchdirs = safe_malloc(sizeof (char *));
970*fa9e4066Sahrens 			} else {
971*fa9e4066Sahrens 				char **tmp = safe_malloc((nsearch + 1) *
972*fa9e4066Sahrens 				    sizeof (char *));
973*fa9e4066Sahrens 				bcopy(searchdirs, tmp, nsearch *
974*fa9e4066Sahrens 				    sizeof (char *));
975*fa9e4066Sahrens 				free(searchdirs);
976*fa9e4066Sahrens 				searchdirs = tmp;
977*fa9e4066Sahrens 			}
978*fa9e4066Sahrens 			searchdirs[nsearch++] = optarg;
979*fa9e4066Sahrens 			break;
980*fa9e4066Sahrens 		case 'f':
981*fa9e4066Sahrens 			do_force = TRUE;
982*fa9e4066Sahrens 			break;
983*fa9e4066Sahrens 		case 'o':
984*fa9e4066Sahrens 			mntopts = optarg;
985*fa9e4066Sahrens 			break;
986*fa9e4066Sahrens 		case 'R':
987*fa9e4066Sahrens 			altroot = optarg;
988*fa9e4066Sahrens 			break;
989*fa9e4066Sahrens 		case ':':
990*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
991*fa9e4066Sahrens 			    "'%c' option\n"), optopt);
992*fa9e4066Sahrens 			usage(FALSE);
993*fa9e4066Sahrens 			break;
994*fa9e4066Sahrens 		case '?':
995*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
996*fa9e4066Sahrens 			    optopt);
997*fa9e4066Sahrens 			usage(FALSE);
998*fa9e4066Sahrens 		}
999*fa9e4066Sahrens 	}
1000*fa9e4066Sahrens 
1001*fa9e4066Sahrens 	argc -= optind;
1002*fa9e4066Sahrens 	argv += optind;
1003*fa9e4066Sahrens 
1004*fa9e4066Sahrens 	if (searchdirs == NULL) {
1005*fa9e4066Sahrens 		searchdirs = safe_malloc(sizeof (char *));
1006*fa9e4066Sahrens 		searchdirs[0] = "/dev/dsk";
1007*fa9e4066Sahrens 		nsearch = 1;
1008*fa9e4066Sahrens 	}
1009*fa9e4066Sahrens 
1010*fa9e4066Sahrens 	/* check argument count */
1011*fa9e4066Sahrens 	if (do_all) {
1012*fa9e4066Sahrens 		if (argc != 0) {
1013*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
1014*fa9e4066Sahrens 			usage(FALSE);
1015*fa9e4066Sahrens 		}
1016*fa9e4066Sahrens 	} else {
1017*fa9e4066Sahrens 		if (argc > 2) {
1018*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many arguments\n"));
1019*fa9e4066Sahrens 			usage(FALSE);
1020*fa9e4066Sahrens 		}
1021*fa9e4066Sahrens 
1022*fa9e4066Sahrens 		/*
1023*fa9e4066Sahrens 		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1024*fa9e4066Sahrens 		 * here because otherwise any attempt to discover pools will
1025*fa9e4066Sahrens 		 * silently fail.
1026*fa9e4066Sahrens 		 */
1027*fa9e4066Sahrens 		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1028*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot "
1029*fa9e4066Sahrens 			    "discover pools: permission denied\n"));
1030*fa9e4066Sahrens 			return (1);
1031*fa9e4066Sahrens 		}
1032*fa9e4066Sahrens 	}
1033*fa9e4066Sahrens 
1034*fa9e4066Sahrens 	if ((pools = zpool_find_import(nsearch, searchdirs)) == NULL)
1035*fa9e4066Sahrens 		return (1);
1036*fa9e4066Sahrens 
1037*fa9e4066Sahrens 	/*
1038*fa9e4066Sahrens 	 * We now have a list of all available pools in the given directories.
1039*fa9e4066Sahrens 	 * Depending on the arguments given, we do one of the following:
1040*fa9e4066Sahrens 	 *
1041*fa9e4066Sahrens 	 *	<none>	Iterate through all pools and display information about
1042*fa9e4066Sahrens 	 *		each one.
1043*fa9e4066Sahrens 	 *
1044*fa9e4066Sahrens 	 *	-a	Iterate through all pools and try to import each one.
1045*fa9e4066Sahrens 	 *
1046*fa9e4066Sahrens 	 *	<id>	Find the pool that corresponds to the given GUID/pool
1047*fa9e4066Sahrens 	 *		name and import that one.
1048*fa9e4066Sahrens 	 */
1049*fa9e4066Sahrens 	if (argc != 0) {
1050*fa9e4066Sahrens 		char *endptr;
1051*fa9e4066Sahrens 
1052*fa9e4066Sahrens 		errno = 0;
1053*fa9e4066Sahrens 		searchguid = strtoull(argv[0], &endptr, 10);
1054*fa9e4066Sahrens 		if (errno != 0 || *endptr != '\0')
1055*fa9e4066Sahrens 			searchname = argv[0];
1056*fa9e4066Sahrens 		else
1057*fa9e4066Sahrens 			searchname = NULL;
1058*fa9e4066Sahrens 		found_config = NULL;
1059*fa9e4066Sahrens 	}
1060*fa9e4066Sahrens 
1061*fa9e4066Sahrens 	err = 0;
1062*fa9e4066Sahrens 	elem = NULL;
1063*fa9e4066Sahrens 	first = TRUE;
1064*fa9e4066Sahrens 	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1065*fa9e4066Sahrens 
1066*fa9e4066Sahrens 		verify(nvpair_value_nvlist(elem, &config) == 0);
1067*fa9e4066Sahrens 
1068*fa9e4066Sahrens 		if (argc == 0) {
1069*fa9e4066Sahrens 			if (first)
1070*fa9e4066Sahrens 				first = FALSE;
1071*fa9e4066Sahrens 			else
1072*fa9e4066Sahrens 				(void) printf("\n");
1073*fa9e4066Sahrens 
1074*fa9e4066Sahrens 			if (do_all)
1075*fa9e4066Sahrens 				err |= do_import(config, NULL, mntopts,
1076*fa9e4066Sahrens 				    altroot, do_force);
1077*fa9e4066Sahrens 			else
1078*fa9e4066Sahrens 				show_import(config);
1079*fa9e4066Sahrens 		} else if (searchname != NULL) {
1080*fa9e4066Sahrens 			char *name;
1081*fa9e4066Sahrens 
1082*fa9e4066Sahrens 			/*
1083*fa9e4066Sahrens 			 * We are searching for a pool based on name.
1084*fa9e4066Sahrens 			 */
1085*fa9e4066Sahrens 			verify(nvlist_lookup_string(config,
1086*fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1087*fa9e4066Sahrens 
1088*fa9e4066Sahrens 			if (strcmp(name, searchname) == 0) {
1089*fa9e4066Sahrens 				if (found_config != NULL) {
1090*fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1091*fa9e4066Sahrens 					    "cannot import '%s': more than "
1092*fa9e4066Sahrens 					    "one matching pool\n"), searchname);
1093*fa9e4066Sahrens 					(void) fprintf(stderr, gettext(
1094*fa9e4066Sahrens 					    "import by numeric ID instead\n"));
1095*fa9e4066Sahrens 					err = TRUE;
1096*fa9e4066Sahrens 				}
1097*fa9e4066Sahrens 				found_config = config;
1098*fa9e4066Sahrens 			}
1099*fa9e4066Sahrens 		} else {
1100*fa9e4066Sahrens 			uint64_t guid;
1101*fa9e4066Sahrens 
1102*fa9e4066Sahrens 			/*
1103*fa9e4066Sahrens 			 * Search for a pool by guid.
1104*fa9e4066Sahrens 			 */
1105*fa9e4066Sahrens 			verify(nvlist_lookup_uint64(config,
1106*fa9e4066Sahrens 			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1107*fa9e4066Sahrens 
1108*fa9e4066Sahrens 			if (guid == searchguid)
1109*fa9e4066Sahrens 				found_config = config;
1110*fa9e4066Sahrens 		}
1111*fa9e4066Sahrens 	}
1112*fa9e4066Sahrens 
1113*fa9e4066Sahrens 	/*
1114*fa9e4066Sahrens 	 * If we were searching for a specific pool, verify that we found a
1115*fa9e4066Sahrens 	 * pool, and then do the import.
1116*fa9e4066Sahrens 	 */
1117*fa9e4066Sahrens 	if (argc != 0 && err == 0) {
1118*fa9e4066Sahrens 		if (found_config == NULL) {
1119*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("cannot import '%s': "
1120*fa9e4066Sahrens 			    "no such pool available\n"), argv[0]);
1121*fa9e4066Sahrens 			err = TRUE;
1122*fa9e4066Sahrens 		} else {
1123*fa9e4066Sahrens 			err |= do_import(found_config, argc == 1 ? NULL :
1124*fa9e4066Sahrens 			    argv[1], mntopts, altroot, do_force);
1125*fa9e4066Sahrens 		}
1126*fa9e4066Sahrens 	}
1127*fa9e4066Sahrens 
1128*fa9e4066Sahrens 	/*
1129*fa9e4066Sahrens 	 * If we were just looking for pools, report an error if none were
1130*fa9e4066Sahrens 	 * found.
1131*fa9e4066Sahrens 	 */
1132*fa9e4066Sahrens 	if (argc == 0 && first)
1133*fa9e4066Sahrens 		(void) fprintf(stderr,
1134*fa9e4066Sahrens 		    gettext("no pools available to import\n"));
1135*fa9e4066Sahrens 
1136*fa9e4066Sahrens 	nvlist_free(pools);
1137*fa9e4066Sahrens 
1138*fa9e4066Sahrens 	return (err ? 1 : 0);
1139*fa9e4066Sahrens }
1140*fa9e4066Sahrens 
1141*fa9e4066Sahrens typedef struct iostat_cbdata {
1142*fa9e4066Sahrens 	zpool_list_t *cb_list;
1143*fa9e4066Sahrens 	int cb_verbose;
1144*fa9e4066Sahrens 	int cb_iteration;
1145*fa9e4066Sahrens 	int cb_namewidth;
1146*fa9e4066Sahrens } iostat_cbdata_t;
1147*fa9e4066Sahrens 
1148*fa9e4066Sahrens static void
1149*fa9e4066Sahrens print_iostat_separator(iostat_cbdata_t *cb)
1150*fa9e4066Sahrens {
1151*fa9e4066Sahrens 	int i = 0;
1152*fa9e4066Sahrens 
1153*fa9e4066Sahrens 	for (i = 0; i < cb->cb_namewidth; i++)
1154*fa9e4066Sahrens 		(void) printf("-");
1155*fa9e4066Sahrens 	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1156*fa9e4066Sahrens }
1157*fa9e4066Sahrens 
1158*fa9e4066Sahrens static void
1159*fa9e4066Sahrens print_iostat_header(iostat_cbdata_t *cb)
1160*fa9e4066Sahrens {
1161*fa9e4066Sahrens 	(void) printf("%*s     capacity     operations    bandwidth\n",
1162*fa9e4066Sahrens 	    cb->cb_namewidth, "");
1163*fa9e4066Sahrens 	(void) printf("%-*s   used  avail   read  write   read  write\n",
1164*fa9e4066Sahrens 	    cb->cb_namewidth, "pool");
1165*fa9e4066Sahrens 	print_iostat_separator(cb);
1166*fa9e4066Sahrens }
1167*fa9e4066Sahrens 
1168*fa9e4066Sahrens /*
1169*fa9e4066Sahrens  * Display a single statistic.
1170*fa9e4066Sahrens  */
1171*fa9e4066Sahrens void
1172*fa9e4066Sahrens print_one_stat(uint64_t value)
1173*fa9e4066Sahrens {
1174*fa9e4066Sahrens 	char buf[64];
1175*fa9e4066Sahrens 
1176*fa9e4066Sahrens 	zfs_nicenum(value, buf, sizeof (buf));
1177*fa9e4066Sahrens 	(void) printf("  %5s", buf);
1178*fa9e4066Sahrens }
1179*fa9e4066Sahrens 
1180*fa9e4066Sahrens /*
1181*fa9e4066Sahrens  * Print out all the statistics for the given vdev.  This can either be the
1182*fa9e4066Sahrens  * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1183*fa9e4066Sahrens  * is a verbose output, and we don't want to display the toplevel pool stats.
1184*fa9e4066Sahrens  */
1185*fa9e4066Sahrens void
1186*fa9e4066Sahrens print_vdev_stats(const char *name, nvlist_t *oldnv, nvlist_t *newnv,
1187*fa9e4066Sahrens 	iostat_cbdata_t *cb, int depth)
1188*fa9e4066Sahrens {
1189*fa9e4066Sahrens 	nvlist_t **oldchild, **newchild;
1190*fa9e4066Sahrens 	uint_t c, children;
1191*fa9e4066Sahrens 	vdev_stat_t *oldvs, *newvs;
1192*fa9e4066Sahrens 	vdev_stat_t zerovs = { 0 };
1193*fa9e4066Sahrens 	uint64_t tdelta;
1194*fa9e4066Sahrens 	double scale;
1195*fa9e4066Sahrens 
1196*fa9e4066Sahrens 	if (oldnv != NULL) {
1197*fa9e4066Sahrens 		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1198*fa9e4066Sahrens 		    (uint64_t **)&oldvs, &c) == 0);
1199*fa9e4066Sahrens 	} else {
1200*fa9e4066Sahrens 		oldvs = &zerovs;
1201*fa9e4066Sahrens 	}
1202*fa9e4066Sahrens 
1203*fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1204*fa9e4066Sahrens 	    (uint64_t **)&newvs, &c) == 0);
1205*fa9e4066Sahrens 
1206*fa9e4066Sahrens 	if (strlen(name) + depth > cb->cb_namewidth)
1207*fa9e4066Sahrens 		(void) printf("%*s%s", depth, "", name);
1208*fa9e4066Sahrens 	else
1209*fa9e4066Sahrens 		(void) printf("%*s%s%*s", depth, "", name,
1210*fa9e4066Sahrens 		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1211*fa9e4066Sahrens 
1212*fa9e4066Sahrens 	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1213*fa9e4066Sahrens 
1214*fa9e4066Sahrens 	if (tdelta == 0)
1215*fa9e4066Sahrens 		scale = 1.0;
1216*fa9e4066Sahrens 	else
1217*fa9e4066Sahrens 		scale = (double)NANOSEC / tdelta;
1218*fa9e4066Sahrens 
1219*fa9e4066Sahrens 	/* only toplevel vdevs have capacity stats */
1220*fa9e4066Sahrens 	if (newvs->vs_space == 0) {
1221*fa9e4066Sahrens 		(void) printf("      -      -");
1222*fa9e4066Sahrens 	} else {
1223*fa9e4066Sahrens 		print_one_stat(newvs->vs_alloc);
1224*fa9e4066Sahrens 		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1225*fa9e4066Sahrens 	}
1226*fa9e4066Sahrens 
1227*fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1228*fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_READ])));
1229*fa9e4066Sahrens 
1230*fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1231*fa9e4066Sahrens 	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1232*fa9e4066Sahrens 
1233*fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1234*fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1235*fa9e4066Sahrens 
1236*fa9e4066Sahrens 	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1237*fa9e4066Sahrens 	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1238*fa9e4066Sahrens 
1239*fa9e4066Sahrens 	(void) printf("\n");
1240*fa9e4066Sahrens 
1241*fa9e4066Sahrens 	if (!cb->cb_verbose)
1242*fa9e4066Sahrens 		return;
1243*fa9e4066Sahrens 
1244*fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1245*fa9e4066Sahrens 	    &newchild, &children) != 0)
1246*fa9e4066Sahrens 		return;
1247*fa9e4066Sahrens 
1248*fa9e4066Sahrens 	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1249*fa9e4066Sahrens 	    &oldchild, &c) != 0)
1250*fa9e4066Sahrens 		return;
1251*fa9e4066Sahrens 
1252*fa9e4066Sahrens 	for (c = 0; c < children; c++)
1253*fa9e4066Sahrens 		print_vdev_stats(vdev_get_name(newchild[c]),
1254*fa9e4066Sahrens 		    oldnv ? oldchild[c] : NULL, newchild[c], cb, depth + 2);
1255*fa9e4066Sahrens }
1256*fa9e4066Sahrens 
1257*fa9e4066Sahrens /*
1258*fa9e4066Sahrens  * Callback to print out the iostats for the given pool.
1259*fa9e4066Sahrens  */
1260*fa9e4066Sahrens int
1261*fa9e4066Sahrens print_iostat(zpool_handle_t *zhp, void *data)
1262*fa9e4066Sahrens {
1263*fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1264*fa9e4066Sahrens 	nvlist_t *oldconfig, *newconfig;
1265*fa9e4066Sahrens 	nvlist_t *oldnvroot, *newnvroot;
1266*fa9e4066Sahrens 	uint64_t oldtxg, newtxg;
1267*fa9e4066Sahrens 
1268*fa9e4066Sahrens 	if (zpool_refresh_stats(zhp, &oldconfig, &newconfig) != 0) {
1269*fa9e4066Sahrens 		/*
1270*fa9e4066Sahrens 		 * This pool has disappeared, so remove it
1271*fa9e4066Sahrens 		 * from the list and continue.
1272*fa9e4066Sahrens 		 */
1273*fa9e4066Sahrens 		pool_list_remove(cb->cb_list, zhp);
1274*fa9e4066Sahrens 		return (0);
1275*fa9e4066Sahrens 	}
1276*fa9e4066Sahrens 
1277*fa9e4066Sahrens 	if (cb->cb_iteration == 1) {
1278*fa9e4066Sahrens 		if (oldconfig != NULL)
1279*fa9e4066Sahrens 			nvlist_free(oldconfig);
1280*fa9e4066Sahrens 		oldconfig = NULL;
1281*fa9e4066Sahrens 	}
1282*fa9e4066Sahrens 
1283*fa9e4066Sahrens 	verify(nvlist_lookup_uint64(newconfig, ZPOOL_CONFIG_POOL_TXG,
1284*fa9e4066Sahrens 	    &newtxg) == 0);
1285*fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1286*fa9e4066Sahrens 	    &newnvroot) == 0);
1287*fa9e4066Sahrens 
1288*fa9e4066Sahrens 	if (oldconfig == NULL ||
1289*fa9e4066Sahrens 	    nvlist_lookup_uint64(oldconfig, ZPOOL_CONFIG_POOL_TXG, &oldtxg) ||
1290*fa9e4066Sahrens 	    oldtxg != newtxg ||
1291*fa9e4066Sahrens 	    nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE, &oldnvroot))
1292*fa9e4066Sahrens 		oldnvroot = NULL;
1293*fa9e4066Sahrens 
1294*fa9e4066Sahrens 	/*
1295*fa9e4066Sahrens 	 * Print out the statistics for the pool.
1296*fa9e4066Sahrens 	 */
1297*fa9e4066Sahrens 	print_vdev_stats(zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1298*fa9e4066Sahrens 
1299*fa9e4066Sahrens 	if (cb->cb_verbose)
1300*fa9e4066Sahrens 		print_iostat_separator(cb);
1301*fa9e4066Sahrens 
1302*fa9e4066Sahrens 	if (oldconfig != NULL)
1303*fa9e4066Sahrens 		nvlist_free(oldconfig);
1304*fa9e4066Sahrens 
1305*fa9e4066Sahrens 	return (0);
1306*fa9e4066Sahrens }
1307*fa9e4066Sahrens 
1308*fa9e4066Sahrens int
1309*fa9e4066Sahrens get_namewidth(zpool_handle_t *zhp, void *data)
1310*fa9e4066Sahrens {
1311*fa9e4066Sahrens 	iostat_cbdata_t *cb = data;
1312*fa9e4066Sahrens 	nvlist_t *config, *nvroot;
1313*fa9e4066Sahrens 
1314*fa9e4066Sahrens 	if ((config = zpool_get_config(zhp)) != NULL) {
1315*fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1316*fa9e4066Sahrens 		    &nvroot) == 0);
1317*fa9e4066Sahrens 		if (!cb->cb_verbose)
1318*fa9e4066Sahrens 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1319*fa9e4066Sahrens 		else
1320*fa9e4066Sahrens 			cb->cb_namewidth = max_width(nvroot, 0, 0);
1321*fa9e4066Sahrens 	}
1322*fa9e4066Sahrens 
1323*fa9e4066Sahrens 	/*
1324*fa9e4066Sahrens 	 * The width must fall into the range [10,38].  The upper limit is the
1325*fa9e4066Sahrens 	 * maximum we can have and still fit in 80 columns.
1326*fa9e4066Sahrens 	 */
1327*fa9e4066Sahrens 	if (cb->cb_namewidth < 10)
1328*fa9e4066Sahrens 		cb->cb_namewidth = 10;
1329*fa9e4066Sahrens 	if (cb->cb_namewidth > 38)
1330*fa9e4066Sahrens 		cb->cb_namewidth = 38;
1331*fa9e4066Sahrens 
1332*fa9e4066Sahrens 	return (0);
1333*fa9e4066Sahrens }
1334*fa9e4066Sahrens 
1335*fa9e4066Sahrens /*
1336*fa9e4066Sahrens  * zpool iostat [-v] [pool] ... [interval [count]]
1337*fa9e4066Sahrens  *
1338*fa9e4066Sahrens  *	-v	Display statistics for individual vdevs
1339*fa9e4066Sahrens  *
1340*fa9e4066Sahrens  * This command can be tricky because we want to be able to deal with pool
1341*fa9e4066Sahrens  * creation/destruction as well as vdev configuration changes.  The bulk of this
1342*fa9e4066Sahrens  * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1343*fa9e4066Sahrens  * on pool_list_update() to detect the addition of new pools.  Configuration
1344*fa9e4066Sahrens  * changes are all handled within libzfs.
1345*fa9e4066Sahrens  */
1346*fa9e4066Sahrens int
1347*fa9e4066Sahrens zpool_do_iostat(int argc, char **argv)
1348*fa9e4066Sahrens {
1349*fa9e4066Sahrens 	int c;
1350*fa9e4066Sahrens 	int ret;
1351*fa9e4066Sahrens 	int npools;
1352*fa9e4066Sahrens 	unsigned long interval = 0, count = 0;
1353*fa9e4066Sahrens 	zpool_list_t *list;
1354*fa9e4066Sahrens 	int verbose = FALSE;
1355*fa9e4066Sahrens 	iostat_cbdata_t cb;
1356*fa9e4066Sahrens 
1357*fa9e4066Sahrens 	/* check options */
1358*fa9e4066Sahrens 	while ((c = getopt(argc, argv, "v")) != -1) {
1359*fa9e4066Sahrens 		switch (c) {
1360*fa9e4066Sahrens 		case 'v':
1361*fa9e4066Sahrens 			verbose = TRUE;
1362*fa9e4066Sahrens 			break;
1363*fa9e4066Sahrens 		case '?':
1364*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1365*fa9e4066Sahrens 			    optopt);
1366*fa9e4066Sahrens 			usage(FALSE);
1367*fa9e4066Sahrens 		}
1368*fa9e4066Sahrens 	}
1369*fa9e4066Sahrens 
1370*fa9e4066Sahrens 	argc -= optind;
1371*fa9e4066Sahrens 	argv += optind;
1372*fa9e4066Sahrens 
1373*fa9e4066Sahrens 	/*
1374*fa9e4066Sahrens 	 * Determine if the last argument is an integer or a pool name
1375*fa9e4066Sahrens 	 */
1376*fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1377*fa9e4066Sahrens 		char *end;
1378*fa9e4066Sahrens 
1379*fa9e4066Sahrens 		errno = 0;
1380*fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1381*fa9e4066Sahrens 
1382*fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1383*fa9e4066Sahrens 			if (interval == 0) {
1384*fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1385*fa9e4066Sahrens 				    "cannot be zero\n"));
1386*fa9e4066Sahrens 				usage(FALSE);
1387*fa9e4066Sahrens 			}
1388*fa9e4066Sahrens 
1389*fa9e4066Sahrens 			/*
1390*fa9e4066Sahrens 			 * Ignore the last parameter
1391*fa9e4066Sahrens 			 */
1392*fa9e4066Sahrens 			argc--;
1393*fa9e4066Sahrens 		} else {
1394*fa9e4066Sahrens 			/*
1395*fa9e4066Sahrens 			 * If this is not a valid number, just plow on.  The
1396*fa9e4066Sahrens 			 * user will get a more informative error message later
1397*fa9e4066Sahrens 			 * on.
1398*fa9e4066Sahrens 			 */
1399*fa9e4066Sahrens 			interval = 0;
1400*fa9e4066Sahrens 		}
1401*fa9e4066Sahrens 	}
1402*fa9e4066Sahrens 
1403*fa9e4066Sahrens 	/*
1404*fa9e4066Sahrens 	 * If the last argument is also an integer, then we have both a count
1405*fa9e4066Sahrens 	 * and an integer.
1406*fa9e4066Sahrens 	 */
1407*fa9e4066Sahrens 	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1408*fa9e4066Sahrens 		char *end;
1409*fa9e4066Sahrens 
1410*fa9e4066Sahrens 		errno = 0;
1411*fa9e4066Sahrens 		count = interval;
1412*fa9e4066Sahrens 		interval = strtoul(argv[argc - 1], &end, 10);
1413*fa9e4066Sahrens 
1414*fa9e4066Sahrens 		if (*end == '\0' && errno == 0) {
1415*fa9e4066Sahrens 			if (interval == 0) {
1416*fa9e4066Sahrens 				(void) fprintf(stderr, gettext("interval "
1417*fa9e4066Sahrens 				    "cannot be zero\n"));
1418*fa9e4066Sahrens 				usage(FALSE);
1419*fa9e4066Sahrens 			}
1420*fa9e4066Sahrens 
1421*fa9e4066Sahrens 			/*
1422*fa9e4066Sahrens 			 * Ignore the last parameter
1423*fa9e4066Sahrens 			 */
1424*fa9e4066Sahrens 			argc--;
1425*fa9e4066Sahrens 		} else {
1426*fa9e4066Sahrens 			interval = 0;
1427*fa9e4066Sahrens 		}
1428*fa9e4066Sahrens 	}
1429*fa9e4066Sahrens 
1430*fa9e4066Sahrens 	/*
1431*fa9e4066Sahrens 	 * Construct the list of all interesting pools.
1432*fa9e4066Sahrens 	 */
1433*fa9e4066Sahrens 	ret = 0;
1434*fa9e4066Sahrens 	if ((list = pool_list_get(argc, argv, &ret)) == NULL)
1435*fa9e4066Sahrens 		return (1);
1436*fa9e4066Sahrens 
1437*fa9e4066Sahrens 	if (pool_list_count(list) == 0 && argc != 0)
1438*fa9e4066Sahrens 		return (1);
1439*fa9e4066Sahrens 
1440*fa9e4066Sahrens 	if (pool_list_count(list) == 0 && interval == 0) {
1441*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("no pools available\n"));
1442*fa9e4066Sahrens 		return (1);
1443*fa9e4066Sahrens 	}
1444*fa9e4066Sahrens 
1445*fa9e4066Sahrens 	/*
1446*fa9e4066Sahrens 	 * Enter the main iostat loop.
1447*fa9e4066Sahrens 	 */
1448*fa9e4066Sahrens 	cb.cb_list = list;
1449*fa9e4066Sahrens 	cb.cb_verbose = verbose;
1450*fa9e4066Sahrens 	cb.cb_iteration = 0;
1451*fa9e4066Sahrens 	cb.cb_namewidth = 0;
1452*fa9e4066Sahrens 
1453*fa9e4066Sahrens 	for (;;) {
1454*fa9e4066Sahrens 		pool_list_update(list);
1455*fa9e4066Sahrens 
1456*fa9e4066Sahrens 		if ((npools = pool_list_count(list)) == 0)
1457*fa9e4066Sahrens 			break;
1458*fa9e4066Sahrens 
1459*fa9e4066Sahrens 		/*
1460*fa9e4066Sahrens 		 * Iterate over all pools to determine the maximum width
1461*fa9e4066Sahrens 		 * for the pool / device name column across all pools.
1462*fa9e4066Sahrens 		 */
1463*fa9e4066Sahrens 		cb.cb_namewidth = 0;
1464*fa9e4066Sahrens 		(void) pool_list_iter(list, FALSE, get_namewidth, &cb);
1465*fa9e4066Sahrens 
1466*fa9e4066Sahrens 		/*
1467*fa9e4066Sahrens 		 * If it's the first time, or verbose mode, print the header.
1468*fa9e4066Sahrens 		 */
1469*fa9e4066Sahrens 		if (++cb.cb_iteration == 1 || verbose)
1470*fa9e4066Sahrens 			print_iostat_header(&cb);
1471*fa9e4066Sahrens 
1472*fa9e4066Sahrens 		(void) pool_list_iter(list, FALSE, print_iostat, &cb);
1473*fa9e4066Sahrens 
1474*fa9e4066Sahrens 		/*
1475*fa9e4066Sahrens 		 * If there's more than one pool, and we're not in verbose mode
1476*fa9e4066Sahrens 		 * (which prints a separator for us), then print a separator.
1477*fa9e4066Sahrens 		 */
1478*fa9e4066Sahrens 		if (npools > 1 && !verbose)
1479*fa9e4066Sahrens 			print_iostat_separator(&cb);
1480*fa9e4066Sahrens 
1481*fa9e4066Sahrens 		if (verbose)
1482*fa9e4066Sahrens 			(void) printf("\n");
1483*fa9e4066Sahrens 
1484*fa9e4066Sahrens 		if (interval == 0)
1485*fa9e4066Sahrens 			break;
1486*fa9e4066Sahrens 
1487*fa9e4066Sahrens 		if (count != 0 && --count == 0)
1488*fa9e4066Sahrens 			break;
1489*fa9e4066Sahrens 
1490*fa9e4066Sahrens 		(void) sleep(interval);
1491*fa9e4066Sahrens 	}
1492*fa9e4066Sahrens 
1493*fa9e4066Sahrens 	pool_list_free(list);
1494*fa9e4066Sahrens 
1495*fa9e4066Sahrens 	return (ret);
1496*fa9e4066Sahrens }
1497*fa9e4066Sahrens 
1498*fa9e4066Sahrens typedef struct list_cbdata {
1499*fa9e4066Sahrens 	int	cb_scripted;
1500*fa9e4066Sahrens 	int	cb_first;
1501*fa9e4066Sahrens 	int	cb_fields[MAX_FIELDS];
1502*fa9e4066Sahrens 	int	cb_fieldcount;
1503*fa9e4066Sahrens } list_cbdata_t;
1504*fa9e4066Sahrens 
1505*fa9e4066Sahrens /*
1506*fa9e4066Sahrens  * Given a list of columns to display, output appropriate headers for each one.
1507*fa9e4066Sahrens  */
1508*fa9e4066Sahrens void
1509*fa9e4066Sahrens print_header(int *fields, size_t count)
1510*fa9e4066Sahrens {
1511*fa9e4066Sahrens 	int i;
1512*fa9e4066Sahrens 	column_def_t *col;
1513*fa9e4066Sahrens 	const char *fmt;
1514*fa9e4066Sahrens 
1515*fa9e4066Sahrens 	for (i = 0; i < count; i++) {
1516*fa9e4066Sahrens 		col = &column_table[fields[i]];
1517*fa9e4066Sahrens 		if (i != 0)
1518*fa9e4066Sahrens 			(void) printf("  ");
1519*fa9e4066Sahrens 		if (col->cd_justify == left_justify)
1520*fa9e4066Sahrens 			fmt = "%-*s";
1521*fa9e4066Sahrens 		else
1522*fa9e4066Sahrens 			fmt = "%*s";
1523*fa9e4066Sahrens 
1524*fa9e4066Sahrens 		(void) printf(fmt, i == count - 1 ? strlen(col->cd_title) :
1525*fa9e4066Sahrens 		    col->cd_width, col->cd_title);
1526*fa9e4066Sahrens 	}
1527*fa9e4066Sahrens 
1528*fa9e4066Sahrens 	(void) printf("\n");
1529*fa9e4066Sahrens }
1530*fa9e4066Sahrens 
1531*fa9e4066Sahrens int
1532*fa9e4066Sahrens list_callback(zpool_handle_t *zhp, void *data)
1533*fa9e4066Sahrens {
1534*fa9e4066Sahrens 	list_cbdata_t *cbp = data;
1535*fa9e4066Sahrens 	nvlist_t *config;
1536*fa9e4066Sahrens 	int i;
1537*fa9e4066Sahrens 	char buf[ZPOOL_MAXNAMELEN];
1538*fa9e4066Sahrens 	uint64_t total;
1539*fa9e4066Sahrens 	uint64_t used;
1540*fa9e4066Sahrens 	const char *fmt;
1541*fa9e4066Sahrens 	column_def_t *col;
1542*fa9e4066Sahrens 
1543*fa9e4066Sahrens 	if (cbp->cb_first) {
1544*fa9e4066Sahrens 		if (!cbp->cb_scripted)
1545*fa9e4066Sahrens 			print_header(cbp->cb_fields, cbp->cb_fieldcount);
1546*fa9e4066Sahrens 		cbp->cb_first = FALSE;
1547*fa9e4066Sahrens 	}
1548*fa9e4066Sahrens 
1549*fa9e4066Sahrens 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
1550*fa9e4066Sahrens 		config = NULL;
1551*fa9e4066Sahrens 	} else {
1552*fa9e4066Sahrens 		config = zpool_get_config(zhp);
1553*fa9e4066Sahrens 		total = zpool_get_space_total(zhp);
1554*fa9e4066Sahrens 		used = zpool_get_space_used(zhp);
1555*fa9e4066Sahrens 	}
1556*fa9e4066Sahrens 
1557*fa9e4066Sahrens 	for (i = 0; i < cbp->cb_fieldcount; i++) {
1558*fa9e4066Sahrens 		if (i != 0) {
1559*fa9e4066Sahrens 			if (cbp->cb_scripted)
1560*fa9e4066Sahrens 				(void) printf("\t");
1561*fa9e4066Sahrens 			else
1562*fa9e4066Sahrens 				(void) printf("  ");
1563*fa9e4066Sahrens 		}
1564*fa9e4066Sahrens 
1565*fa9e4066Sahrens 		col = &column_table[cbp->cb_fields[i]];
1566*fa9e4066Sahrens 
1567*fa9e4066Sahrens 		switch (cbp->cb_fields[i]) {
1568*fa9e4066Sahrens 		case ZPOOL_FIELD_NAME:
1569*fa9e4066Sahrens 			(void) strlcpy(buf, zpool_get_name(zhp), sizeof (buf));
1570*fa9e4066Sahrens 			break;
1571*fa9e4066Sahrens 
1572*fa9e4066Sahrens 		case ZPOOL_FIELD_SIZE:
1573*fa9e4066Sahrens 			if (config == NULL)
1574*fa9e4066Sahrens 				(void) strlcpy(buf, "-", sizeof (buf));
1575*fa9e4066Sahrens 			else
1576*fa9e4066Sahrens 				zfs_nicenum(total, buf, sizeof (buf));
1577*fa9e4066Sahrens 			break;
1578*fa9e4066Sahrens 
1579*fa9e4066Sahrens 		case ZPOOL_FIELD_USED:
1580*fa9e4066Sahrens 			if (config == NULL)
1581*fa9e4066Sahrens 				(void) strlcpy(buf, "-", sizeof (buf));
1582*fa9e4066Sahrens 			else
1583*fa9e4066Sahrens 				zfs_nicenum(used, buf, sizeof (buf));
1584*fa9e4066Sahrens 			break;
1585*fa9e4066Sahrens 
1586*fa9e4066Sahrens 		case ZPOOL_FIELD_AVAILABLE:
1587*fa9e4066Sahrens 			if (config == NULL)
1588*fa9e4066Sahrens 				(void) strlcpy(buf, "-", sizeof (buf));
1589*fa9e4066Sahrens 			else
1590*fa9e4066Sahrens 				zfs_nicenum(total - used, buf, sizeof (buf));
1591*fa9e4066Sahrens 			break;
1592*fa9e4066Sahrens 
1593*fa9e4066Sahrens 		case ZPOOL_FIELD_CAPACITY:
1594*fa9e4066Sahrens 			if (config == NULL) {
1595*fa9e4066Sahrens 				(void) strlcpy(buf, "-", sizeof (buf));
1596*fa9e4066Sahrens 			} else {
1597*fa9e4066Sahrens 				uint64_t capacity = (total == 0 ? 0 :
1598*fa9e4066Sahrens 				    (used * 100 / total));
1599*fa9e4066Sahrens 				(void) snprintf(buf, sizeof (buf), "%llu%%",
1600*fa9e4066Sahrens 				    capacity);
1601*fa9e4066Sahrens 			}
1602*fa9e4066Sahrens 			break;
1603*fa9e4066Sahrens 
1604*fa9e4066Sahrens 		case ZPOOL_FIELD_HEALTH:
1605*fa9e4066Sahrens 			if (config == NULL) {
1606*fa9e4066Sahrens 				(void) strlcpy(buf, "FAULTED", sizeof (buf));
1607*fa9e4066Sahrens 			} else {
1608*fa9e4066Sahrens 				nvlist_t *nvroot;
1609*fa9e4066Sahrens 				vdev_stat_t *vs;
1610*fa9e4066Sahrens 				uint_t vsc;
1611*fa9e4066Sahrens 
1612*fa9e4066Sahrens 				verify(nvlist_lookup_nvlist(config,
1613*fa9e4066Sahrens 				    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
1614*fa9e4066Sahrens 				verify(nvlist_lookup_uint64_array(nvroot,
1615*fa9e4066Sahrens 				    ZPOOL_CONFIG_STATS, (uint64_t **)&vs,
1616*fa9e4066Sahrens 				    &vsc) == 0);
1617*fa9e4066Sahrens 				(void) strlcpy(buf, state_to_name(vs->vs_state),
1618*fa9e4066Sahrens 				    sizeof (buf));
1619*fa9e4066Sahrens 			}
1620*fa9e4066Sahrens 			break;
1621*fa9e4066Sahrens 
1622*fa9e4066Sahrens 		case ZPOOL_FIELD_ROOT:
1623*fa9e4066Sahrens 			if (config == NULL)
1624*fa9e4066Sahrens 				(void) strlcpy(buf, "-", sizeof (buf));
1625*fa9e4066Sahrens 			else if (zpool_get_root(zhp, buf, sizeof (buf)) != 0)
1626*fa9e4066Sahrens 				(void) strlcpy(buf, "-", sizeof (buf));
1627*fa9e4066Sahrens 			break;
1628*fa9e4066Sahrens 		}
1629*fa9e4066Sahrens 
1630*fa9e4066Sahrens 		if (cbp->cb_scripted)
1631*fa9e4066Sahrens 			(void) printf("%s", buf);
1632*fa9e4066Sahrens 		else {
1633*fa9e4066Sahrens 			if (col->cd_justify == left_justify)
1634*fa9e4066Sahrens 				fmt = "%-*s";
1635*fa9e4066Sahrens 			else
1636*fa9e4066Sahrens 				fmt = "%*s";
1637*fa9e4066Sahrens 
1638*fa9e4066Sahrens 			(void) printf(fmt, i == cbp->cb_fieldcount - 1 ?
1639*fa9e4066Sahrens 			    strlen(buf) : col->cd_width, buf);
1640*fa9e4066Sahrens 		}
1641*fa9e4066Sahrens 	}
1642*fa9e4066Sahrens 
1643*fa9e4066Sahrens 	(void) printf("\n");
1644*fa9e4066Sahrens 
1645*fa9e4066Sahrens 	return (0);
1646*fa9e4066Sahrens }
1647*fa9e4066Sahrens 
1648*fa9e4066Sahrens /*
1649*fa9e4066Sahrens  * zpool list [-H] [-o field[,field]*] [pool] ...
1650*fa9e4066Sahrens  *
1651*fa9e4066Sahrens  *	-H	Scripted mode.  Don't display headers, and separate fields by
1652*fa9e4066Sahrens  *		a single tab.
1653*fa9e4066Sahrens  *	-o	List of fields to display.  Defaults to all fields, or
1654*fa9e4066Sahrens  *		"name,size,used,available,capacity,health,root"
1655*fa9e4066Sahrens  *
1656*fa9e4066Sahrens  * List all pools in the system, whether or not they're healthy.  Output space
1657*fa9e4066Sahrens  * statistics for each one, as well as health status summary.
1658*fa9e4066Sahrens  */
1659*fa9e4066Sahrens int
1660*fa9e4066Sahrens zpool_do_list(int argc, char **argv)
1661*fa9e4066Sahrens {
1662*fa9e4066Sahrens 	int c;
1663*fa9e4066Sahrens 	int ret;
1664*fa9e4066Sahrens 	list_cbdata_t cb = { 0 };
1665*fa9e4066Sahrens 	static char default_fields[] =
1666*fa9e4066Sahrens 	    "name,size,used,available,capacity,health,root";
1667*fa9e4066Sahrens 	char *fields = default_fields;
1668*fa9e4066Sahrens 	char *value;
1669*fa9e4066Sahrens 
1670*fa9e4066Sahrens 	/* check options */
1671*fa9e4066Sahrens 	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
1672*fa9e4066Sahrens 		switch (c) {
1673*fa9e4066Sahrens 		case 'H':
1674*fa9e4066Sahrens 			cb.cb_scripted = TRUE;
1675*fa9e4066Sahrens 			break;
1676*fa9e4066Sahrens 		case 'o':
1677*fa9e4066Sahrens 			fields = optarg;
1678*fa9e4066Sahrens 			break;
1679*fa9e4066Sahrens 		case ':':
1680*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("missing argument for "
1681*fa9e4066Sahrens 			    "'%c' option\n"), optopt);
1682*fa9e4066Sahrens 			usage(FALSE);
1683*fa9e4066Sahrens 			break;
1684*fa9e4066Sahrens 		case '?':
1685*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1686*fa9e4066Sahrens 			    optopt);
1687*fa9e4066Sahrens 			usage(FALSE);
1688*fa9e4066Sahrens 		}
1689*fa9e4066Sahrens 	}
1690*fa9e4066Sahrens 
1691*fa9e4066Sahrens 	argc -= optind;
1692*fa9e4066Sahrens 	argv += optind;
1693*fa9e4066Sahrens 
1694*fa9e4066Sahrens 	while (*fields != '\0') {
1695*fa9e4066Sahrens 		if (cb.cb_fieldcount == MAX_FIELDS) {
1696*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("too many "
1697*fa9e4066Sahrens 			    "properties given to -o option\n"));
1698*fa9e4066Sahrens 			usage(FALSE);
1699*fa9e4066Sahrens 		}
1700*fa9e4066Sahrens 
1701*fa9e4066Sahrens 		if ((cb.cb_fields[cb.cb_fieldcount] = getsubopt(&fields,
1702*fa9e4066Sahrens 		    column_subopts, &value)) == -1) {
1703*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid property "
1704*fa9e4066Sahrens 			    "'%s'\n"), value);
1705*fa9e4066Sahrens 			usage(FALSE);
1706*fa9e4066Sahrens 		}
1707*fa9e4066Sahrens 
1708*fa9e4066Sahrens 		cb.cb_fieldcount++;
1709*fa9e4066Sahrens 	}
1710*fa9e4066Sahrens 
1711*fa9e4066Sahrens 
1712*fa9e4066Sahrens 	cb.cb_first = TRUE;
1713*fa9e4066Sahrens 
1714*fa9e4066Sahrens 	ret = for_each_pool(argc, argv, TRUE, list_callback, &cb);
1715*fa9e4066Sahrens 
1716*fa9e4066Sahrens 	if (argc == 0 && cb.cb_first) {
1717*fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
1718*fa9e4066Sahrens 		return (0);
1719*fa9e4066Sahrens 	}
1720*fa9e4066Sahrens 
1721*fa9e4066Sahrens 	return (ret);
1722*fa9e4066Sahrens }
1723*fa9e4066Sahrens 
1724*fa9e4066Sahrens static nvlist_t *
1725*fa9e4066Sahrens zpool_get_vdev_by_name(nvlist_t *nv, char *name)
1726*fa9e4066Sahrens {
1727*fa9e4066Sahrens 	nvlist_t **child;
1728*fa9e4066Sahrens 	uint_t c, children;
1729*fa9e4066Sahrens 	nvlist_t *match;
1730*fa9e4066Sahrens 	char *path;
1731*fa9e4066Sahrens 
1732*fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1733*fa9e4066Sahrens 	    &child, &children) != 0) {
1734*fa9e4066Sahrens 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
1735*fa9e4066Sahrens 		if (strncmp(name, "/dev/dsk/", 9) == 0)
1736*fa9e4066Sahrens 			name += 9;
1737*fa9e4066Sahrens 		if (strncmp(path, "/dev/dsk/", 9) == 0)
1738*fa9e4066Sahrens 			path += 9;
1739*fa9e4066Sahrens 		if (strcmp(name, path) == 0)
1740*fa9e4066Sahrens 			return (nv);
1741*fa9e4066Sahrens 		return (NULL);
1742*fa9e4066Sahrens 	}
1743*fa9e4066Sahrens 
1744*fa9e4066Sahrens 	for (c = 0; c < children; c++)
1745*fa9e4066Sahrens 		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
1746*fa9e4066Sahrens 			return (match);
1747*fa9e4066Sahrens 
1748*fa9e4066Sahrens 	return (NULL);
1749*fa9e4066Sahrens }
1750*fa9e4066Sahrens 
1751*fa9e4066Sahrens static int
1752*fa9e4066Sahrens zpool_do_attach_or_replace(int argc, char **argv, int replacing)
1753*fa9e4066Sahrens {
1754*fa9e4066Sahrens 	int force = FALSE;
1755*fa9e4066Sahrens 	int c;
1756*fa9e4066Sahrens 	nvlist_t *nvroot;
1757*fa9e4066Sahrens 	char *poolname, *old_disk, *new_disk;
1758*fa9e4066Sahrens 	zpool_handle_t *zhp;
1759*fa9e4066Sahrens 	nvlist_t *config;
1760*fa9e4066Sahrens 
1761*fa9e4066Sahrens 	/* check options */
1762*fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
1763*fa9e4066Sahrens 		switch (c) {
1764*fa9e4066Sahrens 		case 'f':
1765*fa9e4066Sahrens 			force = TRUE;
1766*fa9e4066Sahrens 			break;
1767*fa9e4066Sahrens 		case '?':
1768*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1769*fa9e4066Sahrens 			    optopt);
1770*fa9e4066Sahrens 			usage(FALSE);
1771*fa9e4066Sahrens 		}
1772*fa9e4066Sahrens 	}
1773*fa9e4066Sahrens 
1774*fa9e4066Sahrens 	argc -= optind;
1775*fa9e4066Sahrens 	argv += optind;
1776*fa9e4066Sahrens 
1777*fa9e4066Sahrens 	/* get pool name and check number of arguments */
1778*fa9e4066Sahrens 	if (argc < 1) {
1779*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
1780*fa9e4066Sahrens 		usage(FALSE);
1781*fa9e4066Sahrens 	}
1782*fa9e4066Sahrens 
1783*fa9e4066Sahrens 	poolname = argv[0];
1784*fa9e4066Sahrens 
1785*fa9e4066Sahrens 	if (argc < 2) {
1786*fa9e4066Sahrens 		(void) fprintf(stderr,
1787*fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
1788*fa9e4066Sahrens 		usage(FALSE);
1789*fa9e4066Sahrens 	}
1790*fa9e4066Sahrens 
1791*fa9e4066Sahrens 	old_disk = argv[1];
1792*fa9e4066Sahrens 
1793*fa9e4066Sahrens 	if (argc < 3) {
1794*fa9e4066Sahrens 		if (!replacing) {
1795*fa9e4066Sahrens 			(void) fprintf(stderr,
1796*fa9e4066Sahrens 			    gettext("missing <new_device> specification\n"));
1797*fa9e4066Sahrens 			usage(FALSE);
1798*fa9e4066Sahrens 		}
1799*fa9e4066Sahrens 		new_disk = old_disk;
1800*fa9e4066Sahrens 		argc -= 1;
1801*fa9e4066Sahrens 		argv += 1;
1802*fa9e4066Sahrens 	} else {
1803*fa9e4066Sahrens 		new_disk = argv[2];
1804*fa9e4066Sahrens 		argc -= 2;
1805*fa9e4066Sahrens 		argv += 2;
1806*fa9e4066Sahrens 	}
1807*fa9e4066Sahrens 
1808*fa9e4066Sahrens 	if (argc > 1) {
1809*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("too many arguments\n"));
1810*fa9e4066Sahrens 		usage(FALSE);
1811*fa9e4066Sahrens 	}
1812*fa9e4066Sahrens 
1813*fa9e4066Sahrens 	if ((zhp = zpool_open(poolname)) == NULL)
1814*fa9e4066Sahrens 		return (1);
1815*fa9e4066Sahrens 
1816*fa9e4066Sahrens 	if ((config = zpool_get_config(zhp)) == NULL) {
1817*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
1818*fa9e4066Sahrens 		    poolname);
1819*fa9e4066Sahrens 		zpool_close(zhp);
1820*fa9e4066Sahrens 		return (1);
1821*fa9e4066Sahrens 	}
1822*fa9e4066Sahrens 
1823*fa9e4066Sahrens 	nvroot = make_root_vdev(config, force, B_FALSE, argc, argv);
1824*fa9e4066Sahrens 	if (nvroot == NULL) {
1825*fa9e4066Sahrens 		zpool_close(zhp);
1826*fa9e4066Sahrens 		return (1);
1827*fa9e4066Sahrens 	}
1828*fa9e4066Sahrens 
1829*fa9e4066Sahrens 	return (zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing));
1830*fa9e4066Sahrens }
1831*fa9e4066Sahrens 
1832*fa9e4066Sahrens /*
1833*fa9e4066Sahrens  * zpool replace [-f] <pool> <device> <new_device>
1834*fa9e4066Sahrens  *
1835*fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
1836*fa9e4066Sahrens  *
1837*fa9e4066Sahrens  * Replace <device> with <new_device>.
1838*fa9e4066Sahrens  */
1839*fa9e4066Sahrens /* ARGSUSED */
1840*fa9e4066Sahrens int
1841*fa9e4066Sahrens zpool_do_replace(int argc, char **argv)
1842*fa9e4066Sahrens {
1843*fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
1844*fa9e4066Sahrens }
1845*fa9e4066Sahrens 
1846*fa9e4066Sahrens /*
1847*fa9e4066Sahrens  * zpool attach [-f] <pool> <device> <new_device>
1848*fa9e4066Sahrens  *
1849*fa9e4066Sahrens  *	-f	Force attach, even if <new_device> appears to be in use.
1850*fa9e4066Sahrens  *
1851*fa9e4066Sahrens  * Attach <new_device> to the mirror containing <device>.  If <device> is not
1852*fa9e4066Sahrens  * part of a mirror, then <device> will be transformed into a mirror of
1853*fa9e4066Sahrens  * <device> and <new_device>.  In either case, <new_device> will begin life
1854*fa9e4066Sahrens  * with a DTL of [0, now], and will immediately begin to resilver itself.
1855*fa9e4066Sahrens  */
1856*fa9e4066Sahrens int
1857*fa9e4066Sahrens zpool_do_attach(int argc, char **argv)
1858*fa9e4066Sahrens {
1859*fa9e4066Sahrens 	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
1860*fa9e4066Sahrens }
1861*fa9e4066Sahrens 
1862*fa9e4066Sahrens /*
1863*fa9e4066Sahrens  * zpool detach [-f] <pool> <device>
1864*fa9e4066Sahrens  *
1865*fa9e4066Sahrens  *	-f	Force detach of <device>, even if DTLs argue against it
1866*fa9e4066Sahrens  *		(not supported yet)
1867*fa9e4066Sahrens  *
1868*fa9e4066Sahrens  * Detach a device from a mirror.  The operation will be refused if <device>
1869*fa9e4066Sahrens  * is the last device in the mirror, or if the DTLs indicate that this device
1870*fa9e4066Sahrens  * has the only valid copy of some data.
1871*fa9e4066Sahrens  */
1872*fa9e4066Sahrens /* ARGSUSED */
1873*fa9e4066Sahrens int
1874*fa9e4066Sahrens zpool_do_detach(int argc, char **argv)
1875*fa9e4066Sahrens {
1876*fa9e4066Sahrens 	int c;
1877*fa9e4066Sahrens 	char *poolname, *path;
1878*fa9e4066Sahrens 	zpool_handle_t *zhp;
1879*fa9e4066Sahrens 
1880*fa9e4066Sahrens 	/* check options */
1881*fa9e4066Sahrens 	while ((c = getopt(argc, argv, "f")) != -1) {
1882*fa9e4066Sahrens 		switch (c) {
1883*fa9e4066Sahrens 		case 'f':
1884*fa9e4066Sahrens 		case '?':
1885*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1886*fa9e4066Sahrens 			    optopt);
1887*fa9e4066Sahrens 			usage(FALSE);
1888*fa9e4066Sahrens 		}
1889*fa9e4066Sahrens 	}
1890*fa9e4066Sahrens 
1891*fa9e4066Sahrens 	argc -= optind;
1892*fa9e4066Sahrens 	argv += optind;
1893*fa9e4066Sahrens 
1894*fa9e4066Sahrens 	/* get pool name and check number of arguments */
1895*fa9e4066Sahrens 	if (argc < 1) {
1896*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
1897*fa9e4066Sahrens 		usage(FALSE);
1898*fa9e4066Sahrens 	}
1899*fa9e4066Sahrens 
1900*fa9e4066Sahrens 	if (argc < 2) {
1901*fa9e4066Sahrens 		(void) fprintf(stderr,
1902*fa9e4066Sahrens 		    gettext("missing <device> specification\n"));
1903*fa9e4066Sahrens 		usage(FALSE);
1904*fa9e4066Sahrens 	}
1905*fa9e4066Sahrens 
1906*fa9e4066Sahrens 	poolname = argv[0];
1907*fa9e4066Sahrens 	path = argv[1];
1908*fa9e4066Sahrens 
1909*fa9e4066Sahrens 	if ((zhp = zpool_open(poolname)) == NULL)
1910*fa9e4066Sahrens 		return (1);
1911*fa9e4066Sahrens 
1912*fa9e4066Sahrens 	return (zpool_vdev_detach(zhp, path));
1913*fa9e4066Sahrens }
1914*fa9e4066Sahrens 
1915*fa9e4066Sahrens /*
1916*fa9e4066Sahrens  * zpool online [-t] <pool> <device>
1917*fa9e4066Sahrens  *
1918*fa9e4066Sahrens  *	-t	Only bring the device on-line temporarily.  The online
1919*fa9e4066Sahrens  *		state will not be persistent across reboots.
1920*fa9e4066Sahrens  */
1921*fa9e4066Sahrens /* ARGSUSED */
1922*fa9e4066Sahrens int
1923*fa9e4066Sahrens zpool_do_online(int argc, char **argv)
1924*fa9e4066Sahrens {
1925*fa9e4066Sahrens 	int c, i;
1926*fa9e4066Sahrens 	char *poolname;
1927*fa9e4066Sahrens 	zpool_handle_t *zhp;
1928*fa9e4066Sahrens 	int ret = 0;
1929*fa9e4066Sahrens 
1930*fa9e4066Sahrens 	/* check options */
1931*fa9e4066Sahrens 	while ((c = getopt(argc, argv, "t")) != -1) {
1932*fa9e4066Sahrens 		switch (c) {
1933*fa9e4066Sahrens 		case 't':
1934*fa9e4066Sahrens 		case '?':
1935*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1936*fa9e4066Sahrens 			    optopt);
1937*fa9e4066Sahrens 			usage(FALSE);
1938*fa9e4066Sahrens 		}
1939*fa9e4066Sahrens 	}
1940*fa9e4066Sahrens 
1941*fa9e4066Sahrens 	argc -= optind;
1942*fa9e4066Sahrens 	argv += optind;
1943*fa9e4066Sahrens 
1944*fa9e4066Sahrens 	/* get pool name and check number of arguments */
1945*fa9e4066Sahrens 	if (argc < 1) {
1946*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
1947*fa9e4066Sahrens 		usage(FALSE);
1948*fa9e4066Sahrens 	}
1949*fa9e4066Sahrens 	if (argc < 2) {
1950*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
1951*fa9e4066Sahrens 		usage(FALSE);
1952*fa9e4066Sahrens 	}
1953*fa9e4066Sahrens 
1954*fa9e4066Sahrens 	poolname = argv[0];
1955*fa9e4066Sahrens 
1956*fa9e4066Sahrens 	if ((zhp = zpool_open(poolname)) == NULL)
1957*fa9e4066Sahrens 		return (1);
1958*fa9e4066Sahrens 
1959*fa9e4066Sahrens 	for (i = 1; i < argc; i++)
1960*fa9e4066Sahrens 		if (zpool_vdev_online(zhp, argv[i]) == 0)
1961*fa9e4066Sahrens 			(void) printf(gettext("Bringing device %s online\n"),
1962*fa9e4066Sahrens 			    argv[i]);
1963*fa9e4066Sahrens 		else
1964*fa9e4066Sahrens 			ret = 1;
1965*fa9e4066Sahrens 
1966*fa9e4066Sahrens 	return (ret);
1967*fa9e4066Sahrens }
1968*fa9e4066Sahrens 
1969*fa9e4066Sahrens /*
1970*fa9e4066Sahrens  * zpool offline [-ft] <pool> <device>
1971*fa9e4066Sahrens  *
1972*fa9e4066Sahrens  *	-f	Force the device into the offline state, even if doing
1973*fa9e4066Sahrens  *		so would appear to compromise pool availability.
1974*fa9e4066Sahrens  *		(not supported yet)
1975*fa9e4066Sahrens  *
1976*fa9e4066Sahrens  *	-t	Only take the device off-line temporarily.  The offline
1977*fa9e4066Sahrens  *		state will not be persistent across reboots.
1978*fa9e4066Sahrens  *		(not supported yet)
1979*fa9e4066Sahrens  */
1980*fa9e4066Sahrens /* ARGSUSED */
1981*fa9e4066Sahrens int
1982*fa9e4066Sahrens zpool_do_offline(int argc, char **argv)
1983*fa9e4066Sahrens {
1984*fa9e4066Sahrens 	int c, i;
1985*fa9e4066Sahrens 	char *poolname;
1986*fa9e4066Sahrens 	zpool_handle_t *zhp;
1987*fa9e4066Sahrens 	int ret = 0;
1988*fa9e4066Sahrens 
1989*fa9e4066Sahrens 	/* check options */
1990*fa9e4066Sahrens 	while ((c = getopt(argc, argv, "ft")) != -1) {
1991*fa9e4066Sahrens 		switch (c) {
1992*fa9e4066Sahrens 		case 'f':
1993*fa9e4066Sahrens 		case 't':
1994*fa9e4066Sahrens 		case '?':
1995*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1996*fa9e4066Sahrens 			    optopt);
1997*fa9e4066Sahrens 			usage(FALSE);
1998*fa9e4066Sahrens 		}
1999*fa9e4066Sahrens 	}
2000*fa9e4066Sahrens 
2001*fa9e4066Sahrens 	argc -= optind;
2002*fa9e4066Sahrens 	argv += optind;
2003*fa9e4066Sahrens 
2004*fa9e4066Sahrens 	/* get pool name and check number of arguments */
2005*fa9e4066Sahrens 	if (argc < 1) {
2006*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name\n"));
2007*fa9e4066Sahrens 		usage(FALSE);
2008*fa9e4066Sahrens 	}
2009*fa9e4066Sahrens 	if (argc < 2) {
2010*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing device name\n"));
2011*fa9e4066Sahrens 		usage(FALSE);
2012*fa9e4066Sahrens 	}
2013*fa9e4066Sahrens 
2014*fa9e4066Sahrens 	poolname = argv[0];
2015*fa9e4066Sahrens 
2016*fa9e4066Sahrens 	if ((zhp = zpool_open(poolname)) == NULL)
2017*fa9e4066Sahrens 		return (1);
2018*fa9e4066Sahrens 
2019*fa9e4066Sahrens 	for (i = 1; i < argc; i++)
2020*fa9e4066Sahrens 		if (zpool_vdev_offline(zhp, argv[i]) == 0)
2021*fa9e4066Sahrens 			(void) printf(gettext("Bringing device %s offline\n"),
2022*fa9e4066Sahrens 			    argv[i]);
2023*fa9e4066Sahrens 		else
2024*fa9e4066Sahrens 			ret = 1;
2025*fa9e4066Sahrens 
2026*fa9e4066Sahrens 	return (ret);
2027*fa9e4066Sahrens }
2028*fa9e4066Sahrens 
2029*fa9e4066Sahrens typedef struct scrub_cbdata {
2030*fa9e4066Sahrens 	int	cb_type;
2031*fa9e4066Sahrens } scrub_cbdata_t;
2032*fa9e4066Sahrens 
2033*fa9e4066Sahrens int
2034*fa9e4066Sahrens scrub_callback(zpool_handle_t *zhp, void *data)
2035*fa9e4066Sahrens {
2036*fa9e4066Sahrens 	scrub_cbdata_t *cb = data;
2037*fa9e4066Sahrens 
2038*fa9e4066Sahrens 	return (zpool_scrub(zhp, cb->cb_type) != 0);
2039*fa9e4066Sahrens }
2040*fa9e4066Sahrens 
2041*fa9e4066Sahrens /*
2042*fa9e4066Sahrens  * zpool scrub [-s] <pool> ...
2043*fa9e4066Sahrens  *
2044*fa9e4066Sahrens  *	-s	Stop.  Stops any in-progress scrub.
2045*fa9e4066Sahrens  */
2046*fa9e4066Sahrens int
2047*fa9e4066Sahrens zpool_do_scrub(int argc, char **argv)
2048*fa9e4066Sahrens {
2049*fa9e4066Sahrens 	int c;
2050*fa9e4066Sahrens 	scrub_cbdata_t cb;
2051*fa9e4066Sahrens 
2052*fa9e4066Sahrens 	cb.cb_type = POOL_SCRUB_EVERYTHING;
2053*fa9e4066Sahrens 
2054*fa9e4066Sahrens 	/* check options */
2055*fa9e4066Sahrens 	while ((c = getopt(argc, argv, "s")) != -1) {
2056*fa9e4066Sahrens 		switch (c) {
2057*fa9e4066Sahrens 		case 's':
2058*fa9e4066Sahrens 			cb.cb_type = POOL_SCRUB_NONE;
2059*fa9e4066Sahrens 			break;
2060*fa9e4066Sahrens 		case '?':
2061*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2062*fa9e4066Sahrens 			    optopt);
2063*fa9e4066Sahrens 			usage(FALSE);
2064*fa9e4066Sahrens 		}
2065*fa9e4066Sahrens 	}
2066*fa9e4066Sahrens 
2067*fa9e4066Sahrens 	argc -= optind;
2068*fa9e4066Sahrens 	argv += optind;
2069*fa9e4066Sahrens 
2070*fa9e4066Sahrens 	if (argc < 1) {
2071*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing pool name argument\n"));
2072*fa9e4066Sahrens 		usage(FALSE);
2073*fa9e4066Sahrens 	}
2074*fa9e4066Sahrens 
2075*fa9e4066Sahrens 	return (for_each_pool(argc, argv, TRUE, scrub_callback, &cb));
2076*fa9e4066Sahrens }
2077*fa9e4066Sahrens 
2078*fa9e4066Sahrens typedef struct status_cbdata {
2079*fa9e4066Sahrens 	int	cb_verbose;
2080*fa9e4066Sahrens 	int	cb_explain;
2081*fa9e4066Sahrens 	int	cb_count;
2082*fa9e4066Sahrens 	int	cb_first;
2083*fa9e4066Sahrens } status_cbdata_t;
2084*fa9e4066Sahrens 
2085*fa9e4066Sahrens /*
2086*fa9e4066Sahrens  * Print out detailed scrub status.
2087*fa9e4066Sahrens  */
2088*fa9e4066Sahrens void
2089*fa9e4066Sahrens print_scrub_status(nvlist_t *nvroot)
2090*fa9e4066Sahrens {
2091*fa9e4066Sahrens 	vdev_stat_t *vs;
2092*fa9e4066Sahrens 	uint_t vsc;
2093*fa9e4066Sahrens 	time_t start, end, now;
2094*fa9e4066Sahrens 	double fraction_done;
2095*fa9e4066Sahrens 	uint64_t examined, total, minutes_left;
2096*fa9e4066Sahrens 	char *scrub_type;
2097*fa9e4066Sahrens 
2098*fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2099*fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
2100*fa9e4066Sahrens 
2101*fa9e4066Sahrens 	/*
2102*fa9e4066Sahrens 	 * If there's never been a scrub, there's not much to say.
2103*fa9e4066Sahrens 	 */
2104*fa9e4066Sahrens 	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2105*fa9e4066Sahrens 		(void) printf(gettext("none requested\n"));
2106*fa9e4066Sahrens 		return;
2107*fa9e4066Sahrens 	}
2108*fa9e4066Sahrens 
2109*fa9e4066Sahrens 	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2110*fa9e4066Sahrens 	    "resilver" : "scrub";
2111*fa9e4066Sahrens 
2112*fa9e4066Sahrens 	start = vs->vs_scrub_start;
2113*fa9e4066Sahrens 	end = vs->vs_scrub_end;
2114*fa9e4066Sahrens 	now = time(NULL);
2115*fa9e4066Sahrens 	examined = vs->vs_scrub_examined;
2116*fa9e4066Sahrens 	total = vs->vs_alloc;
2117*fa9e4066Sahrens 
2118*fa9e4066Sahrens 	if (end != 0) {
2119*fa9e4066Sahrens 		(void) printf(gettext("%s %s with %llu errors on %s"),
2120*fa9e4066Sahrens 		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
2121*fa9e4066Sahrens 		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2122*fa9e4066Sahrens 		return;
2123*fa9e4066Sahrens 	}
2124*fa9e4066Sahrens 
2125*fa9e4066Sahrens 	if (examined == 0)
2126*fa9e4066Sahrens 		examined = 1;
2127*fa9e4066Sahrens 	if (examined > total)
2128*fa9e4066Sahrens 		total = examined;
2129*fa9e4066Sahrens 
2130*fa9e4066Sahrens 	fraction_done = (double)examined / total;
2131*fa9e4066Sahrens 	minutes_left = (uint64_t)((now - start) *
2132*fa9e4066Sahrens 	    (1 - fraction_done) / fraction_done / 60);
2133*fa9e4066Sahrens 
2134*fa9e4066Sahrens 	(void) printf(gettext("%s in progress, %.2f%% done, %lluh%um to go\n"),
2135*fa9e4066Sahrens 	    scrub_type, 100 * fraction_done,
2136*fa9e4066Sahrens 	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2137*fa9e4066Sahrens }
2138*fa9e4066Sahrens 
2139*fa9e4066Sahrens /*
2140*fa9e4066Sahrens  * Print out configuration state as requested by status_callback.
2141*fa9e4066Sahrens  */
2142*fa9e4066Sahrens void
2143*fa9e4066Sahrens print_status_config(const char *name, nvlist_t *nv, int namewidth, int depth)
2144*fa9e4066Sahrens {
2145*fa9e4066Sahrens 	nvlist_t **child;
2146*fa9e4066Sahrens 	uint_t c, children;
2147*fa9e4066Sahrens 	vdev_stat_t *vs;
2148*fa9e4066Sahrens 	char rbuf[6], wbuf[6], cbuf[6], repaired[6];
2149*fa9e4066Sahrens 
2150*fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2151*fa9e4066Sahrens 	    (uint64_t **)&vs, &c) == 0);
2152*fa9e4066Sahrens 
2153*fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2154*fa9e4066Sahrens 	    &child, &children) != 0)
2155*fa9e4066Sahrens 		children = 0;
2156*fa9e4066Sahrens 
2157*fa9e4066Sahrens 	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
2158*fa9e4066Sahrens 	    name, state_to_name(vs->vs_state));
2159*fa9e4066Sahrens 
2160*fa9e4066Sahrens 	zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
2161*fa9e4066Sahrens 	zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
2162*fa9e4066Sahrens 	zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
2163*fa9e4066Sahrens 	(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
2164*fa9e4066Sahrens 
2165*fa9e4066Sahrens 	if (vs->vs_aux != 0) {
2166*fa9e4066Sahrens 		(void) printf("  ");
2167*fa9e4066Sahrens 
2168*fa9e4066Sahrens 		switch (vs->vs_aux) {
2169*fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
2170*fa9e4066Sahrens 			(void) printf(gettext("cannot open"));
2171*fa9e4066Sahrens 			break;
2172*fa9e4066Sahrens 
2173*fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
2174*fa9e4066Sahrens 			(void) printf(gettext("missing device"));
2175*fa9e4066Sahrens 			break;
2176*fa9e4066Sahrens 
2177*fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
2178*fa9e4066Sahrens 			(void) printf(gettext("insufficient replicas"));
2179*fa9e4066Sahrens 			break;
2180*fa9e4066Sahrens 
2181*fa9e4066Sahrens 		default:
2182*fa9e4066Sahrens 			(void) printf(gettext("corrupted data"));
2183*fa9e4066Sahrens 			break;
2184*fa9e4066Sahrens 		}
2185*fa9e4066Sahrens 	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2186*fa9e4066Sahrens 		/*
2187*fa9e4066Sahrens 		 * Report bytes resilvered/repaired on leaf devices.
2188*fa9e4066Sahrens 		 */
2189*fa9e4066Sahrens 		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2190*fa9e4066Sahrens 		(void) printf(gettext("  %s %s"), repaired,
2191*fa9e4066Sahrens 		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2192*fa9e4066Sahrens 		    "resilvered" : "repaired");
2193*fa9e4066Sahrens 	}
2194*fa9e4066Sahrens 
2195*fa9e4066Sahrens 	(void) printf("\n");
2196*fa9e4066Sahrens 
2197*fa9e4066Sahrens 	for (c = 0; c < children; c++)
2198*fa9e4066Sahrens 		print_status_config(vdev_get_name(child[c]), child[c],
2199*fa9e4066Sahrens 		    namewidth, depth + 2);
2200*fa9e4066Sahrens }
2201*fa9e4066Sahrens 
2202*fa9e4066Sahrens /*
2203*fa9e4066Sahrens  * Display a summary of pool status.  Displays a summary such as:
2204*fa9e4066Sahrens  *
2205*fa9e4066Sahrens  *        pool: tank
2206*fa9e4066Sahrens  *	status: DEGRADED
2207*fa9e4066Sahrens  *	reason: One or more devices ...
2208*fa9e4066Sahrens  *         see: http://www.sun.com/msg/ZFS-xxxx-01
2209*fa9e4066Sahrens  *	config:
2210*fa9e4066Sahrens  *		mirror		DEGRADED
2211*fa9e4066Sahrens  *                c1t0d0	OK
2212*fa9e4066Sahrens  *                c2t0d0	FAULTED
2213*fa9e4066Sahrens  *
2214*fa9e4066Sahrens  * When given the '-v' option, we print out the complete config.  If the '-e'
2215*fa9e4066Sahrens  * option is specified, then we print out error rate information as well.
2216*fa9e4066Sahrens  */
2217*fa9e4066Sahrens int
2218*fa9e4066Sahrens status_callback(zpool_handle_t *zhp, void *data)
2219*fa9e4066Sahrens {
2220*fa9e4066Sahrens 	status_cbdata_t *cbp = data;
2221*fa9e4066Sahrens 	nvlist_t *config, *nvroot;
2222*fa9e4066Sahrens 	char *msgid;
2223*fa9e4066Sahrens 	int reason;
2224*fa9e4066Sahrens 	char *health;
2225*fa9e4066Sahrens 
2226*fa9e4066Sahrens 	config = zpool_get_config(zhp);
2227*fa9e4066Sahrens 	reason = zpool_get_status(zhp, &msgid);
2228*fa9e4066Sahrens 
2229*fa9e4066Sahrens 	cbp->cb_count++;
2230*fa9e4066Sahrens 
2231*fa9e4066Sahrens 	/*
2232*fa9e4066Sahrens 	 * If we were given 'zpool status -x', only report those pools with
2233*fa9e4066Sahrens 	 * problems.
2234*fa9e4066Sahrens 	 */
2235*fa9e4066Sahrens 	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain)
2236*fa9e4066Sahrens 		return (0);
2237*fa9e4066Sahrens 
2238*fa9e4066Sahrens 	if (cbp->cb_first)
2239*fa9e4066Sahrens 		cbp->cb_first = FALSE;
2240*fa9e4066Sahrens 	else
2241*fa9e4066Sahrens 		(void) printf("\n");
2242*fa9e4066Sahrens 
2243*fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_HEALTH,
2244*fa9e4066Sahrens 	    &health) == 0);
2245*fa9e4066Sahrens 
2246*fa9e4066Sahrens 	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
2247*fa9e4066Sahrens 	(void) printf(gettext(" state: %s\n"), health);
2248*fa9e4066Sahrens 
2249*fa9e4066Sahrens 	switch (reason) {
2250*fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_R:
2251*fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2252*fa9e4066Sahrens 		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
2253*fa9e4066Sahrens 		    "continue functioning in a degraded state.\n"));
2254*fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2255*fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2256*fa9e4066Sahrens 		break;
2257*fa9e4066Sahrens 
2258*fa9e4066Sahrens 	case ZPOOL_STATUS_MISSING_DEV_NR:
2259*fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2260*fa9e4066Sahrens 		    "be opened.  There are insufficient\n\treplicas for the "
2261*fa9e4066Sahrens 		    "pool to continue functioning.\n"));
2262*fa9e4066Sahrens 		(void) printf(gettext("action: Attach the missing device and "
2263*fa9e4066Sahrens 		    "online it using 'zpool online'.\n"));
2264*fa9e4066Sahrens 		break;
2265*fa9e4066Sahrens 
2266*fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_R:
2267*fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2268*fa9e4066Sahrens 		    "be used because the label is missing or\n\tinvalid.  "
2269*fa9e4066Sahrens 		    "Sufficient replicas exist for the pool to continue\n\t"
2270*fa9e4066Sahrens 		    "functioning in a degraded state.\n"));
2271*fa9e4066Sahrens 		(void) printf(gettext("action: Replace the device using "
2272*fa9e4066Sahrens 		    "'zpool replace'.\n"));
2273*fa9e4066Sahrens 		break;
2274*fa9e4066Sahrens 
2275*fa9e4066Sahrens 	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
2276*fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices could not "
2277*fa9e4066Sahrens 		    "be used because the the label is missing \n\tor invalid.  "
2278*fa9e4066Sahrens 		    "There are insufficient replicas for the pool to "
2279*fa9e4066Sahrens 		    "continue\n\tfunctioning.\n"));
2280*fa9e4066Sahrens 		(void) printf(gettext("action: Destroy and re-create the pool "
2281*fa9e4066Sahrens 		    "from a backup source.\n"));
2282*fa9e4066Sahrens 		break;
2283*fa9e4066Sahrens 
2284*fa9e4066Sahrens 	case ZPOOL_STATUS_FAILING_DEV:
2285*fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
2286*fa9e4066Sahrens 		    "experienced an unrecoverable error.  An\n\tattempt was "
2287*fa9e4066Sahrens 		    "made to correct the error.  Applications are "
2288*fa9e4066Sahrens 		    "unaffected.\n"));
2289*fa9e4066Sahrens 		(void) printf(gettext("action: Determine if the device needs "
2290*fa9e4066Sahrens 		    "to be replaced, and clear the errors\n\tusing "
2291*fa9e4066Sahrens 		    "'zpool online' or replace the device with 'zpool "
2292*fa9e4066Sahrens 		    "replace'.\n"));
2293*fa9e4066Sahrens 		break;
2294*fa9e4066Sahrens 
2295*fa9e4066Sahrens 	case ZPOOL_STATUS_OFFLINE_DEV:
2296*fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices has "
2297*fa9e4066Sahrens 		    "been taken offline by the adminstrator.\n\tSufficient "
2298*fa9e4066Sahrens 		    "replicas exist for the pool to continue functioning in "
2299*fa9e4066Sahrens 		    "a\n\tdegraded state.\n"));
2300*fa9e4066Sahrens 		(void) printf(gettext("action: Online the device using "
2301*fa9e4066Sahrens 		    "'zpool online' or replace the device with\n\t'zpool "
2302*fa9e4066Sahrens 		    "replace'.\n"));
2303*fa9e4066Sahrens 		break;
2304*fa9e4066Sahrens 
2305*fa9e4066Sahrens 	case ZPOOL_STATUS_RESILVERING:
2306*fa9e4066Sahrens 		(void) printf(gettext("status: One or more devices is "
2307*fa9e4066Sahrens 		    "currently being resilvered.  The pool will\n\tcontinue "
2308*fa9e4066Sahrens 		    "to function, possibly in a degraded state.\n"));
2309*fa9e4066Sahrens 		(void) printf(gettext("action: Wait for the resilver to "
2310*fa9e4066Sahrens 		    "complete.\n"));
2311*fa9e4066Sahrens 		break;
2312*fa9e4066Sahrens 
2313*fa9e4066Sahrens 	default:
2314*fa9e4066Sahrens 		/*
2315*fa9e4066Sahrens 		 * The remaining errors can't actually be generated, yet.
2316*fa9e4066Sahrens 		 */
2317*fa9e4066Sahrens 		assert(reason == ZPOOL_STATUS_OK);
2318*fa9e4066Sahrens 	}
2319*fa9e4066Sahrens 
2320*fa9e4066Sahrens 	if (msgid != NULL)
2321*fa9e4066Sahrens 		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
2322*fa9e4066Sahrens 		    msgid);
2323*fa9e4066Sahrens 
2324*fa9e4066Sahrens 	if (config != NULL) {
2325*fa9e4066Sahrens 		int namewidth;
2326*fa9e4066Sahrens 
2327*fa9e4066Sahrens 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2328*fa9e4066Sahrens 		    &nvroot) == 0);
2329*fa9e4066Sahrens 
2330*fa9e4066Sahrens 		(void) printf(gettext(" scrub: "));
2331*fa9e4066Sahrens 		print_scrub_status(nvroot);
2332*fa9e4066Sahrens 
2333*fa9e4066Sahrens 		namewidth = max_width(nvroot, 0, 0);
2334*fa9e4066Sahrens 		if (namewidth < 10)
2335*fa9e4066Sahrens 			namewidth = 10;
2336*fa9e4066Sahrens 
2337*fa9e4066Sahrens 		(void) printf(gettext("config:\n\n"));
2338*fa9e4066Sahrens 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
2339*fa9e4066Sahrens 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
2340*fa9e4066Sahrens 		print_status_config(zpool_get_name(zhp), nvroot, namewidth, 0);
2341*fa9e4066Sahrens 	} else {
2342*fa9e4066Sahrens 		(void) printf(gettext("config: The configuration cannot be "
2343*fa9e4066Sahrens 		    "determined.\n"));
2344*fa9e4066Sahrens 	}
2345*fa9e4066Sahrens 
2346*fa9e4066Sahrens 	return (0);
2347*fa9e4066Sahrens }
2348*fa9e4066Sahrens 
2349*fa9e4066Sahrens /*
2350*fa9e4066Sahrens  * zpool status [-vx] [pool] ...
2351*fa9e4066Sahrens  *
2352*fa9e4066Sahrens  *	-v	Display complete error logs
2353*fa9e4066Sahrens  *	-x	Display only pools with potential problems
2354*fa9e4066Sahrens  *
2355*fa9e4066Sahrens  * Describes the health status of all pools or some subset.
2356*fa9e4066Sahrens  */
2357*fa9e4066Sahrens int
2358*fa9e4066Sahrens zpool_do_status(int argc, char **argv)
2359*fa9e4066Sahrens {
2360*fa9e4066Sahrens 	int c;
2361*fa9e4066Sahrens 	int ret;
2362*fa9e4066Sahrens 	status_cbdata_t cb = { 0 };
2363*fa9e4066Sahrens 
2364*fa9e4066Sahrens 	/* check options */
2365*fa9e4066Sahrens 	while ((c = getopt(argc, argv, "vx")) != -1) {
2366*fa9e4066Sahrens 		switch (c) {
2367*fa9e4066Sahrens 		case 'v':
2368*fa9e4066Sahrens 			cb.cb_verbose = TRUE;
2369*fa9e4066Sahrens 			break;
2370*fa9e4066Sahrens 		case 'x':
2371*fa9e4066Sahrens 			cb.cb_explain = TRUE;
2372*fa9e4066Sahrens 			break;
2373*fa9e4066Sahrens 		case '?':
2374*fa9e4066Sahrens 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2375*fa9e4066Sahrens 			    optopt);
2376*fa9e4066Sahrens 			usage(FALSE);
2377*fa9e4066Sahrens 		}
2378*fa9e4066Sahrens 	}
2379*fa9e4066Sahrens 
2380*fa9e4066Sahrens 	argc -= optind;
2381*fa9e4066Sahrens 	argv += optind;
2382*fa9e4066Sahrens 
2383*fa9e4066Sahrens 	cb.cb_first = TRUE;
2384*fa9e4066Sahrens 
2385*fa9e4066Sahrens 	ret = for_each_pool(argc, argv, TRUE, status_callback, &cb);
2386*fa9e4066Sahrens 
2387*fa9e4066Sahrens 	if (argc == 0 && cb.cb_count == 0)
2388*fa9e4066Sahrens 		(void) printf(gettext("no pools available\n"));
2389*fa9e4066Sahrens 	else if (cb.cb_explain && cb.cb_first) {
2390*fa9e4066Sahrens 		if (argc == 0) {
2391*fa9e4066Sahrens 			(void) printf(gettext("all pools are healthy\n"));
2392*fa9e4066Sahrens 		} else {
2393*fa9e4066Sahrens 			int i;
2394*fa9e4066Sahrens 			for (i = 0; i < argc; i++)
2395*fa9e4066Sahrens 				(void) printf(gettext("pool '%s' is healthy\n"),
2396*fa9e4066Sahrens 				    argv[i]);
2397*fa9e4066Sahrens 		}
2398*fa9e4066Sahrens 	}
2399*fa9e4066Sahrens 
2400*fa9e4066Sahrens 	return (ret);
2401*fa9e4066Sahrens }
2402*fa9e4066Sahrens 
2403*fa9e4066Sahrens int
2404*fa9e4066Sahrens main(int argc, char **argv)
2405*fa9e4066Sahrens {
2406*fa9e4066Sahrens 	int ret;
2407*fa9e4066Sahrens 	int i;
2408*fa9e4066Sahrens 	char *cmdname;
2409*fa9e4066Sahrens 
2410*fa9e4066Sahrens 	(void) setlocale(LC_ALL, "");
2411*fa9e4066Sahrens 	(void) textdomain(TEXT_DOMAIN);
2412*fa9e4066Sahrens 
2413*fa9e4066Sahrens 	opterr = 0;
2414*fa9e4066Sahrens 
2415*fa9e4066Sahrens 	/*
2416*fa9e4066Sahrens 	 * Make sure the user has specified some command.
2417*fa9e4066Sahrens 	 */
2418*fa9e4066Sahrens 	if (argc < 2) {
2419*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("missing command\n"));
2420*fa9e4066Sahrens 		usage(FALSE);
2421*fa9e4066Sahrens 	}
2422*fa9e4066Sahrens 
2423*fa9e4066Sahrens 	cmdname = argv[1];
2424*fa9e4066Sahrens 
2425*fa9e4066Sahrens 	/*
2426*fa9e4066Sahrens 	 * Special case '-?'
2427*fa9e4066Sahrens 	 */
2428*fa9e4066Sahrens 	if (strcmp(cmdname, "-?") == 0)
2429*fa9e4066Sahrens 		usage(TRUE);
2430*fa9e4066Sahrens 
2431*fa9e4066Sahrens 	/*
2432*fa9e4066Sahrens 	 * Run the appropriate command.
2433*fa9e4066Sahrens 	 */
2434*fa9e4066Sahrens 	for (i = 0; i < NCOMMAND; i++) {
2435*fa9e4066Sahrens 		if (command_table[i].name == NULL)
2436*fa9e4066Sahrens 			continue;
2437*fa9e4066Sahrens 
2438*fa9e4066Sahrens 		if (strcmp(cmdname, command_table[i].name) == 0) {
2439*fa9e4066Sahrens 			current_command = &command_table[i];
2440*fa9e4066Sahrens 			ret = command_table[i].func(argc - 1, argv + 1);
2441*fa9e4066Sahrens 			break;
2442*fa9e4066Sahrens 		}
2443*fa9e4066Sahrens 	}
2444*fa9e4066Sahrens 
2445*fa9e4066Sahrens 	/*
2446*fa9e4066Sahrens 	 * 'freeze' is a vile debugging abomination, so we treat it as such.
2447*fa9e4066Sahrens 	 */
2448*fa9e4066Sahrens 	if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
2449*fa9e4066Sahrens 		char buf[8192];
2450*fa9e4066Sahrens 		int fd = open("/dev/zpoolctl", O_RDWR);
2451*fa9e4066Sahrens 		(void) strcpy((void *)buf, argv[2]);
2452*fa9e4066Sahrens 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
2453*fa9e4066Sahrens 	}
2454*fa9e4066Sahrens 
2455*fa9e4066Sahrens 	if (i == NCOMMAND) {
2456*fa9e4066Sahrens 		(void) fprintf(stderr, gettext("unrecognized "
2457*fa9e4066Sahrens 		    "command '%s'\n"), cmdname);
2458*fa9e4066Sahrens 		usage(FALSE);
2459*fa9e4066Sahrens 	}
2460*fa9e4066Sahrens 
2461*fa9e4066Sahrens 	/*
2462*fa9e4066Sahrens 	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
2463*fa9e4066Sahrens 	 * for the purposes of running ::findleaks.
2464*fa9e4066Sahrens 	 */
2465*fa9e4066Sahrens 	if (getenv("ZFS_ABORT") != NULL) {
2466*fa9e4066Sahrens 		(void) printf("dumping core by request\n");
2467*fa9e4066Sahrens 		abort();
2468*fa9e4066Sahrens 	}
2469*fa9e4066Sahrens 
2470*fa9e4066Sahrens 	return (ret);
2471*fa9e4066Sahrens }
2472