zpool_main.c revision 236155
1168404Spjd/*
2168404Spjd * CDDL HEADER START
3168404Spjd *
4168404Spjd * The contents of this file are subject to the terms of the
5168404Spjd * Common Development and Distribution License (the "License").
6168404Spjd * You may not use this file except in compliance with the License.
7168404Spjd *
8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9168404Spjd * or http://www.opensolaris.org/os/licensing.
10168404Spjd * See the License for the specific language governing permissions
11168404Spjd * and limitations under the License.
12168404Spjd *
13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each
14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15168404Spjd * If applicable, add the following below this CDDL HEADER, with the
16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying
17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner]
18168404Spjd *
19168404Spjd * CDDL HEADER END
20168404Spjd */
21168404Spjd
22168404Spjd/*
23219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24227497Smm * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
25236155Smm * Copyright (c) 2012 by Delphix. All rights reserved.
26236145Smm * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
27236155Smm * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
28168404Spjd */
29168404Spjd
30168404Spjd#include <solaris.h>
31168404Spjd#include <assert.h>
32168404Spjd#include <ctype.h>
33168404Spjd#include <dirent.h>
34168404Spjd#include <errno.h>
35168404Spjd#include <fcntl.h>
36168404Spjd#include <libgen.h>
37168404Spjd#include <libintl.h>
38168404Spjd#include <libuutil.h>
39168404Spjd#include <locale.h>
40168404Spjd#include <stdio.h>
41168404Spjd#include <stdlib.h>
42168404Spjd#include <string.h>
43168404Spjd#include <strings.h>
44168404Spjd#include <unistd.h>
45168404Spjd#include <priv.h>
46185029Spjd#include <pwd.h>
47185029Spjd#include <zone.h>
48168404Spjd#include <sys/time.h>
49236155Smm#include <zfs_prop.h>
50168404Spjd#include <sys/fs/zfs.h>
51168404Spjd#include <sys/stat.h>
52168404Spjd
53168404Spjd#include <libzfs.h>
54168404Spjd
55168404Spjd#include "zpool_util.h"
56185029Spjd#include "zfs_comutil.h"
57168404Spjd
58219089Spjd#include "statcommon.h"
59219089Spjd
60168404Spjdstatic int zpool_do_create(int, char **);
61168404Spjdstatic int zpool_do_destroy(int, char **);
62168404Spjd
63168404Spjdstatic int zpool_do_add(int, char **);
64168404Spjdstatic int zpool_do_remove(int, char **);
65224171Sgibbsstatic int zpool_do_labelclear(int, char **);
66168404Spjd
67168404Spjdstatic int zpool_do_list(int, char **);
68168404Spjdstatic int zpool_do_iostat(int, char **);
69168404Spjdstatic int zpool_do_status(int, char **);
70168404Spjd
71168404Spjdstatic int zpool_do_online(int, char **);
72168404Spjdstatic int zpool_do_offline(int, char **);
73168404Spjdstatic int zpool_do_clear(int, char **);
74236155Smmstatic int zpool_do_reopen(int, char **);
75168404Spjd
76228103Smmstatic int zpool_do_reguid(int, char **);
77228103Smm
78168404Spjdstatic int zpool_do_attach(int, char **);
79168404Spjdstatic int zpool_do_detach(int, char **);
80168404Spjdstatic int zpool_do_replace(int, char **);
81219089Spjdstatic int zpool_do_split(int, char **);
82168404Spjd
83168404Spjdstatic int zpool_do_scrub(int, char **);
84168404Spjd
85168404Spjdstatic int zpool_do_import(int, char **);
86168404Spjdstatic int zpool_do_export(int, char **);
87168404Spjd
88168404Spjdstatic int zpool_do_upgrade(int, char **);
89168404Spjd
90168404Spjdstatic int zpool_do_history(int, char **);
91168404Spjd
92168404Spjdstatic int zpool_do_get(int, char **);
93168404Spjdstatic int zpool_do_set(int, char **);
94168404Spjd
95168404Spjd/*
96168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's
97168404Spjd * debugging facilities.
98168404Spjd */
99185029Spjd
100185029Spjd#ifdef DEBUG
101168404Spjdconst char *
102168404Spjd_umem_debug_init(void)
103168404Spjd{
104168404Spjd	return ("default,verbose"); /* $UMEM_DEBUG setting */
105168404Spjd}
106168404Spjd
107168404Spjdconst char *
108168404Spjd_umem_logging_init(void)
109168404Spjd{
110168404Spjd	return ("fail,contents"); /* $UMEM_LOGGING setting */
111168404Spjd}
112185029Spjd#endif
113168404Spjd
114168404Spjdtypedef enum {
115168404Spjd	HELP_ADD,
116168404Spjd	HELP_ATTACH,
117168404Spjd	HELP_CLEAR,
118168404Spjd	HELP_CREATE,
119168404Spjd	HELP_DESTROY,
120168404Spjd	HELP_DETACH,
121168404Spjd	HELP_EXPORT,
122168404Spjd	HELP_HISTORY,
123168404Spjd	HELP_IMPORT,
124168404Spjd	HELP_IOSTAT,
125224171Sgibbs	HELP_LABELCLEAR,
126168404Spjd	HELP_LIST,
127168404Spjd	HELP_OFFLINE,
128168404Spjd	HELP_ONLINE,
129168404Spjd	HELP_REPLACE,
130168404Spjd	HELP_REMOVE,
131168404Spjd	HELP_SCRUB,
132168404Spjd	HELP_STATUS,
133168404Spjd	HELP_UPGRADE,
134168404Spjd	HELP_GET,
135219089Spjd	HELP_SET,
136228103Smm	HELP_SPLIT,
137236155Smm	HELP_REGUID,
138236155Smm	HELP_REOPEN
139168404Spjd} zpool_help_t;
140168404Spjd
141168404Spjd
142168404Spjdtypedef struct zpool_command {
143168404Spjd	const char	*name;
144168404Spjd	int		(*func)(int, char **);
145168404Spjd	zpool_help_t	usage;
146168404Spjd} zpool_command_t;
147168404Spjd
148168404Spjd/*
149168404Spjd * Master command table.  Each ZFS command has a name, associated function, and
150168404Spjd * usage message.  The usage messages need to be internationalized, so we have
151168404Spjd * to have a function to return the usage message based on a command index.
152168404Spjd *
153168404Spjd * These commands are organized according to how they are displayed in the usage
154168404Spjd * message.  An empty command (one with a NULL name) indicates an empty line in
155168404Spjd * the generic usage message.
156168404Spjd */
157168404Spjdstatic zpool_command_t command_table[] = {
158168404Spjd	{ "create",	zpool_do_create,	HELP_CREATE		},
159168404Spjd	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
160168404Spjd	{ NULL },
161168404Spjd	{ "add",	zpool_do_add,		HELP_ADD		},
162168404Spjd	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
163168404Spjd	{ NULL },
164224171Sgibbs	{ "labelclear",	zpool_do_labelclear,	HELP_LABELCLEAR		},
165224171Sgibbs	{ NULL },
166168404Spjd	{ "list",	zpool_do_list,		HELP_LIST		},
167168404Spjd	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
168168404Spjd	{ "status",	zpool_do_status,	HELP_STATUS		},
169168404Spjd	{ NULL },
170168404Spjd	{ "online",	zpool_do_online,	HELP_ONLINE		},
171168404Spjd	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
172168404Spjd	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
173236155Smm	{ "reopen",	zpool_do_reopen,	HELP_REOPEN		},
174168404Spjd	{ NULL },
175168404Spjd	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
176168404Spjd	{ "detach",	zpool_do_detach,	HELP_DETACH		},
177168404Spjd	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
178219089Spjd	{ "split",	zpool_do_split,		HELP_SPLIT		},
179168404Spjd	{ NULL },
180168404Spjd	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
181168404Spjd	{ NULL },
182168404Spjd	{ "import",	zpool_do_import,	HELP_IMPORT		},
183168404Spjd	{ "export",	zpool_do_export,	HELP_EXPORT		},
184168404Spjd	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
185228103Smm	{ "reguid",	zpool_do_reguid,	HELP_REGUID		},
186168404Spjd	{ NULL },
187168404Spjd	{ "history",	zpool_do_history,	HELP_HISTORY		},
188168404Spjd	{ "get",	zpool_do_get,		HELP_GET		},
189168404Spjd	{ "set",	zpool_do_set,		HELP_SET		},
190168404Spjd};
191168404Spjd
192168404Spjd#define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
193168404Spjd
194168404Spjdzpool_command_t *current_command;
195185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN];
196168404Spjd
197219089Spjdstatic uint_t timestamp_fmt = NODATE;
198219089Spjd
199168404Spjdstatic const char *
200168404Spjdget_usage(zpool_help_t idx) {
201168404Spjd	switch (idx) {
202168404Spjd	case HELP_ADD:
203168404Spjd		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
204168404Spjd	case HELP_ATTACH:
205168404Spjd		return (gettext("\tattach [-f] <pool> <device> "
206185029Spjd		    "<new-device>\n"));
207168404Spjd	case HELP_CLEAR:
208219089Spjd		return (gettext("\tclear [-nF] <pool> [device]\n"));
209168404Spjd	case HELP_CREATE:
210185029Spjd		return (gettext("\tcreate [-fn] [-o property=value] ... \n"
211185029Spjd		    "\t    [-O file-system-property=value] ... \n"
212185029Spjd		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
213168404Spjd	case HELP_DESTROY:
214168404Spjd		return (gettext("\tdestroy [-f] <pool>\n"));
215168404Spjd	case HELP_DETACH:
216168404Spjd		return (gettext("\tdetach <pool> <device>\n"));
217168404Spjd	case HELP_EXPORT:
218168404Spjd		return (gettext("\texport [-f] <pool> ...\n"));
219168404Spjd	case HELP_HISTORY:
220185029Spjd		return (gettext("\thistory [-il] [<pool>] ...\n"));
221168404Spjd	case HELP_IMPORT:
222168404Spjd		return (gettext("\timport [-d dir] [-D]\n"
223219089Spjd		    "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n"
224185029Spjd		    "\timport [-o mntopts] [-o property=value] ... \n"
225219089Spjd		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
226219089Spjd		    "[-R root] [-F [-n]] -a\n"
227185029Spjd		    "\timport [-o mntopts] [-o property=value] ... \n"
228219089Spjd		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
229219089Spjd		    "[-R root] [-F [-n]]\n"
230219089Spjd		    "\t    <pool | id> [newpool]\n"));
231168404Spjd	case HELP_IOSTAT:
232219089Spjd		return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
233168404Spjd		    "[count]]\n"));
234224171Sgibbs	case HELP_LABELCLEAR:
235224171Sgibbs		return (gettext("\tlabelclear [-f] <vdev>\n"));
236168404Spjd	case HELP_LIST:
237185029Spjd		return (gettext("\tlist [-H] [-o property[,...]] "
238219089Spjd		    "[-T d|u] [pool] ... [interval [count]]\n"));
239168404Spjd	case HELP_OFFLINE:
240168404Spjd		return (gettext("\toffline [-t] <pool> <device> ...\n"));
241168404Spjd	case HELP_ONLINE:
242228020Smm		return (gettext("\tonline [-e] <pool> <device> ...\n"));
243168404Spjd	case HELP_REPLACE:
244168404Spjd		return (gettext("\treplace [-f] <pool> <device> "
245185029Spjd		    "[new-device]\n"));
246168404Spjd	case HELP_REMOVE:
247185029Spjd		return (gettext("\tremove <pool> <device> ...\n"));
248236155Smm	case HELP_REOPEN:
249236155Smm		return (""); /* Undocumented command */
250168404Spjd	case HELP_SCRUB:
251168404Spjd		return (gettext("\tscrub [-s] <pool> ...\n"));
252168404Spjd	case HELP_STATUS:
253219089Spjd		return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
254219089Spjd		    "[count]]\n"));
255168404Spjd	case HELP_UPGRADE:
256228020Smm		return (gettext("\tupgrade [-v]\n"
257185029Spjd		    "\tupgrade [-V version] <-a | pool ...>\n"));
258168404Spjd	case HELP_GET:
259185029Spjd		return (gettext("\tget <\"all\" | property[,...]> "
260168404Spjd		    "<pool> ...\n"));
261168404Spjd	case HELP_SET:
262168404Spjd		return (gettext("\tset <property=value> <pool> \n"));
263219089Spjd	case HELP_SPLIT:
264219089Spjd		return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
265219089Spjd		    "\t    [-o property=value] <pool> <newpool> "
266219089Spjd		    "[<device> ...]\n"));
267228103Smm	case HELP_REGUID:
268228103Smm		return (gettext("\treguid <pool>\n"));
269168404Spjd	}
270168404Spjd
271168404Spjd	abort();
272168404Spjd	/* NOTREACHED */
273168404Spjd}
274168404Spjd
275168404Spjd
276168404Spjd/*
277168404Spjd * Callback routine that will print out a pool property value.
278168404Spjd */
279185029Spjdstatic int
280185029Spjdprint_prop_cb(int prop, void *cb)
281168404Spjd{
282168404Spjd	FILE *fp = cb;
283168404Spjd
284219089Spjd	(void) fprintf(fp, "\t%-15s  ", zpool_prop_to_name(prop));
285168404Spjd
286185029Spjd	if (zpool_prop_readonly(prop))
287185029Spjd		(void) fprintf(fp, "  NO   ");
288185029Spjd	else
289219089Spjd		(void) fprintf(fp, " YES   ");
290185029Spjd
291168404Spjd	if (zpool_prop_values(prop) == NULL)
292168404Spjd		(void) fprintf(fp, "-\n");
293168404Spjd	else
294168404Spjd		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
295168404Spjd
296185029Spjd	return (ZPROP_CONT);
297168404Spjd}
298168404Spjd
299168404Spjd/*
300168404Spjd * Display usage message.  If we're inside a command, display only the usage for
301168404Spjd * that command.  Otherwise, iterate over the entire command table and display
302168404Spjd * a complete usage message.
303168404Spjd */
304168404Spjdvoid
305168404Spjdusage(boolean_t requested)
306168404Spjd{
307168404Spjd	FILE *fp = requested ? stdout : stderr;
308168404Spjd
309168404Spjd	if (current_command == NULL) {
310168404Spjd		int i;
311168404Spjd
312168404Spjd		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
313168404Spjd		(void) fprintf(fp,
314168404Spjd		    gettext("where 'command' is one of the following:\n\n"));
315168404Spjd
316168404Spjd		for (i = 0; i < NCOMMAND; i++) {
317168404Spjd			if (command_table[i].name == NULL)
318168404Spjd				(void) fprintf(fp, "\n");
319168404Spjd			else
320168404Spjd				(void) fprintf(fp, "%s",
321168404Spjd				    get_usage(command_table[i].usage));
322168404Spjd		}
323168404Spjd	} else {
324168404Spjd		(void) fprintf(fp, gettext("usage:\n"));
325168404Spjd		(void) fprintf(fp, "%s", get_usage(current_command->usage));
326168404Spjd	}
327168404Spjd
328168404Spjd	if (current_command != NULL &&
329168404Spjd	    ((strcmp(current_command->name, "set") == 0) ||
330185029Spjd	    (strcmp(current_command->name, "get") == 0) ||
331185029Spjd	    (strcmp(current_command->name, "list") == 0))) {
332168404Spjd
333168404Spjd		(void) fprintf(fp,
334168404Spjd		    gettext("\nthe following properties are supported:\n"));
335168404Spjd
336219089Spjd		(void) fprintf(fp, "\n\t%-15s  %s   %s\n\n",
337185029Spjd		    "PROPERTY", "EDIT", "VALUES");
338168404Spjd
339168404Spjd		/* Iterate over all properties */
340185029Spjd		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
341185029Spjd		    ZFS_TYPE_POOL);
342168404Spjd	}
343168404Spjd
344168404Spjd	/*
345168404Spjd	 * See comments at end of main().
346168404Spjd	 */
347168404Spjd	if (getenv("ZFS_ABORT") != NULL) {
348168404Spjd		(void) printf("dumping core by request\n");
349168404Spjd		abort();
350168404Spjd	}
351168404Spjd
352168404Spjd	exit(requested ? 0 : 2);
353168404Spjd}
354168404Spjd
355168404Spjdvoid
356185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
357185029Spjd    boolean_t print_logs)
358168404Spjd{
359168404Spjd	nvlist_t **child;
360168404Spjd	uint_t c, children;
361168404Spjd	char *vname;
362168404Spjd
363168404Spjd	if (name != NULL)
364168404Spjd		(void) printf("\t%*s%s\n", indent, "", name);
365168404Spjd
366168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
367168404Spjd	    &child, &children) != 0)
368168404Spjd		return;
369168404Spjd
370168404Spjd	for (c = 0; c < children; c++) {
371185029Spjd		uint64_t is_log = B_FALSE;
372185029Spjd
373185029Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
374185029Spjd		    &is_log);
375185029Spjd		if ((is_log && !print_logs) || (!is_log && print_logs))
376185029Spjd			continue;
377185029Spjd
378219089Spjd		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
379185029Spjd		print_vdev_tree(zhp, vname, child[c], indent + 2,
380185029Spjd		    B_FALSE);
381168404Spjd		free(vname);
382168404Spjd	}
383168404Spjd}
384168404Spjd
385168404Spjd/*
386185029Spjd * Add a property pair (name, string-value) into a property nvlist.
387185029Spjd */
388185029Spjdstatic int
389185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props,
390185029Spjd    boolean_t poolprop)
391185029Spjd{
392185029Spjd	zpool_prop_t prop = ZPROP_INVAL;
393185029Spjd	zfs_prop_t fprop;
394185029Spjd	nvlist_t *proplist;
395185029Spjd	const char *normnm;
396185029Spjd	char *strval;
397185029Spjd
398185029Spjd	if (*props == NULL &&
399185029Spjd	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
400185029Spjd		(void) fprintf(stderr,
401185029Spjd		    gettext("internal error: out of memory\n"));
402185029Spjd		return (1);
403185029Spjd	}
404185029Spjd
405185029Spjd	proplist = *props;
406185029Spjd
407185029Spjd	if (poolprop) {
408185029Spjd		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
409185029Spjd			(void) fprintf(stderr, gettext("property '%s' is "
410185029Spjd			    "not a valid pool property\n"), propname);
411185029Spjd			return (2);
412185029Spjd		}
413185029Spjd		normnm = zpool_prop_to_name(prop);
414185029Spjd	} else {
415209962Smm		if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
416209962Smm			normnm = zfs_prop_to_name(fprop);
417209962Smm		} else {
418209962Smm			normnm = propname;
419185029Spjd		}
420185029Spjd	}
421185029Spjd
422185029Spjd	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
423185029Spjd	    prop != ZPOOL_PROP_CACHEFILE) {
424185029Spjd		(void) fprintf(stderr, gettext("property '%s' "
425185029Spjd		    "specified multiple times\n"), propname);
426185029Spjd		return (2);
427185029Spjd	}
428185029Spjd
429185029Spjd	if (nvlist_add_string(proplist, normnm, propval) != 0) {
430185029Spjd		(void) fprintf(stderr, gettext("internal "
431185029Spjd		    "error: out of memory\n"));
432185029Spjd		return (1);
433185029Spjd	}
434185029Spjd
435185029Spjd	return (0);
436185029Spjd}
437185029Spjd
438185029Spjd/*
439168404Spjd * zpool add [-fn] <pool> <vdev> ...
440168404Spjd *
441168404Spjd *	-f	Force addition of devices, even if they appear in use
442168404Spjd *	-n	Do not add the devices, but display the resulting layout if
443168404Spjd *		they were to be added.
444168404Spjd *
445168404Spjd * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
446168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
447168404Spjd * libzfs.
448168404Spjd */
449168404Spjdint
450168404Spjdzpool_do_add(int argc, char **argv)
451168404Spjd{
452168404Spjd	boolean_t force = B_FALSE;
453168404Spjd	boolean_t dryrun = B_FALSE;
454168404Spjd	int c;
455168404Spjd	nvlist_t *nvroot;
456168404Spjd	char *poolname;
457168404Spjd	int ret;
458168404Spjd	zpool_handle_t *zhp;
459168404Spjd	nvlist_t *config;
460168404Spjd
461168404Spjd	/* check options */
462168404Spjd	while ((c = getopt(argc, argv, "fn")) != -1) {
463168404Spjd		switch (c) {
464168404Spjd		case 'f':
465168404Spjd			force = B_TRUE;
466168404Spjd			break;
467168404Spjd		case 'n':
468168404Spjd			dryrun = B_TRUE;
469168404Spjd			break;
470168404Spjd		case '?':
471168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
472168404Spjd			    optopt);
473168404Spjd			usage(B_FALSE);
474168404Spjd		}
475168404Spjd	}
476168404Spjd
477168404Spjd	argc -= optind;
478168404Spjd	argv += optind;
479168404Spjd
480168404Spjd	/* get pool name and check number of arguments */
481168404Spjd	if (argc < 1) {
482168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
483168404Spjd		usage(B_FALSE);
484168404Spjd	}
485168404Spjd	if (argc < 2) {
486168404Spjd		(void) fprintf(stderr, gettext("missing vdev specification\n"));
487168404Spjd		usage(B_FALSE);
488168404Spjd	}
489168404Spjd
490168404Spjd	poolname = argv[0];
491168404Spjd
492168404Spjd	argc--;
493168404Spjd	argv++;
494168404Spjd
495168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
496168404Spjd		return (1);
497168404Spjd
498168404Spjd	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
499168404Spjd		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
500168404Spjd		    poolname);
501168404Spjd		zpool_close(zhp);
502168404Spjd		return (1);
503168404Spjd	}
504168404Spjd
505168404Spjd	/* pass off to get_vdev_spec for processing */
506185029Spjd	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
507185029Spjd	    argc, argv);
508168404Spjd	if (nvroot == NULL) {
509168404Spjd		zpool_close(zhp);
510168404Spjd		return (1);
511168404Spjd	}
512168404Spjd
513168404Spjd	if (dryrun) {
514168404Spjd		nvlist_t *poolnvroot;
515168404Spjd
516168404Spjd		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
517168404Spjd		    &poolnvroot) == 0);
518168404Spjd
519168404Spjd		(void) printf(gettext("would update '%s' to the following "
520168404Spjd		    "configuration:\n"), zpool_get_name(zhp));
521168404Spjd
522185029Spjd		/* print original main pool and new tree */
523185029Spjd		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
524185029Spjd		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
525168404Spjd
526185029Spjd		/* Do the same for the logs */
527185029Spjd		if (num_logs(poolnvroot) > 0) {
528185029Spjd			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
529185029Spjd			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
530185029Spjd		} else if (num_logs(nvroot) > 0) {
531185029Spjd			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
532185029Spjd		}
533185029Spjd
534168404Spjd		ret = 0;
535168404Spjd	} else {
536168404Spjd		ret = (zpool_add(zhp, nvroot) != 0);
537168404Spjd	}
538168404Spjd
539168404Spjd	nvlist_free(nvroot);
540168404Spjd	zpool_close(zhp);
541168404Spjd
542168404Spjd	return (ret);
543168404Spjd}
544168404Spjd
545168404Spjd/*
546219089Spjd * zpool remove  <pool> <vdev> ...
547168404Spjd *
548219089Spjd * Removes the given vdev from the pool.  Currently, this supports removing
549219089Spjd * spares, cache, and log devices from the pool.
550168404Spjd */
551168404Spjdint
552168404Spjdzpool_do_remove(int argc, char **argv)
553168404Spjd{
554168404Spjd	char *poolname;
555185029Spjd	int i, ret = 0;
556168404Spjd	zpool_handle_t *zhp;
557168404Spjd
558168404Spjd	argc--;
559168404Spjd	argv++;
560168404Spjd
561168404Spjd	/* get pool name and check number of arguments */
562168404Spjd	if (argc < 1) {
563168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
564168404Spjd		usage(B_FALSE);
565168404Spjd	}
566168404Spjd	if (argc < 2) {
567168404Spjd		(void) fprintf(stderr, gettext("missing device\n"));
568168404Spjd		usage(B_FALSE);
569168404Spjd	}
570168404Spjd
571168404Spjd	poolname = argv[0];
572168404Spjd
573168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
574168404Spjd		return (1);
575168404Spjd
576185029Spjd	for (i = 1; i < argc; i++) {
577185029Spjd		if (zpool_vdev_remove(zhp, argv[i]) != 0)
578185029Spjd			ret = 1;
579168404Spjd	}
580168404Spjd
581168404Spjd	return (ret);
582168404Spjd}
583168404Spjd
584168404Spjd/*
585224171Sgibbs * zpool labelclear <vdev>
586224171Sgibbs *
587224171Sgibbs * Verifies that the vdev is not active and zeros out the label information
588224171Sgibbs * on the device.
589224171Sgibbs */
590224171Sgibbsint
591224171Sgibbszpool_do_labelclear(int argc, char **argv)
592224171Sgibbs{
593224171Sgibbs	char *vdev, *name;
594224171Sgibbs	int c, fd = -1, ret = 0;
595224171Sgibbs	pool_state_t state;
596224171Sgibbs	boolean_t inuse = B_FALSE;
597224171Sgibbs	boolean_t force = B_FALSE;
598224171Sgibbs
599224171Sgibbs	/* check options */
600224171Sgibbs	while ((c = getopt(argc, argv, "f")) != -1) {
601224171Sgibbs		switch (c) {
602224171Sgibbs		case 'f':
603224171Sgibbs			force = B_TRUE;
604224171Sgibbs			break;
605224171Sgibbs		default:
606224171Sgibbs			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
607224171Sgibbs			    optopt);
608224171Sgibbs			usage(B_FALSE);
609224171Sgibbs		}
610224171Sgibbs	}
611224171Sgibbs
612224171Sgibbs	argc -= optind;
613224171Sgibbs	argv += optind;
614224171Sgibbs
615224171Sgibbs	/* get vdev name */
616224171Sgibbs	if (argc < 1) {
617224171Sgibbs		(void) fprintf(stderr, gettext("missing vdev device name\n"));
618224171Sgibbs		usage(B_FALSE);
619224171Sgibbs	}
620224171Sgibbs
621224171Sgibbs	vdev = argv[0];
622224171Sgibbs	if ((fd = open(vdev, O_RDWR)) < 0) {
623224171Sgibbs		(void) fprintf(stderr, gettext("Unable to open %s\n"), vdev);
624224171Sgibbs		return (B_FALSE);
625224171Sgibbs	}
626224171Sgibbs
627224171Sgibbs	name = NULL;
628224171Sgibbs	if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0) {
629224171Sgibbs		if (force)
630224171Sgibbs			goto wipe_label;
631224171Sgibbs
632224171Sgibbs		(void) fprintf(stderr,
633224171Sgibbs		    gettext("Unable to determine pool state for %s\n"
634224171Sgibbs		    "Use -f to force the clearing any label data\n"), vdev);
635224171Sgibbs
636224171Sgibbs		return (1);
637224171Sgibbs	}
638224171Sgibbs
639224171Sgibbs	if (inuse) {
640224171Sgibbs		switch (state) {
641224171Sgibbs		default:
642224171Sgibbs		case POOL_STATE_ACTIVE:
643224171Sgibbs		case POOL_STATE_SPARE:
644224171Sgibbs		case POOL_STATE_L2CACHE:
645224171Sgibbs			(void) fprintf(stderr,
646224171Sgibbsgettext("labelclear operation failed.\n"
647224171Sgibbs	"\tVdev %s is a member (%s), of pool \"%s\".\n"
648224171Sgibbs	"\tTo remove label information from this device, export or destroy\n"
649224171Sgibbs	"\tthe pool, or remove %s from the configuration of this pool\n"
650224171Sgibbs	"\tand retry the labelclear operation\n"),
651224171Sgibbs			    vdev, zpool_pool_state_to_name(state), name, vdev);
652224171Sgibbs			ret = 1;
653224171Sgibbs			goto errout;
654224171Sgibbs
655224171Sgibbs		case POOL_STATE_EXPORTED:
656224171Sgibbs			if (force)
657224171Sgibbs				break;
658224171Sgibbs
659224171Sgibbs			(void) fprintf(stderr,
660224171Sgibbsgettext("labelclear operation failed.\n"
661224171Sgibbs	"\tVdev %s is a member of the exported pool \"%s\".\n"
662224171Sgibbs	"\tUse \"zpool labelclear -f %s\" to force the removal of label\n"
663224171Sgibbs	"\tinformation.\n"),
664224171Sgibbs			    vdev, name, vdev);
665224171Sgibbs			ret = 1;
666224171Sgibbs			goto errout;
667224171Sgibbs
668224171Sgibbs		case POOL_STATE_POTENTIALLY_ACTIVE:
669224171Sgibbs			if (force)
670224171Sgibbs				break;
671224171Sgibbs
672224171Sgibbs			(void) fprintf(stderr,
673224171Sgibbsgettext("labelclear operation failed.\n"
674224171Sgibbs	"\tVdev %s is a member of the pool \"%s\".\n"
675224171Sgibbs	"\tThis pool is unknown to this system, but may be active on\n"
676224171Sgibbs	"\tanother system. Use \'zpool labelclear -f %s\' to force the\n"
677224171Sgibbs	"\tremoval of label information.\n"),
678224171Sgibbs			    vdev, name, vdev);
679224171Sgibbs			ret = 1;
680224171Sgibbs			goto errout;
681224171Sgibbs
682224171Sgibbs		case POOL_STATE_DESTROYED:
683224171Sgibbs			/* inuse should never be set for a destoryed pool... */
684224171Sgibbs			break;
685224171Sgibbs		}
686224171Sgibbs	}
687224171Sgibbs
688224171Sgibbswipe_label:
689224171Sgibbs	if (zpool_clear_label(fd) != 0) {
690224171Sgibbs		(void) fprintf(stderr,
691224171Sgibbs		    gettext("Label clear failed on vdev %s\n"), vdev);
692224171Sgibbs		ret = 1;
693224171Sgibbs	}
694224171Sgibbs
695224171Sgibbserrout:
696224171Sgibbs	close(fd);
697224171Sgibbs	if (name != NULL)
698224171Sgibbs		free(name);
699224171Sgibbs
700224171Sgibbs	return (ret);
701224171Sgibbs}
702224171Sgibbs
703224171Sgibbs/*
704185029Spjd * zpool create [-fn] [-o property=value] ...
705185029Spjd *		[-O file-system-property=value] ...
706185029Spjd *		[-R root] [-m mountpoint] <pool> <dev> ...
707168404Spjd *
708168404Spjd *	-f	Force creation, even if devices appear in use
709168404Spjd *	-n	Do not create the pool, but display the resulting layout if it
710168404Spjd *		were to be created.
711168404Spjd *      -R	Create a pool under an alternate root
712168404Spjd *      -m	Set default mountpoint for the root dataset.  By default it's
713168404Spjd *      	'/<pool>'
714185029Spjd *	-o	Set property=value.
715185029Spjd *	-O	Set fsproperty=value in the pool's root file system
716168404Spjd *
717168404Spjd * Creates the named pool according to the given vdev specification.  The
718168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
719168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents
720168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation.
721168404Spjd */
722168404Spjdint
723168404Spjdzpool_do_create(int argc, char **argv)
724168404Spjd{
725168404Spjd	boolean_t force = B_FALSE;
726168404Spjd	boolean_t dryrun = B_FALSE;
727168404Spjd	int c;
728185029Spjd	nvlist_t *nvroot = NULL;
729168404Spjd	char *poolname;
730185029Spjd	int ret = 1;
731168404Spjd	char *altroot = NULL;
732168404Spjd	char *mountpoint = NULL;
733185029Spjd	nvlist_t *fsprops = NULL;
734185029Spjd	nvlist_t *props = NULL;
735185029Spjd	char *propval;
736168404Spjd
737168404Spjd	/* check options */
738185029Spjd	while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) {
739168404Spjd		switch (c) {
740168404Spjd		case 'f':
741168404Spjd			force = B_TRUE;
742168404Spjd			break;
743168404Spjd		case 'n':
744168404Spjd			dryrun = B_TRUE;
745168404Spjd			break;
746168404Spjd		case 'R':
747168404Spjd			altroot = optarg;
748185029Spjd			if (add_prop_list(zpool_prop_to_name(
749185029Spjd			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
750185029Spjd				goto errout;
751185029Spjd			if (nvlist_lookup_string(props,
752185029Spjd			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
753185029Spjd			    &propval) == 0)
754185029Spjd				break;
755185029Spjd			if (add_prop_list(zpool_prop_to_name(
756185029Spjd			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
757185029Spjd				goto errout;
758168404Spjd			break;
759168404Spjd		case 'm':
760168404Spjd			mountpoint = optarg;
761168404Spjd			break;
762185029Spjd		case 'o':
763185029Spjd			if ((propval = strchr(optarg, '=')) == NULL) {
764185029Spjd				(void) fprintf(stderr, gettext("missing "
765185029Spjd				    "'=' for -o option\n"));
766185029Spjd				goto errout;
767185029Spjd			}
768185029Spjd			*propval = '\0';
769185029Spjd			propval++;
770185029Spjd
771185029Spjd			if (add_prop_list(optarg, propval, &props, B_TRUE))
772185029Spjd				goto errout;
773185029Spjd			break;
774185029Spjd		case 'O':
775185029Spjd			if ((propval = strchr(optarg, '=')) == NULL) {
776185029Spjd				(void) fprintf(stderr, gettext("missing "
777185029Spjd				    "'=' for -O option\n"));
778185029Spjd				goto errout;
779185029Spjd			}
780185029Spjd			*propval = '\0';
781185029Spjd			propval++;
782185029Spjd
783185029Spjd			if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
784185029Spjd				goto errout;
785185029Spjd			break;
786168404Spjd		case ':':
787168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
788168404Spjd			    "'%c' option\n"), optopt);
789185029Spjd			goto badusage;
790168404Spjd		case '?':
791168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
792168404Spjd			    optopt);
793185029Spjd			goto badusage;
794168404Spjd		}
795168404Spjd	}
796168404Spjd
797168404Spjd	argc -= optind;
798168404Spjd	argv += optind;
799168404Spjd
800168404Spjd	/* get pool name and check number of arguments */
801168404Spjd	if (argc < 1) {
802168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
803185029Spjd		goto badusage;
804168404Spjd	}
805168404Spjd	if (argc < 2) {
806168404Spjd		(void) fprintf(stderr, gettext("missing vdev specification\n"));
807185029Spjd		goto badusage;
808168404Spjd	}
809168404Spjd
810168404Spjd	poolname = argv[0];
811168404Spjd
812168404Spjd	/*
813168404Spjd	 * As a special case, check for use of '/' in the name, and direct the
814168404Spjd	 * user to use 'zfs create' instead.
815168404Spjd	 */
816168404Spjd	if (strchr(poolname, '/') != NULL) {
817168404Spjd		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
818168404Spjd		    "character '/' in pool name\n"), poolname);
819168404Spjd		(void) fprintf(stderr, gettext("use 'zfs create' to "
820168404Spjd		    "create a dataset\n"));
821185029Spjd		goto errout;
822168404Spjd	}
823168404Spjd
824168404Spjd	/* pass off to get_vdev_spec for bulk processing */
825185029Spjd	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
826185029Spjd	    argc - 1, argv + 1);
827168404Spjd	if (nvroot == NULL)
828185029Spjd		goto errout;
829168404Spjd
830168404Spjd	/* make_root_vdev() allows 0 toplevel children if there are spares */
831185029Spjd	if (!zfs_allocatable_devs(nvroot)) {
832168404Spjd		(void) fprintf(stderr, gettext("invalid vdev "
833168404Spjd		    "specification: at least one toplevel vdev must be "
834168404Spjd		    "specified\n"));
835185029Spjd		goto errout;
836168404Spjd	}
837168404Spjd
838168404Spjd
839168404Spjd	if (altroot != NULL && altroot[0] != '/') {
840168404Spjd		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
841168404Spjd		    "must be an absolute path\n"), altroot);
842185029Spjd		goto errout;
843168404Spjd	}
844168404Spjd
845168404Spjd	/*
846168404Spjd	 * Check the validity of the mountpoint and direct the user to use the
847168404Spjd	 * '-m' mountpoint option if it looks like its in use.
848168404Spjd	 */
849168404Spjd	if (mountpoint == NULL ||
850168404Spjd	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
851168404Spjd	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
852168404Spjd		char buf[MAXPATHLEN];
853185029Spjd		DIR *dirp;
854168404Spjd
855168404Spjd		if (mountpoint && mountpoint[0] != '/') {
856168404Spjd			(void) fprintf(stderr, gettext("invalid mountpoint "
857168404Spjd			    "'%s': must be an absolute path, 'legacy', or "
858168404Spjd			    "'none'\n"), mountpoint);
859185029Spjd			goto errout;
860168404Spjd		}
861168404Spjd
862168404Spjd		if (mountpoint == NULL) {
863168404Spjd			if (altroot != NULL)
864168404Spjd				(void) snprintf(buf, sizeof (buf), "%s/%s",
865168404Spjd				    altroot, poolname);
866168404Spjd			else
867168404Spjd				(void) snprintf(buf, sizeof (buf), "/%s",
868168404Spjd				    poolname);
869168404Spjd		} else {
870168404Spjd			if (altroot != NULL)
871168404Spjd				(void) snprintf(buf, sizeof (buf), "%s%s",
872168404Spjd				    altroot, mountpoint);
873168404Spjd			else
874168404Spjd				(void) snprintf(buf, sizeof (buf), "%s",
875168404Spjd				    mountpoint);
876168404Spjd		}
877168404Spjd
878185029Spjd		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
879185029Spjd			(void) fprintf(stderr, gettext("mountpoint '%s' : "
880185029Spjd			    "%s\n"), buf, strerror(errno));
881185029Spjd			(void) fprintf(stderr, gettext("use '-m' "
882185029Spjd			    "option to provide a different default\n"));
883185029Spjd			goto errout;
884185029Spjd		} else if (dirp) {
885185029Spjd			int count = 0;
886185029Spjd
887185029Spjd			while (count < 3 && readdir(dirp) != NULL)
888185029Spjd				count++;
889185029Spjd			(void) closedir(dirp);
890185029Spjd
891185029Spjd			if (count > 2) {
892168404Spjd				(void) fprintf(stderr, gettext("mountpoint "
893168404Spjd				    "'%s' exists and is not empty\n"), buf);
894185029Spjd				(void) fprintf(stderr, gettext("use '-m' "
895185029Spjd				    "option to provide a "
896185029Spjd				    "different default\n"));
897185029Spjd				goto errout;
898185029Spjd			}
899168404Spjd		}
900168404Spjd	}
901168404Spjd
902168404Spjd	if (dryrun) {
903168404Spjd		/*
904168404Spjd		 * For a dry run invocation, print out a basic message and run
905168404Spjd		 * through all the vdevs in the list and print out in an
906168404Spjd		 * appropriate hierarchy.
907168404Spjd		 */
908168404Spjd		(void) printf(gettext("would create '%s' with the "
909168404Spjd		    "following layout:\n\n"), poolname);
910168404Spjd
911185029Spjd		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
912185029Spjd		if (num_logs(nvroot) > 0)
913185029Spjd			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
914168404Spjd
915168404Spjd		ret = 0;
916168404Spjd	} else {
917168404Spjd		/*
918168404Spjd		 * Hand off to libzfs.
919168404Spjd		 */
920185029Spjd		if (zpool_create(g_zfs, poolname,
921185029Spjd		    nvroot, props, fsprops) == 0) {
922168404Spjd			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
923168404Spjd			    ZFS_TYPE_FILESYSTEM);
924168404Spjd			if (pool != NULL) {
925168404Spjd				if (mountpoint != NULL)
926168404Spjd					verify(zfs_prop_set(pool,
927168404Spjd					    zfs_prop_to_name(
928168404Spjd					    ZFS_PROP_MOUNTPOINT),
929168404Spjd					    mountpoint) == 0);
930168404Spjd				if (zfs_mount(pool, NULL, 0) == 0)
931185029Spjd					ret = zfs_shareall(pool);
932168404Spjd				zfs_close(pool);
933168404Spjd			}
934168404Spjd		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
935168404Spjd			(void) fprintf(stderr, gettext("pool name may have "
936168404Spjd			    "been omitted\n"));
937168404Spjd		}
938168404Spjd	}
939168404Spjd
940185029Spjderrout:
941168404Spjd	nvlist_free(nvroot);
942185029Spjd	nvlist_free(fsprops);
943185029Spjd	nvlist_free(props);
944168404Spjd	return (ret);
945185029Spjdbadusage:
946185029Spjd	nvlist_free(fsprops);
947185029Spjd	nvlist_free(props);
948185029Spjd	usage(B_FALSE);
949185029Spjd	return (2);
950168404Spjd}
951168404Spjd
952168404Spjd/*
953168404Spjd * zpool destroy <pool>
954168404Spjd *
955168404Spjd * 	-f	Forcefully unmount any datasets
956168404Spjd *
957168404Spjd * Destroy the given pool.  Automatically unmounts any datasets in the pool.
958168404Spjd */
959168404Spjdint
960168404Spjdzpool_do_destroy(int argc, char **argv)
961168404Spjd{
962168404Spjd	boolean_t force = B_FALSE;
963168404Spjd	int c;
964168404Spjd	char *pool;
965168404Spjd	zpool_handle_t *zhp;
966168404Spjd	int ret;
967168404Spjd
968168404Spjd	/* check options */
969168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
970168404Spjd		switch (c) {
971168404Spjd		case 'f':
972168404Spjd			force = B_TRUE;
973168404Spjd			break;
974168404Spjd		case '?':
975168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
976168404Spjd			    optopt);
977168404Spjd			usage(B_FALSE);
978168404Spjd		}
979168404Spjd	}
980168404Spjd
981168404Spjd	argc -= optind;
982168404Spjd	argv += optind;
983168404Spjd
984168404Spjd	/* check arguments */
985168404Spjd	if (argc < 1) {
986168404Spjd		(void) fprintf(stderr, gettext("missing pool argument\n"));
987168404Spjd		usage(B_FALSE);
988168404Spjd	}
989168404Spjd	if (argc > 1) {
990168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
991168404Spjd		usage(B_FALSE);
992168404Spjd	}
993168404Spjd
994168404Spjd	pool = argv[0];
995168404Spjd
996168404Spjd	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
997168404Spjd		/*
998168404Spjd		 * As a special case, check for use of '/' in the name, and
999168404Spjd		 * direct the user to use 'zfs destroy' instead.
1000168404Spjd		 */
1001168404Spjd		if (strchr(pool, '/') != NULL)
1002168404Spjd			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
1003168404Spjd			    "destroy a dataset\n"));
1004168404Spjd		return (1);
1005168404Spjd	}
1006168404Spjd
1007168404Spjd	if (zpool_disable_datasets(zhp, force) != 0) {
1008168404Spjd		(void) fprintf(stderr, gettext("could not destroy '%s': "
1009168404Spjd		    "could not unmount datasets\n"), zpool_get_name(zhp));
1010168404Spjd		return (1);
1011168404Spjd	}
1012168404Spjd
1013168404Spjd	ret = (zpool_destroy(zhp) != 0);
1014168404Spjd
1015168404Spjd	zpool_close(zhp);
1016168404Spjd
1017168404Spjd	return (ret);
1018168404Spjd}
1019168404Spjd
1020168404Spjd/*
1021168404Spjd * zpool export [-f] <pool> ...
1022168404Spjd *
1023168404Spjd *	-f	Forcefully unmount datasets
1024168404Spjd *
1025168404Spjd * Export the given pools.  By default, the command will attempt to cleanly
1026168404Spjd * unmount any active datasets within the pool.  If the '-f' flag is specified,
1027168404Spjd * then the datasets will be forcefully unmounted.
1028168404Spjd */
1029168404Spjdint
1030168404Spjdzpool_do_export(int argc, char **argv)
1031168404Spjd{
1032168404Spjd	boolean_t force = B_FALSE;
1033207670Smm	boolean_t hardforce = B_FALSE;
1034168404Spjd	int c;
1035168404Spjd	zpool_handle_t *zhp;
1036168404Spjd	int ret;
1037168404Spjd	int i;
1038168404Spjd
1039168404Spjd	/* check options */
1040207670Smm	while ((c = getopt(argc, argv, "fF")) != -1) {
1041168404Spjd		switch (c) {
1042168404Spjd		case 'f':
1043168404Spjd			force = B_TRUE;
1044168404Spjd			break;
1045207670Smm		case 'F':
1046207670Smm			hardforce = B_TRUE;
1047207670Smm			break;
1048168404Spjd		case '?':
1049168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1050168404Spjd			    optopt);
1051168404Spjd			usage(B_FALSE);
1052168404Spjd		}
1053168404Spjd	}
1054168404Spjd
1055168404Spjd	argc -= optind;
1056168404Spjd	argv += optind;
1057168404Spjd
1058168404Spjd	/* check arguments */
1059168404Spjd	if (argc < 1) {
1060168404Spjd		(void) fprintf(stderr, gettext("missing pool argument\n"));
1061168404Spjd		usage(B_FALSE);
1062168404Spjd	}
1063168404Spjd
1064168404Spjd	ret = 0;
1065168404Spjd	for (i = 0; i < argc; i++) {
1066168404Spjd		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
1067168404Spjd			ret = 1;
1068168404Spjd			continue;
1069168404Spjd		}
1070168404Spjd
1071168404Spjd		if (zpool_disable_datasets(zhp, force) != 0) {
1072168404Spjd			ret = 1;
1073168404Spjd			zpool_close(zhp);
1074168404Spjd			continue;
1075168404Spjd		}
1076168404Spjd
1077207670Smm		if (hardforce) {
1078207670Smm			if (zpool_export_force(zhp) != 0)
1079207670Smm				ret = 1;
1080207670Smm		} else if (zpool_export(zhp, force) != 0) {
1081168404Spjd			ret = 1;
1082207670Smm		}
1083168404Spjd
1084168404Spjd		zpool_close(zhp);
1085168404Spjd	}
1086168404Spjd
1087168404Spjd	return (ret);
1088168404Spjd}
1089168404Spjd
1090168404Spjd/*
1091168404Spjd * Given a vdev configuration, determine the maximum width needed for the device
1092168404Spjd * name column.
1093168404Spjd */
1094168404Spjdstatic int
1095168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
1096168404Spjd{
1097219089Spjd	char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
1098168404Spjd	nvlist_t **child;
1099168404Spjd	uint_t c, children;
1100168404Spjd	int ret;
1101168404Spjd
1102168404Spjd	if (strlen(name) + depth > max)
1103168404Spjd		max = strlen(name) + depth;
1104168404Spjd
1105168404Spjd	free(name);
1106168404Spjd
1107168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1108168404Spjd	    &child, &children) == 0) {
1109168404Spjd		for (c = 0; c < children; c++)
1110168404Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
1111168404Spjd			    max)) > max)
1112168404Spjd				max = ret;
1113168404Spjd	}
1114168404Spjd
1115185029Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1116185029Spjd	    &child, &children) == 0) {
1117185029Spjd		for (c = 0; c < children; c++)
1118185029Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
1119185029Spjd			    max)) > max)
1120185029Spjd				max = ret;
1121185029Spjd	}
1122185029Spjd
1123168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1124168404Spjd	    &child, &children) == 0) {
1125168404Spjd		for (c = 0; c < children; c++)
1126168404Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
1127168404Spjd			    max)) > max)
1128168404Spjd				max = ret;
1129168404Spjd	}
1130168404Spjd
1131168404Spjd
1132168404Spjd	return (max);
1133168404Spjd}
1134168404Spjd
1135213197Smmtypedef struct spare_cbdata {
1136213197Smm	uint64_t	cb_guid;
1137213197Smm	zpool_handle_t	*cb_zhp;
1138213197Smm} spare_cbdata_t;
1139168404Spjd
1140213197Smmstatic boolean_t
1141213197Smmfind_vdev(nvlist_t *nv, uint64_t search)
1142213197Smm{
1143213197Smm	uint64_t guid;
1144213197Smm	nvlist_t **child;
1145213197Smm	uint_t c, children;
1146213197Smm
1147213197Smm	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
1148213197Smm	    search == guid)
1149213197Smm		return (B_TRUE);
1150213197Smm
1151213197Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1152213197Smm	    &child, &children) == 0) {
1153213197Smm		for (c = 0; c < children; c++)
1154213197Smm			if (find_vdev(child[c], search))
1155213197Smm				return (B_TRUE);
1156213197Smm	}
1157213197Smm
1158213197Smm	return (B_FALSE);
1159213197Smm}
1160213197Smm
1161213197Smmstatic int
1162213197Smmfind_spare(zpool_handle_t *zhp, void *data)
1163213197Smm{
1164213197Smm	spare_cbdata_t *cbp = data;
1165213197Smm	nvlist_t *config, *nvroot;
1166213197Smm
1167213197Smm	config = zpool_get_config(zhp, NULL);
1168213197Smm	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1169213197Smm	    &nvroot) == 0);
1170213197Smm
1171213197Smm	if (find_vdev(nvroot, cbp->cb_guid)) {
1172213197Smm		cbp->cb_zhp = zhp;
1173213197Smm		return (1);
1174213197Smm	}
1175213197Smm
1176213197Smm	zpool_close(zhp);
1177213197Smm	return (0);
1178213197Smm}
1179213197Smm
1180168404Spjd/*
1181213197Smm * Print out configuration state as requested by status_callback.
1182213197Smm */
1183213197Smmvoid
1184213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
1185213197Smm    int namewidth, int depth, boolean_t isspare)
1186213197Smm{
1187213197Smm	nvlist_t **child;
1188213197Smm	uint_t c, children;
1189219089Spjd	pool_scan_stat_t *ps = NULL;
1190213197Smm	vdev_stat_t *vs;
1191219089Spjd	char rbuf[6], wbuf[6], cbuf[6];
1192213197Smm	char *vname;
1193213197Smm	uint64_t notpresent;
1194213197Smm	spare_cbdata_t cb;
1195224169Sgibbs	const char *state;
1196213197Smm
1197213197Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1198213197Smm	    &child, &children) != 0)
1199213197Smm		children = 0;
1200213197Smm
1201219089Spjd	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1202219089Spjd	    (uint64_t **)&vs, &c) == 0);
1203219089Spjd
1204213197Smm	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1205213197Smm	if (isspare) {
1206213197Smm		/*
1207213197Smm		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
1208213197Smm		 * online drives.
1209213197Smm		 */
1210213197Smm		if (vs->vs_aux == VDEV_AUX_SPARED)
1211213197Smm			state = "INUSE";
1212213197Smm		else if (vs->vs_state == VDEV_STATE_HEALTHY)
1213213197Smm			state = "AVAIL";
1214213197Smm	}
1215213197Smm
1216213197Smm	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
1217213197Smm	    name, state);
1218213197Smm
1219213197Smm	if (!isspare) {
1220213197Smm		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
1221213197Smm		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
1222213197Smm		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
1223213197Smm		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
1224213197Smm	}
1225213197Smm
1226213197Smm	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1227224170Sgibbs	    &notpresent) == 0 ||
1228224170Sgibbs	    vs->vs_state <= VDEV_STATE_CANT_OPEN) {
1229213197Smm		char *path;
1230224170Sgibbs		if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0)
1231224170Sgibbs			(void) printf("  was %s", path);
1232213197Smm	} else if (vs->vs_aux != 0) {
1233213197Smm		(void) printf("  ");
1234213197Smm
1235213197Smm		switch (vs->vs_aux) {
1236213197Smm		case VDEV_AUX_OPEN_FAILED:
1237213197Smm			(void) printf(gettext("cannot open"));
1238213197Smm			break;
1239213197Smm
1240213197Smm		case VDEV_AUX_BAD_GUID_SUM:
1241213197Smm			(void) printf(gettext("missing device"));
1242213197Smm			break;
1243213197Smm
1244213197Smm		case VDEV_AUX_NO_REPLICAS:
1245213197Smm			(void) printf(gettext("insufficient replicas"));
1246213197Smm			break;
1247213197Smm
1248213197Smm		case VDEV_AUX_VERSION_NEWER:
1249213197Smm			(void) printf(gettext("newer version"));
1250213197Smm			break;
1251213197Smm
1252213197Smm		case VDEV_AUX_SPARED:
1253213197Smm			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1254213197Smm			    &cb.cb_guid) == 0);
1255213197Smm			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
1256213197Smm				if (strcmp(zpool_get_name(cb.cb_zhp),
1257213197Smm				    zpool_get_name(zhp)) == 0)
1258213197Smm					(void) printf(gettext("currently in "
1259213197Smm					    "use"));
1260213197Smm				else
1261213197Smm					(void) printf(gettext("in use by "
1262213197Smm					    "pool '%s'"),
1263213197Smm					    zpool_get_name(cb.cb_zhp));
1264213197Smm				zpool_close(cb.cb_zhp);
1265213197Smm			} else {
1266213197Smm				(void) printf(gettext("currently in use"));
1267213197Smm			}
1268213197Smm			break;
1269213197Smm
1270213197Smm		case VDEV_AUX_ERR_EXCEEDED:
1271213197Smm			(void) printf(gettext("too many errors"));
1272213197Smm			break;
1273213197Smm
1274213197Smm		case VDEV_AUX_IO_FAILURE:
1275213197Smm			(void) printf(gettext("experienced I/O failures"));
1276213197Smm			break;
1277213197Smm
1278213197Smm		case VDEV_AUX_BAD_LOG:
1279213197Smm			(void) printf(gettext("bad intent log"));
1280213197Smm			break;
1281213197Smm
1282219089Spjd		case VDEV_AUX_EXTERNAL:
1283219089Spjd			(void) printf(gettext("external device fault"));
1284219089Spjd			break;
1285219089Spjd
1286219089Spjd		case VDEV_AUX_SPLIT_POOL:
1287219089Spjd			(void) printf(gettext("split into new pool"));
1288219089Spjd			break;
1289219089Spjd
1290213197Smm		default:
1291213197Smm			(void) printf(gettext("corrupted data"));
1292213197Smm			break;
1293213197Smm		}
1294213197Smm	}
1295213197Smm
1296219089Spjd	(void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS,
1297219089Spjd	    (uint64_t **)&ps, &c);
1298219089Spjd
1299219089Spjd	if (ps && ps->pss_state == DSS_SCANNING &&
1300219089Spjd	    vs->vs_scan_processed != 0 && children == 0) {
1301219089Spjd		(void) printf(gettext("  (%s)"),
1302219089Spjd		    (ps->pss_func == POOL_SCAN_RESILVER) ?
1303219089Spjd		    "resilvering" : "repairing");
1304219089Spjd	}
1305219089Spjd
1306213197Smm	(void) printf("\n");
1307213197Smm
1308213197Smm	for (c = 0; c < children; c++) {
1309219089Spjd		uint64_t islog = B_FALSE, ishole = B_FALSE;
1310213197Smm
1311219089Spjd		/* Don't print logs or holes here */
1312213197Smm		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1313219089Spjd		    &islog);
1314219089Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
1315219089Spjd		    &ishole);
1316219089Spjd		if (islog || ishole)
1317213197Smm			continue;
1318219089Spjd		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1319213197Smm		print_status_config(zhp, vname, child[c],
1320213197Smm		    namewidth, depth + 2, isspare);
1321213197Smm		free(vname);
1322213197Smm	}
1323213197Smm}
1324213197Smm
1325213197Smm
1326213197Smm/*
1327168404Spjd * Print the configuration of an exported pool.  Iterate over all vdevs in the
1328168404Spjd * pool, printing out the name and status for each one.
1329168404Spjd */
1330168404Spjdvoid
1331213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
1332168404Spjd{
1333168404Spjd	nvlist_t **child;
1334168404Spjd	uint_t c, children;
1335168404Spjd	vdev_stat_t *vs;
1336168404Spjd	char *type, *vname;
1337168404Spjd
1338168404Spjd	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
1339219089Spjd	if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
1340219089Spjd	    strcmp(type, VDEV_TYPE_HOLE) == 0)
1341168404Spjd		return;
1342168404Spjd
1343219089Spjd	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1344168404Spjd	    (uint64_t **)&vs, &c) == 0);
1345168404Spjd
1346168404Spjd	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
1347185029Spjd	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1348168404Spjd
1349168404Spjd	if (vs->vs_aux != 0) {
1350185029Spjd		(void) printf("  ");
1351168404Spjd
1352168404Spjd		switch (vs->vs_aux) {
1353168404Spjd		case VDEV_AUX_OPEN_FAILED:
1354168404Spjd			(void) printf(gettext("cannot open"));
1355168404Spjd			break;
1356168404Spjd
1357168404Spjd		case VDEV_AUX_BAD_GUID_SUM:
1358168404Spjd			(void) printf(gettext("missing device"));
1359168404Spjd			break;
1360168404Spjd
1361168404Spjd		case VDEV_AUX_NO_REPLICAS:
1362168404Spjd			(void) printf(gettext("insufficient replicas"));
1363168404Spjd			break;
1364168404Spjd
1365168404Spjd		case VDEV_AUX_VERSION_NEWER:
1366168404Spjd			(void) printf(gettext("newer version"));
1367168404Spjd			break;
1368168404Spjd
1369185029Spjd		case VDEV_AUX_ERR_EXCEEDED:
1370185029Spjd			(void) printf(gettext("too many errors"));
1371185029Spjd			break;
1372185029Spjd
1373168404Spjd		default:
1374168404Spjd			(void) printf(gettext("corrupted data"));
1375168404Spjd			break;
1376168404Spjd		}
1377168404Spjd	}
1378168404Spjd	(void) printf("\n");
1379168404Spjd
1380168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1381168404Spjd	    &child, &children) != 0)
1382168404Spjd		return;
1383168404Spjd
1384168404Spjd	for (c = 0; c < children; c++) {
1385185029Spjd		uint64_t is_log = B_FALSE;
1386185029Spjd
1387185029Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1388185029Spjd		    &is_log);
1389213197Smm		if (is_log)
1390185029Spjd			continue;
1391185029Spjd
1392219089Spjd		vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
1393213197Smm		print_import_config(vname, child[c], namewidth, depth + 2);
1394168404Spjd		free(vname);
1395168404Spjd	}
1396168404Spjd
1397185029Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1398185029Spjd	    &child, &children) == 0) {
1399185029Spjd		(void) printf(gettext("\tcache\n"));
1400185029Spjd		for (c = 0; c < children; c++) {
1401219089Spjd			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1402185029Spjd			(void) printf("\t  %s\n", vname);
1403185029Spjd			free(vname);
1404185029Spjd		}
1405185029Spjd	}
1406185029Spjd
1407168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1408185029Spjd	    &child, &children) == 0) {
1409185029Spjd		(void) printf(gettext("\tspares\n"));
1410185029Spjd		for (c = 0; c < children; c++) {
1411219089Spjd			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1412185029Spjd			(void) printf("\t  %s\n", vname);
1413185029Spjd			free(vname);
1414185029Spjd		}
1415168404Spjd	}
1416168404Spjd}
1417168404Spjd
1418168404Spjd/*
1419213197Smm * Print log vdevs.
1420213197Smm * Logs are recorded as top level vdevs in the main pool child array
1421213197Smm * but with "is_log" set to 1. We use either print_status_config() or
1422213197Smm * print_import_config() to print the top level logs then any log
1423213197Smm * children (eg mirrored slogs) are printed recursively - which
1424213197Smm * works because only the top level vdev is marked "is_log"
1425213197Smm */
1426213197Smmstatic void
1427213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
1428213197Smm{
1429213197Smm	uint_t c, children;
1430213197Smm	nvlist_t **child;
1431213197Smm
1432213197Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1433213197Smm	    &children) != 0)
1434213197Smm		return;
1435213197Smm
1436213197Smm	(void) printf(gettext("\tlogs\n"));
1437213197Smm
1438213197Smm	for (c = 0; c < children; c++) {
1439213197Smm		uint64_t is_log = B_FALSE;
1440213197Smm		char *name;
1441213197Smm
1442213197Smm		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1443213197Smm		    &is_log);
1444213197Smm		if (!is_log)
1445213197Smm			continue;
1446219089Spjd		name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1447213197Smm		if (verbose)
1448213197Smm			print_status_config(zhp, name, child[c], namewidth,
1449213197Smm			    2, B_FALSE);
1450213197Smm		else
1451213197Smm			print_import_config(name, child[c], namewidth, 2);
1452213197Smm		free(name);
1453213197Smm	}
1454213197Smm}
1455219089Spjd
1456213197Smm/*
1457168404Spjd * Display the status for the given pool.
1458168404Spjd */
1459168404Spjdstatic void
1460168404Spjdshow_import(nvlist_t *config)
1461168404Spjd{
1462168404Spjd	uint64_t pool_state;
1463168404Spjd	vdev_stat_t *vs;
1464168404Spjd	char *name;
1465168404Spjd	uint64_t guid;
1466168404Spjd	char *msgid;
1467168404Spjd	nvlist_t *nvroot;
1468168404Spjd	int reason;
1469168404Spjd	const char *health;
1470168404Spjd	uint_t vsc;
1471168404Spjd	int namewidth;
1472228103Smm	char *comment;
1473168404Spjd
1474168404Spjd	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1475168404Spjd	    &name) == 0);
1476168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1477168404Spjd	    &guid) == 0);
1478168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1479168404Spjd	    &pool_state) == 0);
1480168404Spjd	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1481168404Spjd	    &nvroot) == 0);
1482168404Spjd
1483219089Spjd	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
1484168404Spjd	    (uint64_t **)&vs, &vsc) == 0);
1485185029Spjd	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1486168404Spjd
1487168404Spjd	reason = zpool_import_status(config, &msgid);
1488168404Spjd
1489228103Smm	(void) printf(gettext("   pool: %s\n"), name);
1490228103Smm	(void) printf(gettext("     id: %llu\n"), (u_longlong_t)guid);
1491228103Smm	(void) printf(gettext("  state: %s"), health);
1492168404Spjd	if (pool_state == POOL_STATE_DESTROYED)
1493168404Spjd		(void) printf(gettext(" (DESTROYED)"));
1494168404Spjd	(void) printf("\n");
1495168404Spjd
1496168404Spjd	switch (reason) {
1497168404Spjd	case ZPOOL_STATUS_MISSING_DEV_R:
1498168404Spjd	case ZPOOL_STATUS_MISSING_DEV_NR:
1499168404Spjd	case ZPOOL_STATUS_BAD_GUID_SUM:
1500228103Smm		(void) printf(gettext(" status: One or more devices are "
1501228103Smm		    "missing from the system.\n"));
1502168404Spjd		break;
1503168404Spjd
1504168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1505168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1506228103Smm		(void) printf(gettext(" status: One or more devices contains "
1507168404Spjd		    "corrupted data.\n"));
1508168404Spjd		break;
1509168404Spjd
1510168404Spjd	case ZPOOL_STATUS_CORRUPT_DATA:
1511228103Smm		(void) printf(
1512228103Smm		    gettext(" status: The pool data is corrupted.\n"));
1513168404Spjd		break;
1514168404Spjd
1515168404Spjd	case ZPOOL_STATUS_OFFLINE_DEV:
1516228103Smm		(void) printf(gettext(" status: One or more devices "
1517168404Spjd		    "are offlined.\n"));
1518168404Spjd		break;
1519168404Spjd
1520168404Spjd	case ZPOOL_STATUS_CORRUPT_POOL:
1521228103Smm		(void) printf(gettext(" status: The pool metadata is "
1522168404Spjd		    "corrupted.\n"));
1523168404Spjd		break;
1524168404Spjd
1525168404Spjd	case ZPOOL_STATUS_VERSION_OLDER:
1526228103Smm		(void) printf(gettext(" status: The pool is formatted using an "
1527168404Spjd		    "older on-disk version.\n"));
1528168404Spjd		break;
1529168404Spjd
1530168404Spjd	case ZPOOL_STATUS_VERSION_NEWER:
1531228103Smm		(void) printf(gettext(" status: The pool is formatted using an "
1532168404Spjd		    "incompatible version.\n"));
1533168404Spjd		break;
1534168404Spjd
1535168498Spjd	case ZPOOL_STATUS_HOSTID_MISMATCH:
1536228103Smm		(void) printf(gettext(" status: The pool was last accessed by "
1537168498Spjd		    "another system.\n"));
1538168498Spjd		break;
1539185029Spjd
1540185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_R:
1541185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_NR:
1542228103Smm		(void) printf(gettext(" status: One or more devices are "
1543185029Spjd		    "faulted.\n"));
1544185029Spjd		break;
1545185029Spjd
1546185029Spjd	case ZPOOL_STATUS_BAD_LOG:
1547228103Smm		(void) printf(gettext(" status: An intent log record cannot be "
1548185029Spjd		    "read.\n"));
1549185029Spjd		break;
1550185029Spjd
1551219089Spjd	case ZPOOL_STATUS_RESILVERING:
1552228103Smm		(void) printf(gettext(" status: One or more devices were being "
1553219089Spjd		    "resilvered.\n"));
1554219089Spjd		break;
1555219089Spjd
1556168404Spjd	default:
1557168404Spjd		/*
1558168404Spjd		 * No other status can be seen when importing pools.
1559168404Spjd		 */
1560168404Spjd		assert(reason == ZPOOL_STATUS_OK);
1561168404Spjd	}
1562168404Spjd
1563168404Spjd	/*
1564168404Spjd	 * Print out an action according to the overall state of the pool.
1565168404Spjd	 */
1566168404Spjd	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1567168404Spjd		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1568228103Smm			(void) printf(gettext(" action: The pool can be "
1569168404Spjd			    "imported using its name or numeric identifier, "
1570168404Spjd			    "though\n\tsome features will not be available "
1571168404Spjd			    "without an explicit 'zpool upgrade'.\n"));
1572168498Spjd		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
1573228103Smm			(void) printf(gettext(" action: The pool can be "
1574168498Spjd			    "imported using its name or numeric "
1575168498Spjd			    "identifier and\n\tthe '-f' flag.\n"));
1576168404Spjd		else
1577228103Smm			(void) printf(gettext(" action: The pool can be "
1578168404Spjd			    "imported using its name or numeric "
1579168404Spjd			    "identifier.\n"));
1580168404Spjd	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1581228103Smm		(void) printf(gettext(" action: The pool can be imported "
1582168404Spjd		    "despite missing or damaged devices.  The\n\tfault "
1583168404Spjd		    "tolerance of the pool may be compromised if imported.\n"));
1584168404Spjd	} else {
1585168404Spjd		switch (reason) {
1586168404Spjd		case ZPOOL_STATUS_VERSION_NEWER:
1587228103Smm			(void) printf(gettext(" action: The pool cannot be "
1588168404Spjd			    "imported.  Access the pool on a system running "
1589168404Spjd			    "newer\n\tsoftware, or recreate the pool from "
1590168404Spjd			    "backup.\n"));
1591168404Spjd			break;
1592168404Spjd		case ZPOOL_STATUS_MISSING_DEV_R:
1593168404Spjd		case ZPOOL_STATUS_MISSING_DEV_NR:
1594168404Spjd		case ZPOOL_STATUS_BAD_GUID_SUM:
1595228103Smm			(void) printf(gettext(" action: The pool cannot be "
1596168404Spjd			    "imported. Attach the missing\n\tdevices and try "
1597168404Spjd			    "again.\n"));
1598168404Spjd			break;
1599168404Spjd		default:
1600228103Smm			(void) printf(gettext(" action: The pool cannot be "
1601168404Spjd			    "imported due to damaged devices or data.\n"));
1602168404Spjd		}
1603168404Spjd	}
1604168404Spjd
1605228103Smm	/* Print the comment attached to the pool. */
1606228103Smm	if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
1607228103Smm		(void) printf(gettext("comment: %s\n"), comment);
1608228103Smm
1609168404Spjd	/*
1610168404Spjd	 * If the state is "closed" or "can't open", and the aux state
1611168404Spjd	 * is "corrupt data":
1612168404Spjd	 */
1613168404Spjd	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
1614168404Spjd	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
1615168404Spjd	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1616168404Spjd		if (pool_state == POOL_STATE_DESTROYED)
1617168404Spjd			(void) printf(gettext("\tThe pool was destroyed, "
1618168404Spjd			    "but can be imported using the '-Df' flags.\n"));
1619168404Spjd		else if (pool_state != POOL_STATE_EXPORTED)
1620168404Spjd			(void) printf(gettext("\tThe pool may be active on "
1621185029Spjd			    "another system, but can be imported using\n\t"
1622168404Spjd			    "the '-f' flag.\n"));
1623168404Spjd	}
1624168404Spjd
1625168404Spjd	if (msgid != NULL)
1626236146Smm		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
1627168404Spjd		    msgid);
1628168404Spjd
1629228103Smm	(void) printf(gettext(" config:\n\n"));
1630168404Spjd
1631168404Spjd	namewidth = max_width(NULL, nvroot, 0, 0);
1632168404Spjd	if (namewidth < 10)
1633168404Spjd		namewidth = 10;
1634168404Spjd
1635213197Smm	print_import_config(name, nvroot, namewidth, 0);
1636213197Smm	if (num_logs(nvroot) > 0)
1637213197Smm		print_logs(NULL, nvroot, namewidth, B_FALSE);
1638185029Spjd
1639168404Spjd	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
1640168404Spjd		(void) printf(gettext("\n\tAdditional devices are known to "
1641168404Spjd		    "be part of this pool, though their\n\texact "
1642168404Spjd		    "configuration cannot be determined.\n"));
1643168404Spjd	}
1644168404Spjd}
1645168404Spjd
1646168404Spjd/*
1647168404Spjd * Perform the import for the given configuration.  This passes the heavy
1648185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained
1649185029Spjd * within the pool.
1650168404Spjd */
1651168404Spjdstatic int
1652168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts,
1653219089Spjd    nvlist_t *props, int flags)
1654168404Spjd{
1655168404Spjd	zpool_handle_t *zhp;
1656168404Spjd	char *name;
1657168404Spjd	uint64_t state;
1658168404Spjd	uint64_t version;
1659168404Spjd
1660168404Spjd	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1661168404Spjd	    &name) == 0);
1662168404Spjd
1663168404Spjd	verify(nvlist_lookup_uint64(config,
1664168404Spjd	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1665168404Spjd	verify(nvlist_lookup_uint64(config,
1666168404Spjd	    ZPOOL_CONFIG_VERSION, &version) == 0);
1667185029Spjd	if (version > SPA_VERSION) {
1668168404Spjd		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1669168404Spjd		    "is formatted using a newer ZFS version\n"), name);
1670168404Spjd		return (1);
1671219089Spjd	} else if (state != POOL_STATE_EXPORTED &&
1672219089Spjd	    !(flags & ZFS_IMPORT_ANY_HOST)) {
1673168498Spjd		uint64_t hostid;
1674168498Spjd
1675168498Spjd		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
1676168498Spjd		    &hostid) == 0) {
1677168498Spjd			if ((unsigned long)hostid != gethostid()) {
1678168498Spjd				char *hostname;
1679168498Spjd				uint64_t timestamp;
1680168498Spjd				time_t t;
1681168498Spjd
1682168498Spjd				verify(nvlist_lookup_string(config,
1683168498Spjd				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
1684168498Spjd				verify(nvlist_lookup_uint64(config,
1685168498Spjd				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
1686168498Spjd				t = timestamp;
1687168498Spjd				(void) fprintf(stderr, gettext("cannot import "
1688168498Spjd				    "'%s': pool may be in use from other "
1689168498Spjd				    "system, it was last accessed by %s "
1690168498Spjd				    "(hostid: 0x%lx) on %s"), name, hostname,
1691168498Spjd				    (unsigned long)hostid,
1692168498Spjd				    asctime(localtime(&t)));
1693168498Spjd				(void) fprintf(stderr, gettext("use '-f' to "
1694168498Spjd				    "import anyway\n"));
1695168498Spjd				return (1);
1696168498Spjd			}
1697168498Spjd		} else {
1698168498Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
1699168498Spjd			    "pool may be in use from other system\n"), name);
1700168498Spjd			(void) fprintf(stderr, gettext("use '-f' to import "
1701168498Spjd			    "anyway\n"));
1702168498Spjd			return (1);
1703168498Spjd		}
1704168404Spjd	}
1705168404Spjd
1706219089Spjd	if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
1707168404Spjd		return (1);
1708168404Spjd
1709168404Spjd	if (newname != NULL)
1710168404Spjd		name = (char *)newname;
1711168404Spjd
1712209962Smm	if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
1713209962Smm		return (1);
1714168404Spjd
1715209962Smm	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
1716219089Spjd	    !(flags & ZFS_IMPORT_ONLY) &&
1717209962Smm	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1718168404Spjd		zpool_close(zhp);
1719168404Spjd		return (1);
1720168404Spjd	}
1721168404Spjd
1722168404Spjd	zpool_close(zhp);
1723219089Spjd	return (0);
1724168404Spjd}
1725168404Spjd
1726168404Spjd/*
1727168404Spjd * zpool import [-d dir] [-D]
1728185029Spjd *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
1729185029Spjd *              [-d dir | -c cachefile] [-f] -a
1730185029Spjd *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
1731219089Spjd *              [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool]
1732168404Spjd *
1733185029Spjd *	 -c	Read pool information from a cachefile instead of searching
1734185029Spjd *		devices.
1735185029Spjd *
1736168404Spjd *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1737168404Spjd *		one directory can be specified using multiple '-d' options.
1738168404Spjd *
1739168404Spjd *       -D     Scan for previously destroyed pools or import all or only
1740168404Spjd *              specified destroyed pools.
1741168404Spjd *
1742168404Spjd *       -R	Temporarily import the pool, with all mountpoints relative to
1743168404Spjd *		the given root.  The pool will remain exported when the machine
1744168404Spjd *		is rebooted.
1745168404Spjd *
1746219089Spjd *       -V	Import even in the presence of faulted vdevs.  This is an
1747185029Spjd *       	intentionally undocumented option for testing purposes, and
1748185029Spjd *       	treats the pool configuration as complete, leaving any bad
1749209962Smm *		vdevs in the FAULTED state. In other words, it does verbatim
1750209962Smm *		import.
1751185029Spjd *
1752219089Spjd *       -f	Force import, even if it appears that the pool is active.
1753219089Spjd *
1754219089Spjd *       -F     Attempt rewind if necessary.
1755219089Spjd *
1756219089Spjd *       -n     See if rewind would work, but don't actually rewind.
1757219089Spjd *
1758219089Spjd *       -N     Import the pool but don't mount datasets.
1759219089Spjd *
1760219089Spjd *       -T     Specify a starting txg to use for import. This option is
1761219089Spjd *       	intentionally undocumented option for testing purposes.
1762219089Spjd *
1763168404Spjd *       -a	Import all pools found.
1764168404Spjd *
1765185029Spjd *       -o	Set property=value and/or temporary mount options (without '=').
1766185029Spjd *
1767168404Spjd * The import command scans for pools to import, and import pools based on pool
1768168404Spjd * name and GUID.  The pool can also be renamed as part of the import process.
1769168404Spjd */
1770168404Spjdint
1771168404Spjdzpool_do_import(int argc, char **argv)
1772168404Spjd{
1773168404Spjd	char **searchdirs = NULL;
1774168404Spjd	int nsearch = 0;
1775168404Spjd	int c;
1776219089Spjd	int err = 0;
1777185029Spjd	nvlist_t *pools = NULL;
1778168404Spjd	boolean_t do_all = B_FALSE;
1779168404Spjd	boolean_t do_destroyed = B_FALSE;
1780168404Spjd	char *mntopts = NULL;
1781168404Spjd	nvpair_t *elem;
1782168404Spjd	nvlist_t *config;
1783185029Spjd	uint64_t searchguid = 0;
1784185029Spjd	char *searchname = NULL;
1785185029Spjd	char *propval;
1786168404Spjd	nvlist_t *found_config;
1787219089Spjd	nvlist_t *policy = NULL;
1788185029Spjd	nvlist_t *props = NULL;
1789168404Spjd	boolean_t first;
1790219089Spjd	int flags = ZFS_IMPORT_NORMAL;
1791219089Spjd	uint32_t rewind_policy = ZPOOL_NO_REWIND;
1792219089Spjd	boolean_t dryrun = B_FALSE;
1793219089Spjd	boolean_t do_rewind = B_FALSE;
1794219089Spjd	boolean_t xtreme_rewind = B_FALSE;
1795219089Spjd	uint64_t pool_state, txg = -1ULL;
1796185029Spjd	char *cachefile = NULL;
1797219089Spjd	importargs_t idata = { 0 };
1798219089Spjd	char *endptr;
1799168404Spjd
1800168404Spjd	/* check options */
1801219089Spjd	while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) {
1802168404Spjd		switch (c) {
1803168404Spjd		case 'a':
1804168404Spjd			do_all = B_TRUE;
1805168404Spjd			break;
1806185029Spjd		case 'c':
1807185029Spjd			cachefile = optarg;
1808185029Spjd			break;
1809168404Spjd		case 'd':
1810168404Spjd			if (searchdirs == NULL) {
1811168404Spjd				searchdirs = safe_malloc(sizeof (char *));
1812168404Spjd			} else {
1813168404Spjd				char **tmp = safe_malloc((nsearch + 1) *
1814168404Spjd				    sizeof (char *));
1815168404Spjd				bcopy(searchdirs, tmp, nsearch *
1816168404Spjd				    sizeof (char *));
1817168404Spjd				free(searchdirs);
1818168404Spjd				searchdirs = tmp;
1819168404Spjd			}
1820168404Spjd			searchdirs[nsearch++] = optarg;
1821168404Spjd			break;
1822168404Spjd		case 'D':
1823168404Spjd			do_destroyed = B_TRUE;
1824168404Spjd			break;
1825168404Spjd		case 'f':
1826219089Spjd			flags |= ZFS_IMPORT_ANY_HOST;
1827168404Spjd			break;
1828185029Spjd		case 'F':
1829219089Spjd			do_rewind = B_TRUE;
1830185029Spjd			break;
1831219089Spjd		case 'm':
1832219089Spjd			flags |= ZFS_IMPORT_MISSING_LOG;
1833219089Spjd			break;
1834219089Spjd		case 'n':
1835219089Spjd			dryrun = B_TRUE;
1836219089Spjd			break;
1837219089Spjd		case 'N':
1838219089Spjd			flags |= ZFS_IMPORT_ONLY;
1839219089Spjd			break;
1840168404Spjd		case 'o':
1841185029Spjd			if ((propval = strchr(optarg, '=')) != NULL) {
1842185029Spjd				*propval = '\0';
1843185029Spjd				propval++;
1844185029Spjd				if (add_prop_list(optarg, propval,
1845185029Spjd				    &props, B_TRUE))
1846185029Spjd					goto error;
1847185029Spjd			} else {
1848185029Spjd				mntopts = optarg;
1849185029Spjd			}
1850168404Spjd			break;
1851168404Spjd		case 'R':
1852185029Spjd			if (add_prop_list(zpool_prop_to_name(
1853185029Spjd			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1854185029Spjd				goto error;
1855185029Spjd			if (nvlist_lookup_string(props,
1856185029Spjd			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
1857185029Spjd			    &propval) == 0)
1858185029Spjd				break;
1859185029Spjd			if (add_prop_list(zpool_prop_to_name(
1860185029Spjd			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1861185029Spjd				goto error;
1862168404Spjd			break;
1863219089Spjd		case 'T':
1864219089Spjd			errno = 0;
1865219089Spjd			txg = strtoull(optarg, &endptr, 10);
1866219089Spjd			if (errno != 0 || *endptr != '\0') {
1867219089Spjd				(void) fprintf(stderr,
1868219089Spjd				    gettext("invalid txg value\n"));
1869219089Spjd				usage(B_FALSE);
1870219089Spjd			}
1871219089Spjd			rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
1872219089Spjd			break;
1873219089Spjd		case 'V':
1874219089Spjd			flags |= ZFS_IMPORT_VERBATIM;
1875219089Spjd			break;
1876219089Spjd		case 'X':
1877219089Spjd			xtreme_rewind = B_TRUE;
1878219089Spjd			break;
1879168404Spjd		case ':':
1880168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
1881168404Spjd			    "'%c' option\n"), optopt);
1882168404Spjd			usage(B_FALSE);
1883168404Spjd			break;
1884168404Spjd		case '?':
1885168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1886168404Spjd			    optopt);
1887168404Spjd			usage(B_FALSE);
1888168404Spjd		}
1889168404Spjd	}
1890168404Spjd
1891168404Spjd	argc -= optind;
1892168404Spjd	argv += optind;
1893168404Spjd
1894185029Spjd	if (cachefile && nsearch != 0) {
1895185029Spjd		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
1896185029Spjd		usage(B_FALSE);
1897185029Spjd	}
1898185029Spjd
1899219089Spjd	if ((dryrun || xtreme_rewind) && !do_rewind) {
1900219089Spjd		(void) fprintf(stderr,
1901219089Spjd		    gettext("-n or -X only meaningful with -F\n"));
1902219089Spjd		usage(B_FALSE);
1903219089Spjd	}
1904219089Spjd	if (dryrun)
1905219089Spjd		rewind_policy = ZPOOL_TRY_REWIND;
1906219089Spjd	else if (do_rewind)
1907219089Spjd		rewind_policy = ZPOOL_DO_REWIND;
1908219089Spjd	if (xtreme_rewind)
1909219089Spjd		rewind_policy |= ZPOOL_EXTREME_REWIND;
1910219089Spjd
1911219089Spjd	/* In the future, we can capture further policy and include it here */
1912219089Spjd	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
1913219089Spjd	    nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 ||
1914219089Spjd	    nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
1915219089Spjd		goto error;
1916219089Spjd
1917168404Spjd	if (searchdirs == NULL) {
1918168404Spjd		searchdirs = safe_malloc(sizeof (char *));
1919235478Savg		searchdirs[0] = "/dev";
1920168404Spjd		nsearch = 1;
1921168404Spjd	}
1922168404Spjd
1923168404Spjd	/* check argument count */
1924168404Spjd	if (do_all) {
1925168404Spjd		if (argc != 0) {
1926168404Spjd			(void) fprintf(stderr, gettext("too many arguments\n"));
1927168404Spjd			usage(B_FALSE);
1928168404Spjd		}
1929168404Spjd	} else {
1930168404Spjd		if (argc > 2) {
1931168404Spjd			(void) fprintf(stderr, gettext("too many arguments\n"));
1932168404Spjd			usage(B_FALSE);
1933168404Spjd		}
1934168404Spjd
1935168404Spjd		/*
1936168404Spjd		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1937168404Spjd		 * here because otherwise any attempt to discover pools will
1938168404Spjd		 * silently fail.
1939168404Spjd		 */
1940168404Spjd		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1941168404Spjd			(void) fprintf(stderr, gettext("cannot "
1942168404Spjd			    "discover pools: permission denied\n"));
1943168404Spjd			free(searchdirs);
1944219089Spjd			nvlist_free(policy);
1945168404Spjd			return (1);
1946168404Spjd		}
1947168404Spjd	}
1948168404Spjd
1949168404Spjd	/*
1950168404Spjd	 * Depending on the arguments given, we do one of the following:
1951168404Spjd	 *
1952168404Spjd	 *	<none>	Iterate through all pools and display information about
1953168404Spjd	 *		each one.
1954168404Spjd	 *
1955168404Spjd	 *	-a	Iterate through all pools and try to import each one.
1956168404Spjd	 *
1957168404Spjd	 *	<id>	Find the pool that corresponds to the given GUID/pool
1958168404Spjd	 *		name and import that one.
1959168404Spjd	 *
1960168404Spjd	 *	-D	Above options applies only to destroyed pools.
1961168404Spjd	 */
1962168404Spjd	if (argc != 0) {
1963168404Spjd		char *endptr;
1964168404Spjd
1965168404Spjd		errno = 0;
1966168404Spjd		searchguid = strtoull(argv[0], &endptr, 10);
1967168404Spjd		if (errno != 0 || *endptr != '\0')
1968168404Spjd			searchname = argv[0];
1969168404Spjd		found_config = NULL;
1970168404Spjd
1971185029Spjd		/*
1972219089Spjd		 * User specified a name or guid.  Ensure it's unique.
1973185029Spjd		 */
1974219089Spjd		idata.unique = B_TRUE;
1975185029Spjd	}
1976185029Spjd
1977219089Spjd
1978219089Spjd	idata.path = searchdirs;
1979219089Spjd	idata.paths = nsearch;
1980219089Spjd	idata.poolname = searchname;
1981219089Spjd	idata.guid = searchguid;
1982219089Spjd	idata.cachefile = cachefile;
1983219089Spjd
1984219089Spjd	pools = zpool_search_import(g_zfs, &idata);
1985219089Spjd
1986219089Spjd	if (pools != NULL && idata.exists &&
1987219089Spjd	    (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
1988219089Spjd		(void) fprintf(stderr, gettext("cannot import '%s': "
1989219089Spjd		    "a pool with that name already exists\n"),
1990219089Spjd		    argv[0]);
1991219089Spjd		(void) fprintf(stderr, gettext("use the form '%s "
1992219089Spjd		    "<pool | id> <newpool>' to give it a new name\n"),
1993219089Spjd		    "zpool import");
1994219089Spjd		err = 1;
1995219089Spjd	} else if (pools == NULL && idata.exists) {
1996219089Spjd		(void) fprintf(stderr, gettext("cannot import '%s': "
1997219089Spjd		    "a pool with that name is already created/imported,\n"),
1998219089Spjd		    argv[0]);
1999219089Spjd		(void) fprintf(stderr, gettext("and no additional pools "
2000219089Spjd		    "with that name were found\n"));
2001219089Spjd		err = 1;
2002219089Spjd	} else if (pools == NULL) {
2003185029Spjd		if (argc != 0) {
2004185029Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
2005185029Spjd			    "no such pool available\n"), argv[0]);
2006185029Spjd		}
2007219089Spjd		err = 1;
2008219089Spjd	}
2009219089Spjd
2010219089Spjd	if (err == 1) {
2011185029Spjd		free(searchdirs);
2012219089Spjd		nvlist_free(policy);
2013185029Spjd		return (1);
2014185029Spjd	}
2015185029Spjd
2016185029Spjd	/*
2017185029Spjd	 * At this point we have a list of import candidate configs. Even if
2018185029Spjd	 * we were searching by pool name or guid, we still need to
2019185029Spjd	 * post-process the list to deal with pool state and possible
2020185029Spjd	 * duplicate names.
2021185029Spjd	 */
2022168404Spjd	err = 0;
2023168404Spjd	elem = NULL;
2024168404Spjd	first = B_TRUE;
2025168404Spjd	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
2026168404Spjd
2027168404Spjd		verify(nvpair_value_nvlist(elem, &config) == 0);
2028168404Spjd
2029168404Spjd		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
2030168404Spjd		    &pool_state) == 0);
2031168404Spjd		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
2032168404Spjd			continue;
2033168404Spjd		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
2034168404Spjd			continue;
2035168404Spjd
2036219089Spjd		verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY,
2037219089Spjd		    policy) == 0);
2038219089Spjd
2039168404Spjd		if (argc == 0) {
2040168404Spjd			if (first)
2041168404Spjd				first = B_FALSE;
2042168404Spjd			else if (!do_all)
2043168404Spjd				(void) printf("\n");
2044168404Spjd
2045219089Spjd			if (do_all) {
2046168404Spjd				err |= do_import(config, NULL, mntopts,
2047219089Spjd				    props, flags);
2048219089Spjd			} else {
2049168404Spjd				show_import(config);
2050219089Spjd			}
2051168404Spjd		} else if (searchname != NULL) {
2052168404Spjd			char *name;
2053168404Spjd
2054168404Spjd			/*
2055168404Spjd			 * We are searching for a pool based on name.
2056168404Spjd			 */
2057168404Spjd			verify(nvlist_lookup_string(config,
2058168404Spjd			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
2059168404Spjd
2060168404Spjd			if (strcmp(name, searchname) == 0) {
2061168404Spjd				if (found_config != NULL) {
2062168404Spjd					(void) fprintf(stderr, gettext(
2063168404Spjd					    "cannot import '%s': more than "
2064168404Spjd					    "one matching pool\n"), searchname);
2065168404Spjd					(void) fprintf(stderr, gettext(
2066168404Spjd					    "import by numeric ID instead\n"));
2067168404Spjd					err = B_TRUE;
2068168404Spjd				}
2069168404Spjd				found_config = config;
2070168404Spjd			}
2071168404Spjd		} else {
2072168404Spjd			uint64_t guid;
2073168404Spjd
2074168404Spjd			/*
2075168404Spjd			 * Search for a pool by guid.
2076168404Spjd			 */
2077168404Spjd			verify(nvlist_lookup_uint64(config,
2078168404Spjd			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
2079168404Spjd
2080168404Spjd			if (guid == searchguid)
2081168404Spjd				found_config = config;
2082168404Spjd		}
2083168404Spjd	}
2084168404Spjd
2085168404Spjd	/*
2086168404Spjd	 * If we were searching for a specific pool, verify that we found a
2087168404Spjd	 * pool, and then do the import.
2088168404Spjd	 */
2089168404Spjd	if (argc != 0 && err == 0) {
2090168404Spjd		if (found_config == NULL) {
2091168404Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
2092168404Spjd			    "no such pool available\n"), argv[0]);
2093168404Spjd			err = B_TRUE;
2094168404Spjd		} else {
2095168404Spjd			err |= do_import(found_config, argc == 1 ? NULL :
2096219089Spjd			    argv[1], mntopts, props, flags);
2097168404Spjd		}
2098168404Spjd	}
2099168404Spjd
2100168404Spjd	/*
2101168404Spjd	 * If we were just looking for pools, report an error if none were
2102168404Spjd	 * found.
2103168404Spjd	 */
2104168404Spjd	if (argc == 0 && first)
2105168404Spjd		(void) fprintf(stderr,
2106168404Spjd		    gettext("no pools available to import\n"));
2107168404Spjd
2108185029Spjderror:
2109185029Spjd	nvlist_free(props);
2110168404Spjd	nvlist_free(pools);
2111219089Spjd	nvlist_free(policy);
2112168404Spjd	free(searchdirs);
2113168404Spjd
2114168404Spjd	return (err ? 1 : 0);
2115168404Spjd}
2116168404Spjd
2117168404Spjdtypedef struct iostat_cbdata {
2118236155Smm	boolean_t cb_verbose;
2119236155Smm	int cb_namewidth;
2120236155Smm	int cb_iteration;
2121168404Spjd	zpool_list_t *cb_list;
2122168404Spjd} iostat_cbdata_t;
2123168404Spjd
2124168404Spjdstatic void
2125168404Spjdprint_iostat_separator(iostat_cbdata_t *cb)
2126168404Spjd{
2127168404Spjd	int i = 0;
2128168404Spjd
2129168404Spjd	for (i = 0; i < cb->cb_namewidth; i++)
2130168404Spjd		(void) printf("-");
2131168404Spjd	(void) printf("  -----  -----  -----  -----  -----  -----\n");
2132168404Spjd}
2133168404Spjd
2134168404Spjdstatic void
2135168404Spjdprint_iostat_header(iostat_cbdata_t *cb)
2136168404Spjd{
2137168404Spjd	(void) printf("%*s     capacity     operations    bandwidth\n",
2138168404Spjd	    cb->cb_namewidth, "");
2139219089Spjd	(void) printf("%-*s  alloc   free   read  write   read  write\n",
2140168404Spjd	    cb->cb_namewidth, "pool");
2141168404Spjd	print_iostat_separator(cb);
2142168404Spjd}
2143168404Spjd
2144168404Spjd/*
2145168404Spjd * Display a single statistic.
2146168404Spjd */
2147185029Spjdstatic void
2148168404Spjdprint_one_stat(uint64_t value)
2149168404Spjd{
2150168404Spjd	char buf[64];
2151168404Spjd
2152168404Spjd	zfs_nicenum(value, buf, sizeof (buf));
2153168404Spjd	(void) printf("  %5s", buf);
2154168404Spjd}
2155168404Spjd
2156168404Spjd/*
2157168404Spjd * Print out all the statistics for the given vdev.  This can either be the
2158168404Spjd * toplevel configuration, or called recursively.  If 'name' is NULL, then this
2159168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats.
2160168404Spjd */
2161168404Spjdvoid
2162168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
2163168404Spjd    nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
2164168404Spjd{
2165168404Spjd	nvlist_t **oldchild, **newchild;
2166168404Spjd	uint_t c, children;
2167168404Spjd	vdev_stat_t *oldvs, *newvs;
2168168404Spjd	vdev_stat_t zerovs = { 0 };
2169168404Spjd	uint64_t tdelta;
2170168404Spjd	double scale;
2171168404Spjd	char *vname;
2172168404Spjd
2173168404Spjd	if (oldnv != NULL) {
2174219089Spjd		verify(nvlist_lookup_uint64_array(oldnv,
2175219089Spjd		    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
2176168404Spjd	} else {
2177168404Spjd		oldvs = &zerovs;
2178168404Spjd	}
2179168404Spjd
2180219089Spjd	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
2181168404Spjd	    (uint64_t **)&newvs, &c) == 0);
2182168404Spjd
2183168404Spjd	if (strlen(name) + depth > cb->cb_namewidth)
2184168404Spjd		(void) printf("%*s%s", depth, "", name);
2185168404Spjd	else
2186168404Spjd		(void) printf("%*s%s%*s", depth, "", name,
2187168404Spjd		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
2188168404Spjd
2189168404Spjd	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
2190168404Spjd
2191168404Spjd	if (tdelta == 0)
2192168404Spjd		scale = 1.0;
2193168404Spjd	else
2194168404Spjd		scale = (double)NANOSEC / tdelta;
2195168404Spjd
2196168404Spjd	/* only toplevel vdevs have capacity stats */
2197168404Spjd	if (newvs->vs_space == 0) {
2198168404Spjd		(void) printf("      -      -");
2199168404Spjd	} else {
2200168404Spjd		print_one_stat(newvs->vs_alloc);
2201168404Spjd		print_one_stat(newvs->vs_space - newvs->vs_alloc);
2202168404Spjd	}
2203168404Spjd
2204168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
2205168404Spjd	    oldvs->vs_ops[ZIO_TYPE_READ])));
2206168404Spjd
2207168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
2208168404Spjd	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
2209168404Spjd
2210168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
2211168404Spjd	    oldvs->vs_bytes[ZIO_TYPE_READ])));
2212168404Spjd
2213168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
2214168404Spjd	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
2215168404Spjd
2216168404Spjd	(void) printf("\n");
2217168404Spjd
2218168404Spjd	if (!cb->cb_verbose)
2219168404Spjd		return;
2220168404Spjd
2221168404Spjd	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
2222168404Spjd	    &newchild, &children) != 0)
2223168404Spjd		return;
2224168404Spjd
2225168404Spjd	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
2226168404Spjd	    &oldchild, &c) != 0)
2227168404Spjd		return;
2228168404Spjd
2229168404Spjd	for (c = 0; c < children; c++) {
2230227497Smm		uint64_t ishole = B_FALSE, islog = B_FALSE;
2231219089Spjd
2232227497Smm		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
2233227497Smm		    &ishole);
2234227497Smm
2235227497Smm		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
2236227497Smm		    &islog);
2237227497Smm
2238227497Smm		if (ishole || islog)
2239219089Spjd			continue;
2240219089Spjd
2241219089Spjd		vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
2242168404Spjd		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2243168404Spjd		    newchild[c], cb, depth + 2);
2244168404Spjd		free(vname);
2245168404Spjd	}
2246185029Spjd
2247185029Spjd	/*
2248227497Smm	 * Log device section
2249227497Smm	 */
2250227497Smm
2251227497Smm	if (num_logs(newnv) > 0) {
2252227497Smm		(void) printf("%-*s      -      -      -      -      -      "
2253227497Smm		    "-\n", cb->cb_namewidth, "logs");
2254227497Smm
2255227497Smm		for (c = 0; c < children; c++) {
2256227497Smm			uint64_t islog = B_FALSE;
2257227497Smm			(void) nvlist_lookup_uint64(newchild[c],
2258227497Smm			    ZPOOL_CONFIG_IS_LOG, &islog);
2259227497Smm
2260227497Smm			if (islog) {
2261227497Smm				vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
2262227497Smm				    B_FALSE);
2263227497Smm				print_vdev_stats(zhp, vname, oldnv ?
2264227497Smm				    oldchild[c] : NULL, newchild[c],
2265227497Smm				    cb, depth + 2);
2266227497Smm				free(vname);
2267227497Smm			}
2268227497Smm		}
2269227497Smm
2270227497Smm	}
2271227497Smm
2272227497Smm	/*
2273185029Spjd	 * Include level 2 ARC devices in iostat output
2274185029Spjd	 */
2275185029Spjd	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
2276185029Spjd	    &newchild, &children) != 0)
2277185029Spjd		return;
2278185029Spjd
2279185029Spjd	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
2280185029Spjd	    &oldchild, &c) != 0)
2281185029Spjd		return;
2282185029Spjd
2283185029Spjd	if (children > 0) {
2284185029Spjd		(void) printf("%-*s      -      -      -      -      -      "
2285185029Spjd		    "-\n", cb->cb_namewidth, "cache");
2286185029Spjd		for (c = 0; c < children; c++) {
2287219089Spjd			vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
2288219089Spjd			    B_FALSE);
2289185029Spjd			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2290185029Spjd			    newchild[c], cb, depth + 2);
2291185029Spjd			free(vname);
2292185029Spjd		}
2293185029Spjd	}
2294168404Spjd}
2295168404Spjd
2296168404Spjdstatic int
2297168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data)
2298168404Spjd{
2299168404Spjd	iostat_cbdata_t *cb = data;
2300168404Spjd	boolean_t missing;
2301168404Spjd
2302168404Spjd	/*
2303168404Spjd	 * If the pool has disappeared, remove it from the list and continue.
2304168404Spjd	 */
2305168404Spjd	if (zpool_refresh_stats(zhp, &missing) != 0)
2306168404Spjd		return (-1);
2307168404Spjd
2308168404Spjd	if (missing)
2309168404Spjd		pool_list_remove(cb->cb_list, zhp);
2310168404Spjd
2311168404Spjd	return (0);
2312168404Spjd}
2313168404Spjd
2314168404Spjd/*
2315168404Spjd * Callback to print out the iostats for the given pool.
2316168404Spjd */
2317168404Spjdint
2318168404Spjdprint_iostat(zpool_handle_t *zhp, void *data)
2319168404Spjd{
2320168404Spjd	iostat_cbdata_t *cb = data;
2321168404Spjd	nvlist_t *oldconfig, *newconfig;
2322168404Spjd	nvlist_t *oldnvroot, *newnvroot;
2323168404Spjd
2324168404Spjd	newconfig = zpool_get_config(zhp, &oldconfig);
2325168404Spjd
2326168404Spjd	if (cb->cb_iteration == 1)
2327168404Spjd		oldconfig = NULL;
2328168404Spjd
2329168404Spjd	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
2330168404Spjd	    &newnvroot) == 0);
2331168404Spjd
2332168404Spjd	if (oldconfig == NULL)
2333168404Spjd		oldnvroot = NULL;
2334168404Spjd	else
2335168404Spjd		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
2336168404Spjd		    &oldnvroot) == 0);
2337168404Spjd
2338168404Spjd	/*
2339168404Spjd	 * Print out the statistics for the pool.
2340168404Spjd	 */
2341168404Spjd	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
2342168404Spjd
2343168404Spjd	if (cb->cb_verbose)
2344168404Spjd		print_iostat_separator(cb);
2345168404Spjd
2346168404Spjd	return (0);
2347168404Spjd}
2348168404Spjd
2349168404Spjdint
2350168404Spjdget_namewidth(zpool_handle_t *zhp, void *data)
2351168404Spjd{
2352168404Spjd	iostat_cbdata_t *cb = data;
2353168404Spjd	nvlist_t *config, *nvroot;
2354168404Spjd
2355168404Spjd	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
2356168404Spjd		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2357168404Spjd		    &nvroot) == 0);
2358168404Spjd		if (!cb->cb_verbose)
2359168404Spjd			cb->cb_namewidth = strlen(zpool_get_name(zhp));
2360168404Spjd		else
2361236145Smm			cb->cb_namewidth = max_width(zhp, nvroot, 0,
2362236145Smm			    cb->cb_namewidth);
2363168404Spjd	}
2364168404Spjd
2365168404Spjd	/*
2366168404Spjd	 * The width must fall into the range [10,38].  The upper limit is the
2367168404Spjd	 * maximum we can have and still fit in 80 columns.
2368168404Spjd	 */
2369168404Spjd	if (cb->cb_namewidth < 10)
2370168404Spjd		cb->cb_namewidth = 10;
2371168404Spjd	if (cb->cb_namewidth > 38)
2372168404Spjd		cb->cb_namewidth = 38;
2373168404Spjd
2374168404Spjd	return (0);
2375168404Spjd}
2376168404Spjd
2377168404Spjd/*
2378219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one.
2379168404Spjd */
2380219089Spjdstatic void
2381219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv,
2382219089Spjd    unsigned long *cnt)
2383168404Spjd{
2384168404Spjd	unsigned long interval = 0, count = 0;
2385219089Spjd	int argc = *argcp, errno;
2386168404Spjd
2387168404Spjd	/*
2388168404Spjd	 * Determine if the last argument is an integer or a pool name
2389168404Spjd	 */
2390168404Spjd	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2391168404Spjd		char *end;
2392168404Spjd
2393168404Spjd		errno = 0;
2394168404Spjd		interval = strtoul(argv[argc - 1], &end, 10);
2395168404Spjd
2396168404Spjd		if (*end == '\0' && errno == 0) {
2397168404Spjd			if (interval == 0) {
2398168404Spjd				(void) fprintf(stderr, gettext("interval "
2399168404Spjd				    "cannot be zero\n"));
2400168404Spjd				usage(B_FALSE);
2401168404Spjd			}
2402168404Spjd			/*
2403168404Spjd			 * Ignore the last parameter
2404168404Spjd			 */
2405168404Spjd			argc--;
2406168404Spjd		} else {
2407168404Spjd			/*
2408168404Spjd			 * If this is not a valid number, just plow on.  The
2409168404Spjd			 * user will get a more informative error message later
2410168404Spjd			 * on.
2411168404Spjd			 */
2412168404Spjd			interval = 0;
2413168404Spjd		}
2414168404Spjd	}
2415168404Spjd
2416168404Spjd	/*
2417168404Spjd	 * If the last argument is also an integer, then we have both a count
2418219089Spjd	 * and an interval.
2419168404Spjd	 */
2420168404Spjd	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2421168404Spjd		char *end;
2422168404Spjd
2423168404Spjd		errno = 0;
2424168404Spjd		count = interval;
2425168404Spjd		interval = strtoul(argv[argc - 1], &end, 10);
2426168404Spjd
2427168404Spjd		if (*end == '\0' && errno == 0) {
2428168404Spjd			if (interval == 0) {
2429168404Spjd				(void) fprintf(stderr, gettext("interval "
2430168404Spjd				    "cannot be zero\n"));
2431168404Spjd				usage(B_FALSE);
2432168404Spjd			}
2433168404Spjd
2434168404Spjd			/*
2435168404Spjd			 * Ignore the last parameter
2436168404Spjd			 */
2437168404Spjd			argc--;
2438168404Spjd		} else {
2439168404Spjd			interval = 0;
2440168404Spjd		}
2441168404Spjd	}
2442168404Spjd
2443219089Spjd	*iv = interval;
2444219089Spjd	*cnt = count;
2445219089Spjd	*argcp = argc;
2446219089Spjd}
2447219089Spjd
2448219089Spjdstatic void
2449219089Spjdget_timestamp_arg(char c)
2450219089Spjd{
2451219089Spjd	if (c == 'u')
2452219089Spjd		timestamp_fmt = UDATE;
2453219089Spjd	else if (c == 'd')
2454219089Spjd		timestamp_fmt = DDATE;
2455219089Spjd	else
2456219089Spjd		usage(B_FALSE);
2457219089Spjd}
2458219089Spjd
2459219089Spjd/*
2460219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]]
2461219089Spjd *
2462219089Spjd *	-v	Display statistics for individual vdevs
2463219089Spjd *	-T	Display a timestamp in date(1) or Unix format
2464219089Spjd *
2465219089Spjd * This command can be tricky because we want to be able to deal with pool
2466219089Spjd * creation/destruction as well as vdev configuration changes.  The bulk of this
2467219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
2468219089Spjd * on pool_list_update() to detect the addition of new pools.  Configuration
2469219089Spjd * changes are all handled within libzfs.
2470219089Spjd */
2471219089Spjdint
2472219089Spjdzpool_do_iostat(int argc, char **argv)
2473219089Spjd{
2474219089Spjd	int c;
2475219089Spjd	int ret;
2476219089Spjd	int npools;
2477219089Spjd	unsigned long interval = 0, count = 0;
2478219089Spjd	zpool_list_t *list;
2479219089Spjd	boolean_t verbose = B_FALSE;
2480219089Spjd	iostat_cbdata_t cb;
2481219089Spjd
2482219089Spjd	/* check options */
2483219089Spjd	while ((c = getopt(argc, argv, "T:v")) != -1) {
2484219089Spjd		switch (c) {
2485219089Spjd		case 'T':
2486219089Spjd			get_timestamp_arg(*optarg);
2487219089Spjd			break;
2488219089Spjd		case 'v':
2489219089Spjd			verbose = B_TRUE;
2490219089Spjd			break;
2491219089Spjd		case '?':
2492219089Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2493219089Spjd			    optopt);
2494219089Spjd			usage(B_FALSE);
2495219089Spjd		}
2496219089Spjd	}
2497219089Spjd
2498219089Spjd	argc -= optind;
2499219089Spjd	argv += optind;
2500219089Spjd
2501219089Spjd	get_interval_count(&argc, argv, &interval, &count);
2502219089Spjd
2503168404Spjd	/*
2504168404Spjd	 * Construct the list of all interesting pools.
2505168404Spjd	 */
2506168404Spjd	ret = 0;
2507168404Spjd	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
2508168404Spjd		return (1);
2509168404Spjd
2510168404Spjd	if (pool_list_count(list) == 0 && argc != 0) {
2511168404Spjd		pool_list_free(list);
2512168404Spjd		return (1);
2513168404Spjd	}
2514168404Spjd
2515168404Spjd	if (pool_list_count(list) == 0 && interval == 0) {
2516168404Spjd		pool_list_free(list);
2517168404Spjd		(void) fprintf(stderr, gettext("no pools available\n"));
2518168404Spjd		return (1);
2519168404Spjd	}
2520168404Spjd
2521168404Spjd	/*
2522168404Spjd	 * Enter the main iostat loop.
2523168404Spjd	 */
2524168404Spjd	cb.cb_list = list;
2525168404Spjd	cb.cb_verbose = verbose;
2526168404Spjd	cb.cb_iteration = 0;
2527168404Spjd	cb.cb_namewidth = 0;
2528168404Spjd
2529168404Spjd	for (;;) {
2530168404Spjd		pool_list_update(list);
2531168404Spjd
2532168404Spjd		if ((npools = pool_list_count(list)) == 0)
2533168404Spjd			break;
2534168404Spjd
2535168404Spjd		/*
2536168404Spjd		 * Refresh all statistics.  This is done as an explicit step
2537168404Spjd		 * before calculating the maximum name width, so that any
2538168404Spjd		 * configuration changes are properly accounted for.
2539168404Spjd		 */
2540168404Spjd		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
2541168404Spjd
2542168404Spjd		/*
2543168404Spjd		 * Iterate over all pools to determine the maximum width
2544168404Spjd		 * for the pool / device name column across all pools.
2545168404Spjd		 */
2546168404Spjd		cb.cb_namewidth = 0;
2547168404Spjd		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2548168404Spjd
2549219089Spjd		if (timestamp_fmt != NODATE)
2550219089Spjd			print_timestamp(timestamp_fmt);
2551219089Spjd
2552168404Spjd		/*
2553168404Spjd		 * If it's the first time, or verbose mode, print the header.
2554168404Spjd		 */
2555168404Spjd		if (++cb.cb_iteration == 1 || verbose)
2556168404Spjd			print_iostat_header(&cb);
2557168404Spjd
2558168404Spjd		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2559168404Spjd
2560168404Spjd		/*
2561168404Spjd		 * If there's more than one pool, and we're not in verbose mode
2562168404Spjd		 * (which prints a separator for us), then print a separator.
2563168404Spjd		 */
2564168404Spjd		if (npools > 1 && !verbose)
2565168404Spjd			print_iostat_separator(&cb);
2566168404Spjd
2567168404Spjd		if (verbose)
2568168404Spjd			(void) printf("\n");
2569168404Spjd
2570168404Spjd		/*
2571168404Spjd		 * Flush the output so that redirection to a file isn't buffered
2572168404Spjd		 * indefinitely.
2573168404Spjd		 */
2574168404Spjd		(void) fflush(stdout);
2575168404Spjd
2576168404Spjd		if (interval == 0)
2577168404Spjd			break;
2578168404Spjd
2579168404Spjd		if (count != 0 && --count == 0)
2580168404Spjd			break;
2581168404Spjd
2582168404Spjd		(void) sleep(interval);
2583168404Spjd	}
2584168404Spjd
2585168404Spjd	pool_list_free(list);
2586168404Spjd
2587168404Spjd	return (ret);
2588168404Spjd}
2589168404Spjd
2590168404Spjdtypedef struct list_cbdata {
2591236155Smm	boolean_t	cb_verbose;
2592236155Smm	int		cb_namewidth;
2593168404Spjd	boolean_t	cb_scripted;
2594185029Spjd	zprop_list_t	*cb_proplist;
2595168404Spjd} list_cbdata_t;
2596168404Spjd
2597168404Spjd/*
2598168404Spjd * Given a list of columns to display, output appropriate headers for each one.
2599168404Spjd */
2600185029Spjdstatic void
2601236155Smmprint_header(list_cbdata_t *cb)
2602168404Spjd{
2603236155Smm	zprop_list_t *pl = cb->cb_proplist;
2604185029Spjd	const char *header;
2605185029Spjd	boolean_t first = B_TRUE;
2606185029Spjd	boolean_t right_justify;
2607236155Smm	size_t width = 0;
2608168404Spjd
2609185029Spjd	for (; pl != NULL; pl = pl->pl_next) {
2610185029Spjd		if (pl->pl_prop == ZPROP_INVAL)
2611185029Spjd			continue;
2612185029Spjd
2613236155Smm		width = pl->pl_width;
2614236155Smm		if (first && cb->cb_verbose) {
2615236155Smm			/*
2616236155Smm			 * Reset the width to accommodate the verbose listing
2617236155Smm			 * of devices.
2618236155Smm			 */
2619236155Smm			width = cb->cb_namewidth;
2620236155Smm		}
2621236155Smm
2622185029Spjd		if (!first)
2623168404Spjd			(void) printf("  ");
2624168404Spjd		else
2625185029Spjd			first = B_FALSE;
2626168404Spjd
2627185029Spjd		header = zpool_prop_column_name(pl->pl_prop);
2628185029Spjd		right_justify = zpool_prop_align_right(pl->pl_prop);
2629185029Spjd
2630185029Spjd		if (pl->pl_next == NULL && !right_justify)
2631185029Spjd			(void) printf("%s", header);
2632185029Spjd		else if (right_justify)
2633236155Smm			(void) printf("%*s", width, header);
2634185029Spjd		else
2635236155Smm			(void) printf("%-*s", width, header);
2636236155Smm
2637168404Spjd	}
2638168404Spjd
2639168404Spjd	(void) printf("\n");
2640168404Spjd}
2641168404Spjd
2642185029Spjd/*
2643185029Spjd * Given a pool and a list of properties, print out all the properties according
2644185029Spjd * to the described layout.
2645185029Spjd */
2646185029Spjdstatic void
2647236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
2648168404Spjd{
2649236155Smm	zprop_list_t *pl = cb->cb_proplist;
2650185029Spjd	boolean_t first = B_TRUE;
2651185029Spjd	char property[ZPOOL_MAXPROPLEN];
2652185029Spjd	char *propstr;
2653185029Spjd	boolean_t right_justify;
2654236155Smm	size_t width;
2655168404Spjd
2656185029Spjd	for (; pl != NULL; pl = pl->pl_next) {
2657236155Smm
2658236155Smm		width = pl->pl_width;
2659236155Smm		if (first && cb->cb_verbose) {
2660236155Smm			/*
2661236155Smm			 * Reset the width to accommodate the verbose listing
2662236155Smm			 * of devices.
2663236155Smm			 */
2664236155Smm			width = cb->cb_namewidth;
2665236155Smm		}
2666236155Smm
2667185029Spjd		if (!first) {
2668236155Smm			if (cb->cb_scripted)
2669168404Spjd				(void) printf("\t");
2670168404Spjd			else
2671168404Spjd				(void) printf("  ");
2672185029Spjd		} else {
2673185029Spjd			first = B_FALSE;
2674168404Spjd		}
2675168404Spjd
2676185029Spjd		right_justify = B_FALSE;
2677185029Spjd		if (pl->pl_prop != ZPROP_INVAL) {
2678236155Smm			if (pl->pl_prop == ZPOOL_PROP_EXPANDSZ &&
2679236155Smm			    zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0)
2680236155Smm				propstr = "-";
2681236155Smm			else if (zpool_get_prop(zhp, pl->pl_prop, property,
2682185029Spjd			    sizeof (property), NULL) != 0)
2683185029Spjd				propstr = "-";
2684168404Spjd			else
2685185029Spjd				propstr = property;
2686168404Spjd
2687185029Spjd			right_justify = zpool_prop_align_right(pl->pl_prop);
2688185029Spjd		} else {
2689185029Spjd			propstr = "-";
2690185029Spjd		}
2691168404Spjd
2692168404Spjd
2693185029Spjd		/*
2694185029Spjd		 * If this is being called in scripted mode, or if this is the
2695185029Spjd		 * last column and it is left-justified, don't include a width
2696185029Spjd		 * format specifier.
2697185029Spjd		 */
2698236155Smm		if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
2699185029Spjd			(void) printf("%s", propstr);
2700185029Spjd		else if (right_justify)
2701185029Spjd			(void) printf("%*s", width, propstr);
2702185029Spjd		else
2703185029Spjd			(void) printf("%-*s", width, propstr);
2704185029Spjd	}
2705168404Spjd
2706185029Spjd	(void) printf("\n");
2707185029Spjd}
2708168404Spjd
2709236155Smmstatic void
2710236155Smmprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted)
2711236155Smm{
2712236155Smm	char propval[64];
2713236155Smm	boolean_t fixed;
2714236155Smm	size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
2715236155Smm
2716236155Smm	zfs_nicenum(value, propval, sizeof (propval));
2717236155Smm
2718236155Smm	if (prop == ZPOOL_PROP_EXPANDSZ && value == 0)
2719236155Smm		(void) strlcpy(propval, "-", sizeof (propval));
2720236155Smm
2721236155Smm	if (scripted)
2722236155Smm		(void) printf("\t%s", propval);
2723236155Smm	else
2724236155Smm		(void) printf("  %*s", width, propval);
2725236155Smm}
2726236155Smm
2727236155Smmvoid
2728236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
2729236155Smm    list_cbdata_t *cb, int depth)
2730236155Smm{
2731236155Smm	nvlist_t **child;
2732236155Smm	vdev_stat_t *vs;
2733236155Smm	uint_t c, children;
2734236155Smm	char *vname;
2735236155Smm	boolean_t scripted = cb->cb_scripted;
2736236155Smm
2737236155Smm	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
2738236155Smm	    (uint64_t **)&vs, &c) == 0);
2739236155Smm
2740236155Smm	if (name != NULL) {
2741236155Smm		if (scripted)
2742236155Smm			(void) printf("\t%s", name);
2743236155Smm		else if (strlen(name) + depth > cb->cb_namewidth)
2744236155Smm			(void) printf("%*s%s", depth, "", name);
2745236155Smm		else
2746236155Smm			(void) printf("%*s%s%*s", depth, "", name,
2747236155Smm			    (int)(cb->cb_namewidth - strlen(name) - depth), "");
2748236155Smm
2749236155Smm		/* only toplevel vdevs have capacity stats */
2750236155Smm		if (vs->vs_space == 0) {
2751236155Smm			if (scripted)
2752236155Smm				(void) printf("\t-\t-\t-");
2753236155Smm			else
2754236155Smm				(void) printf("      -      -      -");
2755236155Smm		} else {
2756236155Smm			print_one_column(ZPOOL_PROP_SIZE, vs->vs_space,
2757236155Smm			    scripted);
2758236155Smm			print_one_column(ZPOOL_PROP_CAPACITY, vs->vs_alloc,
2759236155Smm			    scripted);
2760236155Smm			print_one_column(ZPOOL_PROP_FREE,
2761236155Smm			    vs->vs_space - vs->vs_alloc, scripted);
2762236155Smm		}
2763236155Smm		print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize,
2764236155Smm		    scripted);
2765236155Smm		(void) printf("\n");
2766236155Smm	}
2767236155Smm
2768236155Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2769236155Smm	    &child, &children) != 0)
2770236155Smm		return;
2771236155Smm
2772236155Smm	for (c = 0; c < children; c++) {
2773236155Smm		uint64_t ishole = B_FALSE;
2774236155Smm
2775236155Smm		if (nvlist_lookup_uint64(child[c],
2776236155Smm		    ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
2777236155Smm			continue;
2778236155Smm
2779236155Smm		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
2780236155Smm		print_list_stats(zhp, vname, child[c], cb, depth + 2);
2781236155Smm		free(vname);
2782236155Smm	}
2783236155Smm
2784236155Smm	/*
2785236155Smm	 * Include level 2 ARC devices in iostat output
2786236155Smm	 */
2787236155Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
2788236155Smm	    &child, &children) != 0)
2789236155Smm		return;
2790236155Smm
2791236155Smm	if (children > 0) {
2792236155Smm		(void) printf("%-*s      -      -      -      -      -      "
2793236155Smm		    "-\n", cb->cb_namewidth, "cache");
2794236155Smm		for (c = 0; c < children; c++) {
2795236155Smm			vname = zpool_vdev_name(g_zfs, zhp, child[c],
2796236155Smm			    B_FALSE);
2797236155Smm			print_list_stats(zhp, vname, child[c], cb, depth + 2);
2798236155Smm			free(vname);
2799236155Smm		}
2800236155Smm	}
2801236155Smm}
2802236155Smm
2803236155Smm
2804185029Spjd/*
2805185029Spjd * Generic callback function to list a pool.
2806185029Spjd */
2807185029Spjdint
2808185029Spjdlist_callback(zpool_handle_t *zhp, void *data)
2809185029Spjd{
2810185029Spjd	list_cbdata_t *cbp = data;
2811236155Smm	nvlist_t *config;
2812236155Smm	nvlist_t *nvroot;
2813168404Spjd
2814236155Smm	config = zpool_get_config(zhp, NULL);
2815168404Spjd
2816236155Smm	print_pool(zhp, cbp);
2817236155Smm	if (!cbp->cb_verbose)
2818236155Smm		return (0);
2819168404Spjd
2820236155Smm	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2821236155Smm	    &nvroot) == 0);
2822236155Smm	print_list_stats(zhp, NULL, nvroot, cbp, 0);
2823236155Smm
2824168404Spjd	return (0);
2825168404Spjd}
2826168404Spjd
2827168404Spjd/*
2828219089Spjd * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
2829168404Spjd *
2830185029Spjd *	-H	Scripted mode.  Don't display headers, and separate properties
2831185029Spjd *		by a single tab.
2832185029Spjd *	-o	List of properties to display.  Defaults to
2833219089Spjd *		"name,size,allocated,free,capacity,health,altroot"
2834219089Spjd *	-T	Display a timestamp in date(1) or Unix format
2835168404Spjd *
2836168404Spjd * List all pools in the system, whether or not they're healthy.  Output space
2837168404Spjd * statistics for each one, as well as health status summary.
2838168404Spjd */
2839168404Spjdint
2840168404Spjdzpool_do_list(int argc, char **argv)
2841168404Spjd{
2842168404Spjd	int c;
2843168404Spjd	int ret;
2844168404Spjd	list_cbdata_t cb = { 0 };
2845185029Spjd	static char default_props[] =
2846236155Smm	    "name,size,allocated,free,capacity,dedupratio,"
2847236155Smm	    "health,altroot";
2848185029Spjd	char *props = default_props;
2849219089Spjd	unsigned long interval = 0, count = 0;
2850236155Smm	zpool_list_t *list;
2851236155Smm	boolean_t first = B_TRUE;
2852168404Spjd
2853168404Spjd	/* check options */
2854236155Smm	while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) {
2855168404Spjd		switch (c) {
2856168404Spjd		case 'H':
2857168404Spjd			cb.cb_scripted = B_TRUE;
2858168404Spjd			break;
2859168404Spjd		case 'o':
2860185029Spjd			props = optarg;
2861168404Spjd			break;
2862219089Spjd		case 'T':
2863219089Spjd			get_timestamp_arg(*optarg);
2864219089Spjd			break;
2865236155Smm		case 'v':
2866236155Smm			cb.cb_verbose = B_TRUE;
2867236155Smm			break;
2868168404Spjd		case ':':
2869168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
2870168404Spjd			    "'%c' option\n"), optopt);
2871168404Spjd			usage(B_FALSE);
2872168404Spjd			break;
2873168404Spjd		case '?':
2874168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2875168404Spjd			    optopt);
2876168404Spjd			usage(B_FALSE);
2877168404Spjd		}
2878168404Spjd	}
2879168404Spjd
2880168404Spjd	argc -= optind;
2881168404Spjd	argv += optind;
2882168404Spjd
2883219089Spjd	get_interval_count(&argc, argv, &interval, &count);
2884219089Spjd
2885185029Spjd	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
2886185029Spjd		usage(B_FALSE);
2887168404Spjd
2888236155Smm	if ((list = pool_list_get(argc, argv, &cb.cb_proplist, &ret)) == NULL)
2889236155Smm		return (1);
2890168404Spjd
2891236155Smm	if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
2892236155Smm		(void) printf(gettext("no pools available\n"));
2893236155Smm		zprop_free_list(cb.cb_proplist);
2894236155Smm		return (0);
2895236155Smm	}
2896236155Smm
2897219089Spjd	for (;;) {
2898236155Smm		pool_list_update(list);
2899168404Spjd
2900236155Smm		if (pool_list_count(list) == 0)
2901236155Smm			break;
2902236155Smm
2903236155Smm		cb.cb_namewidth = 0;
2904236155Smm		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2905236155Smm
2906219089Spjd		if (timestamp_fmt != NODATE)
2907219089Spjd			print_timestamp(timestamp_fmt);
2908168404Spjd
2909236155Smm		if (!cb.cb_scripted && (first || cb.cb_verbose)) {
2910236155Smm			print_header(&cb);
2911236155Smm			first = B_FALSE;
2912219089Spjd		}
2913236155Smm		ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
2914219089Spjd
2915219089Spjd		if (interval == 0)
2916219089Spjd			break;
2917219089Spjd
2918219089Spjd		if (count != 0 && --count == 0)
2919219089Spjd			break;
2920219089Spjd
2921219089Spjd		(void) sleep(interval);
2922168404Spjd	}
2923168404Spjd
2924219089Spjd	zprop_free_list(cb.cb_proplist);
2925168404Spjd	return (ret);
2926168404Spjd}
2927168404Spjd
2928168404Spjdstatic nvlist_t *
2929168404Spjdzpool_get_vdev_by_name(nvlist_t *nv, char *name)
2930168404Spjd{
2931168404Spjd	nvlist_t **child;
2932168404Spjd	uint_t c, children;
2933168404Spjd	nvlist_t *match;
2934168404Spjd	char *path;
2935168404Spjd
2936168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2937168404Spjd	    &child, &children) != 0) {
2938168404Spjd		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2939219089Spjd		if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
2940219089Spjd			name += sizeof(_PATH_DEV) - 1;
2941219089Spjd		if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
2942219089Spjd			path += sizeof(_PATH_DEV) - 1;
2943168404Spjd		if (strcmp(name, path) == 0)
2944168404Spjd			return (nv);
2945168404Spjd		return (NULL);
2946168404Spjd	}
2947168404Spjd
2948168404Spjd	for (c = 0; c < children; c++)
2949168404Spjd		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2950168404Spjd			return (match);
2951168404Spjd
2952168404Spjd	return (NULL);
2953168404Spjd}
2954168404Spjd
2955168404Spjdstatic int
2956168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing)
2957168404Spjd{
2958168404Spjd	boolean_t force = B_FALSE;
2959168404Spjd	int c;
2960168404Spjd	nvlist_t *nvroot;
2961168404Spjd	char *poolname, *old_disk, *new_disk;
2962168404Spjd	zpool_handle_t *zhp;
2963168404Spjd	int ret;
2964168404Spjd
2965168404Spjd	/* check options */
2966168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
2967168404Spjd		switch (c) {
2968168404Spjd		case 'f':
2969168404Spjd			force = B_TRUE;
2970168404Spjd			break;
2971168404Spjd		case '?':
2972168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2973168404Spjd			    optopt);
2974168404Spjd			usage(B_FALSE);
2975168404Spjd		}
2976168404Spjd	}
2977168404Spjd
2978168404Spjd	argc -= optind;
2979168404Spjd	argv += optind;
2980168404Spjd
2981168404Spjd	/* get pool name and check number of arguments */
2982168404Spjd	if (argc < 1) {
2983168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
2984168404Spjd		usage(B_FALSE);
2985168404Spjd	}
2986168404Spjd
2987168404Spjd	poolname = argv[0];
2988168404Spjd
2989168404Spjd	if (argc < 2) {
2990168404Spjd		(void) fprintf(stderr,
2991168404Spjd		    gettext("missing <device> specification\n"));
2992168404Spjd		usage(B_FALSE);
2993168404Spjd	}
2994168404Spjd
2995168404Spjd	old_disk = argv[1];
2996168404Spjd
2997168404Spjd	if (argc < 3) {
2998168404Spjd		if (!replacing) {
2999168404Spjd			(void) fprintf(stderr,
3000168404Spjd			    gettext("missing <new_device> specification\n"));
3001168404Spjd			usage(B_FALSE);
3002168404Spjd		}
3003168404Spjd		new_disk = old_disk;
3004168404Spjd		argc -= 1;
3005168404Spjd		argv += 1;
3006168404Spjd	} else {
3007168404Spjd		new_disk = argv[2];
3008168404Spjd		argc -= 2;
3009168404Spjd		argv += 2;
3010168404Spjd	}
3011168404Spjd
3012168404Spjd	if (argc > 1) {
3013168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
3014168404Spjd		usage(B_FALSE);
3015168404Spjd	}
3016168404Spjd
3017168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3018168404Spjd		return (1);
3019168404Spjd
3020185029Spjd	if (zpool_get_config(zhp, NULL) == NULL) {
3021168404Spjd		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
3022168404Spjd		    poolname);
3023168404Spjd		zpool_close(zhp);
3024168404Spjd		return (1);
3025168404Spjd	}
3026168404Spjd
3027185029Spjd	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
3028185029Spjd	    argc, argv);
3029168404Spjd	if (nvroot == NULL) {
3030168404Spjd		zpool_close(zhp);
3031168404Spjd		return (1);
3032168404Spjd	}
3033168404Spjd
3034168404Spjd	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
3035168404Spjd
3036168404Spjd	nvlist_free(nvroot);
3037168404Spjd	zpool_close(zhp);
3038168404Spjd
3039168404Spjd	return (ret);
3040168404Spjd}
3041168404Spjd
3042168404Spjd/*
3043168404Spjd * zpool replace [-f] <pool> <device> <new_device>
3044168404Spjd *
3045168404Spjd *	-f	Force attach, even if <new_device> appears to be in use.
3046168404Spjd *
3047168404Spjd * Replace <device> with <new_device>.
3048168404Spjd */
3049168404Spjd/* ARGSUSED */
3050168404Spjdint
3051168404Spjdzpool_do_replace(int argc, char **argv)
3052168404Spjd{
3053168404Spjd	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
3054168404Spjd}
3055168404Spjd
3056168404Spjd/*
3057168404Spjd * zpool attach [-f] <pool> <device> <new_device>
3058168404Spjd *
3059168404Spjd *	-f	Force attach, even if <new_device> appears to be in use.
3060168404Spjd *
3061168404Spjd * Attach <new_device> to the mirror containing <device>.  If <device> is not
3062168404Spjd * part of a mirror, then <device> will be transformed into a mirror of
3063168404Spjd * <device> and <new_device>.  In either case, <new_device> will begin life
3064168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself.
3065168404Spjd */
3066168404Spjdint
3067168404Spjdzpool_do_attach(int argc, char **argv)
3068168404Spjd{
3069168404Spjd	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
3070168404Spjd}
3071168404Spjd
3072168404Spjd/*
3073168404Spjd * zpool detach [-f] <pool> <device>
3074168404Spjd *
3075168404Spjd *	-f	Force detach of <device>, even if DTLs argue against it
3076168404Spjd *		(not supported yet)
3077168404Spjd *
3078168404Spjd * Detach a device from a mirror.  The operation will be refused if <device>
3079168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device
3080168404Spjd * has the only valid copy of some data.
3081168404Spjd */
3082168404Spjd/* ARGSUSED */
3083168404Spjdint
3084168404Spjdzpool_do_detach(int argc, char **argv)
3085168404Spjd{
3086168404Spjd	int c;
3087168404Spjd	char *poolname, *path;
3088168404Spjd	zpool_handle_t *zhp;
3089168404Spjd	int ret;
3090168404Spjd
3091168404Spjd	/* check options */
3092168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
3093168404Spjd		switch (c) {
3094168404Spjd		case 'f':
3095168404Spjd		case '?':
3096168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3097168404Spjd			    optopt);
3098168404Spjd			usage(B_FALSE);
3099168404Spjd		}
3100168404Spjd	}
3101168404Spjd
3102168404Spjd	argc -= optind;
3103168404Spjd	argv += optind;
3104168404Spjd
3105168404Spjd	/* get pool name and check number of arguments */
3106168404Spjd	if (argc < 1) {
3107168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
3108168404Spjd		usage(B_FALSE);
3109168404Spjd	}
3110168404Spjd
3111168404Spjd	if (argc < 2) {
3112168404Spjd		(void) fprintf(stderr,
3113168404Spjd		    gettext("missing <device> specification\n"));
3114168404Spjd		usage(B_FALSE);
3115168404Spjd	}
3116168404Spjd
3117168404Spjd	poolname = argv[0];
3118168404Spjd	path = argv[1];
3119168404Spjd
3120168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3121168404Spjd		return (1);
3122168404Spjd
3123168404Spjd	ret = zpool_vdev_detach(zhp, path);
3124168404Spjd
3125168404Spjd	zpool_close(zhp);
3126168404Spjd
3127168404Spjd	return (ret);
3128168404Spjd}
3129168404Spjd
3130168404Spjd/*
3131219089Spjd * zpool split [-n] [-o prop=val] ...
3132219089Spjd *		[-o mntopt] ...
3133219089Spjd *		[-R altroot] <pool> <newpool> [<device> ...]
3134219089Spjd *
3135219089Spjd *	-n	Do not split the pool, but display the resulting layout if
3136219089Spjd *		it were to be split.
3137219089Spjd *	-o	Set property=value, or set mount options.
3138219089Spjd *	-R	Mount the split-off pool under an alternate root.
3139219089Spjd *
3140219089Spjd * Splits the named pool and gives it the new pool name.  Devices to be split
3141219089Spjd * off may be listed, provided that no more than one device is specified
3142219089Spjd * per top-level vdev mirror.  The newly split pool is left in an exported
3143219089Spjd * state unless -R is specified.
3144219089Spjd *
3145219089Spjd * Restrictions: the top-level of the pool pool must only be made up of
3146219089Spjd * mirrors; all devices in the pool must be healthy; no device may be
3147219089Spjd * undergoing a resilvering operation.
3148219089Spjd */
3149219089Spjdint
3150219089Spjdzpool_do_split(int argc, char **argv)
3151219089Spjd{
3152219089Spjd	char *srcpool, *newpool, *propval;
3153219089Spjd	char *mntopts = NULL;
3154219089Spjd	splitflags_t flags;
3155219089Spjd	int c, ret = 0;
3156219089Spjd	zpool_handle_t *zhp;
3157219089Spjd	nvlist_t *config, *props = NULL;
3158219089Spjd
3159219089Spjd	flags.dryrun = B_FALSE;
3160219089Spjd	flags.import = B_FALSE;
3161219089Spjd
3162219089Spjd	/* check options */
3163219089Spjd	while ((c = getopt(argc, argv, ":R:no:")) != -1) {
3164219089Spjd		switch (c) {
3165219089Spjd		case 'R':
3166219089Spjd			flags.import = B_TRUE;
3167219089Spjd			if (add_prop_list(
3168219089Spjd			    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
3169219089Spjd			    &props, B_TRUE) != 0) {
3170219089Spjd				if (props)
3171219089Spjd					nvlist_free(props);
3172219089Spjd				usage(B_FALSE);
3173219089Spjd			}
3174219089Spjd			break;
3175219089Spjd		case 'n':
3176219089Spjd			flags.dryrun = B_TRUE;
3177219089Spjd			break;
3178219089Spjd		case 'o':
3179219089Spjd			if ((propval = strchr(optarg, '=')) != NULL) {
3180219089Spjd				*propval = '\0';
3181219089Spjd				propval++;
3182219089Spjd				if (add_prop_list(optarg, propval,
3183219089Spjd				    &props, B_TRUE) != 0) {
3184219089Spjd					if (props)
3185219089Spjd						nvlist_free(props);
3186219089Spjd					usage(B_FALSE);
3187219089Spjd				}
3188219089Spjd			} else {
3189219089Spjd				mntopts = optarg;
3190219089Spjd			}
3191219089Spjd			break;
3192219089Spjd		case ':':
3193219089Spjd			(void) fprintf(stderr, gettext("missing argument for "
3194219089Spjd			    "'%c' option\n"), optopt);
3195219089Spjd			usage(B_FALSE);
3196219089Spjd			break;
3197219089Spjd		case '?':
3198219089Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3199219089Spjd			    optopt);
3200219089Spjd			usage(B_FALSE);
3201219089Spjd			break;
3202219089Spjd		}
3203219089Spjd	}
3204219089Spjd
3205219089Spjd	if (!flags.import && mntopts != NULL) {
3206219089Spjd		(void) fprintf(stderr, gettext("setting mntopts is only "
3207219089Spjd		    "valid when importing the pool\n"));
3208219089Spjd		usage(B_FALSE);
3209219089Spjd	}
3210219089Spjd
3211219089Spjd	argc -= optind;
3212219089Spjd	argv += optind;
3213219089Spjd
3214219089Spjd	if (argc < 1) {
3215219089Spjd		(void) fprintf(stderr, gettext("Missing pool name\n"));
3216219089Spjd		usage(B_FALSE);
3217219089Spjd	}
3218219089Spjd	if (argc < 2) {
3219219089Spjd		(void) fprintf(stderr, gettext("Missing new pool name\n"));
3220219089Spjd		usage(B_FALSE);
3221219089Spjd	}
3222219089Spjd
3223219089Spjd	srcpool = argv[0];
3224219089Spjd	newpool = argv[1];
3225219089Spjd
3226219089Spjd	argc -= 2;
3227219089Spjd	argv += 2;
3228219089Spjd
3229219089Spjd	if ((zhp = zpool_open(g_zfs, srcpool)) == NULL)
3230219089Spjd		return (1);
3231219089Spjd
3232219089Spjd	config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
3233219089Spjd	if (config == NULL) {
3234219089Spjd		ret = 1;
3235219089Spjd	} else {
3236219089Spjd		if (flags.dryrun) {
3237219089Spjd			(void) printf(gettext("would create '%s' with the "
3238219089Spjd			    "following layout:\n\n"), newpool);
3239219089Spjd			print_vdev_tree(NULL, newpool, config, 0, B_FALSE);
3240219089Spjd		}
3241219089Spjd		nvlist_free(config);
3242219089Spjd	}
3243219089Spjd
3244219089Spjd	zpool_close(zhp);
3245219089Spjd
3246219089Spjd	if (ret != 0 || flags.dryrun || !flags.import)
3247219089Spjd		return (ret);
3248219089Spjd
3249219089Spjd	/*
3250219089Spjd	 * The split was successful. Now we need to open the new
3251219089Spjd	 * pool and import it.
3252219089Spjd	 */
3253219089Spjd	if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
3254219089Spjd		return (1);
3255219089Spjd	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
3256219089Spjd	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
3257219089Spjd		ret = 1;
3258219089Spjd		(void) fprintf(stderr, gettext("Split was succssful, but "
3259219089Spjd		    "the datasets could not all be mounted\n"));
3260219089Spjd		(void) fprintf(stderr, gettext("Try doing '%s' with a "
3261219089Spjd		    "different altroot\n"), "zpool import");
3262219089Spjd	}
3263219089Spjd	zpool_close(zhp);
3264219089Spjd
3265219089Spjd	return (ret);
3266219089Spjd}
3267219089Spjd
3268219089Spjd
3269219089Spjd
3270219089Spjd/*
3271168404Spjd * zpool online <pool> <device> ...
3272168404Spjd */
3273168404Spjdint
3274168404Spjdzpool_do_online(int argc, char **argv)
3275168404Spjd{
3276168404Spjd	int c, i;
3277168404Spjd	char *poolname;
3278168404Spjd	zpool_handle_t *zhp;
3279168404Spjd	int ret = 0;
3280185029Spjd	vdev_state_t newstate;
3281219089Spjd	int flags = 0;
3282168404Spjd
3283168404Spjd	/* check options */
3284219089Spjd	while ((c = getopt(argc, argv, "et")) != -1) {
3285168404Spjd		switch (c) {
3286219089Spjd		case 'e':
3287219089Spjd			flags |= ZFS_ONLINE_EXPAND;
3288219089Spjd			break;
3289168404Spjd		case 't':
3290168404Spjd		case '?':
3291168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3292168404Spjd			    optopt);
3293168404Spjd			usage(B_FALSE);
3294168404Spjd		}
3295168404Spjd	}
3296168404Spjd
3297168404Spjd	argc -= optind;
3298168404Spjd	argv += optind;
3299168404Spjd
3300168404Spjd	/* get pool name and check number of arguments */
3301168404Spjd	if (argc < 1) {
3302168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
3303168404Spjd		usage(B_FALSE);
3304168404Spjd	}
3305168404Spjd	if (argc < 2) {
3306168404Spjd		(void) fprintf(stderr, gettext("missing device name\n"));
3307168404Spjd		usage(B_FALSE);
3308168404Spjd	}
3309168404Spjd
3310168404Spjd	poolname = argv[0];
3311168404Spjd
3312168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3313168404Spjd		return (1);
3314168404Spjd
3315185029Spjd	for (i = 1; i < argc; i++) {
3316219089Spjd		if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
3317185029Spjd			if (newstate != VDEV_STATE_HEALTHY) {
3318185029Spjd				(void) printf(gettext("warning: device '%s' "
3319185029Spjd				    "onlined, but remains in faulted state\n"),
3320185029Spjd				    argv[i]);
3321185029Spjd				if (newstate == VDEV_STATE_FAULTED)
3322185029Spjd					(void) printf(gettext("use 'zpool "
3323185029Spjd					    "clear' to restore a faulted "
3324185029Spjd					    "device\n"));
3325185029Spjd				else
3326185029Spjd					(void) printf(gettext("use 'zpool "
3327185029Spjd					    "replace' to replace devices "
3328185029Spjd					    "that are no longer present\n"));
3329185029Spjd			}
3330185029Spjd		} else {
3331168404Spjd			ret = 1;
3332185029Spjd		}
3333185029Spjd	}
3334168404Spjd
3335168404Spjd	zpool_close(zhp);
3336168404Spjd
3337168404Spjd	return (ret);
3338168404Spjd}
3339168404Spjd
3340168404Spjd/*
3341168404Spjd * zpool offline [-ft] <pool> <device> ...
3342168404Spjd *
3343168404Spjd *	-f	Force the device into the offline state, even if doing
3344168404Spjd *		so would appear to compromise pool availability.
3345168404Spjd *		(not supported yet)
3346168404Spjd *
3347168404Spjd *	-t	Only take the device off-line temporarily.  The offline
3348168404Spjd *		state will not be persistent across reboots.
3349168404Spjd */
3350168404Spjd/* ARGSUSED */
3351168404Spjdint
3352168404Spjdzpool_do_offline(int argc, char **argv)
3353168404Spjd{
3354168404Spjd	int c, i;
3355168404Spjd	char *poolname;
3356168404Spjd	zpool_handle_t *zhp;
3357168404Spjd	int ret = 0;
3358168404Spjd	boolean_t istmp = B_FALSE;
3359168404Spjd
3360168404Spjd	/* check options */
3361168404Spjd	while ((c = getopt(argc, argv, "ft")) != -1) {
3362168404Spjd		switch (c) {
3363168404Spjd		case 't':
3364168404Spjd			istmp = B_TRUE;
3365168404Spjd			break;
3366168404Spjd		case 'f':
3367168404Spjd		case '?':
3368168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3369168404Spjd			    optopt);
3370168404Spjd			usage(B_FALSE);
3371168404Spjd		}
3372168404Spjd	}
3373168404Spjd
3374168404Spjd	argc -= optind;
3375168404Spjd	argv += optind;
3376168404Spjd
3377168404Spjd	/* get pool name and check number of arguments */
3378168404Spjd	if (argc < 1) {
3379168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
3380168404Spjd		usage(B_FALSE);
3381168404Spjd	}
3382168404Spjd	if (argc < 2) {
3383168404Spjd		(void) fprintf(stderr, gettext("missing device name\n"));
3384168404Spjd		usage(B_FALSE);
3385168404Spjd	}
3386168404Spjd
3387168404Spjd	poolname = argv[0];
3388168404Spjd
3389168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3390168404Spjd		return (1);
3391168404Spjd
3392185029Spjd	for (i = 1; i < argc; i++) {
3393185029Spjd		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
3394168404Spjd			ret = 1;
3395185029Spjd	}
3396168404Spjd
3397168404Spjd	zpool_close(zhp);
3398168404Spjd
3399168404Spjd	return (ret);
3400168404Spjd}
3401168404Spjd
3402168404Spjd/*
3403168404Spjd * zpool clear <pool> [device]
3404168404Spjd *
3405168404Spjd * Clear all errors associated with a pool or a particular device.
3406168404Spjd */
3407168404Spjdint
3408168404Spjdzpool_do_clear(int argc, char **argv)
3409168404Spjd{
3410219089Spjd	int c;
3411168404Spjd	int ret = 0;
3412219089Spjd	boolean_t dryrun = B_FALSE;
3413219089Spjd	boolean_t do_rewind = B_FALSE;
3414219089Spjd	boolean_t xtreme_rewind = B_FALSE;
3415219089Spjd	uint32_t rewind_policy = ZPOOL_NO_REWIND;
3416219089Spjd	nvlist_t *policy = NULL;
3417168404Spjd	zpool_handle_t *zhp;
3418168404Spjd	char *pool, *device;
3419168404Spjd
3420219089Spjd	/* check options */
3421219089Spjd	while ((c = getopt(argc, argv, "FnX")) != -1) {
3422219089Spjd		switch (c) {
3423219089Spjd		case 'F':
3424219089Spjd			do_rewind = B_TRUE;
3425219089Spjd			break;
3426219089Spjd		case 'n':
3427219089Spjd			dryrun = B_TRUE;
3428219089Spjd			break;
3429219089Spjd		case 'X':
3430219089Spjd			xtreme_rewind = B_TRUE;
3431219089Spjd			break;
3432219089Spjd		case '?':
3433219089Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3434219089Spjd			    optopt);
3435219089Spjd			usage(B_FALSE);
3436219089Spjd		}
3437219089Spjd	}
3438219089Spjd
3439219089Spjd	argc -= optind;
3440219089Spjd	argv += optind;
3441219089Spjd
3442219089Spjd	if (argc < 1) {
3443168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
3444168404Spjd		usage(B_FALSE);
3445168404Spjd	}
3446168404Spjd
3447219089Spjd	if (argc > 2) {
3448168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
3449168404Spjd		usage(B_FALSE);
3450168404Spjd	}
3451168404Spjd
3452219089Spjd	if ((dryrun || xtreme_rewind) && !do_rewind) {
3453219089Spjd		(void) fprintf(stderr,
3454219089Spjd		    gettext("-n or -X only meaningful with -F\n"));
3455219089Spjd		usage(B_FALSE);
3456219089Spjd	}
3457219089Spjd	if (dryrun)
3458219089Spjd		rewind_policy = ZPOOL_TRY_REWIND;
3459219089Spjd	else if (do_rewind)
3460219089Spjd		rewind_policy = ZPOOL_DO_REWIND;
3461219089Spjd	if (xtreme_rewind)
3462219089Spjd		rewind_policy |= ZPOOL_EXTREME_REWIND;
3463168404Spjd
3464219089Spjd	/* In future, further rewind policy choices can be passed along here */
3465219089Spjd	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
3466219089Spjd	    nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
3467168404Spjd		return (1);
3468168404Spjd
3469219089Spjd	pool = argv[0];
3470219089Spjd	device = argc == 2 ? argv[1] : NULL;
3471219089Spjd
3472219089Spjd	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
3473219089Spjd		nvlist_free(policy);
3474219089Spjd		return (1);
3475219089Spjd	}
3476219089Spjd
3477219089Spjd	if (zpool_clear(zhp, device, policy) != 0)
3478168404Spjd		ret = 1;
3479168404Spjd
3480168404Spjd	zpool_close(zhp);
3481168404Spjd
3482219089Spjd	nvlist_free(policy);
3483219089Spjd
3484168404Spjd	return (ret);
3485168404Spjd}
3486168404Spjd
3487228103Smm/*
3488228103Smm * zpool reguid <pool>
3489228103Smm */
3490228103Smmint
3491228103Smmzpool_do_reguid(int argc, char **argv)
3492228103Smm{
3493228103Smm	int c;
3494228103Smm	char *poolname;
3495228103Smm	zpool_handle_t *zhp;
3496228103Smm	int ret = 0;
3497228103Smm
3498228103Smm	/* check options */
3499228103Smm	while ((c = getopt(argc, argv, "")) != -1) {
3500228103Smm		switch (c) {
3501228103Smm		case '?':
3502228103Smm			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3503228103Smm			    optopt);
3504228103Smm			usage(B_FALSE);
3505228103Smm		}
3506228103Smm	}
3507228103Smm
3508228103Smm	argc -= optind;
3509228103Smm	argv += optind;
3510228103Smm
3511228103Smm	/* get pool name and check number of arguments */
3512228103Smm	if (argc < 1) {
3513228103Smm		(void) fprintf(stderr, gettext("missing pool name\n"));
3514228103Smm		usage(B_FALSE);
3515228103Smm	}
3516228103Smm
3517228103Smm	if (argc > 1) {
3518228103Smm		(void) fprintf(stderr, gettext("too many arguments\n"));
3519228103Smm		usage(B_FALSE);
3520228103Smm	}
3521228103Smm
3522228103Smm	poolname = argv[0];
3523228103Smm	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3524228103Smm		return (1);
3525228103Smm
3526228103Smm	ret = zpool_reguid(zhp);
3527228103Smm
3528228103Smm	zpool_close(zhp);
3529228103Smm	return (ret);
3530228103Smm}
3531228103Smm
3532228103Smm
3533236155Smm/*
3534236155Smm * zpool reopen <pool>
3535236155Smm *
3536236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs.
3537236155Smm *
3538236155Smm * NOTE: This command is currently undocumented.  If the command is ever
3539236155Smm * exposed then the appropriate usage() messages will need to be made.
3540236155Smm */
3541236155Smmint
3542236155Smmzpool_do_reopen(int argc, char **argv)
3543236155Smm{
3544236155Smm	int ret = 0;
3545236155Smm	zpool_handle_t *zhp;
3546236155Smm	char *pool;
3547236155Smm
3548236155Smm	argc--;
3549236155Smm	argv++;
3550236155Smm
3551236155Smm	if (argc != 1)
3552236155Smm		return (2);
3553236155Smm
3554236155Smm	pool = argv[0];
3555236155Smm	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
3556236155Smm		return (1);
3557236155Smm
3558236155Smm	ret = zpool_reopen(zhp);
3559236155Smm	zpool_close(zhp);
3560236155Smm	return (ret);
3561236155Smm}
3562236155Smm
3563168404Spjdtypedef struct scrub_cbdata {
3564168404Spjd	int	cb_type;
3565168404Spjd	int	cb_argc;
3566168404Spjd	char	**cb_argv;
3567168404Spjd} scrub_cbdata_t;
3568168404Spjd
3569168404Spjdint
3570168404Spjdscrub_callback(zpool_handle_t *zhp, void *data)
3571168404Spjd{
3572168404Spjd	scrub_cbdata_t *cb = data;
3573168404Spjd	int err;
3574168404Spjd
3575168404Spjd	/*
3576168404Spjd	 * Ignore faulted pools.
3577168404Spjd	 */
3578168404Spjd	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
3579168404Spjd		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
3580168404Spjd		    "currently unavailable\n"), zpool_get_name(zhp));
3581168404Spjd		return (1);
3582168404Spjd	}
3583168404Spjd
3584219089Spjd	err = zpool_scan(zhp, cb->cb_type);
3585168404Spjd
3586168404Spjd	return (err != 0);
3587168404Spjd}
3588168404Spjd
3589168404Spjd/*
3590168404Spjd * zpool scrub [-s] <pool> ...
3591168404Spjd *
3592168404Spjd *	-s	Stop.  Stops any in-progress scrub.
3593168404Spjd */
3594168404Spjdint
3595168404Spjdzpool_do_scrub(int argc, char **argv)
3596168404Spjd{
3597168404Spjd	int c;
3598168404Spjd	scrub_cbdata_t cb;
3599168404Spjd
3600219089Spjd	cb.cb_type = POOL_SCAN_SCRUB;
3601168404Spjd
3602168404Spjd	/* check options */
3603168404Spjd	while ((c = getopt(argc, argv, "s")) != -1) {
3604168404Spjd		switch (c) {
3605168404Spjd		case 's':
3606219089Spjd			cb.cb_type = POOL_SCAN_NONE;
3607168404Spjd			break;
3608168404Spjd		case '?':
3609168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3610168404Spjd			    optopt);
3611168404Spjd			usage(B_FALSE);
3612168404Spjd		}
3613168404Spjd	}
3614168404Spjd
3615168404Spjd	cb.cb_argc = argc;
3616168404Spjd	cb.cb_argv = argv;
3617168404Spjd	argc -= optind;
3618168404Spjd	argv += optind;
3619168404Spjd
3620168404Spjd	if (argc < 1) {
3621168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
3622168404Spjd		usage(B_FALSE);
3623168404Spjd	}
3624168404Spjd
3625168404Spjd	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
3626168404Spjd}
3627168404Spjd
3628168404Spjdtypedef struct status_cbdata {
3629168404Spjd	int		cb_count;
3630168404Spjd	boolean_t	cb_allpools;
3631168404Spjd	boolean_t	cb_verbose;
3632168404Spjd	boolean_t	cb_explain;
3633168404Spjd	boolean_t	cb_first;
3634219089Spjd	boolean_t	cb_dedup_stats;
3635168404Spjd} status_cbdata_t;
3636168404Spjd
3637168404Spjd/*
3638168404Spjd * Print out detailed scrub status.
3639168404Spjd */
3640168404Spjdvoid
3641219089Spjdprint_scan_status(pool_scan_stat_t *ps)
3642168404Spjd{
3643219089Spjd	time_t start, end;
3644219089Spjd	uint64_t elapsed, mins_left, hours_left;
3645219089Spjd	uint64_t pass_exam, examined, total;
3646219089Spjd	uint_t rate;
3647168404Spjd	double fraction_done;
3648219089Spjd	char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
3649168404Spjd
3650226583Spjd	(void) printf(gettext("  scan: "));
3651168404Spjd
3652219089Spjd	/* If there's never been a scan, there's not much to say. */
3653219089Spjd	if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
3654219089Spjd	    ps->pss_func >= POOL_SCAN_FUNCS) {
3655168404Spjd		(void) printf(gettext("none requested\n"));
3656168404Spjd		return;
3657168404Spjd	}
3658168404Spjd
3659219089Spjd	start = ps->pss_start_time;
3660219089Spjd	end = ps->pss_end_time;
3661219089Spjd	zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
3662168404Spjd
3663219089Spjd	assert(ps->pss_func == POOL_SCAN_SCRUB ||
3664219089Spjd	    ps->pss_func == POOL_SCAN_RESILVER);
3665219089Spjd	/*
3666219089Spjd	 * Scan is finished or canceled.
3667219089Spjd	 */
3668219089Spjd	if (ps->pss_state == DSS_FINISHED) {
3669219089Spjd		uint64_t minutes_taken = (end - start) / 60;
3670219089Spjd		char *fmt;
3671168404Spjd
3672219089Spjd		if (ps->pss_func == POOL_SCAN_SCRUB) {
3673219089Spjd			fmt = gettext("scrub repaired %s in %lluh%um with "
3674219089Spjd			    "%llu errors on %s");
3675219089Spjd		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
3676219089Spjd			fmt = gettext("resilvered %s in %lluh%um with "
3677219089Spjd			    "%llu errors on %s");
3678219089Spjd		}
3679219089Spjd		/* LINTED */
3680219089Spjd		(void) printf(fmt, processed_buf,
3681185029Spjd		    (u_longlong_t)(minutes_taken / 60),
3682185029Spjd		    (uint_t)(minutes_taken % 60),
3683219089Spjd		    (u_longlong_t)ps->pss_errors,
3684219089Spjd		    ctime((time_t *)&end));
3685168404Spjd		return;
3686219089Spjd	} else if (ps->pss_state == DSS_CANCELED) {
3687219089Spjd		if (ps->pss_func == POOL_SCAN_SCRUB) {
3688219089Spjd			(void) printf(gettext("scrub canceled on %s"),
3689219089Spjd			    ctime(&end));
3690219089Spjd		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
3691219089Spjd			(void) printf(gettext("resilver canceled on %s"),
3692219089Spjd			    ctime(&end));
3693219089Spjd		}
3694219089Spjd		return;
3695168404Spjd	}
3696168404Spjd
3697219089Spjd	assert(ps->pss_state == DSS_SCANNING);
3698168404Spjd
3699219089Spjd	/*
3700219089Spjd	 * Scan is in progress.
3701219089Spjd	 */
3702219089Spjd	if (ps->pss_func == POOL_SCAN_SCRUB) {
3703219089Spjd		(void) printf(gettext("scrub in progress since %s"),
3704219089Spjd		    ctime(&start));
3705219089Spjd	} else if (ps->pss_func == POOL_SCAN_RESILVER) {
3706219089Spjd		(void) printf(gettext("resilver in progress since %s"),
3707219089Spjd		    ctime(&start));
3708219089Spjd	}
3709219089Spjd
3710219089Spjd	examined = ps->pss_examined ? ps->pss_examined : 1;
3711219089Spjd	total = ps->pss_to_examine;
3712168404Spjd	fraction_done = (double)examined / total;
3713168404Spjd
3714219089Spjd	/* elapsed time for this pass */
3715219089Spjd	elapsed = time(NULL) - ps->pss_pass_start;
3716219089Spjd	elapsed = elapsed ? elapsed : 1;
3717219089Spjd	pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1;
3718219089Spjd	rate = pass_exam / elapsed;
3719219089Spjd	rate = rate ? rate : 1;
3720219089Spjd	mins_left = ((total - examined) / rate) / 60;
3721219089Spjd	hours_left = mins_left / 60;
3722219089Spjd
3723219089Spjd	zfs_nicenum(examined, examined_buf, sizeof (examined_buf));
3724219089Spjd	zfs_nicenum(total, total_buf, sizeof (total_buf));
3725219089Spjd	zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
3726219089Spjd
3727219089Spjd	/*
3728219089Spjd	 * do not print estimated time if hours_left is more than 30 days
3729219089Spjd	 */
3730226583Spjd	(void) printf(gettext("        %s scanned out of %s at %s/s"),
3731219089Spjd	    examined_buf, total_buf, rate_buf);
3732219089Spjd	if (hours_left < (30 * 24)) {
3733219089Spjd		(void) printf(gettext(", %lluh%um to go\n"),
3734219089Spjd		    (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
3735219089Spjd	} else {
3736219089Spjd		(void) printf(gettext(
3737219089Spjd		    ", (scan is slow, no estimated time)\n"));
3738219089Spjd	}
3739219089Spjd
3740219089Spjd	if (ps->pss_func == POOL_SCAN_RESILVER) {
3741226583Spjd		(void) printf(gettext("        %s resilvered, %.2f%% done\n"),
3742219089Spjd		    processed_buf, 100 * fraction_done);
3743219089Spjd	} else if (ps->pss_func == POOL_SCAN_SCRUB) {
3744226583Spjd		(void) printf(gettext("        %s repaired, %.2f%% done\n"),
3745219089Spjd		    processed_buf, 100 * fraction_done);
3746219089Spjd	}
3747168404Spjd}
3748168404Spjd
3749168404Spjdstatic void
3750168404Spjdprint_error_log(zpool_handle_t *zhp)
3751168404Spjd{
3752185029Spjd	nvlist_t *nverrlist = NULL;
3753168404Spjd	nvpair_t *elem;
3754168404Spjd	char *pathname;
3755168404Spjd	size_t len = MAXPATHLEN * 2;
3756168404Spjd
3757168404Spjd	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
3758168404Spjd		(void) printf("errors: List of errors unavailable "
3759168404Spjd		    "(insufficient privileges)\n");
3760168404Spjd		return;
3761168404Spjd	}
3762168404Spjd
3763168404Spjd	(void) printf("errors: Permanent errors have been "
3764168404Spjd	    "detected in the following files:\n\n");
3765168404Spjd
3766168404Spjd	pathname = safe_malloc(len);
3767168404Spjd	elem = NULL;
3768168404Spjd	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
3769168404Spjd		nvlist_t *nv;
3770168404Spjd		uint64_t dsobj, obj;
3771168404Spjd
3772168404Spjd		verify(nvpair_value_nvlist(elem, &nv) == 0);
3773168404Spjd		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
3774168404Spjd		    &dsobj) == 0);
3775168404Spjd		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
3776168404Spjd		    &obj) == 0);
3777168404Spjd		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
3778168404Spjd		(void) printf("%7s %s\n", "", pathname);
3779168404Spjd	}
3780168404Spjd	free(pathname);
3781168404Spjd	nvlist_free(nverrlist);
3782168404Spjd}
3783168404Spjd
3784168404Spjdstatic void
3785168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
3786168404Spjd    int namewidth)
3787168404Spjd{
3788168404Spjd	uint_t i;
3789168404Spjd	char *name;
3790168404Spjd
3791168404Spjd	if (nspares == 0)
3792168404Spjd		return;
3793168404Spjd
3794168404Spjd	(void) printf(gettext("\tspares\n"));
3795168404Spjd
3796168404Spjd	for (i = 0; i < nspares; i++) {
3797219089Spjd		name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE);
3798168404Spjd		print_status_config(zhp, name, spares[i],
3799209962Smm		    namewidth, 2, B_TRUE);
3800168404Spjd		free(name);
3801168404Spjd	}
3802168404Spjd}
3803168404Spjd
3804185029Spjdstatic void
3805185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
3806185029Spjd    int namewidth)
3807185029Spjd{
3808185029Spjd	uint_t i;
3809185029Spjd	char *name;
3810185029Spjd
3811185029Spjd	if (nl2cache == 0)
3812185029Spjd		return;
3813185029Spjd
3814185029Spjd	(void) printf(gettext("\tcache\n"));
3815185029Spjd
3816185029Spjd	for (i = 0; i < nl2cache; i++) {
3817219089Spjd		name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE);
3818185029Spjd		print_status_config(zhp, name, l2cache[i],
3819209962Smm		    namewidth, 2, B_FALSE);
3820185029Spjd		free(name);
3821185029Spjd	}
3822185029Spjd}
3823185029Spjd
3824219089Spjdstatic void
3825219089Spjdprint_dedup_stats(nvlist_t *config)
3826219089Spjd{
3827219089Spjd	ddt_histogram_t *ddh;
3828219089Spjd	ddt_stat_t *dds;
3829219089Spjd	ddt_object_t *ddo;
3830219089Spjd	uint_t c;
3831219089Spjd
3832219089Spjd	/*
3833219089Spjd	 * If the pool was faulted then we may not have been able to
3834219089Spjd	 * obtain the config. Otherwise, if have anything in the dedup
3835219089Spjd	 * table continue processing the stats.
3836219089Spjd	 */
3837219089Spjd	if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
3838227497Smm	    (uint64_t **)&ddo, &c) != 0)
3839219089Spjd		return;
3840219089Spjd
3841219089Spjd	(void) printf("\n");
3842227497Smm	(void) printf(gettext(" dedup: "));
3843227497Smm	if (ddo->ddo_count == 0) {
3844227497Smm		(void) printf(gettext("no DDT entries\n"));
3845227497Smm		return;
3846227497Smm	}
3847227497Smm
3848219089Spjd	(void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
3849219089Spjd	    (u_longlong_t)ddo->ddo_count,
3850219089Spjd	    (u_longlong_t)ddo->ddo_dspace,
3851219089Spjd	    (u_longlong_t)ddo->ddo_mspace);
3852219089Spjd
3853219089Spjd	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
3854219089Spjd	    (uint64_t **)&dds, &c) == 0);
3855219089Spjd	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
3856219089Spjd	    (uint64_t **)&ddh, &c) == 0);
3857219089Spjd	zpool_dump_ddt(dds, ddh);
3858219089Spjd}
3859219089Spjd
3860168404Spjd/*
3861168404Spjd * Display a summary of pool status.  Displays a summary such as:
3862168404Spjd *
3863168404Spjd *        pool: tank
3864168404Spjd *	status: DEGRADED
3865168404Spjd *	reason: One or more devices ...
3866236146Smm *         see: http://illumos.org/msg/ZFS-xxxx-01
3867168404Spjd *	config:
3868168404Spjd *		mirror		DEGRADED
3869168404Spjd *                c1t0d0	OK
3870168404Spjd *                c2t0d0	UNAVAIL
3871168404Spjd *
3872168404Spjd * When given the '-v' option, we print out the complete config.  If the '-e'
3873168404Spjd * option is specified, then we print out error rate information as well.
3874168404Spjd */
3875168404Spjdint
3876168404Spjdstatus_callback(zpool_handle_t *zhp, void *data)
3877168404Spjd{
3878168404Spjd	status_cbdata_t *cbp = data;
3879168404Spjd	nvlist_t *config, *nvroot;
3880168404Spjd	char *msgid;
3881168404Spjd	int reason;
3882168404Spjd	const char *health;
3883168404Spjd	uint_t c;
3884168404Spjd	vdev_stat_t *vs;
3885168404Spjd
3886168404Spjd	config = zpool_get_config(zhp, NULL);
3887168404Spjd	reason = zpool_get_status(zhp, &msgid);
3888168404Spjd
3889168404Spjd	cbp->cb_count++;
3890168404Spjd
3891168404Spjd	/*
3892168404Spjd	 * If we were given 'zpool status -x', only report those pools with
3893168404Spjd	 * problems.
3894168404Spjd	 */
3895168404Spjd	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
3896168404Spjd		if (!cbp->cb_allpools) {
3897168404Spjd			(void) printf(gettext("pool '%s' is healthy\n"),
3898168404Spjd			    zpool_get_name(zhp));
3899168404Spjd			if (cbp->cb_first)
3900168404Spjd				cbp->cb_first = B_FALSE;
3901168404Spjd		}
3902168404Spjd		return (0);
3903168404Spjd	}
3904168404Spjd
3905168404Spjd	if (cbp->cb_first)
3906168404Spjd		cbp->cb_first = B_FALSE;
3907168404Spjd	else
3908168404Spjd		(void) printf("\n");
3909168404Spjd
3910168404Spjd	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
3911168404Spjd	    &nvroot) == 0);
3912219089Spjd	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
3913168404Spjd	    (uint64_t **)&vs, &c) == 0);
3914185029Spjd	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3915168404Spjd
3916168404Spjd	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
3917168404Spjd	(void) printf(gettext(" state: %s\n"), health);
3918168404Spjd
3919168404Spjd	switch (reason) {
3920168404Spjd	case ZPOOL_STATUS_MISSING_DEV_R:
3921168404Spjd		(void) printf(gettext("status: One or more devices could not "
3922168404Spjd		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
3923168404Spjd		    "continue functioning in a degraded state.\n"));
3924168404Spjd		(void) printf(gettext("action: Attach the missing device and "
3925168404Spjd		    "online it using 'zpool online'.\n"));
3926168404Spjd		break;
3927168404Spjd
3928168404Spjd	case ZPOOL_STATUS_MISSING_DEV_NR:
3929168404Spjd		(void) printf(gettext("status: One or more devices could not "
3930168404Spjd		    "be opened.  There are insufficient\n\treplicas for the "
3931168404Spjd		    "pool to continue functioning.\n"));
3932168404Spjd		(void) printf(gettext("action: Attach the missing device and "
3933168404Spjd		    "online it using 'zpool online'.\n"));
3934168404Spjd		break;
3935168404Spjd
3936168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_R:
3937168404Spjd		(void) printf(gettext("status: One or more devices could not "
3938168404Spjd		    "be used because the label is missing or\n\tinvalid.  "
3939168404Spjd		    "Sufficient replicas exist for the pool to continue\n\t"
3940168404Spjd		    "functioning in a degraded state.\n"));
3941168404Spjd		(void) printf(gettext("action: Replace the device using "
3942168404Spjd		    "'zpool replace'.\n"));
3943168404Spjd		break;
3944168404Spjd
3945168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3946168404Spjd		(void) printf(gettext("status: One or more devices could not "
3947168404Spjd		    "be used because the label is missing \n\tor invalid.  "
3948168404Spjd		    "There are insufficient replicas for the pool to "
3949168404Spjd		    "continue\n\tfunctioning.\n"));
3950219089Spjd		zpool_explain_recover(zpool_get_handle(zhp),
3951219089Spjd		    zpool_get_name(zhp), reason, config);
3952168404Spjd		break;
3953168404Spjd
3954168404Spjd	case ZPOOL_STATUS_FAILING_DEV:
3955168404Spjd		(void) printf(gettext("status: One or more devices has "
3956168404Spjd		    "experienced an unrecoverable error.  An\n\tattempt was "
3957168404Spjd		    "made to correct the error.  Applications are "
3958168404Spjd		    "unaffected.\n"));
3959168404Spjd		(void) printf(gettext("action: Determine if the device needs "
3960168404Spjd		    "to be replaced, and clear the errors\n\tusing "
3961168404Spjd		    "'zpool clear' or replace the device with 'zpool "
3962168404Spjd		    "replace'.\n"));
3963168404Spjd		break;
3964168404Spjd
3965168404Spjd	case ZPOOL_STATUS_OFFLINE_DEV:
3966168404Spjd		(void) printf(gettext("status: One or more devices has "
3967168404Spjd		    "been taken offline by the administrator.\n\tSufficient "
3968168404Spjd		    "replicas exist for the pool to continue functioning in "
3969168404Spjd		    "a\n\tdegraded state.\n"));
3970168404Spjd		(void) printf(gettext("action: Online the device using "
3971168404Spjd		    "'zpool online' or replace the device with\n\t'zpool "
3972168404Spjd		    "replace'.\n"));
3973168404Spjd		break;
3974168404Spjd
3975219089Spjd	case ZPOOL_STATUS_REMOVED_DEV:
3976219089Spjd		(void) printf(gettext("status: One or more devices has "
3977219089Spjd		    "been removed by the administrator.\n\tSufficient "
3978219089Spjd		    "replicas exist for the pool to continue functioning in "
3979219089Spjd		    "a\n\tdegraded state.\n"));
3980219089Spjd		(void) printf(gettext("action: Online the device using "
3981219089Spjd		    "'zpool online' or replace the device with\n\t'zpool "
3982219089Spjd		    "replace'.\n"));
3983219089Spjd		break;
3984219089Spjd
3985168404Spjd	case ZPOOL_STATUS_RESILVERING:
3986168404Spjd		(void) printf(gettext("status: One or more devices is "
3987168404Spjd		    "currently being resilvered.  The pool will\n\tcontinue "
3988168404Spjd		    "to function, possibly in a degraded state.\n"));
3989168404Spjd		(void) printf(gettext("action: Wait for the resilver to "
3990168404Spjd		    "complete.\n"));
3991168404Spjd		break;
3992168404Spjd
3993168404Spjd	case ZPOOL_STATUS_CORRUPT_DATA:
3994168404Spjd		(void) printf(gettext("status: One or more devices has "
3995168404Spjd		    "experienced an error resulting in data\n\tcorruption.  "
3996168404Spjd		    "Applications may be affected.\n"));
3997168404Spjd		(void) printf(gettext("action: Restore the file in question "
3998168404Spjd		    "if possible.  Otherwise restore the\n\tentire pool from "
3999168404Spjd		    "backup.\n"));
4000168404Spjd		break;
4001168404Spjd
4002168404Spjd	case ZPOOL_STATUS_CORRUPT_POOL:
4003168404Spjd		(void) printf(gettext("status: The pool metadata is corrupted "
4004168404Spjd		    "and the pool cannot be opened.\n"));
4005219089Spjd		zpool_explain_recover(zpool_get_handle(zhp),
4006219089Spjd		    zpool_get_name(zhp), reason, config);
4007168404Spjd		break;
4008168404Spjd
4009168404Spjd	case ZPOOL_STATUS_VERSION_OLDER:
4010168404Spjd		(void) printf(gettext("status: The pool is formatted using an "
4011168404Spjd		    "older on-disk format.  The pool can\n\tstill be used, but "
4012168404Spjd		    "some features are unavailable.\n"));
4013168404Spjd		(void) printf(gettext("action: Upgrade the pool using 'zpool "
4014168404Spjd		    "upgrade'.  Once this is done, the\n\tpool will no longer "
4015168404Spjd		    "be accessible on older software versions.\n"));
4016168404Spjd		break;
4017168404Spjd
4018168404Spjd	case ZPOOL_STATUS_VERSION_NEWER:
4019168404Spjd		(void) printf(gettext("status: The pool has been upgraded to a "
4020168404Spjd		    "newer, incompatible on-disk version.\n\tThe pool cannot "
4021168404Spjd		    "be accessed on this system.\n"));
4022168404Spjd		(void) printf(gettext("action: Access the pool from a system "
4023168404Spjd		    "running more recent software, or\n\trestore the pool from "
4024168404Spjd		    "backup.\n"));
4025168404Spjd		break;
4026168404Spjd
4027185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_R:
4028185029Spjd		(void) printf(gettext("status: One or more devices are "
4029185029Spjd		    "faulted in response to persistent errors.\n\tSufficient "
4030185029Spjd		    "replicas exist for the pool to continue functioning "
4031185029Spjd		    "in a\n\tdegraded state.\n"));
4032185029Spjd		(void) printf(gettext("action: Replace the faulted device, "
4033185029Spjd		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
4034185029Spjd		break;
4035185029Spjd
4036185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_NR:
4037185029Spjd		(void) printf(gettext("status: One or more devices are "
4038185029Spjd		    "faulted in response to persistent errors.  There are "
4039185029Spjd		    "insufficient replicas for the pool to\n\tcontinue "
4040185029Spjd		    "functioning.\n"));
4041185029Spjd		(void) printf(gettext("action: Destroy and re-create the pool "
4042185029Spjd		    "from a backup source.  Manually marking the device\n"
4043185029Spjd		    "\trepaired using 'zpool clear' may allow some data "
4044185029Spjd		    "to be recovered.\n"));
4045185029Spjd		break;
4046185029Spjd
4047185029Spjd	case ZPOOL_STATUS_IO_FAILURE_WAIT:
4048185029Spjd	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
4049185029Spjd		(void) printf(gettext("status: One or more devices are "
4050185029Spjd		    "faulted in response to IO failures.\n"));
4051185029Spjd		(void) printf(gettext("action: Make sure the affected devices "
4052185029Spjd		    "are connected, then run 'zpool clear'.\n"));
4053185029Spjd		break;
4054185029Spjd
4055185029Spjd	case ZPOOL_STATUS_BAD_LOG:
4056185029Spjd		(void) printf(gettext("status: An intent log record "
4057185029Spjd		    "could not be read.\n"
4058185029Spjd		    "\tWaiting for adminstrator intervention to fix the "
4059185029Spjd		    "faulted pool.\n"));
4060185029Spjd		(void) printf(gettext("action: Either restore the affected "
4061185029Spjd		    "device(s) and run 'zpool online',\n"
4062185029Spjd		    "\tor ignore the intent log records by running "
4063185029Spjd		    "'zpool clear'.\n"));
4064185029Spjd		break;
4065185029Spjd
4066168404Spjd	default:
4067168404Spjd		/*
4068168404Spjd		 * The remaining errors can't actually be generated, yet.
4069168404Spjd		 */
4070168404Spjd		assert(reason == ZPOOL_STATUS_OK);
4071168404Spjd	}
4072168404Spjd
4073168404Spjd	if (msgid != NULL)
4074236146Smm		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
4075168404Spjd		    msgid);
4076168404Spjd
4077168404Spjd	if (config != NULL) {
4078168404Spjd		int namewidth;
4079168404Spjd		uint64_t nerr;
4080185029Spjd		nvlist_t **spares, **l2cache;
4081185029Spjd		uint_t nspares, nl2cache;
4082219089Spjd		pool_scan_stat_t *ps = NULL;
4083168404Spjd
4084219089Spjd		(void) nvlist_lookup_uint64_array(nvroot,
4085219089Spjd		    ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
4086219089Spjd		print_scan_status(ps);
4087168404Spjd
4088168404Spjd		namewidth = max_width(zhp, nvroot, 0, 0);
4089168404Spjd		if (namewidth < 10)
4090168404Spjd			namewidth = 10;
4091168404Spjd
4092168404Spjd		(void) printf(gettext("config:\n\n"));
4093168404Spjd		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
4094168404Spjd		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
4095168404Spjd		print_status_config(zhp, zpool_get_name(zhp), nvroot,
4096209962Smm		    namewidth, 0, B_FALSE);
4097209962Smm
4098185029Spjd		if (num_logs(nvroot) > 0)
4099213197Smm			print_logs(zhp, nvroot, namewidth, B_TRUE);
4100185029Spjd		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
4101185029Spjd		    &l2cache, &nl2cache) == 0)
4102185029Spjd			print_l2cache(zhp, l2cache, nl2cache, namewidth);
4103185029Spjd
4104168404Spjd		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
4105168404Spjd		    &spares, &nspares) == 0)
4106168404Spjd			print_spares(zhp, spares, nspares, namewidth);
4107168404Spjd
4108168404Spjd		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
4109168404Spjd		    &nerr) == 0) {
4110168404Spjd			nvlist_t *nverrlist = NULL;
4111168404Spjd
4112168404Spjd			/*
4113168404Spjd			 * If the approximate error count is small, get a
4114168404Spjd			 * precise count by fetching the entire log and
4115168404Spjd			 * uniquifying the results.
4116168404Spjd			 */
4117185029Spjd			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
4118168404Spjd			    zpool_get_errlog(zhp, &nverrlist) == 0) {
4119168404Spjd				nvpair_t *elem;
4120168404Spjd
4121168404Spjd				elem = NULL;
4122168404Spjd				nerr = 0;
4123168404Spjd				while ((elem = nvlist_next_nvpair(nverrlist,
4124168404Spjd				    elem)) != NULL) {
4125168404Spjd					nerr++;
4126168404Spjd				}
4127168404Spjd			}
4128168404Spjd			nvlist_free(nverrlist);
4129168404Spjd
4130168404Spjd			(void) printf("\n");
4131168404Spjd
4132168404Spjd			if (nerr == 0)
4133168404Spjd				(void) printf(gettext("errors: No known data "
4134168404Spjd				    "errors\n"));
4135168404Spjd			else if (!cbp->cb_verbose)
4136168404Spjd				(void) printf(gettext("errors: %llu data "
4137168404Spjd				    "errors, use '-v' for a list\n"),
4138168404Spjd				    (u_longlong_t)nerr);
4139168404Spjd			else
4140168404Spjd				print_error_log(zhp);
4141168404Spjd		}
4142219089Spjd
4143219089Spjd		if (cbp->cb_dedup_stats)
4144219089Spjd			print_dedup_stats(config);
4145168404Spjd	} else {
4146168404Spjd		(void) printf(gettext("config: The configuration cannot be "
4147168404Spjd		    "determined.\n"));
4148168404Spjd	}
4149168404Spjd
4150168404Spjd	return (0);
4151168404Spjd}
4152168404Spjd
4153168404Spjd/*
4154219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]]
4155168404Spjd *
4156168404Spjd *	-v	Display complete error logs
4157168404Spjd *	-x	Display only pools with potential problems
4158219089Spjd *	-D	Display dedup status (undocumented)
4159219089Spjd *	-T	Display a timestamp in date(1) or Unix format
4160168404Spjd *
4161168404Spjd * Describes the health status of all pools or some subset.
4162168404Spjd */
4163168404Spjdint
4164168404Spjdzpool_do_status(int argc, char **argv)
4165168404Spjd{
4166168404Spjd	int c;
4167168404Spjd	int ret;
4168219089Spjd	unsigned long interval = 0, count = 0;
4169168404Spjd	status_cbdata_t cb = { 0 };
4170168404Spjd
4171168404Spjd	/* check options */
4172219089Spjd	while ((c = getopt(argc, argv, "vxDT:")) != -1) {
4173168404Spjd		switch (c) {
4174168404Spjd		case 'v':
4175168404Spjd			cb.cb_verbose = B_TRUE;
4176168404Spjd			break;
4177168404Spjd		case 'x':
4178168404Spjd			cb.cb_explain = B_TRUE;
4179168404Spjd			break;
4180219089Spjd		case 'D':
4181219089Spjd			cb.cb_dedup_stats = B_TRUE;
4182219089Spjd			break;
4183219089Spjd		case 'T':
4184219089Spjd			get_timestamp_arg(*optarg);
4185219089Spjd			break;
4186168404Spjd		case '?':
4187168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4188168404Spjd			    optopt);
4189168404Spjd			usage(B_FALSE);
4190168404Spjd		}
4191168404Spjd	}
4192168404Spjd
4193168404Spjd	argc -= optind;
4194168404Spjd	argv += optind;
4195168404Spjd
4196219089Spjd	get_interval_count(&argc, argv, &interval, &count);
4197168404Spjd
4198168404Spjd	if (argc == 0)
4199168404Spjd		cb.cb_allpools = B_TRUE;
4200168404Spjd
4201219089Spjd	cb.cb_first = B_TRUE;
4202168404Spjd
4203219089Spjd	for (;;) {
4204219089Spjd		if (timestamp_fmt != NODATE)
4205219089Spjd			print_timestamp(timestamp_fmt);
4206168404Spjd
4207219089Spjd		ret = for_each_pool(argc, argv, B_TRUE, NULL,
4208219089Spjd		    status_callback, &cb);
4209219089Spjd
4210219089Spjd		if (argc == 0 && cb.cb_count == 0)
4211219089Spjd			(void) printf(gettext("no pools available\n"));
4212219089Spjd		else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
4213219089Spjd			(void) printf(gettext("all pools are healthy\n"));
4214219089Spjd
4215219089Spjd		if (ret != 0)
4216219089Spjd			return (ret);
4217219089Spjd
4218219089Spjd		if (interval == 0)
4219219089Spjd			break;
4220219089Spjd
4221219089Spjd		if (count != 0 && --count == 0)
4222219089Spjd			break;
4223219089Spjd
4224219089Spjd		(void) sleep(interval);
4225219089Spjd	}
4226219089Spjd
4227219089Spjd	return (0);
4228168404Spjd}
4229168404Spjd
4230168404Spjdtypedef struct upgrade_cbdata {
4231168404Spjd	int	cb_all;
4232168404Spjd	int	cb_first;
4233168404Spjd	int	cb_newer;
4234212050Spjd	char	cb_poolname[ZPOOL_MAXNAMELEN];
4235168404Spjd	int	cb_argc;
4236185029Spjd	uint64_t cb_version;
4237168404Spjd	char	**cb_argv;
4238168404Spjd} upgrade_cbdata_t;
4239168404Spjd
4240168404Spjdstatic int
4241212050Spjdis_root_pool(zpool_handle_t *zhp)
4242212050Spjd{
4243212050Spjd	static struct statfs sfs;
4244212050Spjd	static char *poolname = NULL;
4245212050Spjd	static boolean_t stated = B_FALSE;
4246212050Spjd	char *slash;
4247212050Spjd
4248212067Spjd	if (!stated) {
4249212050Spjd		stated = B_TRUE;
4250212050Spjd		if (statfs("/", &sfs) == -1) {
4251212050Spjd			(void) fprintf(stderr,
4252212050Spjd			    "Unable to stat root file system: %s.\n",
4253212050Spjd			    strerror(errno));
4254212067Spjd			return (0);
4255212050Spjd		}
4256212050Spjd		if (strcmp(sfs.f_fstypename, "zfs") != 0)
4257212067Spjd			return (0);
4258212050Spjd		poolname = sfs.f_mntfromname;
4259212050Spjd		if ((slash = strchr(poolname, '/')) != NULL)
4260212050Spjd			*slash = '\0';
4261212050Spjd	}
4262212050Spjd	return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0);
4263212050Spjd}
4264212050Spjd
4265212050Spjdstatic int
4266168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg)
4267168404Spjd{
4268168404Spjd	upgrade_cbdata_t *cbp = arg;
4269168404Spjd	nvlist_t *config;
4270168404Spjd	uint64_t version;
4271168404Spjd	int ret = 0;
4272168404Spjd
4273168404Spjd	config = zpool_get_config(zhp, NULL);
4274168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
4275168404Spjd	    &version) == 0);
4276168404Spjd
4277185029Spjd	if (!cbp->cb_newer && version < SPA_VERSION) {
4278168404Spjd		if (!cbp->cb_all) {
4279168404Spjd			if (cbp->cb_first) {
4280168404Spjd				(void) printf(gettext("The following pools are "
4281168404Spjd				    "out of date, and can be upgraded.  After "
4282168404Spjd				    "being\nupgraded, these pools will no "
4283168404Spjd				    "longer be accessible by older software "
4284168404Spjd				    "versions.\n\n"));
4285168404Spjd				(void) printf(gettext("VER  POOL\n"));
4286168404Spjd				(void) printf(gettext("---  ------------\n"));
4287168404Spjd				cbp->cb_first = B_FALSE;
4288168404Spjd			}
4289168404Spjd
4290168404Spjd			(void) printf("%2llu   %s\n", (u_longlong_t)version,
4291168404Spjd			    zpool_get_name(zhp));
4292168404Spjd		} else {
4293168404Spjd			cbp->cb_first = B_FALSE;
4294185029Spjd			ret = zpool_upgrade(zhp, cbp->cb_version);
4295168404Spjd			if (!ret) {
4296168404Spjd				(void) printf(gettext("Successfully upgraded "
4297185029Spjd				    "'%s'\n\n"), zpool_get_name(zhp));
4298212050Spjd				if (cbp->cb_poolname[0] == '\0' &&
4299212050Spjd				    is_root_pool(zhp)) {
4300212050Spjd					(void) strlcpy(cbp->cb_poolname,
4301212050Spjd					    zpool_get_name(zhp),
4302212050Spjd					    sizeof(cbp->cb_poolname));
4303212050Spjd				}
4304168404Spjd			}
4305168404Spjd		}
4306185029Spjd	} else if (cbp->cb_newer && version > SPA_VERSION) {
4307168404Spjd		assert(!cbp->cb_all);
4308168404Spjd
4309168404Spjd		if (cbp->cb_first) {
4310168404Spjd			(void) printf(gettext("The following pools are "
4311168404Spjd			    "formatted using a newer software version and\n"
4312168404Spjd			    "cannot be accessed on the current system.\n\n"));
4313168404Spjd			(void) printf(gettext("VER  POOL\n"));
4314168404Spjd			(void) printf(gettext("---  ------------\n"));
4315168404Spjd			cbp->cb_first = B_FALSE;
4316168404Spjd		}
4317168404Spjd
4318168404Spjd		(void) printf("%2llu   %s\n", (u_longlong_t)version,
4319168404Spjd		    zpool_get_name(zhp));
4320168404Spjd	}
4321168404Spjd
4322168404Spjd	zpool_close(zhp);
4323168404Spjd	return (ret);
4324168404Spjd}
4325168404Spjd
4326168404Spjd/* ARGSUSED */
4327168404Spjdstatic int
4328168404Spjdupgrade_one(zpool_handle_t *zhp, void *data)
4329168404Spjd{
4330185029Spjd	upgrade_cbdata_t *cbp = data;
4331185029Spjd	uint64_t cur_version;
4332168404Spjd	int ret;
4333168404Spjd
4334185029Spjd	if (strcmp("log", zpool_get_name(zhp)) == 0) {
4335185029Spjd		(void) printf(gettext("'log' is now a reserved word\n"
4336185029Spjd		    "Pool 'log' must be renamed using export and import"
4337185029Spjd		    " to upgrade.\n"));
4338185029Spjd		return (1);
4339185029Spjd	}
4340168404Spjd
4341185029Spjd	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
4342185029Spjd	if (cur_version > cbp->cb_version) {
4343168404Spjd		(void) printf(gettext("Pool '%s' is already formatted "
4344185029Spjd		    "using more current version '%llu'.\n"),
4345185029Spjd		    zpool_get_name(zhp), cur_version);
4346185029Spjd		return (0);
4347185029Spjd	}
4348185029Spjd	if (cur_version == cbp->cb_version) {
4349185029Spjd		(void) printf(gettext("Pool '%s' is already formatted "
4350168404Spjd		    "using the current version.\n"), zpool_get_name(zhp));
4351168404Spjd		return (0);
4352168404Spjd	}
4353168404Spjd
4354185029Spjd	ret = zpool_upgrade(zhp, cbp->cb_version);
4355168404Spjd
4356168404Spjd	if (!ret) {
4357168404Spjd		(void) printf(gettext("Successfully upgraded '%s' "
4358185029Spjd		    "from version %llu to version %llu\n\n"),
4359185029Spjd		    zpool_get_name(zhp), (u_longlong_t)cur_version,
4360185029Spjd		    (u_longlong_t)cbp->cb_version);
4361212050Spjd		if (cbp->cb_poolname[0] == '\0' && is_root_pool(zhp)) {
4362212050Spjd			(void) strlcpy(cbp->cb_poolname, zpool_get_name(zhp),
4363212050Spjd			    sizeof(cbp->cb_poolname));
4364212050Spjd		}
4365168404Spjd	}
4366168404Spjd
4367168404Spjd	return (ret != 0);
4368168404Spjd}
4369168404Spjd
4370168404Spjd/*
4371168404Spjd * zpool upgrade
4372168404Spjd * zpool upgrade -v
4373185029Spjd * zpool upgrade [-V version] <-a | pool ...>
4374168404Spjd *
4375168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade.
4376168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will
4377168404Spjd * upgrade all pools.
4378168404Spjd */
4379168404Spjdint
4380168404Spjdzpool_do_upgrade(int argc, char **argv)
4381168404Spjd{
4382168404Spjd	int c;
4383168404Spjd	upgrade_cbdata_t cb = { 0 };
4384168404Spjd	int ret = 0;
4385168404Spjd	boolean_t showversions = B_FALSE;
4386185029Spjd	char *end;
4387168404Spjd
4388185029Spjd
4389168404Spjd	/* check options */
4390219089Spjd	while ((c = getopt(argc, argv, ":avV:")) != -1) {
4391168404Spjd		switch (c) {
4392168404Spjd		case 'a':
4393168404Spjd			cb.cb_all = B_TRUE;
4394168404Spjd			break;
4395168404Spjd		case 'v':
4396168404Spjd			showversions = B_TRUE;
4397168404Spjd			break;
4398185029Spjd		case 'V':
4399185029Spjd			cb.cb_version = strtoll(optarg, &end, 10);
4400185029Spjd			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
4401185029Spjd			    cb.cb_version < SPA_VERSION_1) {
4402185029Spjd				(void) fprintf(stderr,
4403185029Spjd				    gettext("invalid version '%s'\n"), optarg);
4404185029Spjd				usage(B_FALSE);
4405185029Spjd			}
4406185029Spjd			break;
4407219089Spjd		case ':':
4408219089Spjd			(void) fprintf(stderr, gettext("missing argument for "
4409219089Spjd			    "'%c' option\n"), optopt);
4410219089Spjd			usage(B_FALSE);
4411219089Spjd			break;
4412168404Spjd		case '?':
4413168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4414168404Spjd			    optopt);
4415168404Spjd			usage(B_FALSE);
4416168404Spjd		}
4417168404Spjd	}
4418168404Spjd
4419168404Spjd	cb.cb_argc = argc;
4420168404Spjd	cb.cb_argv = argv;
4421168404Spjd	argc -= optind;
4422168404Spjd	argv += optind;
4423168404Spjd
4424185029Spjd	if (cb.cb_version == 0) {
4425185029Spjd		cb.cb_version = SPA_VERSION;
4426185029Spjd	} else if (!cb.cb_all && argc == 0) {
4427185029Spjd		(void) fprintf(stderr, gettext("-V option is "
4428185029Spjd		    "incompatible with other arguments\n"));
4429185029Spjd		usage(B_FALSE);
4430185029Spjd	}
4431185029Spjd
4432168404Spjd	if (showversions) {
4433168404Spjd		if (cb.cb_all || argc != 0) {
4434168404Spjd			(void) fprintf(stderr, gettext("-v option is "
4435168404Spjd			    "incompatible with other arguments\n"));
4436168404Spjd			usage(B_FALSE);
4437168404Spjd		}
4438168404Spjd	} else if (cb.cb_all) {
4439168404Spjd		if (argc != 0) {
4440185029Spjd			(void) fprintf(stderr, gettext("-a option should not "
4441185029Spjd			    "be used along with a pool name\n"));
4442168404Spjd			usage(B_FALSE);
4443168404Spjd		}
4444168404Spjd	}
4445168404Spjd
4446185029Spjd	(void) printf(gettext("This system is currently running "
4447185029Spjd	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
4448168404Spjd	cb.cb_first = B_TRUE;
4449168404Spjd	if (showversions) {
4450168404Spjd		(void) printf(gettext("The following versions are "
4451168404Spjd		    "supported:\n\n"));
4452168404Spjd		(void) printf(gettext("VER  DESCRIPTION\n"));
4453168404Spjd		(void) printf("---  -----------------------------------------"
4454168404Spjd		    "---------------\n");
4455168404Spjd		(void) printf(gettext(" 1   Initial ZFS version\n"));
4456168404Spjd		(void) printf(gettext(" 2   Ditto blocks "
4457168404Spjd		    "(replicated metadata)\n"));
4458168404Spjd		(void) printf(gettext(" 3   Hot spares and double parity "
4459168404Spjd		    "RAID-Z\n"));
4460168404Spjd		(void) printf(gettext(" 4   zpool history\n"));
4461168404Spjd		(void) printf(gettext(" 5   Compression using the gzip "
4462168404Spjd		    "algorithm\n"));
4463185029Spjd		(void) printf(gettext(" 6   bootfs pool property\n"));
4464185029Spjd		(void) printf(gettext(" 7   Separate intent log devices\n"));
4465185029Spjd		(void) printf(gettext(" 8   Delegated administration\n"));
4466185029Spjd		(void) printf(gettext(" 9   refquota and refreservation "
4467185029Spjd		    "properties\n"));
4468185029Spjd		(void) printf(gettext(" 10  Cache devices\n"));
4469185029Spjd		(void) printf(gettext(" 11  Improved scrub performance\n"));
4470185029Spjd		(void) printf(gettext(" 12  Snapshot properties\n"));
4471185029Spjd		(void) printf(gettext(" 13  snapused property\n"));
4472209962Smm		(void) printf(gettext(" 14  passthrough-x aclinherit\n"));
4473209962Smm		(void) printf(gettext(" 15  user/group space accounting\n"));
4474219089Spjd		(void) printf(gettext(" 16  stmf property support\n"));
4475219089Spjd		(void) printf(gettext(" 17  Triple-parity RAID-Z\n"));
4476219089Spjd		(void) printf(gettext(" 18  Snapshot user holds\n"));
4477219089Spjd		(void) printf(gettext(" 19  Log device removal\n"));
4478219089Spjd		(void) printf(gettext(" 20  Compression using zle "
4479219089Spjd		    "(zero-length encoding)\n"));
4480219089Spjd		(void) printf(gettext(" 21  Deduplication\n"));
4481219089Spjd		(void) printf(gettext(" 22  Received properties\n"));
4482219089Spjd		(void) printf(gettext(" 23  Slim ZIL\n"));
4483219089Spjd		(void) printf(gettext(" 24  System attributes\n"));
4484219089Spjd		(void) printf(gettext(" 25  Improved scrub stats\n"));
4485219089Spjd		(void) printf(gettext(" 26  Improved snapshot deletion "
4486219089Spjd		    "performance\n"));
4487219089Spjd		(void) printf(gettext(" 27  Improved snapshot creation "
4488219089Spjd		    "performance\n"));
4489219089Spjd		(void) printf(gettext(" 28  Multiple vdev replacements\n"));
4490219089Spjd		(void) printf(gettext("\nFor more information on a particular "
4491219089Spjd		    "version, including supported releases,\n"));
4492219089Spjd		(void) printf(gettext("see the ZFS Administration Guide.\n\n"));
4493168404Spjd	} else if (argc == 0) {
4494168404Spjd		int notfound;
4495168404Spjd
4496168404Spjd		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
4497168404Spjd		notfound = cb.cb_first;
4498168404Spjd
4499168404Spjd		if (!cb.cb_all && ret == 0) {
4500168404Spjd			if (!cb.cb_first)
4501168404Spjd				(void) printf("\n");
4502168404Spjd			cb.cb_first = B_TRUE;
4503168404Spjd			cb.cb_newer = B_TRUE;
4504168404Spjd			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
4505168404Spjd			if (!cb.cb_first) {
4506168404Spjd				notfound = B_FALSE;
4507168404Spjd				(void) printf("\n");
4508168404Spjd			}
4509168404Spjd		}
4510168404Spjd
4511168404Spjd		if (ret == 0) {
4512168404Spjd			if (notfound)
4513168404Spjd				(void) printf(gettext("All pools are formatted "
4514168404Spjd				    "using this version.\n"));
4515168404Spjd			else if (!cb.cb_all)
4516168404Spjd				(void) printf(gettext("Use 'zpool upgrade -v' "
4517168404Spjd				    "for a list of available versions and "
4518168404Spjd				    "their associated\nfeatures.\n"));
4519168404Spjd		}
4520168404Spjd	} else {
4521168404Spjd		ret = for_each_pool(argc, argv, B_FALSE, NULL,
4522168404Spjd		    upgrade_one, &cb);
4523168404Spjd	}
4524168404Spjd
4525212050Spjd	if (cb.cb_poolname[0] != '\0') {
4526212050Spjd		(void) printf(
4527212050Spjd		    "If you boot from pool '%s', don't forget to update boot code.\n"
4528212050Spjd		    "Assuming you use GPT partitioning and da0 is your boot disk\n"
4529212050Spjd		    "the following command will do it:\n"
4530212050Spjd		    "\n"
4531212050Spjd		    "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n",
4532212050Spjd		    cb.cb_poolname);
4533212050Spjd	}
4534212050Spjd
4535168404Spjd	return (ret);
4536168404Spjd}
4537168404Spjd
4538185029Spjdtypedef struct hist_cbdata {
4539185029Spjd	boolean_t first;
4540185029Spjd	int longfmt;
4541185029Spjd	int internal;
4542185029Spjd} hist_cbdata_t;
4543185029Spjd
4544168404Spjd/*
4545168404Spjd * Print out the command history for a specific pool.
4546168404Spjd */
4547168404Spjdstatic int
4548168404Spjdget_history_one(zpool_handle_t *zhp, void *data)
4549168404Spjd{
4550168404Spjd	nvlist_t *nvhis;
4551168404Spjd	nvlist_t **records;
4552168404Spjd	uint_t numrecords;
4553168404Spjd	char *cmdstr;
4554185029Spjd	char *pathstr;
4555168404Spjd	uint64_t dst_time;
4556168404Spjd	time_t tsec;
4557168404Spjd	struct tm t;
4558168404Spjd	char tbuf[30];
4559168404Spjd	int ret, i;
4560185029Spjd	uint64_t who;
4561185029Spjd	struct passwd *pwd;
4562185029Spjd	char *hostname;
4563185029Spjd	char *zonename;
4564185029Spjd	char internalstr[MAXPATHLEN];
4565185029Spjd	hist_cbdata_t *cb = (hist_cbdata_t *)data;
4566185029Spjd	uint64_t txg;
4567185029Spjd	uint64_t ievent;
4568168404Spjd
4569185029Spjd	cb->first = B_FALSE;
4570168404Spjd
4571168404Spjd	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
4572168404Spjd
4573168404Spjd	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
4574168404Spjd		return (ret);
4575168404Spjd
4576168404Spjd	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
4577168404Spjd	    &records, &numrecords) == 0);
4578168404Spjd	for (i = 0; i < numrecords; i++) {
4579168404Spjd		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
4580185029Spjd		    &dst_time) != 0)
4581185029Spjd			continue;
4582185029Spjd
4583185029Spjd		/* is it an internal event or a standard event? */
4584185029Spjd		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
4585185029Spjd		    &cmdstr) != 0) {
4586185029Spjd			if (cb->internal == 0)
4587185029Spjd				continue;
4588185029Spjd
4589185029Spjd			if (nvlist_lookup_uint64(records[i],
4590185029Spjd			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
4591185029Spjd				continue;
4592185029Spjd			verify(nvlist_lookup_uint64(records[i],
4593185029Spjd			    ZPOOL_HIST_TXG, &txg) == 0);
4594185029Spjd			verify(nvlist_lookup_string(records[i],
4595185029Spjd			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
4596185029Spjd			if (ievent >= LOG_END)
4597185029Spjd				continue;
4598185029Spjd			(void) snprintf(internalstr,
4599185029Spjd			    sizeof (internalstr),
4600185029Spjd			    "[internal %s txg:%lld] %s",
4601219089Spjd			    zfs_history_event_names[ievent], txg,
4602185029Spjd			    pathstr);
4603185029Spjd			cmdstr = internalstr;
4604168404Spjd		}
4605185029Spjd		tsec = dst_time;
4606185029Spjd		(void) localtime_r(&tsec, &t);
4607185029Spjd		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
4608185029Spjd		(void) printf("%s %s", tbuf, cmdstr);
4609185029Spjd
4610185029Spjd		if (!cb->longfmt) {
4611185029Spjd			(void) printf("\n");
4612185029Spjd			continue;
4613185029Spjd		}
4614185029Spjd		(void) printf(" [");
4615185029Spjd		if (nvlist_lookup_uint64(records[i],
4616185029Spjd		    ZPOOL_HIST_WHO, &who) == 0) {
4617185029Spjd			pwd = getpwuid((uid_t)who);
4618185029Spjd			if (pwd)
4619185029Spjd				(void) printf("user %s on",
4620185029Spjd				    pwd->pw_name);
4621185029Spjd			else
4622185029Spjd				(void) printf("user %d on",
4623185029Spjd				    (int)who);
4624185029Spjd		} else {
4625185029Spjd			(void) printf(gettext("no info]\n"));
4626185029Spjd			continue;
4627185029Spjd		}
4628185029Spjd		if (nvlist_lookup_string(records[i],
4629185029Spjd		    ZPOOL_HIST_HOST, &hostname) == 0) {
4630185029Spjd			(void) printf(" %s", hostname);
4631185029Spjd		}
4632185029Spjd		if (nvlist_lookup_string(records[i],
4633185029Spjd		    ZPOOL_HIST_ZONE, &zonename) == 0) {
4634185029Spjd			(void) printf(":%s", zonename);
4635185029Spjd		}
4636185029Spjd
4637185029Spjd		(void) printf("]");
4638185029Spjd		(void) printf("\n");
4639168404Spjd	}
4640168404Spjd	(void) printf("\n");
4641168404Spjd	nvlist_free(nvhis);
4642168404Spjd
4643168404Spjd	return (ret);
4644168404Spjd}
4645168404Spjd
4646168404Spjd/*
4647168404Spjd * zpool history <pool>
4648168404Spjd *
4649168404Spjd * Displays the history of commands that modified pools.
4650168404Spjd */
4651185029Spjd
4652185029Spjd
4653168404Spjdint
4654168404Spjdzpool_do_history(int argc, char **argv)
4655168404Spjd{
4656185029Spjd	hist_cbdata_t cbdata = { 0 };
4657168404Spjd	int ret;
4658185029Spjd	int c;
4659168404Spjd
4660185029Spjd	cbdata.first = B_TRUE;
4661185029Spjd	/* check options */
4662185029Spjd	while ((c = getopt(argc, argv, "li")) != -1) {
4663185029Spjd		switch (c) {
4664185029Spjd		case 'l':
4665185029Spjd			cbdata.longfmt = 1;
4666185029Spjd			break;
4667185029Spjd		case 'i':
4668185029Spjd			cbdata.internal = 1;
4669185029Spjd			break;
4670185029Spjd		case '?':
4671185029Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4672185029Spjd			    optopt);
4673185029Spjd			usage(B_FALSE);
4674185029Spjd		}
4675185029Spjd	}
4676168404Spjd	argc -= optind;
4677168404Spjd	argv += optind;
4678168404Spjd
4679168404Spjd	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
4680185029Spjd	    &cbdata);
4681168404Spjd
4682185029Spjd	if (argc == 0 && cbdata.first == B_TRUE) {
4683168404Spjd		(void) printf(gettext("no pools available\n"));
4684168404Spjd		return (0);
4685168404Spjd	}
4686168404Spjd
4687168404Spjd	return (ret);
4688168404Spjd}
4689168404Spjd
4690168404Spjdstatic int
4691168404Spjdget_callback(zpool_handle_t *zhp, void *data)
4692168404Spjd{
4693185029Spjd	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
4694168404Spjd	char value[MAXNAMELEN];
4695185029Spjd	zprop_source_t srctype;
4696185029Spjd	zprop_list_t *pl;
4697168404Spjd
4698168404Spjd	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
4699168404Spjd
4700168404Spjd		/*
4701185029Spjd		 * Skip the special fake placeholder. This will also skip
4702185029Spjd		 * over the name property when 'all' is specified.
4703168404Spjd		 */
4704185029Spjd		if (pl->pl_prop == ZPOOL_PROP_NAME &&
4705168404Spjd		    pl == cbp->cb_proplist)
4706168404Spjd			continue;
4707168404Spjd
4708168404Spjd		if (zpool_get_prop(zhp, pl->pl_prop,
4709168404Spjd		    value, sizeof (value), &srctype) != 0)
4710168404Spjd			continue;
4711168404Spjd
4712185029Spjd		zprop_print_one_property(zpool_get_name(zhp), cbp,
4713219089Spjd		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL,
4714219089Spjd		    NULL);
4715168404Spjd	}
4716168404Spjd	return (0);
4717168404Spjd}
4718168404Spjd
4719168404Spjdint
4720168404Spjdzpool_do_get(int argc, char **argv)
4721168404Spjd{
4722185029Spjd	zprop_get_cbdata_t cb = { 0 };
4723185029Spjd	zprop_list_t fake_name = { 0 };
4724168404Spjd	int ret;
4725168404Spjd
4726168404Spjd	if (argc < 3)
4727168404Spjd		usage(B_FALSE);
4728168404Spjd
4729168404Spjd	cb.cb_first = B_TRUE;
4730185029Spjd	cb.cb_sources = ZPROP_SRC_ALL;
4731168404Spjd	cb.cb_columns[0] = GET_COL_NAME;
4732168404Spjd	cb.cb_columns[1] = GET_COL_PROPERTY;
4733168404Spjd	cb.cb_columns[2] = GET_COL_VALUE;
4734168404Spjd	cb.cb_columns[3] = GET_COL_SOURCE;
4735185029Spjd	cb.cb_type = ZFS_TYPE_POOL;
4736168404Spjd
4737185029Spjd	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
4738185029Spjd	    ZFS_TYPE_POOL) != 0)
4739168404Spjd		usage(B_FALSE);
4740168404Spjd
4741168404Spjd	if (cb.cb_proplist != NULL) {
4742185029Spjd		fake_name.pl_prop = ZPOOL_PROP_NAME;
4743168404Spjd		fake_name.pl_width = strlen(gettext("NAME"));
4744168404Spjd		fake_name.pl_next = cb.cb_proplist;
4745168404Spjd		cb.cb_proplist = &fake_name;
4746168404Spjd	}
4747168404Spjd
4748168404Spjd	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
4749168404Spjd	    get_callback, &cb);
4750168404Spjd
4751168404Spjd	if (cb.cb_proplist == &fake_name)
4752185029Spjd		zprop_free_list(fake_name.pl_next);
4753168404Spjd	else
4754185029Spjd		zprop_free_list(cb.cb_proplist);
4755168404Spjd
4756168404Spjd	return (ret);
4757168404Spjd}
4758168404Spjd
4759168404Spjdtypedef struct set_cbdata {
4760168404Spjd	char *cb_propname;
4761168404Spjd	char *cb_value;
4762168404Spjd	boolean_t cb_any_successful;
4763168404Spjd} set_cbdata_t;
4764168404Spjd
4765168404Spjdint
4766168404Spjdset_callback(zpool_handle_t *zhp, void *data)
4767168404Spjd{
4768168404Spjd	int error;
4769168404Spjd	set_cbdata_t *cb = (set_cbdata_t *)data;
4770168404Spjd
4771168404Spjd	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
4772168404Spjd
4773168404Spjd	if (!error)
4774168404Spjd		cb->cb_any_successful = B_TRUE;
4775168404Spjd
4776168404Spjd	return (error);
4777168404Spjd}
4778168404Spjd
4779168404Spjdint
4780168404Spjdzpool_do_set(int argc, char **argv)
4781168404Spjd{
4782168404Spjd	set_cbdata_t cb = { 0 };
4783168404Spjd	int error;
4784168404Spjd
4785168404Spjd	if (argc > 1 && argv[1][0] == '-') {
4786168404Spjd		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4787168404Spjd		    argv[1][1]);
4788168404Spjd		usage(B_FALSE);
4789168404Spjd	}
4790168404Spjd
4791168404Spjd	if (argc < 2) {
4792168404Spjd		(void) fprintf(stderr, gettext("missing property=value "
4793168404Spjd		    "argument\n"));
4794168404Spjd		usage(B_FALSE);
4795168404Spjd	}
4796168404Spjd
4797168404Spjd	if (argc < 3) {
4798168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
4799168404Spjd		usage(B_FALSE);
4800168404Spjd	}
4801168404Spjd
4802168404Spjd	if (argc > 3) {
4803168404Spjd		(void) fprintf(stderr, gettext("too many pool names\n"));
4804168404Spjd		usage(B_FALSE);
4805168404Spjd	}
4806168404Spjd
4807168404Spjd	cb.cb_propname = argv[1];
4808168404Spjd	cb.cb_value = strchr(cb.cb_propname, '=');
4809168404Spjd	if (cb.cb_value == NULL) {
4810168404Spjd		(void) fprintf(stderr, gettext("missing value in "
4811168404Spjd		    "property=value argument\n"));
4812168404Spjd		usage(B_FALSE);
4813168404Spjd	}
4814168404Spjd
4815168404Spjd	*(cb.cb_value) = '\0';
4816168404Spjd	cb.cb_value++;
4817168404Spjd
4818168404Spjd	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
4819168404Spjd	    set_callback, &cb);
4820168404Spjd
4821168404Spjd	return (error);
4822168404Spjd}
4823168404Spjd
4824168404Spjdstatic int
4825168404Spjdfind_command_idx(char *command, int *idx)
4826168404Spjd{
4827168404Spjd	int i;
4828168404Spjd
4829168404Spjd	for (i = 0; i < NCOMMAND; i++) {
4830168404Spjd		if (command_table[i].name == NULL)
4831168404Spjd			continue;
4832168404Spjd
4833168404Spjd		if (strcmp(command, command_table[i].name) == 0) {
4834168404Spjd			*idx = i;
4835168404Spjd			return (0);
4836168404Spjd		}
4837168404Spjd	}
4838168404Spjd	return (1);
4839168404Spjd}
4840168404Spjd
4841168404Spjdint
4842168404Spjdmain(int argc, char **argv)
4843168404Spjd{
4844168404Spjd	int ret;
4845168404Spjd	int i;
4846168404Spjd	char *cmdname;
4847168404Spjd
4848168404Spjd	(void) setlocale(LC_ALL, "");
4849168404Spjd	(void) textdomain(TEXT_DOMAIN);
4850168404Spjd
4851168404Spjd	if ((g_zfs = libzfs_init()) == NULL) {
4852168404Spjd		(void) fprintf(stderr, gettext("internal error: failed to "
4853168404Spjd		    "initialize ZFS library\n"));
4854168404Spjd		return (1);
4855168404Spjd	}
4856168404Spjd
4857168404Spjd	libzfs_print_on_error(g_zfs, B_TRUE);
4858168404Spjd
4859168404Spjd	opterr = 0;
4860168404Spjd
4861168404Spjd	/*
4862168404Spjd	 * Make sure the user has specified some command.
4863168404Spjd	 */
4864168404Spjd	if (argc < 2) {
4865168404Spjd		(void) fprintf(stderr, gettext("missing command\n"));
4866168404Spjd		usage(B_FALSE);
4867168404Spjd	}
4868168404Spjd
4869168404Spjd	cmdname = argv[1];
4870168404Spjd
4871168404Spjd	/*
4872168404Spjd	 * Special case '-?'
4873168404Spjd	 */
4874168404Spjd	if (strcmp(cmdname, "-?") == 0)
4875168404Spjd		usage(B_TRUE);
4876168404Spjd
4877185029Spjd	zpool_set_history_str("zpool", argc, argv, history_str);
4878185029Spjd	verify(zpool_stage_history(g_zfs, history_str) == 0);
4879185029Spjd
4880168404Spjd	/*
4881168404Spjd	 * Run the appropriate command.
4882168404Spjd	 */
4883168404Spjd	if (find_command_idx(cmdname, &i) == 0) {
4884168404Spjd		current_command = &command_table[i];
4885168404Spjd		ret = command_table[i].func(argc - 1, argv + 1);
4886185029Spjd	} else if (strchr(cmdname, '=')) {
4887185029Spjd		verify(find_command_idx("set", &i) == 0);
4888185029Spjd		current_command = &command_table[i];
4889185029Spjd		ret = command_table[i].func(argc, argv);
4890185029Spjd	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
4891185029Spjd		/*
4892185029Spjd		 * 'freeze' is a vile debugging abomination, so we treat
4893185029Spjd		 * it as such.
4894185029Spjd		 */
4895168404Spjd		char buf[16384];
4896168404Spjd		int fd = open(ZFS_DEV, O_RDWR);
4897168404Spjd		(void) strcpy((void *)buf, argv[2]);
4898168404Spjd		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
4899185029Spjd	} else {
4900168404Spjd		(void) fprintf(stderr, gettext("unrecognized "
4901168404Spjd		    "command '%s'\n"), cmdname);
4902168404Spjd		usage(B_FALSE);
4903168404Spjd	}
4904168404Spjd
4905168404Spjd	libzfs_fini(g_zfs);
4906168404Spjd
4907168404Spjd	/*
4908168404Spjd	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
4909168404Spjd	 * for the purposes of running ::findleaks.
4910168404Spjd	 */
4911168404Spjd	if (getenv("ZFS_ABORT") != NULL) {
4912168404Spjd		(void) printf("dumping core by request\n");
4913168404Spjd		abort();
4914168404Spjd	}
4915168404Spjd
4916168404Spjd	return (ret);
4917168404Spjd}
4918