zpool_main.c revision 238926
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"
57236884Smm#include "zfeature_common.h"
58168404Spjd
59219089Spjd#include "statcommon.h"
60219089Spjd
61168404Spjdstatic int zpool_do_create(int, char **);
62168404Spjdstatic int zpool_do_destroy(int, char **);
63168404Spjd
64168404Spjdstatic int zpool_do_add(int, char **);
65168404Spjdstatic int zpool_do_remove(int, char **);
66224171Sgibbsstatic int zpool_do_labelclear(int, char **);
67168404Spjd
68168404Spjdstatic int zpool_do_list(int, char **);
69168404Spjdstatic int zpool_do_iostat(int, char **);
70168404Spjdstatic int zpool_do_status(int, char **);
71168404Spjd
72168404Spjdstatic int zpool_do_online(int, char **);
73168404Spjdstatic int zpool_do_offline(int, char **);
74168404Spjdstatic int zpool_do_clear(int, char **);
75236155Smmstatic int zpool_do_reopen(int, char **);
76168404Spjd
77228103Smmstatic int zpool_do_reguid(int, char **);
78228103Smm
79168404Spjdstatic int zpool_do_attach(int, char **);
80168404Spjdstatic int zpool_do_detach(int, char **);
81168404Spjdstatic int zpool_do_replace(int, char **);
82219089Spjdstatic int zpool_do_split(int, char **);
83168404Spjd
84168404Spjdstatic int zpool_do_scrub(int, char **);
85168404Spjd
86168404Spjdstatic int zpool_do_import(int, char **);
87168404Spjdstatic int zpool_do_export(int, char **);
88168404Spjd
89168404Spjdstatic int zpool_do_upgrade(int, char **);
90168404Spjd
91168404Spjdstatic int zpool_do_history(int, char **);
92168404Spjd
93168404Spjdstatic int zpool_do_get(int, char **);
94168404Spjdstatic int zpool_do_set(int, char **);
95168404Spjd
96168404Spjd/*
97168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's
98168404Spjd * debugging facilities.
99168404Spjd */
100185029Spjd
101185029Spjd#ifdef DEBUG
102168404Spjdconst char *
103168404Spjd_umem_debug_init(void)
104168404Spjd{
105168404Spjd	return ("default,verbose"); /* $UMEM_DEBUG setting */
106168404Spjd}
107168404Spjd
108168404Spjdconst char *
109168404Spjd_umem_logging_init(void)
110168404Spjd{
111168404Spjd	return ("fail,contents"); /* $UMEM_LOGGING setting */
112168404Spjd}
113185029Spjd#endif
114168404Spjd
115168404Spjdtypedef enum {
116168404Spjd	HELP_ADD,
117168404Spjd	HELP_ATTACH,
118168404Spjd	HELP_CLEAR,
119168404Spjd	HELP_CREATE,
120168404Spjd	HELP_DESTROY,
121168404Spjd	HELP_DETACH,
122168404Spjd	HELP_EXPORT,
123168404Spjd	HELP_HISTORY,
124168404Spjd	HELP_IMPORT,
125168404Spjd	HELP_IOSTAT,
126224171Sgibbs	HELP_LABELCLEAR,
127168404Spjd	HELP_LIST,
128168404Spjd	HELP_OFFLINE,
129168404Spjd	HELP_ONLINE,
130168404Spjd	HELP_REPLACE,
131168404Spjd	HELP_REMOVE,
132168404Spjd	HELP_SCRUB,
133168404Spjd	HELP_STATUS,
134168404Spjd	HELP_UPGRADE,
135168404Spjd	HELP_GET,
136219089Spjd	HELP_SET,
137228103Smm	HELP_SPLIT,
138236155Smm	HELP_REGUID,
139236155Smm	HELP_REOPEN
140168404Spjd} zpool_help_t;
141168404Spjd
142168404Spjd
143168404Spjdtypedef struct zpool_command {
144168404Spjd	const char	*name;
145168404Spjd	int		(*func)(int, char **);
146168404Spjd	zpool_help_t	usage;
147168404Spjd} zpool_command_t;
148168404Spjd
149168404Spjd/*
150168404Spjd * Master command table.  Each ZFS command has a name, associated function, and
151168404Spjd * usage message.  The usage messages need to be internationalized, so we have
152168404Spjd * to have a function to return the usage message based on a command index.
153168404Spjd *
154168404Spjd * These commands are organized according to how they are displayed in the usage
155168404Spjd * message.  An empty command (one with a NULL name) indicates an empty line in
156168404Spjd * the generic usage message.
157168404Spjd */
158168404Spjdstatic zpool_command_t command_table[] = {
159168404Spjd	{ "create",	zpool_do_create,	HELP_CREATE		},
160168404Spjd	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
161168404Spjd	{ NULL },
162168404Spjd	{ "add",	zpool_do_add,		HELP_ADD		},
163168404Spjd	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
164168404Spjd	{ NULL },
165224171Sgibbs	{ "labelclear",	zpool_do_labelclear,	HELP_LABELCLEAR		},
166224171Sgibbs	{ NULL },
167168404Spjd	{ "list",	zpool_do_list,		HELP_LIST		},
168168404Spjd	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
169168404Spjd	{ "status",	zpool_do_status,	HELP_STATUS		},
170168404Spjd	{ NULL },
171168404Spjd	{ "online",	zpool_do_online,	HELP_ONLINE		},
172168404Spjd	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
173168404Spjd	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
174236155Smm	{ "reopen",	zpool_do_reopen,	HELP_REOPEN		},
175168404Spjd	{ NULL },
176168404Spjd	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
177168404Spjd	{ "detach",	zpool_do_detach,	HELP_DETACH		},
178168404Spjd	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
179219089Spjd	{ "split",	zpool_do_split,		HELP_SPLIT		},
180168404Spjd	{ NULL },
181168404Spjd	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
182168404Spjd	{ NULL },
183168404Spjd	{ "import",	zpool_do_import,	HELP_IMPORT		},
184168404Spjd	{ "export",	zpool_do_export,	HELP_EXPORT		},
185168404Spjd	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
186228103Smm	{ "reguid",	zpool_do_reguid,	HELP_REGUID		},
187168404Spjd	{ NULL },
188168404Spjd	{ "history",	zpool_do_history,	HELP_HISTORY		},
189168404Spjd	{ "get",	zpool_do_get,		HELP_GET		},
190168404Spjd	{ "set",	zpool_do_set,		HELP_SET		},
191168404Spjd};
192168404Spjd
193168404Spjd#define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
194168404Spjd
195168404Spjdzpool_command_t *current_command;
196185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN];
197168404Spjd
198219089Spjdstatic uint_t timestamp_fmt = NODATE;
199219089Spjd
200168404Spjdstatic const char *
201168404Spjdget_usage(zpool_help_t idx) {
202168404Spjd	switch (idx) {
203168404Spjd	case HELP_ADD:
204168404Spjd		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
205168404Spjd	case HELP_ATTACH:
206168404Spjd		return (gettext("\tattach [-f] <pool> <device> "
207185029Spjd		    "<new-device>\n"));
208168404Spjd	case HELP_CLEAR:
209219089Spjd		return (gettext("\tclear [-nF] <pool> [device]\n"));
210168404Spjd	case HELP_CREATE:
211236884Smm		return (gettext("\tcreate [-fnd] [-o property=value] ... \n"
212185029Spjd		    "\t    [-O file-system-property=value] ... \n"
213185029Spjd		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
214168404Spjd	case HELP_DESTROY:
215168404Spjd		return (gettext("\tdestroy [-f] <pool>\n"));
216168404Spjd	case HELP_DETACH:
217168404Spjd		return (gettext("\tdetach <pool> <device>\n"));
218168404Spjd	case HELP_EXPORT:
219168404Spjd		return (gettext("\texport [-f] <pool> ...\n"));
220168404Spjd	case HELP_HISTORY:
221185029Spjd		return (gettext("\thistory [-il] [<pool>] ...\n"));
222168404Spjd	case HELP_IMPORT:
223168404Spjd		return (gettext("\timport [-d dir] [-D]\n"
224219089Spjd		    "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n"
225185029Spjd		    "\timport [-o mntopts] [-o property=value] ... \n"
226219089Spjd		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
227219089Spjd		    "[-R root] [-F [-n]] -a\n"
228185029Spjd		    "\timport [-o mntopts] [-o property=value] ... \n"
229219089Spjd		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
230219089Spjd		    "[-R root] [-F [-n]]\n"
231219089Spjd		    "\t    <pool | id> [newpool]\n"));
232168404Spjd	case HELP_IOSTAT:
233219089Spjd		return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
234168404Spjd		    "[count]]\n"));
235224171Sgibbs	case HELP_LABELCLEAR:
236224171Sgibbs		return (gettext("\tlabelclear [-f] <vdev>\n"));
237168404Spjd	case HELP_LIST:
238236960Smm		return (gettext("\tlist [-Hv] [-o property[,...]] "
239219089Spjd		    "[-T d|u] [pool] ... [interval [count]]\n"));
240168404Spjd	case HELP_OFFLINE:
241168404Spjd		return (gettext("\toffline [-t] <pool> <device> ...\n"));
242168404Spjd	case HELP_ONLINE:
243228020Smm		return (gettext("\tonline [-e] <pool> <device> ...\n"));
244168404Spjd	case HELP_REPLACE:
245168404Spjd		return (gettext("\treplace [-f] <pool> <device> "
246185029Spjd		    "[new-device]\n"));
247168404Spjd	case HELP_REMOVE:
248185029Spjd		return (gettext("\tremove <pool> <device> ...\n"));
249236155Smm	case HELP_REOPEN:
250236155Smm		return (""); /* Undocumented command */
251168404Spjd	case HELP_SCRUB:
252168404Spjd		return (gettext("\tscrub [-s] <pool> ...\n"));
253168404Spjd	case HELP_STATUS:
254219089Spjd		return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
255219089Spjd		    "[count]]\n"));
256168404Spjd	case HELP_UPGRADE:
257228020Smm		return (gettext("\tupgrade [-v]\n"
258185029Spjd		    "\tupgrade [-V version] <-a | pool ...>\n"));
259168404Spjd	case HELP_GET:
260185029Spjd		return (gettext("\tget <\"all\" | property[,...]> "
261168404Spjd		    "<pool> ...\n"));
262168404Spjd	case HELP_SET:
263168404Spjd		return (gettext("\tset <property=value> <pool> \n"));
264219089Spjd	case HELP_SPLIT:
265219089Spjd		return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
266219089Spjd		    "\t    [-o property=value] <pool> <newpool> "
267219089Spjd		    "[<device> ...]\n"));
268228103Smm	case HELP_REGUID:
269228103Smm		return (gettext("\treguid <pool>\n"));
270168404Spjd	}
271168404Spjd
272168404Spjd	abort();
273168404Spjd	/* NOTREACHED */
274168404Spjd}
275168404Spjd
276168404Spjd
277168404Spjd/*
278168404Spjd * Callback routine that will print out a pool property value.
279168404Spjd */
280185029Spjdstatic int
281185029Spjdprint_prop_cb(int prop, void *cb)
282168404Spjd{
283168404Spjd	FILE *fp = cb;
284168404Spjd
285219089Spjd	(void) fprintf(fp, "\t%-15s  ", zpool_prop_to_name(prop));
286168404Spjd
287185029Spjd	if (zpool_prop_readonly(prop))
288185029Spjd		(void) fprintf(fp, "  NO   ");
289185029Spjd	else
290219089Spjd		(void) fprintf(fp, " YES   ");
291185029Spjd
292168404Spjd	if (zpool_prop_values(prop) == NULL)
293168404Spjd		(void) fprintf(fp, "-\n");
294168404Spjd	else
295168404Spjd		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
296168404Spjd
297185029Spjd	return (ZPROP_CONT);
298168404Spjd}
299168404Spjd
300168404Spjd/*
301168404Spjd * Display usage message.  If we're inside a command, display only the usage for
302168404Spjd * that command.  Otherwise, iterate over the entire command table and display
303168404Spjd * a complete usage message.
304168404Spjd */
305168404Spjdvoid
306168404Spjdusage(boolean_t requested)
307168404Spjd{
308168404Spjd	FILE *fp = requested ? stdout : stderr;
309168404Spjd
310168404Spjd	if (current_command == NULL) {
311168404Spjd		int i;
312168404Spjd
313168404Spjd		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
314168404Spjd		(void) fprintf(fp,
315168404Spjd		    gettext("where 'command' is one of the following:\n\n"));
316168404Spjd
317168404Spjd		for (i = 0; i < NCOMMAND; i++) {
318168404Spjd			if (command_table[i].name == NULL)
319168404Spjd				(void) fprintf(fp, "\n");
320168404Spjd			else
321168404Spjd				(void) fprintf(fp, "%s",
322168404Spjd				    get_usage(command_table[i].usage));
323168404Spjd		}
324168404Spjd	} else {
325168404Spjd		(void) fprintf(fp, gettext("usage:\n"));
326168404Spjd		(void) fprintf(fp, "%s", get_usage(current_command->usage));
327168404Spjd	}
328168404Spjd
329168404Spjd	if (current_command != NULL &&
330168404Spjd	    ((strcmp(current_command->name, "set") == 0) ||
331185029Spjd	    (strcmp(current_command->name, "get") == 0) ||
332185029Spjd	    (strcmp(current_command->name, "list") == 0))) {
333168404Spjd
334168404Spjd		(void) fprintf(fp,
335168404Spjd		    gettext("\nthe following properties are supported:\n"));
336168404Spjd
337219089Spjd		(void) fprintf(fp, "\n\t%-15s  %s   %s\n\n",
338185029Spjd		    "PROPERTY", "EDIT", "VALUES");
339168404Spjd
340168404Spjd		/* Iterate over all properties */
341185029Spjd		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
342185029Spjd		    ZFS_TYPE_POOL);
343236884Smm
344236884Smm		(void) fprintf(fp, "\t%-15s   ", "feature@...");
345236884Smm		(void) fprintf(fp, "YES   disabled | enabled | active\n");
346236884Smm
347236884Smm		(void) fprintf(fp, gettext("\nThe feature@ properties must be "
348236884Smm		    "appended with a feature name.\nSee zpool-features(5).\n"));
349168404Spjd	}
350168404Spjd
351168404Spjd	/*
352168404Spjd	 * See comments at end of main().
353168404Spjd	 */
354168404Spjd	if (getenv("ZFS_ABORT") != NULL) {
355168404Spjd		(void) printf("dumping core by request\n");
356168404Spjd		abort();
357168404Spjd	}
358168404Spjd
359168404Spjd	exit(requested ? 0 : 2);
360168404Spjd}
361168404Spjd
362168404Spjdvoid
363185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
364185029Spjd    boolean_t print_logs)
365168404Spjd{
366168404Spjd	nvlist_t **child;
367168404Spjd	uint_t c, children;
368168404Spjd	char *vname;
369168404Spjd
370168404Spjd	if (name != NULL)
371168404Spjd		(void) printf("\t%*s%s\n", indent, "", name);
372168404Spjd
373168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
374168404Spjd	    &child, &children) != 0)
375168404Spjd		return;
376168404Spjd
377168404Spjd	for (c = 0; c < children; c++) {
378185029Spjd		uint64_t is_log = B_FALSE;
379185029Spjd
380185029Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
381185029Spjd		    &is_log);
382185029Spjd		if ((is_log && !print_logs) || (!is_log && print_logs))
383185029Spjd			continue;
384185029Spjd
385219089Spjd		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
386185029Spjd		print_vdev_tree(zhp, vname, child[c], indent + 2,
387185029Spjd		    B_FALSE);
388168404Spjd		free(vname);
389168404Spjd	}
390168404Spjd}
391168404Spjd
392238926Smmstatic boolean_t
393238926Smmprop_list_contains_feature(nvlist_t *proplist)
394238926Smm{
395238926Smm	nvpair_t *nvp;
396238926Smm	for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp;
397238926Smm	    nvp = nvlist_next_nvpair(proplist, nvp)) {
398238926Smm		if (zpool_prop_feature(nvpair_name(nvp)))
399238926Smm			return (B_TRUE);
400238926Smm	}
401238926Smm	return (B_FALSE);
402238926Smm}
403238926Smm
404168404Spjd/*
405185029Spjd * Add a property pair (name, string-value) into a property nvlist.
406185029Spjd */
407185029Spjdstatic int
408185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props,
409185029Spjd    boolean_t poolprop)
410185029Spjd{
411185029Spjd	zpool_prop_t prop = ZPROP_INVAL;
412185029Spjd	zfs_prop_t fprop;
413185029Spjd	nvlist_t *proplist;
414185029Spjd	const char *normnm;
415185029Spjd	char *strval;
416185029Spjd
417185029Spjd	if (*props == NULL &&
418185029Spjd	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
419185029Spjd		(void) fprintf(stderr,
420185029Spjd		    gettext("internal error: out of memory\n"));
421185029Spjd		return (1);
422185029Spjd	}
423185029Spjd
424185029Spjd	proplist = *props;
425185029Spjd
426185029Spjd	if (poolprop) {
427238926Smm		const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
428238926Smm
429236884Smm		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
430236884Smm		    !zpool_prop_feature(propname)) {
431185029Spjd			(void) fprintf(stderr, gettext("property '%s' is "
432185029Spjd			    "not a valid pool property\n"), propname);
433185029Spjd			return (2);
434185029Spjd		}
435238926Smm
436238926Smm		/*
437238926Smm		 * feature@ properties and version should not be specified
438238926Smm		 * at the same time.
439238926Smm		 */
440238926Smm		if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) &&
441238926Smm		    nvlist_exists(proplist, vname)) ||
442238926Smm		    (prop == ZPOOL_PROP_VERSION &&
443238926Smm		    prop_list_contains_feature(proplist))) {
444238926Smm			(void) fprintf(stderr, gettext("'feature@' and "
445238926Smm			    "'version' properties cannot be specified "
446238926Smm			    "together\n"));
447238926Smm			return (2);
448238926Smm		}
449238926Smm
450238926Smm
451236884Smm		if (zpool_prop_feature(propname))
452236884Smm			normnm = propname;
453236884Smm		else
454236884Smm			normnm = zpool_prop_to_name(prop);
455185029Spjd	} else {
456209962Smm		if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
457209962Smm			normnm = zfs_prop_to_name(fprop);
458209962Smm		} else {
459209962Smm			normnm = propname;
460185029Spjd		}
461185029Spjd	}
462185029Spjd
463185029Spjd	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
464185029Spjd	    prop != ZPOOL_PROP_CACHEFILE) {
465185029Spjd		(void) fprintf(stderr, gettext("property '%s' "
466185029Spjd		    "specified multiple times\n"), propname);
467185029Spjd		return (2);
468185029Spjd	}
469185029Spjd
470185029Spjd	if (nvlist_add_string(proplist, normnm, propval) != 0) {
471185029Spjd		(void) fprintf(stderr, gettext("internal "
472185029Spjd		    "error: out of memory\n"));
473185029Spjd		return (1);
474185029Spjd	}
475185029Spjd
476185029Spjd	return (0);
477185029Spjd}
478185029Spjd
479185029Spjd/*
480168404Spjd * zpool add [-fn] <pool> <vdev> ...
481168404Spjd *
482168404Spjd *	-f	Force addition of devices, even if they appear in use
483168404Spjd *	-n	Do not add the devices, but display the resulting layout if
484168404Spjd *		they were to be added.
485168404Spjd *
486168404Spjd * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
487168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
488168404Spjd * libzfs.
489168404Spjd */
490168404Spjdint
491168404Spjdzpool_do_add(int argc, char **argv)
492168404Spjd{
493168404Spjd	boolean_t force = B_FALSE;
494168404Spjd	boolean_t dryrun = B_FALSE;
495168404Spjd	int c;
496168404Spjd	nvlist_t *nvroot;
497168404Spjd	char *poolname;
498168404Spjd	int ret;
499168404Spjd	zpool_handle_t *zhp;
500168404Spjd	nvlist_t *config;
501168404Spjd
502168404Spjd	/* check options */
503168404Spjd	while ((c = getopt(argc, argv, "fn")) != -1) {
504168404Spjd		switch (c) {
505168404Spjd		case 'f':
506168404Spjd			force = B_TRUE;
507168404Spjd			break;
508168404Spjd		case 'n':
509168404Spjd			dryrun = B_TRUE;
510168404Spjd			break;
511168404Spjd		case '?':
512168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
513168404Spjd			    optopt);
514168404Spjd			usage(B_FALSE);
515168404Spjd		}
516168404Spjd	}
517168404Spjd
518168404Spjd	argc -= optind;
519168404Spjd	argv += optind;
520168404Spjd
521168404Spjd	/* get pool name and check number of arguments */
522168404Spjd	if (argc < 1) {
523168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
524168404Spjd		usage(B_FALSE);
525168404Spjd	}
526168404Spjd	if (argc < 2) {
527168404Spjd		(void) fprintf(stderr, gettext("missing vdev specification\n"));
528168404Spjd		usage(B_FALSE);
529168404Spjd	}
530168404Spjd
531168404Spjd	poolname = argv[0];
532168404Spjd
533168404Spjd	argc--;
534168404Spjd	argv++;
535168404Spjd
536168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
537168404Spjd		return (1);
538168404Spjd
539168404Spjd	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
540168404Spjd		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
541168404Spjd		    poolname);
542168404Spjd		zpool_close(zhp);
543168404Spjd		return (1);
544168404Spjd	}
545168404Spjd
546168404Spjd	/* pass off to get_vdev_spec for processing */
547185029Spjd	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
548185029Spjd	    argc, argv);
549168404Spjd	if (nvroot == NULL) {
550168404Spjd		zpool_close(zhp);
551168404Spjd		return (1);
552168404Spjd	}
553168404Spjd
554168404Spjd	if (dryrun) {
555168404Spjd		nvlist_t *poolnvroot;
556168404Spjd
557168404Spjd		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
558168404Spjd		    &poolnvroot) == 0);
559168404Spjd
560168404Spjd		(void) printf(gettext("would update '%s' to the following "
561168404Spjd		    "configuration:\n"), zpool_get_name(zhp));
562168404Spjd
563185029Spjd		/* print original main pool and new tree */
564185029Spjd		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
565185029Spjd		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
566168404Spjd
567185029Spjd		/* Do the same for the logs */
568185029Spjd		if (num_logs(poolnvroot) > 0) {
569185029Spjd			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
570185029Spjd			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
571185029Spjd		} else if (num_logs(nvroot) > 0) {
572185029Spjd			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
573185029Spjd		}
574185029Spjd
575168404Spjd		ret = 0;
576168404Spjd	} else {
577168404Spjd		ret = (zpool_add(zhp, nvroot) != 0);
578168404Spjd	}
579168404Spjd
580168404Spjd	nvlist_free(nvroot);
581168404Spjd	zpool_close(zhp);
582168404Spjd
583168404Spjd	return (ret);
584168404Spjd}
585168404Spjd
586168404Spjd/*
587219089Spjd * zpool remove  <pool> <vdev> ...
588168404Spjd *
589219089Spjd * Removes the given vdev from the pool.  Currently, this supports removing
590219089Spjd * spares, cache, and log devices from the pool.
591168404Spjd */
592168404Spjdint
593168404Spjdzpool_do_remove(int argc, char **argv)
594168404Spjd{
595168404Spjd	char *poolname;
596185029Spjd	int i, ret = 0;
597168404Spjd	zpool_handle_t *zhp;
598168404Spjd
599168404Spjd	argc--;
600168404Spjd	argv++;
601168404Spjd
602168404Spjd	/* get pool name and check number of arguments */
603168404Spjd	if (argc < 1) {
604168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
605168404Spjd		usage(B_FALSE);
606168404Spjd	}
607168404Spjd	if (argc < 2) {
608168404Spjd		(void) fprintf(stderr, gettext("missing device\n"));
609168404Spjd		usage(B_FALSE);
610168404Spjd	}
611168404Spjd
612168404Spjd	poolname = argv[0];
613168404Spjd
614168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
615168404Spjd		return (1);
616168404Spjd
617185029Spjd	for (i = 1; i < argc; i++) {
618185029Spjd		if (zpool_vdev_remove(zhp, argv[i]) != 0)
619185029Spjd			ret = 1;
620168404Spjd	}
621168404Spjd
622168404Spjd	return (ret);
623168404Spjd}
624168404Spjd
625168404Spjd/*
626224171Sgibbs * zpool labelclear <vdev>
627224171Sgibbs *
628224171Sgibbs * Verifies that the vdev is not active and zeros out the label information
629224171Sgibbs * on the device.
630224171Sgibbs */
631224171Sgibbsint
632224171Sgibbszpool_do_labelclear(int argc, char **argv)
633224171Sgibbs{
634224171Sgibbs	char *vdev, *name;
635224171Sgibbs	int c, fd = -1, ret = 0;
636224171Sgibbs	pool_state_t state;
637224171Sgibbs	boolean_t inuse = B_FALSE;
638224171Sgibbs	boolean_t force = B_FALSE;
639224171Sgibbs
640224171Sgibbs	/* check options */
641224171Sgibbs	while ((c = getopt(argc, argv, "f")) != -1) {
642224171Sgibbs		switch (c) {
643224171Sgibbs		case 'f':
644224171Sgibbs			force = B_TRUE;
645224171Sgibbs			break;
646224171Sgibbs		default:
647224171Sgibbs			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
648224171Sgibbs			    optopt);
649224171Sgibbs			usage(B_FALSE);
650224171Sgibbs		}
651224171Sgibbs	}
652224171Sgibbs
653224171Sgibbs	argc -= optind;
654224171Sgibbs	argv += optind;
655224171Sgibbs
656224171Sgibbs	/* get vdev name */
657224171Sgibbs	if (argc < 1) {
658224171Sgibbs		(void) fprintf(stderr, gettext("missing vdev device name\n"));
659224171Sgibbs		usage(B_FALSE);
660224171Sgibbs	}
661224171Sgibbs
662224171Sgibbs	vdev = argv[0];
663224171Sgibbs	if ((fd = open(vdev, O_RDWR)) < 0) {
664224171Sgibbs		(void) fprintf(stderr, gettext("Unable to open %s\n"), vdev);
665224171Sgibbs		return (B_FALSE);
666224171Sgibbs	}
667224171Sgibbs
668224171Sgibbs	name = NULL;
669224171Sgibbs	if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0) {
670224171Sgibbs		if (force)
671224171Sgibbs			goto wipe_label;
672224171Sgibbs
673224171Sgibbs		(void) fprintf(stderr,
674224171Sgibbs		    gettext("Unable to determine pool state for %s\n"
675224171Sgibbs		    "Use -f to force the clearing any label data\n"), vdev);
676224171Sgibbs
677224171Sgibbs		return (1);
678224171Sgibbs	}
679224171Sgibbs
680224171Sgibbs	if (inuse) {
681224171Sgibbs		switch (state) {
682224171Sgibbs		default:
683224171Sgibbs		case POOL_STATE_ACTIVE:
684224171Sgibbs		case POOL_STATE_SPARE:
685224171Sgibbs		case POOL_STATE_L2CACHE:
686224171Sgibbs			(void) fprintf(stderr,
687224171Sgibbsgettext("labelclear operation failed.\n"
688224171Sgibbs	"\tVdev %s is a member (%s), of pool \"%s\".\n"
689224171Sgibbs	"\tTo remove label information from this device, export or destroy\n"
690224171Sgibbs	"\tthe pool, or remove %s from the configuration of this pool\n"
691224171Sgibbs	"\tand retry the labelclear operation\n"),
692224171Sgibbs			    vdev, zpool_pool_state_to_name(state), name, vdev);
693224171Sgibbs			ret = 1;
694224171Sgibbs			goto errout;
695224171Sgibbs
696224171Sgibbs		case POOL_STATE_EXPORTED:
697224171Sgibbs			if (force)
698224171Sgibbs				break;
699224171Sgibbs
700224171Sgibbs			(void) fprintf(stderr,
701224171Sgibbsgettext("labelclear operation failed.\n"
702224171Sgibbs	"\tVdev %s is a member of the exported pool \"%s\".\n"
703224171Sgibbs	"\tUse \"zpool labelclear -f %s\" to force the removal of label\n"
704224171Sgibbs	"\tinformation.\n"),
705224171Sgibbs			    vdev, name, vdev);
706224171Sgibbs			ret = 1;
707224171Sgibbs			goto errout;
708224171Sgibbs
709224171Sgibbs		case POOL_STATE_POTENTIALLY_ACTIVE:
710224171Sgibbs			if (force)
711224171Sgibbs				break;
712224171Sgibbs
713224171Sgibbs			(void) fprintf(stderr,
714224171Sgibbsgettext("labelclear operation failed.\n"
715224171Sgibbs	"\tVdev %s is a member of the pool \"%s\".\n"
716224171Sgibbs	"\tThis pool is unknown to this system, but may be active on\n"
717224171Sgibbs	"\tanother system. Use \'zpool labelclear -f %s\' to force the\n"
718224171Sgibbs	"\tremoval of label information.\n"),
719224171Sgibbs			    vdev, name, vdev);
720224171Sgibbs			ret = 1;
721224171Sgibbs			goto errout;
722224171Sgibbs
723224171Sgibbs		case POOL_STATE_DESTROYED:
724224171Sgibbs			/* inuse should never be set for a destoryed pool... */
725224171Sgibbs			break;
726224171Sgibbs		}
727224171Sgibbs	}
728224171Sgibbs
729224171Sgibbswipe_label:
730224171Sgibbs	if (zpool_clear_label(fd) != 0) {
731224171Sgibbs		(void) fprintf(stderr,
732224171Sgibbs		    gettext("Label clear failed on vdev %s\n"), vdev);
733224171Sgibbs		ret = 1;
734224171Sgibbs	}
735224171Sgibbs
736224171Sgibbserrout:
737224171Sgibbs	close(fd);
738224171Sgibbs	if (name != NULL)
739224171Sgibbs		free(name);
740224171Sgibbs
741224171Sgibbs	return (ret);
742224171Sgibbs}
743224171Sgibbs
744224171Sgibbs/*
745236884Smm * zpool create [-fnd] [-o property=value] ...
746185029Spjd *		[-O file-system-property=value] ...
747185029Spjd *		[-R root] [-m mountpoint] <pool> <dev> ...
748168404Spjd *
749168404Spjd *	-f	Force creation, even if devices appear in use
750168404Spjd *	-n	Do not create the pool, but display the resulting layout if it
751168404Spjd *		were to be created.
752168404Spjd *      -R	Create a pool under an alternate root
753168404Spjd *      -m	Set default mountpoint for the root dataset.  By default it's
754236884Smm *		'/<pool>'
755185029Spjd *	-o	Set property=value.
756236884Smm *	-d	Don't automatically enable all supported pool features
757236884Smm *		(individual features can be enabled with -o).
758185029Spjd *	-O	Set fsproperty=value in the pool's root file system
759168404Spjd *
760168404Spjd * Creates the named pool according to the given vdev specification.  The
761168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
762168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents
763168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation.
764168404Spjd */
765168404Spjdint
766168404Spjdzpool_do_create(int argc, char **argv)
767168404Spjd{
768168404Spjd	boolean_t force = B_FALSE;
769168404Spjd	boolean_t dryrun = B_FALSE;
770236884Smm	boolean_t enable_all_pool_feat = B_TRUE;
771168404Spjd	int c;
772185029Spjd	nvlist_t *nvroot = NULL;
773168404Spjd	char *poolname;
774185029Spjd	int ret = 1;
775168404Spjd	char *altroot = NULL;
776168404Spjd	char *mountpoint = NULL;
777185029Spjd	nvlist_t *fsprops = NULL;
778185029Spjd	nvlist_t *props = NULL;
779185029Spjd	char *propval;
780168404Spjd
781168404Spjd	/* check options */
782236884Smm	while ((c = getopt(argc, argv, ":fndR:m:o:O:")) != -1) {
783168404Spjd		switch (c) {
784168404Spjd		case 'f':
785168404Spjd			force = B_TRUE;
786168404Spjd			break;
787168404Spjd		case 'n':
788168404Spjd			dryrun = B_TRUE;
789168404Spjd			break;
790236884Smm		case 'd':
791236884Smm			enable_all_pool_feat = B_FALSE;
792236884Smm			break;
793168404Spjd		case 'R':
794168404Spjd			altroot = optarg;
795185029Spjd			if (add_prop_list(zpool_prop_to_name(
796185029Spjd			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
797185029Spjd				goto errout;
798185029Spjd			if (nvlist_lookup_string(props,
799185029Spjd			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
800185029Spjd			    &propval) == 0)
801185029Spjd				break;
802185029Spjd			if (add_prop_list(zpool_prop_to_name(
803185029Spjd			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
804185029Spjd				goto errout;
805168404Spjd			break;
806168404Spjd		case 'm':
807168404Spjd			mountpoint = optarg;
808168404Spjd			break;
809185029Spjd		case 'o':
810185029Spjd			if ((propval = strchr(optarg, '=')) == NULL) {
811185029Spjd				(void) fprintf(stderr, gettext("missing "
812185029Spjd				    "'=' for -o option\n"));
813185029Spjd				goto errout;
814185029Spjd			}
815185029Spjd			*propval = '\0';
816185029Spjd			propval++;
817185029Spjd
818185029Spjd			if (add_prop_list(optarg, propval, &props, B_TRUE))
819185029Spjd				goto errout;
820236884Smm
821236884Smm			/*
822236884Smm			 * If the user is creating a pool that doesn't support
823236884Smm			 * feature flags, don't enable any features.
824236884Smm			 */
825236884Smm			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) {
826236884Smm				char *end;
827236884Smm				u_longlong_t ver;
828236884Smm
829236884Smm				ver = strtoull(propval, &end, 10);
830236884Smm				if (*end == '\0' &&
831236884Smm				    ver < SPA_VERSION_FEATURES) {
832236884Smm					enable_all_pool_feat = B_FALSE;
833236884Smm				}
834236884Smm			}
835185029Spjd			break;
836185029Spjd		case 'O':
837185029Spjd			if ((propval = strchr(optarg, '=')) == NULL) {
838185029Spjd				(void) fprintf(stderr, gettext("missing "
839185029Spjd				    "'=' for -O option\n"));
840185029Spjd				goto errout;
841185029Spjd			}
842185029Spjd			*propval = '\0';
843185029Spjd			propval++;
844185029Spjd
845185029Spjd			if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
846185029Spjd				goto errout;
847185029Spjd			break;
848168404Spjd		case ':':
849168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
850168404Spjd			    "'%c' option\n"), optopt);
851185029Spjd			goto badusage;
852168404Spjd		case '?':
853168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
854168404Spjd			    optopt);
855185029Spjd			goto badusage;
856168404Spjd		}
857168404Spjd	}
858168404Spjd
859168404Spjd	argc -= optind;
860168404Spjd	argv += optind;
861168404Spjd
862168404Spjd	/* get pool name and check number of arguments */
863168404Spjd	if (argc < 1) {
864168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
865185029Spjd		goto badusage;
866168404Spjd	}
867168404Spjd	if (argc < 2) {
868168404Spjd		(void) fprintf(stderr, gettext("missing vdev specification\n"));
869185029Spjd		goto badusage;
870168404Spjd	}
871168404Spjd
872168404Spjd	poolname = argv[0];
873168404Spjd
874168404Spjd	/*
875168404Spjd	 * As a special case, check for use of '/' in the name, and direct the
876168404Spjd	 * user to use 'zfs create' instead.
877168404Spjd	 */
878168404Spjd	if (strchr(poolname, '/') != NULL) {
879168404Spjd		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
880168404Spjd		    "character '/' in pool name\n"), poolname);
881168404Spjd		(void) fprintf(stderr, gettext("use 'zfs create' to "
882168404Spjd		    "create a dataset\n"));
883185029Spjd		goto errout;
884168404Spjd	}
885168404Spjd
886168404Spjd	/* pass off to get_vdev_spec for bulk processing */
887185029Spjd	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
888185029Spjd	    argc - 1, argv + 1);
889168404Spjd	if (nvroot == NULL)
890185029Spjd		goto errout;
891168404Spjd
892168404Spjd	/* make_root_vdev() allows 0 toplevel children if there are spares */
893185029Spjd	if (!zfs_allocatable_devs(nvroot)) {
894168404Spjd		(void) fprintf(stderr, gettext("invalid vdev "
895168404Spjd		    "specification: at least one toplevel vdev must be "
896168404Spjd		    "specified\n"));
897185029Spjd		goto errout;
898168404Spjd	}
899168404Spjd
900168404Spjd	if (altroot != NULL && altroot[0] != '/') {
901168404Spjd		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
902168404Spjd		    "must be an absolute path\n"), altroot);
903185029Spjd		goto errout;
904168404Spjd	}
905168404Spjd
906168404Spjd	/*
907168404Spjd	 * Check the validity of the mountpoint and direct the user to use the
908168404Spjd	 * '-m' mountpoint option if it looks like its in use.
909168404Spjd	 */
910168404Spjd	if (mountpoint == NULL ||
911168404Spjd	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
912168404Spjd	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
913168404Spjd		char buf[MAXPATHLEN];
914185029Spjd		DIR *dirp;
915168404Spjd
916168404Spjd		if (mountpoint && mountpoint[0] != '/') {
917168404Spjd			(void) fprintf(stderr, gettext("invalid mountpoint "
918168404Spjd			    "'%s': must be an absolute path, 'legacy', or "
919168404Spjd			    "'none'\n"), mountpoint);
920185029Spjd			goto errout;
921168404Spjd		}
922168404Spjd
923168404Spjd		if (mountpoint == NULL) {
924168404Spjd			if (altroot != NULL)
925168404Spjd				(void) snprintf(buf, sizeof (buf), "%s/%s",
926168404Spjd				    altroot, poolname);
927168404Spjd			else
928168404Spjd				(void) snprintf(buf, sizeof (buf), "/%s",
929168404Spjd				    poolname);
930168404Spjd		} else {
931168404Spjd			if (altroot != NULL)
932168404Spjd				(void) snprintf(buf, sizeof (buf), "%s%s",
933168404Spjd				    altroot, mountpoint);
934168404Spjd			else
935168404Spjd				(void) snprintf(buf, sizeof (buf), "%s",
936168404Spjd				    mountpoint);
937168404Spjd		}
938168404Spjd
939185029Spjd		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
940185029Spjd			(void) fprintf(stderr, gettext("mountpoint '%s' : "
941185029Spjd			    "%s\n"), buf, strerror(errno));
942185029Spjd			(void) fprintf(stderr, gettext("use '-m' "
943185029Spjd			    "option to provide a different default\n"));
944185029Spjd			goto errout;
945185029Spjd		} else if (dirp) {
946185029Spjd			int count = 0;
947185029Spjd
948185029Spjd			while (count < 3 && readdir(dirp) != NULL)
949185029Spjd				count++;
950185029Spjd			(void) closedir(dirp);
951185029Spjd
952185029Spjd			if (count > 2) {
953168404Spjd				(void) fprintf(stderr, gettext("mountpoint "
954168404Spjd				    "'%s' exists and is not empty\n"), buf);
955185029Spjd				(void) fprintf(stderr, gettext("use '-m' "
956185029Spjd				    "option to provide a "
957185029Spjd				    "different default\n"));
958185029Spjd				goto errout;
959185029Spjd			}
960168404Spjd		}
961168404Spjd	}
962168404Spjd
963168404Spjd	if (dryrun) {
964168404Spjd		/*
965168404Spjd		 * For a dry run invocation, print out a basic message and run
966168404Spjd		 * through all the vdevs in the list and print out in an
967168404Spjd		 * appropriate hierarchy.
968168404Spjd		 */
969168404Spjd		(void) printf(gettext("would create '%s' with the "
970168404Spjd		    "following layout:\n\n"), poolname);
971168404Spjd
972185029Spjd		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
973185029Spjd		if (num_logs(nvroot) > 0)
974185029Spjd			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
975168404Spjd
976168404Spjd		ret = 0;
977168404Spjd	} else {
978168404Spjd		/*
979168404Spjd		 * Hand off to libzfs.
980168404Spjd		 */
981236884Smm		if (enable_all_pool_feat) {
982236884Smm			int i;
983236884Smm			for (i = 0; i < SPA_FEATURES; i++) {
984236884Smm				char propname[MAXPATHLEN];
985236884Smm				zfeature_info_t *feat = &spa_feature_table[i];
986236884Smm
987236884Smm				(void) snprintf(propname, sizeof (propname),
988236884Smm				    "feature@%s", feat->fi_uname);
989236884Smm
990236884Smm				/*
991236884Smm				 * Skip feature if user specified it manually
992236884Smm				 * on the command line.
993236884Smm				 */
994236884Smm				if (nvlist_exists(props, propname))
995236884Smm					continue;
996236884Smm
997236884Smm				if (add_prop_list(propname, ZFS_FEATURE_ENABLED,
998236884Smm				    &props, B_TRUE) != 0)
999236884Smm					goto errout;
1000236884Smm			}
1001236884Smm		}
1002185029Spjd		if (zpool_create(g_zfs, poolname,
1003185029Spjd		    nvroot, props, fsprops) == 0) {
1004168404Spjd			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
1005168404Spjd			    ZFS_TYPE_FILESYSTEM);
1006168404Spjd			if (pool != NULL) {
1007168404Spjd				if (mountpoint != NULL)
1008168404Spjd					verify(zfs_prop_set(pool,
1009168404Spjd					    zfs_prop_to_name(
1010168404Spjd					    ZFS_PROP_MOUNTPOINT),
1011168404Spjd					    mountpoint) == 0);
1012168404Spjd				if (zfs_mount(pool, NULL, 0) == 0)
1013185029Spjd					ret = zfs_shareall(pool);
1014168404Spjd				zfs_close(pool);
1015168404Spjd			}
1016168404Spjd		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
1017168404Spjd			(void) fprintf(stderr, gettext("pool name may have "
1018168404Spjd			    "been omitted\n"));
1019168404Spjd		}
1020168404Spjd	}
1021168404Spjd
1022185029Spjderrout:
1023168404Spjd	nvlist_free(nvroot);
1024185029Spjd	nvlist_free(fsprops);
1025185029Spjd	nvlist_free(props);
1026168404Spjd	return (ret);
1027185029Spjdbadusage:
1028185029Spjd	nvlist_free(fsprops);
1029185029Spjd	nvlist_free(props);
1030185029Spjd	usage(B_FALSE);
1031185029Spjd	return (2);
1032168404Spjd}
1033168404Spjd
1034168404Spjd/*
1035168404Spjd * zpool destroy <pool>
1036168404Spjd *
1037168404Spjd * 	-f	Forcefully unmount any datasets
1038168404Spjd *
1039168404Spjd * Destroy the given pool.  Automatically unmounts any datasets in the pool.
1040168404Spjd */
1041168404Spjdint
1042168404Spjdzpool_do_destroy(int argc, char **argv)
1043168404Spjd{
1044168404Spjd	boolean_t force = B_FALSE;
1045168404Spjd	int c;
1046168404Spjd	char *pool;
1047168404Spjd	zpool_handle_t *zhp;
1048168404Spjd	int ret;
1049168404Spjd
1050168404Spjd	/* check options */
1051168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
1052168404Spjd		switch (c) {
1053168404Spjd		case 'f':
1054168404Spjd			force = B_TRUE;
1055168404Spjd			break;
1056168404Spjd		case '?':
1057168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1058168404Spjd			    optopt);
1059168404Spjd			usage(B_FALSE);
1060168404Spjd		}
1061168404Spjd	}
1062168404Spjd
1063168404Spjd	argc -= optind;
1064168404Spjd	argv += optind;
1065168404Spjd
1066168404Spjd	/* check arguments */
1067168404Spjd	if (argc < 1) {
1068168404Spjd		(void) fprintf(stderr, gettext("missing pool argument\n"));
1069168404Spjd		usage(B_FALSE);
1070168404Spjd	}
1071168404Spjd	if (argc > 1) {
1072168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
1073168404Spjd		usage(B_FALSE);
1074168404Spjd	}
1075168404Spjd
1076168404Spjd	pool = argv[0];
1077168404Spjd
1078168404Spjd	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
1079168404Spjd		/*
1080168404Spjd		 * As a special case, check for use of '/' in the name, and
1081168404Spjd		 * direct the user to use 'zfs destroy' instead.
1082168404Spjd		 */
1083168404Spjd		if (strchr(pool, '/') != NULL)
1084168404Spjd			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
1085168404Spjd			    "destroy a dataset\n"));
1086168404Spjd		return (1);
1087168404Spjd	}
1088168404Spjd
1089168404Spjd	if (zpool_disable_datasets(zhp, force) != 0) {
1090168404Spjd		(void) fprintf(stderr, gettext("could not destroy '%s': "
1091168404Spjd		    "could not unmount datasets\n"), zpool_get_name(zhp));
1092168404Spjd		return (1);
1093168404Spjd	}
1094168404Spjd
1095168404Spjd	ret = (zpool_destroy(zhp) != 0);
1096168404Spjd
1097168404Spjd	zpool_close(zhp);
1098168404Spjd
1099168404Spjd	return (ret);
1100168404Spjd}
1101168404Spjd
1102168404Spjd/*
1103168404Spjd * zpool export [-f] <pool> ...
1104168404Spjd *
1105168404Spjd *	-f	Forcefully unmount datasets
1106168404Spjd *
1107168404Spjd * Export the given pools.  By default, the command will attempt to cleanly
1108168404Spjd * unmount any active datasets within the pool.  If the '-f' flag is specified,
1109168404Spjd * then the datasets will be forcefully unmounted.
1110168404Spjd */
1111168404Spjdint
1112168404Spjdzpool_do_export(int argc, char **argv)
1113168404Spjd{
1114168404Spjd	boolean_t force = B_FALSE;
1115207670Smm	boolean_t hardforce = B_FALSE;
1116168404Spjd	int c;
1117168404Spjd	zpool_handle_t *zhp;
1118168404Spjd	int ret;
1119168404Spjd	int i;
1120168404Spjd
1121168404Spjd	/* check options */
1122207670Smm	while ((c = getopt(argc, argv, "fF")) != -1) {
1123168404Spjd		switch (c) {
1124168404Spjd		case 'f':
1125168404Spjd			force = B_TRUE;
1126168404Spjd			break;
1127207670Smm		case 'F':
1128207670Smm			hardforce = B_TRUE;
1129207670Smm			break;
1130168404Spjd		case '?':
1131168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1132168404Spjd			    optopt);
1133168404Spjd			usage(B_FALSE);
1134168404Spjd		}
1135168404Spjd	}
1136168404Spjd
1137168404Spjd	argc -= optind;
1138168404Spjd	argv += optind;
1139168404Spjd
1140168404Spjd	/* check arguments */
1141168404Spjd	if (argc < 1) {
1142168404Spjd		(void) fprintf(stderr, gettext("missing pool argument\n"));
1143168404Spjd		usage(B_FALSE);
1144168404Spjd	}
1145168404Spjd
1146168404Spjd	ret = 0;
1147168404Spjd	for (i = 0; i < argc; i++) {
1148168404Spjd		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
1149168404Spjd			ret = 1;
1150168404Spjd			continue;
1151168404Spjd		}
1152168404Spjd
1153168404Spjd		if (zpool_disable_datasets(zhp, force) != 0) {
1154168404Spjd			ret = 1;
1155168404Spjd			zpool_close(zhp);
1156168404Spjd			continue;
1157168404Spjd		}
1158168404Spjd
1159207670Smm		if (hardforce) {
1160207670Smm			if (zpool_export_force(zhp) != 0)
1161207670Smm				ret = 1;
1162207670Smm		} else if (zpool_export(zhp, force) != 0) {
1163168404Spjd			ret = 1;
1164207670Smm		}
1165168404Spjd
1166168404Spjd		zpool_close(zhp);
1167168404Spjd	}
1168168404Spjd
1169168404Spjd	return (ret);
1170168404Spjd}
1171168404Spjd
1172168404Spjd/*
1173168404Spjd * Given a vdev configuration, determine the maximum width needed for the device
1174168404Spjd * name column.
1175168404Spjd */
1176168404Spjdstatic int
1177168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
1178168404Spjd{
1179219089Spjd	char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
1180168404Spjd	nvlist_t **child;
1181168404Spjd	uint_t c, children;
1182168404Spjd	int ret;
1183168404Spjd
1184168404Spjd	if (strlen(name) + depth > max)
1185168404Spjd		max = strlen(name) + depth;
1186168404Spjd
1187168404Spjd	free(name);
1188168404Spjd
1189168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1190168404Spjd	    &child, &children) == 0) {
1191168404Spjd		for (c = 0; c < children; c++)
1192168404Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
1193168404Spjd			    max)) > max)
1194168404Spjd				max = ret;
1195168404Spjd	}
1196168404Spjd
1197185029Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1198185029Spjd	    &child, &children) == 0) {
1199185029Spjd		for (c = 0; c < children; c++)
1200185029Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
1201185029Spjd			    max)) > max)
1202185029Spjd				max = ret;
1203185029Spjd	}
1204185029Spjd
1205168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1206168404Spjd	    &child, &children) == 0) {
1207168404Spjd		for (c = 0; c < children; c++)
1208168404Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
1209168404Spjd			    max)) > max)
1210168404Spjd				max = ret;
1211168404Spjd	}
1212168404Spjd
1213168404Spjd
1214168404Spjd	return (max);
1215168404Spjd}
1216168404Spjd
1217213197Smmtypedef struct spare_cbdata {
1218213197Smm	uint64_t	cb_guid;
1219213197Smm	zpool_handle_t	*cb_zhp;
1220213197Smm} spare_cbdata_t;
1221168404Spjd
1222213197Smmstatic boolean_t
1223213197Smmfind_vdev(nvlist_t *nv, uint64_t search)
1224213197Smm{
1225213197Smm	uint64_t guid;
1226213197Smm	nvlist_t **child;
1227213197Smm	uint_t c, children;
1228213197Smm
1229213197Smm	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
1230213197Smm	    search == guid)
1231213197Smm		return (B_TRUE);
1232213197Smm
1233213197Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1234213197Smm	    &child, &children) == 0) {
1235213197Smm		for (c = 0; c < children; c++)
1236213197Smm			if (find_vdev(child[c], search))
1237213197Smm				return (B_TRUE);
1238213197Smm	}
1239213197Smm
1240213197Smm	return (B_FALSE);
1241213197Smm}
1242213197Smm
1243213197Smmstatic int
1244213197Smmfind_spare(zpool_handle_t *zhp, void *data)
1245213197Smm{
1246213197Smm	spare_cbdata_t *cbp = data;
1247213197Smm	nvlist_t *config, *nvroot;
1248213197Smm
1249213197Smm	config = zpool_get_config(zhp, NULL);
1250213197Smm	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1251213197Smm	    &nvroot) == 0);
1252213197Smm
1253213197Smm	if (find_vdev(nvroot, cbp->cb_guid)) {
1254213197Smm		cbp->cb_zhp = zhp;
1255213197Smm		return (1);
1256213197Smm	}
1257213197Smm
1258213197Smm	zpool_close(zhp);
1259213197Smm	return (0);
1260213197Smm}
1261213197Smm
1262168404Spjd/*
1263213197Smm * Print out configuration state as requested by status_callback.
1264213197Smm */
1265213197Smmvoid
1266213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
1267213197Smm    int namewidth, int depth, boolean_t isspare)
1268213197Smm{
1269213197Smm	nvlist_t **child;
1270213197Smm	uint_t c, children;
1271219089Spjd	pool_scan_stat_t *ps = NULL;
1272213197Smm	vdev_stat_t *vs;
1273219089Spjd	char rbuf[6], wbuf[6], cbuf[6];
1274213197Smm	char *vname;
1275213197Smm	uint64_t notpresent;
1276213197Smm	spare_cbdata_t cb;
1277224169Sgibbs	const char *state;
1278213197Smm
1279213197Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1280213197Smm	    &child, &children) != 0)
1281213197Smm		children = 0;
1282213197Smm
1283219089Spjd	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1284219089Spjd	    (uint64_t **)&vs, &c) == 0);
1285219089Spjd
1286213197Smm	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1287213197Smm	if (isspare) {
1288213197Smm		/*
1289213197Smm		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
1290213197Smm		 * online drives.
1291213197Smm		 */
1292213197Smm		if (vs->vs_aux == VDEV_AUX_SPARED)
1293213197Smm			state = "INUSE";
1294213197Smm		else if (vs->vs_state == VDEV_STATE_HEALTHY)
1295213197Smm			state = "AVAIL";
1296213197Smm	}
1297213197Smm
1298213197Smm	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
1299213197Smm	    name, state);
1300213197Smm
1301213197Smm	if (!isspare) {
1302213197Smm		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
1303213197Smm		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
1304213197Smm		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
1305213197Smm		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
1306213197Smm	}
1307213197Smm
1308213197Smm	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1309224170Sgibbs	    &notpresent) == 0 ||
1310224170Sgibbs	    vs->vs_state <= VDEV_STATE_CANT_OPEN) {
1311213197Smm		char *path;
1312224170Sgibbs		if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0)
1313224170Sgibbs			(void) printf("  was %s", path);
1314213197Smm	} else if (vs->vs_aux != 0) {
1315213197Smm		(void) printf("  ");
1316213197Smm
1317213197Smm		switch (vs->vs_aux) {
1318213197Smm		case VDEV_AUX_OPEN_FAILED:
1319213197Smm			(void) printf(gettext("cannot open"));
1320213197Smm			break;
1321213197Smm
1322213197Smm		case VDEV_AUX_BAD_GUID_SUM:
1323213197Smm			(void) printf(gettext("missing device"));
1324213197Smm			break;
1325213197Smm
1326213197Smm		case VDEV_AUX_NO_REPLICAS:
1327213197Smm			(void) printf(gettext("insufficient replicas"));
1328213197Smm			break;
1329213197Smm
1330213197Smm		case VDEV_AUX_VERSION_NEWER:
1331213197Smm			(void) printf(gettext("newer version"));
1332213197Smm			break;
1333213197Smm
1334236884Smm		case VDEV_AUX_UNSUP_FEAT:
1335236884Smm			(void) printf(gettext("unsupported feature(s)"));
1336236884Smm			break;
1337236884Smm
1338213197Smm		case VDEV_AUX_SPARED:
1339213197Smm			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1340213197Smm			    &cb.cb_guid) == 0);
1341213197Smm			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
1342213197Smm				if (strcmp(zpool_get_name(cb.cb_zhp),
1343213197Smm				    zpool_get_name(zhp)) == 0)
1344213197Smm					(void) printf(gettext("currently in "
1345213197Smm					    "use"));
1346213197Smm				else
1347213197Smm					(void) printf(gettext("in use by "
1348213197Smm					    "pool '%s'"),
1349213197Smm					    zpool_get_name(cb.cb_zhp));
1350213197Smm				zpool_close(cb.cb_zhp);
1351213197Smm			} else {
1352213197Smm				(void) printf(gettext("currently in use"));
1353213197Smm			}
1354213197Smm			break;
1355213197Smm
1356213197Smm		case VDEV_AUX_ERR_EXCEEDED:
1357213197Smm			(void) printf(gettext("too many errors"));
1358213197Smm			break;
1359213197Smm
1360213197Smm		case VDEV_AUX_IO_FAILURE:
1361213197Smm			(void) printf(gettext("experienced I/O failures"));
1362213197Smm			break;
1363213197Smm
1364213197Smm		case VDEV_AUX_BAD_LOG:
1365213197Smm			(void) printf(gettext("bad intent log"));
1366213197Smm			break;
1367213197Smm
1368219089Spjd		case VDEV_AUX_EXTERNAL:
1369219089Spjd			(void) printf(gettext("external device fault"));
1370219089Spjd			break;
1371219089Spjd
1372219089Spjd		case VDEV_AUX_SPLIT_POOL:
1373219089Spjd			(void) printf(gettext("split into new pool"));
1374219089Spjd			break;
1375219089Spjd
1376213197Smm		default:
1377213197Smm			(void) printf(gettext("corrupted data"));
1378213197Smm			break;
1379213197Smm		}
1380213197Smm	}
1381213197Smm
1382219089Spjd	(void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS,
1383219089Spjd	    (uint64_t **)&ps, &c);
1384219089Spjd
1385219089Spjd	if (ps && ps->pss_state == DSS_SCANNING &&
1386219089Spjd	    vs->vs_scan_processed != 0 && children == 0) {
1387219089Spjd		(void) printf(gettext("  (%s)"),
1388219089Spjd		    (ps->pss_func == POOL_SCAN_RESILVER) ?
1389219089Spjd		    "resilvering" : "repairing");
1390219089Spjd	}
1391219089Spjd
1392213197Smm	(void) printf("\n");
1393213197Smm
1394213197Smm	for (c = 0; c < children; c++) {
1395219089Spjd		uint64_t islog = B_FALSE, ishole = B_FALSE;
1396213197Smm
1397219089Spjd		/* Don't print logs or holes here */
1398213197Smm		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1399219089Spjd		    &islog);
1400219089Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
1401219089Spjd		    &ishole);
1402219089Spjd		if (islog || ishole)
1403213197Smm			continue;
1404219089Spjd		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1405213197Smm		print_status_config(zhp, vname, child[c],
1406213197Smm		    namewidth, depth + 2, isspare);
1407213197Smm		free(vname);
1408213197Smm	}
1409213197Smm}
1410213197Smm
1411213197Smm
1412213197Smm/*
1413168404Spjd * Print the configuration of an exported pool.  Iterate over all vdevs in the
1414168404Spjd * pool, printing out the name and status for each one.
1415168404Spjd */
1416168404Spjdvoid
1417213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
1418168404Spjd{
1419168404Spjd	nvlist_t **child;
1420168404Spjd	uint_t c, children;
1421168404Spjd	vdev_stat_t *vs;
1422168404Spjd	char *type, *vname;
1423168404Spjd
1424168404Spjd	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
1425219089Spjd	if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
1426219089Spjd	    strcmp(type, VDEV_TYPE_HOLE) == 0)
1427168404Spjd		return;
1428168404Spjd
1429219089Spjd	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1430168404Spjd	    (uint64_t **)&vs, &c) == 0);
1431168404Spjd
1432168404Spjd	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
1433185029Spjd	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1434168404Spjd
1435168404Spjd	if (vs->vs_aux != 0) {
1436185029Spjd		(void) printf("  ");
1437168404Spjd
1438168404Spjd		switch (vs->vs_aux) {
1439168404Spjd		case VDEV_AUX_OPEN_FAILED:
1440168404Spjd			(void) printf(gettext("cannot open"));
1441168404Spjd			break;
1442168404Spjd
1443168404Spjd		case VDEV_AUX_BAD_GUID_SUM:
1444168404Spjd			(void) printf(gettext("missing device"));
1445168404Spjd			break;
1446168404Spjd
1447168404Spjd		case VDEV_AUX_NO_REPLICAS:
1448168404Spjd			(void) printf(gettext("insufficient replicas"));
1449168404Spjd			break;
1450168404Spjd
1451168404Spjd		case VDEV_AUX_VERSION_NEWER:
1452168404Spjd			(void) printf(gettext("newer version"));
1453168404Spjd			break;
1454168404Spjd
1455236884Smm		case VDEV_AUX_UNSUP_FEAT:
1456236884Smm			(void) printf(gettext("unsupported feature(s)"));
1457236884Smm			break;
1458236884Smm
1459185029Spjd		case VDEV_AUX_ERR_EXCEEDED:
1460185029Spjd			(void) printf(gettext("too many errors"));
1461185029Spjd			break;
1462185029Spjd
1463168404Spjd		default:
1464168404Spjd			(void) printf(gettext("corrupted data"));
1465168404Spjd			break;
1466168404Spjd		}
1467168404Spjd	}
1468168404Spjd	(void) printf("\n");
1469168404Spjd
1470168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1471168404Spjd	    &child, &children) != 0)
1472168404Spjd		return;
1473168404Spjd
1474168404Spjd	for (c = 0; c < children; c++) {
1475185029Spjd		uint64_t is_log = B_FALSE;
1476185029Spjd
1477185029Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1478185029Spjd		    &is_log);
1479213197Smm		if (is_log)
1480185029Spjd			continue;
1481185029Spjd
1482219089Spjd		vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
1483213197Smm		print_import_config(vname, child[c], namewidth, depth + 2);
1484168404Spjd		free(vname);
1485168404Spjd	}
1486168404Spjd
1487185029Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1488185029Spjd	    &child, &children) == 0) {
1489185029Spjd		(void) printf(gettext("\tcache\n"));
1490185029Spjd		for (c = 0; c < children; c++) {
1491219089Spjd			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1492185029Spjd			(void) printf("\t  %s\n", vname);
1493185029Spjd			free(vname);
1494185029Spjd		}
1495185029Spjd	}
1496185029Spjd
1497168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1498185029Spjd	    &child, &children) == 0) {
1499185029Spjd		(void) printf(gettext("\tspares\n"));
1500185029Spjd		for (c = 0; c < children; c++) {
1501219089Spjd			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1502185029Spjd			(void) printf("\t  %s\n", vname);
1503185029Spjd			free(vname);
1504185029Spjd		}
1505168404Spjd	}
1506168404Spjd}
1507168404Spjd
1508168404Spjd/*
1509213197Smm * Print log vdevs.
1510213197Smm * Logs are recorded as top level vdevs in the main pool child array
1511213197Smm * but with "is_log" set to 1. We use either print_status_config() or
1512213197Smm * print_import_config() to print the top level logs then any log
1513213197Smm * children (eg mirrored slogs) are printed recursively - which
1514213197Smm * works because only the top level vdev is marked "is_log"
1515213197Smm */
1516213197Smmstatic void
1517213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
1518213197Smm{
1519213197Smm	uint_t c, children;
1520213197Smm	nvlist_t **child;
1521213197Smm
1522213197Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1523213197Smm	    &children) != 0)
1524213197Smm		return;
1525213197Smm
1526213197Smm	(void) printf(gettext("\tlogs\n"));
1527213197Smm
1528213197Smm	for (c = 0; c < children; c++) {
1529213197Smm		uint64_t is_log = B_FALSE;
1530213197Smm		char *name;
1531213197Smm
1532213197Smm		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1533213197Smm		    &is_log);
1534213197Smm		if (!is_log)
1535213197Smm			continue;
1536219089Spjd		name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1537213197Smm		if (verbose)
1538213197Smm			print_status_config(zhp, name, child[c], namewidth,
1539213197Smm			    2, B_FALSE);
1540213197Smm		else
1541213197Smm			print_import_config(name, child[c], namewidth, 2);
1542213197Smm		free(name);
1543213197Smm	}
1544213197Smm}
1545219089Spjd
1546213197Smm/*
1547168404Spjd * Display the status for the given pool.
1548168404Spjd */
1549168404Spjdstatic void
1550168404Spjdshow_import(nvlist_t *config)
1551168404Spjd{
1552168404Spjd	uint64_t pool_state;
1553168404Spjd	vdev_stat_t *vs;
1554168404Spjd	char *name;
1555168404Spjd	uint64_t guid;
1556168404Spjd	char *msgid;
1557168404Spjd	nvlist_t *nvroot;
1558168404Spjd	int reason;
1559168404Spjd	const char *health;
1560168404Spjd	uint_t vsc;
1561168404Spjd	int namewidth;
1562228103Smm	char *comment;
1563168404Spjd
1564168404Spjd	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1565168404Spjd	    &name) == 0);
1566168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1567168404Spjd	    &guid) == 0);
1568168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1569168404Spjd	    &pool_state) == 0);
1570168404Spjd	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1571168404Spjd	    &nvroot) == 0);
1572168404Spjd
1573219089Spjd	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
1574168404Spjd	    (uint64_t **)&vs, &vsc) == 0);
1575185029Spjd	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1576168404Spjd
1577168404Spjd	reason = zpool_import_status(config, &msgid);
1578168404Spjd
1579228103Smm	(void) printf(gettext("   pool: %s\n"), name);
1580228103Smm	(void) printf(gettext("     id: %llu\n"), (u_longlong_t)guid);
1581228103Smm	(void) printf(gettext("  state: %s"), health);
1582168404Spjd	if (pool_state == POOL_STATE_DESTROYED)
1583168404Spjd		(void) printf(gettext(" (DESTROYED)"));
1584168404Spjd	(void) printf("\n");
1585168404Spjd
1586168404Spjd	switch (reason) {
1587168404Spjd	case ZPOOL_STATUS_MISSING_DEV_R:
1588168404Spjd	case ZPOOL_STATUS_MISSING_DEV_NR:
1589168404Spjd	case ZPOOL_STATUS_BAD_GUID_SUM:
1590228103Smm		(void) printf(gettext(" status: One or more devices are "
1591228103Smm		    "missing from the system.\n"));
1592168404Spjd		break;
1593168404Spjd
1594168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1595168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1596228103Smm		(void) printf(gettext(" status: One or more devices contains "
1597168404Spjd		    "corrupted data.\n"));
1598168404Spjd		break;
1599168404Spjd
1600168404Spjd	case ZPOOL_STATUS_CORRUPT_DATA:
1601228103Smm		(void) printf(
1602228103Smm		    gettext(" status: The pool data is corrupted.\n"));
1603168404Spjd		break;
1604168404Spjd
1605168404Spjd	case ZPOOL_STATUS_OFFLINE_DEV:
1606228103Smm		(void) printf(gettext(" status: One or more devices "
1607168404Spjd		    "are offlined.\n"));
1608168404Spjd		break;
1609168404Spjd
1610168404Spjd	case ZPOOL_STATUS_CORRUPT_POOL:
1611228103Smm		(void) printf(gettext(" status: The pool metadata is "
1612168404Spjd		    "corrupted.\n"));
1613168404Spjd		break;
1614168404Spjd
1615168404Spjd	case ZPOOL_STATUS_VERSION_OLDER:
1616238926Smm		(void) printf(gettext(" status: The pool is formatted using a "
1617238926Smm		    "legacy on-disk version.\n"));
1618168404Spjd		break;
1619168404Spjd
1620168404Spjd	case ZPOOL_STATUS_VERSION_NEWER:
1621228103Smm		(void) printf(gettext(" status: The pool is formatted using an "
1622168404Spjd		    "incompatible version.\n"));
1623168404Spjd		break;
1624168404Spjd
1625238926Smm	case ZPOOL_STATUS_FEAT_DISABLED:
1626238926Smm		(void) printf(gettext(" status: Some supported features are "
1627238926Smm		    "not enabled on the pool.\n"));
1628238926Smm		break;
1629238926Smm
1630236884Smm	case ZPOOL_STATUS_UNSUP_FEAT_READ:
1631236884Smm		(void) printf(gettext("status: The pool uses the following "
1632236884Smm		    "feature(s) not supported on this sytem:\n"));
1633236884Smm		zpool_print_unsup_feat(config);
1634236884Smm		break;
1635236884Smm
1636236884Smm	case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
1637236884Smm		(void) printf(gettext("status: The pool can only be accessed "
1638236884Smm		    "in read-only mode on this system. It\n\tcannot be "
1639236884Smm		    "accessed in read-write mode because it uses the "
1640236884Smm		    "following\n\tfeature(s) not supported on this system:\n"));
1641236884Smm		zpool_print_unsup_feat(config);
1642236884Smm		break;
1643236884Smm
1644168498Spjd	case ZPOOL_STATUS_HOSTID_MISMATCH:
1645228103Smm		(void) printf(gettext(" status: The pool was last accessed by "
1646168498Spjd		    "another system.\n"));
1647168498Spjd		break;
1648185029Spjd
1649185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_R:
1650185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_NR:
1651228103Smm		(void) printf(gettext(" status: One or more devices are "
1652185029Spjd		    "faulted.\n"));
1653185029Spjd		break;
1654185029Spjd
1655185029Spjd	case ZPOOL_STATUS_BAD_LOG:
1656228103Smm		(void) printf(gettext(" status: An intent log record cannot be "
1657185029Spjd		    "read.\n"));
1658185029Spjd		break;
1659185029Spjd
1660219089Spjd	case ZPOOL_STATUS_RESILVERING:
1661228103Smm		(void) printf(gettext(" status: One or more devices were being "
1662219089Spjd		    "resilvered.\n"));
1663219089Spjd		break;
1664219089Spjd
1665168404Spjd	default:
1666168404Spjd		/*
1667168404Spjd		 * No other status can be seen when importing pools.
1668168404Spjd		 */
1669168404Spjd		assert(reason == ZPOOL_STATUS_OK);
1670168404Spjd	}
1671168404Spjd
1672168404Spjd	/*
1673168404Spjd	 * Print out an action according to the overall state of the pool.
1674168404Spjd	 */
1675168404Spjd	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1676238926Smm		if (reason == ZPOOL_STATUS_VERSION_OLDER ||
1677238926Smm		    reason == ZPOOL_STATUS_FEAT_DISABLED) {
1678228103Smm			(void) printf(gettext(" action: The pool can be "
1679168404Spjd			    "imported using its name or numeric identifier, "
1680168404Spjd			    "though\n\tsome features will not be available "
1681168404Spjd			    "without an explicit 'zpool upgrade'.\n"));
1682238926Smm		} else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) {
1683228103Smm			(void) printf(gettext(" action: The pool can be "
1684168498Spjd			    "imported using its name or numeric "
1685168498Spjd			    "identifier and\n\tthe '-f' flag.\n"));
1686238926Smm		} else {
1687228103Smm			(void) printf(gettext(" action: The pool can be "
1688168404Spjd			    "imported using its name or numeric "
1689168404Spjd			    "identifier.\n"));
1690238926Smm		}
1691168404Spjd	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1692228103Smm		(void) printf(gettext(" action: The pool can be imported "
1693168404Spjd		    "despite missing or damaged devices.  The\n\tfault "
1694168404Spjd		    "tolerance of the pool may be compromised if imported.\n"));
1695168404Spjd	} else {
1696168404Spjd		switch (reason) {
1697168404Spjd		case ZPOOL_STATUS_VERSION_NEWER:
1698228103Smm			(void) printf(gettext(" action: The pool cannot be "
1699168404Spjd			    "imported.  Access the pool on a system running "
1700168404Spjd			    "newer\n\tsoftware, or recreate the pool from "
1701168404Spjd			    "backup.\n"));
1702168404Spjd			break;
1703236884Smm		case ZPOOL_STATUS_UNSUP_FEAT_READ:
1704236884Smm			(void) printf(gettext("action: The pool cannot be "
1705236884Smm			    "imported. Access the pool on a system that "
1706236884Smm			    "supports\n\tthe required feature(s), or recreate "
1707236884Smm			    "the pool from backup.\n"));
1708236884Smm			break;
1709236884Smm		case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
1710236884Smm			(void) printf(gettext("action: The pool cannot be "
1711236884Smm			    "imported in read-write mode. Import the pool "
1712236884Smm			    "with\n"
1713236884Smm			    "\t\"-o readonly=on\", access the pool on a system "
1714236884Smm			    "that supports the\n\trequired feature(s), or "
1715236884Smm			    "recreate the pool from backup.\n"));
1716236884Smm			break;
1717168404Spjd		case ZPOOL_STATUS_MISSING_DEV_R:
1718168404Spjd		case ZPOOL_STATUS_MISSING_DEV_NR:
1719168404Spjd		case ZPOOL_STATUS_BAD_GUID_SUM:
1720228103Smm			(void) printf(gettext(" action: The pool cannot be "
1721168404Spjd			    "imported. Attach the missing\n\tdevices and try "
1722168404Spjd			    "again.\n"));
1723168404Spjd			break;
1724168404Spjd		default:
1725228103Smm			(void) printf(gettext(" action: The pool cannot be "
1726168404Spjd			    "imported due to damaged devices or data.\n"));
1727168404Spjd		}
1728168404Spjd	}
1729168404Spjd
1730228103Smm	/* Print the comment attached to the pool. */
1731228103Smm	if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
1732228103Smm		(void) printf(gettext("comment: %s\n"), comment);
1733228103Smm
1734168404Spjd	/*
1735168404Spjd	 * If the state is "closed" or "can't open", and the aux state
1736168404Spjd	 * is "corrupt data":
1737168404Spjd	 */
1738168404Spjd	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
1739168404Spjd	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
1740168404Spjd	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1741168404Spjd		if (pool_state == POOL_STATE_DESTROYED)
1742168404Spjd			(void) printf(gettext("\tThe pool was destroyed, "
1743168404Spjd			    "but can be imported using the '-Df' flags.\n"));
1744168404Spjd		else if (pool_state != POOL_STATE_EXPORTED)
1745168404Spjd			(void) printf(gettext("\tThe pool may be active on "
1746185029Spjd			    "another system, but can be imported using\n\t"
1747168404Spjd			    "the '-f' flag.\n"));
1748168404Spjd	}
1749168404Spjd
1750168404Spjd	if (msgid != NULL)
1751236146Smm		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
1752168404Spjd		    msgid);
1753168404Spjd
1754228103Smm	(void) printf(gettext(" config:\n\n"));
1755168404Spjd
1756168404Spjd	namewidth = max_width(NULL, nvroot, 0, 0);
1757168404Spjd	if (namewidth < 10)
1758168404Spjd		namewidth = 10;
1759168404Spjd
1760213197Smm	print_import_config(name, nvroot, namewidth, 0);
1761213197Smm	if (num_logs(nvroot) > 0)
1762213197Smm		print_logs(NULL, nvroot, namewidth, B_FALSE);
1763185029Spjd
1764168404Spjd	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
1765168404Spjd		(void) printf(gettext("\n\tAdditional devices are known to "
1766168404Spjd		    "be part of this pool, though their\n\texact "
1767168404Spjd		    "configuration cannot be determined.\n"));
1768168404Spjd	}
1769168404Spjd}
1770168404Spjd
1771168404Spjd/*
1772168404Spjd * Perform the import for the given configuration.  This passes the heavy
1773185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained
1774185029Spjd * within the pool.
1775168404Spjd */
1776168404Spjdstatic int
1777168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts,
1778219089Spjd    nvlist_t *props, int flags)
1779168404Spjd{
1780168404Spjd	zpool_handle_t *zhp;
1781168404Spjd	char *name;
1782168404Spjd	uint64_t state;
1783168404Spjd	uint64_t version;
1784168404Spjd
1785168404Spjd	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1786168404Spjd	    &name) == 0);
1787168404Spjd
1788168404Spjd	verify(nvlist_lookup_uint64(config,
1789168404Spjd	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1790168404Spjd	verify(nvlist_lookup_uint64(config,
1791168404Spjd	    ZPOOL_CONFIG_VERSION, &version) == 0);
1792236884Smm	if (!SPA_VERSION_IS_SUPPORTED(version)) {
1793168404Spjd		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1794236884Smm		    "is formatted using an unsupported ZFS version\n"), name);
1795168404Spjd		return (1);
1796219089Spjd	} else if (state != POOL_STATE_EXPORTED &&
1797219089Spjd	    !(flags & ZFS_IMPORT_ANY_HOST)) {
1798168498Spjd		uint64_t hostid;
1799168498Spjd
1800168498Spjd		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
1801168498Spjd		    &hostid) == 0) {
1802168498Spjd			if ((unsigned long)hostid != gethostid()) {
1803168498Spjd				char *hostname;
1804168498Spjd				uint64_t timestamp;
1805168498Spjd				time_t t;
1806168498Spjd
1807168498Spjd				verify(nvlist_lookup_string(config,
1808168498Spjd				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
1809168498Spjd				verify(nvlist_lookup_uint64(config,
1810168498Spjd				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
1811168498Spjd				t = timestamp;
1812168498Spjd				(void) fprintf(stderr, gettext("cannot import "
1813168498Spjd				    "'%s': pool may be in use from other "
1814168498Spjd				    "system, it was last accessed by %s "
1815168498Spjd				    "(hostid: 0x%lx) on %s"), name, hostname,
1816168498Spjd				    (unsigned long)hostid,
1817168498Spjd				    asctime(localtime(&t)));
1818168498Spjd				(void) fprintf(stderr, gettext("use '-f' to "
1819168498Spjd				    "import anyway\n"));
1820168498Spjd				return (1);
1821168498Spjd			}
1822168498Spjd		} else {
1823168498Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
1824168498Spjd			    "pool may be in use from other system\n"), name);
1825168498Spjd			(void) fprintf(stderr, gettext("use '-f' to import "
1826168498Spjd			    "anyway\n"));
1827168498Spjd			return (1);
1828168498Spjd		}
1829168404Spjd	}
1830168404Spjd
1831219089Spjd	if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
1832168404Spjd		return (1);
1833168404Spjd
1834168404Spjd	if (newname != NULL)
1835168404Spjd		name = (char *)newname;
1836168404Spjd
1837209962Smm	if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
1838209962Smm		return (1);
1839168404Spjd
1840209962Smm	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
1841219089Spjd	    !(flags & ZFS_IMPORT_ONLY) &&
1842209962Smm	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1843168404Spjd		zpool_close(zhp);
1844168404Spjd		return (1);
1845168404Spjd	}
1846168404Spjd
1847168404Spjd	zpool_close(zhp);
1848219089Spjd	return (0);
1849168404Spjd}
1850168404Spjd
1851168404Spjd/*
1852168404Spjd * zpool import [-d dir] [-D]
1853185029Spjd *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
1854185029Spjd *              [-d dir | -c cachefile] [-f] -a
1855185029Spjd *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
1856219089Spjd *              [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool]
1857168404Spjd *
1858185029Spjd *	 -c	Read pool information from a cachefile instead of searching
1859185029Spjd *		devices.
1860185029Spjd *
1861168404Spjd *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1862168404Spjd *		one directory can be specified using multiple '-d' options.
1863168404Spjd *
1864168404Spjd *       -D     Scan for previously destroyed pools or import all or only
1865168404Spjd *              specified destroyed pools.
1866168404Spjd *
1867168404Spjd *       -R	Temporarily import the pool, with all mountpoints relative to
1868168404Spjd *		the given root.  The pool will remain exported when the machine
1869168404Spjd *		is rebooted.
1870168404Spjd *
1871219089Spjd *       -V	Import even in the presence of faulted vdevs.  This is an
1872185029Spjd *       	intentionally undocumented option for testing purposes, and
1873185029Spjd *       	treats the pool configuration as complete, leaving any bad
1874209962Smm *		vdevs in the FAULTED state. In other words, it does verbatim
1875209962Smm *		import.
1876185029Spjd *
1877219089Spjd *       -f	Force import, even if it appears that the pool is active.
1878219089Spjd *
1879219089Spjd *       -F     Attempt rewind if necessary.
1880219089Spjd *
1881219089Spjd *       -n     See if rewind would work, but don't actually rewind.
1882219089Spjd *
1883219089Spjd *       -N     Import the pool but don't mount datasets.
1884219089Spjd *
1885219089Spjd *       -T     Specify a starting txg to use for import. This option is
1886219089Spjd *       	intentionally undocumented option for testing purposes.
1887219089Spjd *
1888168404Spjd *       -a	Import all pools found.
1889168404Spjd *
1890185029Spjd *       -o	Set property=value and/or temporary mount options (without '=').
1891185029Spjd *
1892168404Spjd * The import command scans for pools to import, and import pools based on pool
1893168404Spjd * name and GUID.  The pool can also be renamed as part of the import process.
1894168404Spjd */
1895168404Spjdint
1896168404Spjdzpool_do_import(int argc, char **argv)
1897168404Spjd{
1898168404Spjd	char **searchdirs = NULL;
1899168404Spjd	int nsearch = 0;
1900168404Spjd	int c;
1901219089Spjd	int err = 0;
1902185029Spjd	nvlist_t *pools = NULL;
1903168404Spjd	boolean_t do_all = B_FALSE;
1904168404Spjd	boolean_t do_destroyed = B_FALSE;
1905168404Spjd	char *mntopts = NULL;
1906168404Spjd	nvpair_t *elem;
1907168404Spjd	nvlist_t *config;
1908185029Spjd	uint64_t searchguid = 0;
1909185029Spjd	char *searchname = NULL;
1910185029Spjd	char *propval;
1911168404Spjd	nvlist_t *found_config;
1912219089Spjd	nvlist_t *policy = NULL;
1913185029Spjd	nvlist_t *props = NULL;
1914168404Spjd	boolean_t first;
1915219089Spjd	int flags = ZFS_IMPORT_NORMAL;
1916219089Spjd	uint32_t rewind_policy = ZPOOL_NO_REWIND;
1917219089Spjd	boolean_t dryrun = B_FALSE;
1918219089Spjd	boolean_t do_rewind = B_FALSE;
1919219089Spjd	boolean_t xtreme_rewind = B_FALSE;
1920219089Spjd	uint64_t pool_state, txg = -1ULL;
1921185029Spjd	char *cachefile = NULL;
1922219089Spjd	importargs_t idata = { 0 };
1923219089Spjd	char *endptr;
1924168404Spjd
1925168404Spjd	/* check options */
1926219089Spjd	while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:rR:T:VX")) != -1) {
1927168404Spjd		switch (c) {
1928168404Spjd		case 'a':
1929168404Spjd			do_all = B_TRUE;
1930168404Spjd			break;
1931185029Spjd		case 'c':
1932185029Spjd			cachefile = optarg;
1933185029Spjd			break;
1934168404Spjd		case 'd':
1935168404Spjd			if (searchdirs == NULL) {
1936168404Spjd				searchdirs = safe_malloc(sizeof (char *));
1937168404Spjd			} else {
1938168404Spjd				char **tmp = safe_malloc((nsearch + 1) *
1939168404Spjd				    sizeof (char *));
1940168404Spjd				bcopy(searchdirs, tmp, nsearch *
1941168404Spjd				    sizeof (char *));
1942168404Spjd				free(searchdirs);
1943168404Spjd				searchdirs = tmp;
1944168404Spjd			}
1945168404Spjd			searchdirs[nsearch++] = optarg;
1946168404Spjd			break;
1947168404Spjd		case 'D':
1948168404Spjd			do_destroyed = B_TRUE;
1949168404Spjd			break;
1950168404Spjd		case 'f':
1951219089Spjd			flags |= ZFS_IMPORT_ANY_HOST;
1952168404Spjd			break;
1953185029Spjd		case 'F':
1954219089Spjd			do_rewind = B_TRUE;
1955185029Spjd			break;
1956219089Spjd		case 'm':
1957219089Spjd			flags |= ZFS_IMPORT_MISSING_LOG;
1958219089Spjd			break;
1959219089Spjd		case 'n':
1960219089Spjd			dryrun = B_TRUE;
1961219089Spjd			break;
1962219089Spjd		case 'N':
1963219089Spjd			flags |= ZFS_IMPORT_ONLY;
1964219089Spjd			break;
1965168404Spjd		case 'o':
1966185029Spjd			if ((propval = strchr(optarg, '=')) != NULL) {
1967185029Spjd				*propval = '\0';
1968185029Spjd				propval++;
1969185029Spjd				if (add_prop_list(optarg, propval,
1970185029Spjd				    &props, B_TRUE))
1971185029Spjd					goto error;
1972185029Spjd			} else {
1973185029Spjd				mntopts = optarg;
1974185029Spjd			}
1975168404Spjd			break;
1976168404Spjd		case 'R':
1977185029Spjd			if (add_prop_list(zpool_prop_to_name(
1978185029Spjd			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1979185029Spjd				goto error;
1980185029Spjd			if (nvlist_lookup_string(props,
1981185029Spjd			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
1982185029Spjd			    &propval) == 0)
1983185029Spjd				break;
1984185029Spjd			if (add_prop_list(zpool_prop_to_name(
1985185029Spjd			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1986185029Spjd				goto error;
1987168404Spjd			break;
1988219089Spjd		case 'T':
1989219089Spjd			errno = 0;
1990219089Spjd			txg = strtoull(optarg, &endptr, 10);
1991219089Spjd			if (errno != 0 || *endptr != '\0') {
1992219089Spjd				(void) fprintf(stderr,
1993219089Spjd				    gettext("invalid txg value\n"));
1994219089Spjd				usage(B_FALSE);
1995219089Spjd			}
1996219089Spjd			rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
1997219089Spjd			break;
1998219089Spjd		case 'V':
1999219089Spjd			flags |= ZFS_IMPORT_VERBATIM;
2000219089Spjd			break;
2001219089Spjd		case 'X':
2002219089Spjd			xtreme_rewind = B_TRUE;
2003219089Spjd			break;
2004168404Spjd		case ':':
2005168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
2006168404Spjd			    "'%c' option\n"), optopt);
2007168404Spjd			usage(B_FALSE);
2008168404Spjd			break;
2009168404Spjd		case '?':
2010168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2011168404Spjd			    optopt);
2012168404Spjd			usage(B_FALSE);
2013168404Spjd		}
2014168404Spjd	}
2015168404Spjd
2016168404Spjd	argc -= optind;
2017168404Spjd	argv += optind;
2018168404Spjd
2019185029Spjd	if (cachefile && nsearch != 0) {
2020185029Spjd		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
2021185029Spjd		usage(B_FALSE);
2022185029Spjd	}
2023185029Spjd
2024219089Spjd	if ((dryrun || xtreme_rewind) && !do_rewind) {
2025219089Spjd		(void) fprintf(stderr,
2026219089Spjd		    gettext("-n or -X only meaningful with -F\n"));
2027219089Spjd		usage(B_FALSE);
2028219089Spjd	}
2029219089Spjd	if (dryrun)
2030219089Spjd		rewind_policy = ZPOOL_TRY_REWIND;
2031219089Spjd	else if (do_rewind)
2032219089Spjd		rewind_policy = ZPOOL_DO_REWIND;
2033219089Spjd	if (xtreme_rewind)
2034219089Spjd		rewind_policy |= ZPOOL_EXTREME_REWIND;
2035219089Spjd
2036219089Spjd	/* In the future, we can capture further policy and include it here */
2037219089Spjd	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
2038219089Spjd	    nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 ||
2039219089Spjd	    nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
2040219089Spjd		goto error;
2041219089Spjd
2042168404Spjd	if (searchdirs == NULL) {
2043168404Spjd		searchdirs = safe_malloc(sizeof (char *));
2044235478Savg		searchdirs[0] = "/dev";
2045168404Spjd		nsearch = 1;
2046168404Spjd	}
2047168404Spjd
2048168404Spjd	/* check argument count */
2049168404Spjd	if (do_all) {
2050168404Spjd		if (argc != 0) {
2051168404Spjd			(void) fprintf(stderr, gettext("too many arguments\n"));
2052168404Spjd			usage(B_FALSE);
2053168404Spjd		}
2054168404Spjd	} else {
2055168404Spjd		if (argc > 2) {
2056168404Spjd			(void) fprintf(stderr, gettext("too many arguments\n"));
2057168404Spjd			usage(B_FALSE);
2058168404Spjd		}
2059168404Spjd
2060168404Spjd		/*
2061168404Spjd		 * Check for the SYS_CONFIG privilege.  We do this explicitly
2062168404Spjd		 * here because otherwise any attempt to discover pools will
2063168404Spjd		 * silently fail.
2064168404Spjd		 */
2065168404Spjd		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
2066168404Spjd			(void) fprintf(stderr, gettext("cannot "
2067168404Spjd			    "discover pools: permission denied\n"));
2068168404Spjd			free(searchdirs);
2069219089Spjd			nvlist_free(policy);
2070168404Spjd			return (1);
2071168404Spjd		}
2072168404Spjd	}
2073168404Spjd
2074168404Spjd	/*
2075168404Spjd	 * Depending on the arguments given, we do one of the following:
2076168404Spjd	 *
2077168404Spjd	 *	<none>	Iterate through all pools and display information about
2078168404Spjd	 *		each one.
2079168404Spjd	 *
2080168404Spjd	 *	-a	Iterate through all pools and try to import each one.
2081168404Spjd	 *
2082168404Spjd	 *	<id>	Find the pool that corresponds to the given GUID/pool
2083168404Spjd	 *		name and import that one.
2084168404Spjd	 *
2085168404Spjd	 *	-D	Above options applies only to destroyed pools.
2086168404Spjd	 */
2087168404Spjd	if (argc != 0) {
2088168404Spjd		char *endptr;
2089168404Spjd
2090168404Spjd		errno = 0;
2091168404Spjd		searchguid = strtoull(argv[0], &endptr, 10);
2092168404Spjd		if (errno != 0 || *endptr != '\0')
2093168404Spjd			searchname = argv[0];
2094168404Spjd		found_config = NULL;
2095168404Spjd
2096185029Spjd		/*
2097219089Spjd		 * User specified a name or guid.  Ensure it's unique.
2098185029Spjd		 */
2099219089Spjd		idata.unique = B_TRUE;
2100185029Spjd	}
2101185029Spjd
2102219089Spjd
2103219089Spjd	idata.path = searchdirs;
2104219089Spjd	idata.paths = nsearch;
2105219089Spjd	idata.poolname = searchname;
2106219089Spjd	idata.guid = searchguid;
2107219089Spjd	idata.cachefile = cachefile;
2108219089Spjd
2109219089Spjd	pools = zpool_search_import(g_zfs, &idata);
2110219089Spjd
2111219089Spjd	if (pools != NULL && idata.exists &&
2112219089Spjd	    (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
2113219089Spjd		(void) fprintf(stderr, gettext("cannot import '%s': "
2114219089Spjd		    "a pool with that name already exists\n"),
2115219089Spjd		    argv[0]);
2116219089Spjd		(void) fprintf(stderr, gettext("use the form '%s "
2117219089Spjd		    "<pool | id> <newpool>' to give it a new name\n"),
2118219089Spjd		    "zpool import");
2119219089Spjd		err = 1;
2120219089Spjd	} else if (pools == NULL && idata.exists) {
2121219089Spjd		(void) fprintf(stderr, gettext("cannot import '%s': "
2122219089Spjd		    "a pool with that name is already created/imported,\n"),
2123219089Spjd		    argv[0]);
2124219089Spjd		(void) fprintf(stderr, gettext("and no additional pools "
2125219089Spjd		    "with that name were found\n"));
2126219089Spjd		err = 1;
2127219089Spjd	} else if (pools == NULL) {
2128185029Spjd		if (argc != 0) {
2129185029Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
2130185029Spjd			    "no such pool available\n"), argv[0]);
2131185029Spjd		}
2132219089Spjd		err = 1;
2133219089Spjd	}
2134219089Spjd
2135219089Spjd	if (err == 1) {
2136185029Spjd		free(searchdirs);
2137219089Spjd		nvlist_free(policy);
2138185029Spjd		return (1);
2139185029Spjd	}
2140185029Spjd
2141185029Spjd	/*
2142185029Spjd	 * At this point we have a list of import candidate configs. Even if
2143185029Spjd	 * we were searching by pool name or guid, we still need to
2144185029Spjd	 * post-process the list to deal with pool state and possible
2145185029Spjd	 * duplicate names.
2146185029Spjd	 */
2147168404Spjd	err = 0;
2148168404Spjd	elem = NULL;
2149168404Spjd	first = B_TRUE;
2150168404Spjd	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
2151168404Spjd
2152168404Spjd		verify(nvpair_value_nvlist(elem, &config) == 0);
2153168404Spjd
2154168404Spjd		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
2155168404Spjd		    &pool_state) == 0);
2156168404Spjd		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
2157168404Spjd			continue;
2158168404Spjd		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
2159168404Spjd			continue;
2160168404Spjd
2161219089Spjd		verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY,
2162219089Spjd		    policy) == 0);
2163219089Spjd
2164168404Spjd		if (argc == 0) {
2165168404Spjd			if (first)
2166168404Spjd				first = B_FALSE;
2167168404Spjd			else if (!do_all)
2168168404Spjd				(void) printf("\n");
2169168404Spjd
2170219089Spjd			if (do_all) {
2171168404Spjd				err |= do_import(config, NULL, mntopts,
2172219089Spjd				    props, flags);
2173219089Spjd			} else {
2174168404Spjd				show_import(config);
2175219089Spjd			}
2176168404Spjd		} else if (searchname != NULL) {
2177168404Spjd			char *name;
2178168404Spjd
2179168404Spjd			/*
2180168404Spjd			 * We are searching for a pool based on name.
2181168404Spjd			 */
2182168404Spjd			verify(nvlist_lookup_string(config,
2183168404Spjd			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
2184168404Spjd
2185168404Spjd			if (strcmp(name, searchname) == 0) {
2186168404Spjd				if (found_config != NULL) {
2187168404Spjd					(void) fprintf(stderr, gettext(
2188168404Spjd					    "cannot import '%s': more than "
2189168404Spjd					    "one matching pool\n"), searchname);
2190168404Spjd					(void) fprintf(stderr, gettext(
2191168404Spjd					    "import by numeric ID instead\n"));
2192168404Spjd					err = B_TRUE;
2193168404Spjd				}
2194168404Spjd				found_config = config;
2195168404Spjd			}
2196168404Spjd		} else {
2197168404Spjd			uint64_t guid;
2198168404Spjd
2199168404Spjd			/*
2200168404Spjd			 * Search for a pool by guid.
2201168404Spjd			 */
2202168404Spjd			verify(nvlist_lookup_uint64(config,
2203168404Spjd			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
2204168404Spjd
2205168404Spjd			if (guid == searchguid)
2206168404Spjd				found_config = config;
2207168404Spjd		}
2208168404Spjd	}
2209168404Spjd
2210168404Spjd	/*
2211168404Spjd	 * If we were searching for a specific pool, verify that we found a
2212168404Spjd	 * pool, and then do the import.
2213168404Spjd	 */
2214168404Spjd	if (argc != 0 && err == 0) {
2215168404Spjd		if (found_config == NULL) {
2216168404Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
2217168404Spjd			    "no such pool available\n"), argv[0]);
2218168404Spjd			err = B_TRUE;
2219168404Spjd		} else {
2220168404Spjd			err |= do_import(found_config, argc == 1 ? NULL :
2221219089Spjd			    argv[1], mntopts, props, flags);
2222168404Spjd		}
2223168404Spjd	}
2224168404Spjd
2225168404Spjd	/*
2226168404Spjd	 * If we were just looking for pools, report an error if none were
2227168404Spjd	 * found.
2228168404Spjd	 */
2229168404Spjd	if (argc == 0 && first)
2230168404Spjd		(void) fprintf(stderr,
2231168404Spjd		    gettext("no pools available to import\n"));
2232168404Spjd
2233185029Spjderror:
2234185029Spjd	nvlist_free(props);
2235168404Spjd	nvlist_free(pools);
2236219089Spjd	nvlist_free(policy);
2237168404Spjd	free(searchdirs);
2238168404Spjd
2239168404Spjd	return (err ? 1 : 0);
2240168404Spjd}
2241168404Spjd
2242168404Spjdtypedef struct iostat_cbdata {
2243236155Smm	boolean_t cb_verbose;
2244236155Smm	int cb_namewidth;
2245236155Smm	int cb_iteration;
2246168404Spjd	zpool_list_t *cb_list;
2247168404Spjd} iostat_cbdata_t;
2248168404Spjd
2249168404Spjdstatic void
2250168404Spjdprint_iostat_separator(iostat_cbdata_t *cb)
2251168404Spjd{
2252168404Spjd	int i = 0;
2253168404Spjd
2254168404Spjd	for (i = 0; i < cb->cb_namewidth; i++)
2255168404Spjd		(void) printf("-");
2256168404Spjd	(void) printf("  -----  -----  -----  -----  -----  -----\n");
2257168404Spjd}
2258168404Spjd
2259168404Spjdstatic void
2260168404Spjdprint_iostat_header(iostat_cbdata_t *cb)
2261168404Spjd{
2262168404Spjd	(void) printf("%*s     capacity     operations    bandwidth\n",
2263168404Spjd	    cb->cb_namewidth, "");
2264219089Spjd	(void) printf("%-*s  alloc   free   read  write   read  write\n",
2265168404Spjd	    cb->cb_namewidth, "pool");
2266168404Spjd	print_iostat_separator(cb);
2267168404Spjd}
2268168404Spjd
2269168404Spjd/*
2270168404Spjd * Display a single statistic.
2271168404Spjd */
2272185029Spjdstatic void
2273168404Spjdprint_one_stat(uint64_t value)
2274168404Spjd{
2275168404Spjd	char buf[64];
2276168404Spjd
2277168404Spjd	zfs_nicenum(value, buf, sizeof (buf));
2278168404Spjd	(void) printf("  %5s", buf);
2279168404Spjd}
2280168404Spjd
2281168404Spjd/*
2282168404Spjd * Print out all the statistics for the given vdev.  This can either be the
2283168404Spjd * toplevel configuration, or called recursively.  If 'name' is NULL, then this
2284168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats.
2285168404Spjd */
2286168404Spjdvoid
2287168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
2288168404Spjd    nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
2289168404Spjd{
2290168404Spjd	nvlist_t **oldchild, **newchild;
2291168404Spjd	uint_t c, children;
2292168404Spjd	vdev_stat_t *oldvs, *newvs;
2293168404Spjd	vdev_stat_t zerovs = { 0 };
2294168404Spjd	uint64_t tdelta;
2295168404Spjd	double scale;
2296168404Spjd	char *vname;
2297168404Spjd
2298168404Spjd	if (oldnv != NULL) {
2299219089Spjd		verify(nvlist_lookup_uint64_array(oldnv,
2300219089Spjd		    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
2301168404Spjd	} else {
2302168404Spjd		oldvs = &zerovs;
2303168404Spjd	}
2304168404Spjd
2305219089Spjd	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
2306168404Spjd	    (uint64_t **)&newvs, &c) == 0);
2307168404Spjd
2308168404Spjd	if (strlen(name) + depth > cb->cb_namewidth)
2309168404Spjd		(void) printf("%*s%s", depth, "", name);
2310168404Spjd	else
2311168404Spjd		(void) printf("%*s%s%*s", depth, "", name,
2312168404Spjd		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
2313168404Spjd
2314168404Spjd	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
2315168404Spjd
2316168404Spjd	if (tdelta == 0)
2317168404Spjd		scale = 1.0;
2318168404Spjd	else
2319168404Spjd		scale = (double)NANOSEC / tdelta;
2320168404Spjd
2321168404Spjd	/* only toplevel vdevs have capacity stats */
2322168404Spjd	if (newvs->vs_space == 0) {
2323168404Spjd		(void) printf("      -      -");
2324168404Spjd	} else {
2325168404Spjd		print_one_stat(newvs->vs_alloc);
2326168404Spjd		print_one_stat(newvs->vs_space - newvs->vs_alloc);
2327168404Spjd	}
2328168404Spjd
2329168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
2330168404Spjd	    oldvs->vs_ops[ZIO_TYPE_READ])));
2331168404Spjd
2332168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
2333168404Spjd	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
2334168404Spjd
2335168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
2336168404Spjd	    oldvs->vs_bytes[ZIO_TYPE_READ])));
2337168404Spjd
2338168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
2339168404Spjd	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
2340168404Spjd
2341168404Spjd	(void) printf("\n");
2342168404Spjd
2343168404Spjd	if (!cb->cb_verbose)
2344168404Spjd		return;
2345168404Spjd
2346168404Spjd	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
2347168404Spjd	    &newchild, &children) != 0)
2348168404Spjd		return;
2349168404Spjd
2350168404Spjd	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
2351168404Spjd	    &oldchild, &c) != 0)
2352168404Spjd		return;
2353168404Spjd
2354168404Spjd	for (c = 0; c < children; c++) {
2355227497Smm		uint64_t ishole = B_FALSE, islog = B_FALSE;
2356219089Spjd
2357227497Smm		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
2358227497Smm		    &ishole);
2359227497Smm
2360227497Smm		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
2361227497Smm		    &islog);
2362227497Smm
2363227497Smm		if (ishole || islog)
2364219089Spjd			continue;
2365219089Spjd
2366219089Spjd		vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
2367168404Spjd		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2368168404Spjd		    newchild[c], cb, depth + 2);
2369168404Spjd		free(vname);
2370168404Spjd	}
2371185029Spjd
2372185029Spjd	/*
2373227497Smm	 * Log device section
2374227497Smm	 */
2375227497Smm
2376227497Smm	if (num_logs(newnv) > 0) {
2377227497Smm		(void) printf("%-*s      -      -      -      -      -      "
2378227497Smm		    "-\n", cb->cb_namewidth, "logs");
2379227497Smm
2380227497Smm		for (c = 0; c < children; c++) {
2381227497Smm			uint64_t islog = B_FALSE;
2382227497Smm			(void) nvlist_lookup_uint64(newchild[c],
2383227497Smm			    ZPOOL_CONFIG_IS_LOG, &islog);
2384227497Smm
2385227497Smm			if (islog) {
2386227497Smm				vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
2387227497Smm				    B_FALSE);
2388227497Smm				print_vdev_stats(zhp, vname, oldnv ?
2389227497Smm				    oldchild[c] : NULL, newchild[c],
2390227497Smm				    cb, depth + 2);
2391227497Smm				free(vname);
2392227497Smm			}
2393227497Smm		}
2394227497Smm
2395227497Smm	}
2396227497Smm
2397227497Smm	/*
2398185029Spjd	 * Include level 2 ARC devices in iostat output
2399185029Spjd	 */
2400185029Spjd	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
2401185029Spjd	    &newchild, &children) != 0)
2402185029Spjd		return;
2403185029Spjd
2404185029Spjd	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
2405185029Spjd	    &oldchild, &c) != 0)
2406185029Spjd		return;
2407185029Spjd
2408185029Spjd	if (children > 0) {
2409185029Spjd		(void) printf("%-*s      -      -      -      -      -      "
2410185029Spjd		    "-\n", cb->cb_namewidth, "cache");
2411185029Spjd		for (c = 0; c < children; c++) {
2412219089Spjd			vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
2413219089Spjd			    B_FALSE);
2414185029Spjd			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2415185029Spjd			    newchild[c], cb, depth + 2);
2416185029Spjd			free(vname);
2417185029Spjd		}
2418185029Spjd	}
2419168404Spjd}
2420168404Spjd
2421168404Spjdstatic int
2422168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data)
2423168404Spjd{
2424168404Spjd	iostat_cbdata_t *cb = data;
2425168404Spjd	boolean_t missing;
2426168404Spjd
2427168404Spjd	/*
2428168404Spjd	 * If the pool has disappeared, remove it from the list and continue.
2429168404Spjd	 */
2430168404Spjd	if (zpool_refresh_stats(zhp, &missing) != 0)
2431168404Spjd		return (-1);
2432168404Spjd
2433168404Spjd	if (missing)
2434168404Spjd		pool_list_remove(cb->cb_list, zhp);
2435168404Spjd
2436168404Spjd	return (0);
2437168404Spjd}
2438168404Spjd
2439168404Spjd/*
2440168404Spjd * Callback to print out the iostats for the given pool.
2441168404Spjd */
2442168404Spjdint
2443168404Spjdprint_iostat(zpool_handle_t *zhp, void *data)
2444168404Spjd{
2445168404Spjd	iostat_cbdata_t *cb = data;
2446168404Spjd	nvlist_t *oldconfig, *newconfig;
2447168404Spjd	nvlist_t *oldnvroot, *newnvroot;
2448168404Spjd
2449168404Spjd	newconfig = zpool_get_config(zhp, &oldconfig);
2450168404Spjd
2451168404Spjd	if (cb->cb_iteration == 1)
2452168404Spjd		oldconfig = NULL;
2453168404Spjd
2454168404Spjd	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
2455168404Spjd	    &newnvroot) == 0);
2456168404Spjd
2457168404Spjd	if (oldconfig == NULL)
2458168404Spjd		oldnvroot = NULL;
2459168404Spjd	else
2460168404Spjd		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
2461168404Spjd		    &oldnvroot) == 0);
2462168404Spjd
2463168404Spjd	/*
2464168404Spjd	 * Print out the statistics for the pool.
2465168404Spjd	 */
2466168404Spjd	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
2467168404Spjd
2468168404Spjd	if (cb->cb_verbose)
2469168404Spjd		print_iostat_separator(cb);
2470168404Spjd
2471168404Spjd	return (0);
2472168404Spjd}
2473168404Spjd
2474168404Spjdint
2475168404Spjdget_namewidth(zpool_handle_t *zhp, void *data)
2476168404Spjd{
2477168404Spjd	iostat_cbdata_t *cb = data;
2478168404Spjd	nvlist_t *config, *nvroot;
2479168404Spjd
2480168404Spjd	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
2481168404Spjd		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2482168404Spjd		    &nvroot) == 0);
2483168404Spjd		if (!cb->cb_verbose)
2484168404Spjd			cb->cb_namewidth = strlen(zpool_get_name(zhp));
2485168404Spjd		else
2486236145Smm			cb->cb_namewidth = max_width(zhp, nvroot, 0,
2487236145Smm			    cb->cb_namewidth);
2488168404Spjd	}
2489168404Spjd
2490168404Spjd	/*
2491168404Spjd	 * The width must fall into the range [10,38].  The upper limit is the
2492168404Spjd	 * maximum we can have and still fit in 80 columns.
2493168404Spjd	 */
2494168404Spjd	if (cb->cb_namewidth < 10)
2495168404Spjd		cb->cb_namewidth = 10;
2496168404Spjd	if (cb->cb_namewidth > 38)
2497168404Spjd		cb->cb_namewidth = 38;
2498168404Spjd
2499168404Spjd	return (0);
2500168404Spjd}
2501168404Spjd
2502168404Spjd/*
2503219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one.
2504168404Spjd */
2505219089Spjdstatic void
2506219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv,
2507219089Spjd    unsigned long *cnt)
2508168404Spjd{
2509168404Spjd	unsigned long interval = 0, count = 0;
2510219089Spjd	int argc = *argcp, errno;
2511168404Spjd
2512168404Spjd	/*
2513168404Spjd	 * Determine if the last argument is an integer or a pool name
2514168404Spjd	 */
2515168404Spjd	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2516168404Spjd		char *end;
2517168404Spjd
2518168404Spjd		errno = 0;
2519168404Spjd		interval = strtoul(argv[argc - 1], &end, 10);
2520168404Spjd
2521168404Spjd		if (*end == '\0' && errno == 0) {
2522168404Spjd			if (interval == 0) {
2523168404Spjd				(void) fprintf(stderr, gettext("interval "
2524168404Spjd				    "cannot be zero\n"));
2525168404Spjd				usage(B_FALSE);
2526168404Spjd			}
2527168404Spjd			/*
2528168404Spjd			 * Ignore the last parameter
2529168404Spjd			 */
2530168404Spjd			argc--;
2531168404Spjd		} else {
2532168404Spjd			/*
2533168404Spjd			 * If this is not a valid number, just plow on.  The
2534168404Spjd			 * user will get a more informative error message later
2535168404Spjd			 * on.
2536168404Spjd			 */
2537168404Spjd			interval = 0;
2538168404Spjd		}
2539168404Spjd	}
2540168404Spjd
2541168404Spjd	/*
2542168404Spjd	 * If the last argument is also an integer, then we have both a count
2543219089Spjd	 * and an interval.
2544168404Spjd	 */
2545168404Spjd	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2546168404Spjd		char *end;
2547168404Spjd
2548168404Spjd		errno = 0;
2549168404Spjd		count = interval;
2550168404Spjd		interval = strtoul(argv[argc - 1], &end, 10);
2551168404Spjd
2552168404Spjd		if (*end == '\0' && errno == 0) {
2553168404Spjd			if (interval == 0) {
2554168404Spjd				(void) fprintf(stderr, gettext("interval "
2555168404Spjd				    "cannot be zero\n"));
2556168404Spjd				usage(B_FALSE);
2557168404Spjd			}
2558168404Spjd
2559168404Spjd			/*
2560168404Spjd			 * Ignore the last parameter
2561168404Spjd			 */
2562168404Spjd			argc--;
2563168404Spjd		} else {
2564168404Spjd			interval = 0;
2565168404Spjd		}
2566168404Spjd	}
2567168404Spjd
2568219089Spjd	*iv = interval;
2569219089Spjd	*cnt = count;
2570219089Spjd	*argcp = argc;
2571219089Spjd}
2572219089Spjd
2573219089Spjdstatic void
2574219089Spjdget_timestamp_arg(char c)
2575219089Spjd{
2576219089Spjd	if (c == 'u')
2577219089Spjd		timestamp_fmt = UDATE;
2578219089Spjd	else if (c == 'd')
2579219089Spjd		timestamp_fmt = DDATE;
2580219089Spjd	else
2581219089Spjd		usage(B_FALSE);
2582219089Spjd}
2583219089Spjd
2584219089Spjd/*
2585219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]]
2586219089Spjd *
2587219089Spjd *	-v	Display statistics for individual vdevs
2588219089Spjd *	-T	Display a timestamp in date(1) or Unix format
2589219089Spjd *
2590219089Spjd * This command can be tricky because we want to be able to deal with pool
2591219089Spjd * creation/destruction as well as vdev configuration changes.  The bulk of this
2592219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
2593219089Spjd * on pool_list_update() to detect the addition of new pools.  Configuration
2594219089Spjd * changes are all handled within libzfs.
2595219089Spjd */
2596219089Spjdint
2597219089Spjdzpool_do_iostat(int argc, char **argv)
2598219089Spjd{
2599219089Spjd	int c;
2600219089Spjd	int ret;
2601219089Spjd	int npools;
2602219089Spjd	unsigned long interval = 0, count = 0;
2603219089Spjd	zpool_list_t *list;
2604219089Spjd	boolean_t verbose = B_FALSE;
2605219089Spjd	iostat_cbdata_t cb;
2606219089Spjd
2607219089Spjd	/* check options */
2608219089Spjd	while ((c = getopt(argc, argv, "T:v")) != -1) {
2609219089Spjd		switch (c) {
2610219089Spjd		case 'T':
2611219089Spjd			get_timestamp_arg(*optarg);
2612219089Spjd			break;
2613219089Spjd		case 'v':
2614219089Spjd			verbose = B_TRUE;
2615219089Spjd			break;
2616219089Spjd		case '?':
2617219089Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2618219089Spjd			    optopt);
2619219089Spjd			usage(B_FALSE);
2620219089Spjd		}
2621219089Spjd	}
2622219089Spjd
2623219089Spjd	argc -= optind;
2624219089Spjd	argv += optind;
2625219089Spjd
2626219089Spjd	get_interval_count(&argc, argv, &interval, &count);
2627219089Spjd
2628168404Spjd	/*
2629168404Spjd	 * Construct the list of all interesting pools.
2630168404Spjd	 */
2631168404Spjd	ret = 0;
2632168404Spjd	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
2633168404Spjd		return (1);
2634168404Spjd
2635168404Spjd	if (pool_list_count(list) == 0 && argc != 0) {
2636168404Spjd		pool_list_free(list);
2637168404Spjd		return (1);
2638168404Spjd	}
2639168404Spjd
2640168404Spjd	if (pool_list_count(list) == 0 && interval == 0) {
2641168404Spjd		pool_list_free(list);
2642168404Spjd		(void) fprintf(stderr, gettext("no pools available\n"));
2643168404Spjd		return (1);
2644168404Spjd	}
2645168404Spjd
2646168404Spjd	/*
2647168404Spjd	 * Enter the main iostat loop.
2648168404Spjd	 */
2649168404Spjd	cb.cb_list = list;
2650168404Spjd	cb.cb_verbose = verbose;
2651168404Spjd	cb.cb_iteration = 0;
2652168404Spjd	cb.cb_namewidth = 0;
2653168404Spjd
2654168404Spjd	for (;;) {
2655168404Spjd		pool_list_update(list);
2656168404Spjd
2657168404Spjd		if ((npools = pool_list_count(list)) == 0)
2658168404Spjd			break;
2659168404Spjd
2660168404Spjd		/*
2661168404Spjd		 * Refresh all statistics.  This is done as an explicit step
2662168404Spjd		 * before calculating the maximum name width, so that any
2663168404Spjd		 * configuration changes are properly accounted for.
2664168404Spjd		 */
2665168404Spjd		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
2666168404Spjd
2667168404Spjd		/*
2668168404Spjd		 * Iterate over all pools to determine the maximum width
2669168404Spjd		 * for the pool / device name column across all pools.
2670168404Spjd		 */
2671168404Spjd		cb.cb_namewidth = 0;
2672168404Spjd		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2673168404Spjd
2674219089Spjd		if (timestamp_fmt != NODATE)
2675219089Spjd			print_timestamp(timestamp_fmt);
2676219089Spjd
2677168404Spjd		/*
2678168404Spjd		 * If it's the first time, or verbose mode, print the header.
2679168404Spjd		 */
2680168404Spjd		if (++cb.cb_iteration == 1 || verbose)
2681168404Spjd			print_iostat_header(&cb);
2682168404Spjd
2683168404Spjd		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2684168404Spjd
2685168404Spjd		/*
2686168404Spjd		 * If there's more than one pool, and we're not in verbose mode
2687168404Spjd		 * (which prints a separator for us), then print a separator.
2688168404Spjd		 */
2689168404Spjd		if (npools > 1 && !verbose)
2690168404Spjd			print_iostat_separator(&cb);
2691168404Spjd
2692168404Spjd		if (verbose)
2693168404Spjd			(void) printf("\n");
2694168404Spjd
2695168404Spjd		/*
2696168404Spjd		 * Flush the output so that redirection to a file isn't buffered
2697168404Spjd		 * indefinitely.
2698168404Spjd		 */
2699168404Spjd		(void) fflush(stdout);
2700168404Spjd
2701168404Spjd		if (interval == 0)
2702168404Spjd			break;
2703168404Spjd
2704168404Spjd		if (count != 0 && --count == 0)
2705168404Spjd			break;
2706168404Spjd
2707168404Spjd		(void) sleep(interval);
2708168404Spjd	}
2709168404Spjd
2710168404Spjd	pool_list_free(list);
2711168404Spjd
2712168404Spjd	return (ret);
2713168404Spjd}
2714168404Spjd
2715168404Spjdtypedef struct list_cbdata {
2716236155Smm	boolean_t	cb_verbose;
2717236155Smm	int		cb_namewidth;
2718168404Spjd	boolean_t	cb_scripted;
2719185029Spjd	zprop_list_t	*cb_proplist;
2720168404Spjd} list_cbdata_t;
2721168404Spjd
2722168404Spjd/*
2723168404Spjd * Given a list of columns to display, output appropriate headers for each one.
2724168404Spjd */
2725185029Spjdstatic void
2726236155Smmprint_header(list_cbdata_t *cb)
2727168404Spjd{
2728236155Smm	zprop_list_t *pl = cb->cb_proplist;
2729236884Smm	char headerbuf[ZPOOL_MAXPROPLEN];
2730185029Spjd	const char *header;
2731185029Spjd	boolean_t first = B_TRUE;
2732185029Spjd	boolean_t right_justify;
2733236155Smm	size_t width = 0;
2734168404Spjd
2735185029Spjd	for (; pl != NULL; pl = pl->pl_next) {
2736236155Smm		width = pl->pl_width;
2737236155Smm		if (first && cb->cb_verbose) {
2738236155Smm			/*
2739236155Smm			 * Reset the width to accommodate the verbose listing
2740236155Smm			 * of devices.
2741236155Smm			 */
2742236155Smm			width = cb->cb_namewidth;
2743236155Smm		}
2744236155Smm
2745185029Spjd		if (!first)
2746168404Spjd			(void) printf("  ");
2747168404Spjd		else
2748185029Spjd			first = B_FALSE;
2749168404Spjd
2750236884Smm		right_justify = B_FALSE;
2751236884Smm		if (pl->pl_prop != ZPROP_INVAL) {
2752236884Smm			header = zpool_prop_column_name(pl->pl_prop);
2753236884Smm			right_justify = zpool_prop_align_right(pl->pl_prop);
2754236884Smm		} else {
2755236884Smm			int i;
2756185029Spjd
2757236884Smm			for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
2758236884Smm				headerbuf[i] = toupper(pl->pl_user_prop[i]);
2759236884Smm			headerbuf[i] = '\0';
2760236884Smm			header = headerbuf;
2761236884Smm		}
2762236884Smm
2763185029Spjd		if (pl->pl_next == NULL && !right_justify)
2764185029Spjd			(void) printf("%s", header);
2765185029Spjd		else if (right_justify)
2766236155Smm			(void) printf("%*s", width, header);
2767185029Spjd		else
2768236155Smm			(void) printf("%-*s", width, header);
2769236155Smm
2770168404Spjd	}
2771168404Spjd
2772168404Spjd	(void) printf("\n");
2773168404Spjd}
2774168404Spjd
2775185029Spjd/*
2776185029Spjd * Given a pool and a list of properties, print out all the properties according
2777185029Spjd * to the described layout.
2778185029Spjd */
2779185029Spjdstatic void
2780236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
2781168404Spjd{
2782236155Smm	zprop_list_t *pl = cb->cb_proplist;
2783185029Spjd	boolean_t first = B_TRUE;
2784185029Spjd	char property[ZPOOL_MAXPROPLEN];
2785185029Spjd	char *propstr;
2786185029Spjd	boolean_t right_justify;
2787236155Smm	size_t width;
2788168404Spjd
2789185029Spjd	for (; pl != NULL; pl = pl->pl_next) {
2790236155Smm
2791236155Smm		width = pl->pl_width;
2792236155Smm		if (first && cb->cb_verbose) {
2793236155Smm			/*
2794236155Smm			 * Reset the width to accommodate the verbose listing
2795236155Smm			 * of devices.
2796236155Smm			 */
2797236155Smm			width = cb->cb_namewidth;
2798236155Smm		}
2799236155Smm
2800185029Spjd		if (!first) {
2801236155Smm			if (cb->cb_scripted)
2802168404Spjd				(void) printf("\t");
2803168404Spjd			else
2804168404Spjd				(void) printf("  ");
2805185029Spjd		} else {
2806185029Spjd			first = B_FALSE;
2807168404Spjd		}
2808168404Spjd
2809185029Spjd		right_justify = B_FALSE;
2810185029Spjd		if (pl->pl_prop != ZPROP_INVAL) {
2811236155Smm			if (pl->pl_prop == ZPOOL_PROP_EXPANDSZ &&
2812236155Smm			    zpool_get_prop_int(zhp, pl->pl_prop, NULL) == 0)
2813236155Smm				propstr = "-";
2814236155Smm			else if (zpool_get_prop(zhp, pl->pl_prop, property,
2815185029Spjd			    sizeof (property), NULL) != 0)
2816185029Spjd				propstr = "-";
2817168404Spjd			else
2818185029Spjd				propstr = property;
2819168404Spjd
2820185029Spjd			right_justify = zpool_prop_align_right(pl->pl_prop);
2821236884Smm		} else if ((zpool_prop_feature(pl->pl_user_prop) ||
2822236884Smm		    zpool_prop_unsupported(pl->pl_user_prop)) &&
2823236884Smm		    zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
2824236884Smm		    sizeof (property)) == 0) {
2825236884Smm			propstr = property;
2826185029Spjd		} else {
2827185029Spjd			propstr = "-";
2828185029Spjd		}
2829168404Spjd
2830168404Spjd
2831185029Spjd		/*
2832185029Spjd		 * If this is being called in scripted mode, or if this is the
2833185029Spjd		 * last column and it is left-justified, don't include a width
2834185029Spjd		 * format specifier.
2835185029Spjd		 */
2836236155Smm		if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
2837185029Spjd			(void) printf("%s", propstr);
2838185029Spjd		else if (right_justify)
2839185029Spjd			(void) printf("%*s", width, propstr);
2840185029Spjd		else
2841185029Spjd			(void) printf("%-*s", width, propstr);
2842185029Spjd	}
2843168404Spjd
2844185029Spjd	(void) printf("\n");
2845185029Spjd}
2846168404Spjd
2847236155Smmstatic void
2848236155Smmprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted)
2849236155Smm{
2850236155Smm	char propval[64];
2851236155Smm	boolean_t fixed;
2852236155Smm	size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
2853236155Smm
2854236155Smm	zfs_nicenum(value, propval, sizeof (propval));
2855236155Smm
2856236155Smm	if (prop == ZPOOL_PROP_EXPANDSZ && value == 0)
2857236155Smm		(void) strlcpy(propval, "-", sizeof (propval));
2858236155Smm
2859236155Smm	if (scripted)
2860236155Smm		(void) printf("\t%s", propval);
2861236155Smm	else
2862236155Smm		(void) printf("  %*s", width, propval);
2863236155Smm}
2864236155Smm
2865236155Smmvoid
2866236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
2867236155Smm    list_cbdata_t *cb, int depth)
2868236155Smm{
2869236155Smm	nvlist_t **child;
2870236155Smm	vdev_stat_t *vs;
2871236155Smm	uint_t c, children;
2872236155Smm	char *vname;
2873236155Smm	boolean_t scripted = cb->cb_scripted;
2874236155Smm
2875236155Smm	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
2876236155Smm	    (uint64_t **)&vs, &c) == 0);
2877236155Smm
2878236155Smm	if (name != NULL) {
2879236155Smm		if (scripted)
2880236155Smm			(void) printf("\t%s", name);
2881236155Smm		else if (strlen(name) + depth > cb->cb_namewidth)
2882236155Smm			(void) printf("%*s%s", depth, "", name);
2883236155Smm		else
2884236155Smm			(void) printf("%*s%s%*s", depth, "", name,
2885236155Smm			    (int)(cb->cb_namewidth - strlen(name) - depth), "");
2886236155Smm
2887236155Smm		/* only toplevel vdevs have capacity stats */
2888236155Smm		if (vs->vs_space == 0) {
2889236155Smm			if (scripted)
2890236155Smm				(void) printf("\t-\t-\t-");
2891236155Smm			else
2892236155Smm				(void) printf("      -      -      -");
2893236155Smm		} else {
2894236155Smm			print_one_column(ZPOOL_PROP_SIZE, vs->vs_space,
2895236155Smm			    scripted);
2896236155Smm			print_one_column(ZPOOL_PROP_CAPACITY, vs->vs_alloc,
2897236155Smm			    scripted);
2898236155Smm			print_one_column(ZPOOL_PROP_FREE,
2899236155Smm			    vs->vs_space - vs->vs_alloc, scripted);
2900236155Smm		}
2901236155Smm		print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize,
2902236155Smm		    scripted);
2903236155Smm		(void) printf("\n");
2904236155Smm	}
2905236155Smm
2906236155Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2907236155Smm	    &child, &children) != 0)
2908236155Smm		return;
2909236155Smm
2910236155Smm	for (c = 0; c < children; c++) {
2911236155Smm		uint64_t ishole = B_FALSE;
2912236155Smm
2913236155Smm		if (nvlist_lookup_uint64(child[c],
2914236155Smm		    ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
2915236155Smm			continue;
2916236155Smm
2917236155Smm		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
2918236155Smm		print_list_stats(zhp, vname, child[c], cb, depth + 2);
2919236155Smm		free(vname);
2920236155Smm	}
2921236155Smm
2922236155Smm	/*
2923236155Smm	 * Include level 2 ARC devices in iostat output
2924236155Smm	 */
2925236155Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
2926236155Smm	    &child, &children) != 0)
2927236155Smm		return;
2928236155Smm
2929236155Smm	if (children > 0) {
2930236155Smm		(void) printf("%-*s      -      -      -      -      -      "
2931236155Smm		    "-\n", cb->cb_namewidth, "cache");
2932236155Smm		for (c = 0; c < children; c++) {
2933236155Smm			vname = zpool_vdev_name(g_zfs, zhp, child[c],
2934236155Smm			    B_FALSE);
2935236155Smm			print_list_stats(zhp, vname, child[c], cb, depth + 2);
2936236155Smm			free(vname);
2937236155Smm		}
2938236155Smm	}
2939236155Smm}
2940236155Smm
2941236155Smm
2942185029Spjd/*
2943185029Spjd * Generic callback function to list a pool.
2944185029Spjd */
2945185029Spjdint
2946185029Spjdlist_callback(zpool_handle_t *zhp, void *data)
2947185029Spjd{
2948185029Spjd	list_cbdata_t *cbp = data;
2949236155Smm	nvlist_t *config;
2950236155Smm	nvlist_t *nvroot;
2951168404Spjd
2952236155Smm	config = zpool_get_config(zhp, NULL);
2953168404Spjd
2954236155Smm	print_pool(zhp, cbp);
2955236155Smm	if (!cbp->cb_verbose)
2956236155Smm		return (0);
2957168404Spjd
2958236155Smm	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2959236155Smm	    &nvroot) == 0);
2960236155Smm	print_list_stats(zhp, NULL, nvroot, cbp, 0);
2961236155Smm
2962168404Spjd	return (0);
2963168404Spjd}
2964168404Spjd
2965168404Spjd/*
2966219089Spjd * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
2967168404Spjd *
2968185029Spjd *	-H	Scripted mode.  Don't display headers, and separate properties
2969185029Spjd *		by a single tab.
2970185029Spjd *	-o	List of properties to display.  Defaults to
2971219089Spjd *		"name,size,allocated,free,capacity,health,altroot"
2972219089Spjd *	-T	Display a timestamp in date(1) or Unix format
2973168404Spjd *
2974168404Spjd * List all pools in the system, whether or not they're healthy.  Output space
2975168404Spjd * statistics for each one, as well as health status summary.
2976168404Spjd */
2977168404Spjdint
2978168404Spjdzpool_do_list(int argc, char **argv)
2979168404Spjd{
2980168404Spjd	int c;
2981168404Spjd	int ret;
2982168404Spjd	list_cbdata_t cb = { 0 };
2983185029Spjd	static char default_props[] =
2984236155Smm	    "name,size,allocated,free,capacity,dedupratio,"
2985236155Smm	    "health,altroot";
2986185029Spjd	char *props = default_props;
2987219089Spjd	unsigned long interval = 0, count = 0;
2988236155Smm	zpool_list_t *list;
2989236155Smm	boolean_t first = B_TRUE;
2990168404Spjd
2991168404Spjd	/* check options */
2992236155Smm	while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) {
2993168404Spjd		switch (c) {
2994168404Spjd		case 'H':
2995168404Spjd			cb.cb_scripted = B_TRUE;
2996168404Spjd			break;
2997168404Spjd		case 'o':
2998185029Spjd			props = optarg;
2999168404Spjd			break;
3000219089Spjd		case 'T':
3001219089Spjd			get_timestamp_arg(*optarg);
3002219089Spjd			break;
3003236155Smm		case 'v':
3004236155Smm			cb.cb_verbose = B_TRUE;
3005236155Smm			break;
3006168404Spjd		case ':':
3007168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
3008168404Spjd			    "'%c' option\n"), optopt);
3009168404Spjd			usage(B_FALSE);
3010168404Spjd			break;
3011168404Spjd		case '?':
3012168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3013168404Spjd			    optopt);
3014168404Spjd			usage(B_FALSE);
3015168404Spjd		}
3016168404Spjd	}
3017168404Spjd
3018168404Spjd	argc -= optind;
3019168404Spjd	argv += optind;
3020168404Spjd
3021219089Spjd	get_interval_count(&argc, argv, &interval, &count);
3022219089Spjd
3023185029Spjd	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
3024185029Spjd		usage(B_FALSE);
3025168404Spjd
3026236155Smm	if ((list = pool_list_get(argc, argv, &cb.cb_proplist, &ret)) == NULL)
3027236155Smm		return (1);
3028168404Spjd
3029236155Smm	if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
3030236155Smm		(void) printf(gettext("no pools available\n"));
3031236155Smm		zprop_free_list(cb.cb_proplist);
3032236155Smm		return (0);
3033236155Smm	}
3034236155Smm
3035219089Spjd	for (;;) {
3036236155Smm		pool_list_update(list);
3037168404Spjd
3038236155Smm		if (pool_list_count(list) == 0)
3039236155Smm			break;
3040236155Smm
3041236155Smm		cb.cb_namewidth = 0;
3042236155Smm		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
3043236155Smm
3044219089Spjd		if (timestamp_fmt != NODATE)
3045219089Spjd			print_timestamp(timestamp_fmt);
3046168404Spjd
3047236155Smm		if (!cb.cb_scripted && (first || cb.cb_verbose)) {
3048236155Smm			print_header(&cb);
3049236155Smm			first = B_FALSE;
3050219089Spjd		}
3051236155Smm		ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
3052219089Spjd
3053219089Spjd		if (interval == 0)
3054219089Spjd			break;
3055219089Spjd
3056219089Spjd		if (count != 0 && --count == 0)
3057219089Spjd			break;
3058219089Spjd
3059219089Spjd		(void) sleep(interval);
3060168404Spjd	}
3061168404Spjd
3062219089Spjd	zprop_free_list(cb.cb_proplist);
3063168404Spjd	return (ret);
3064168404Spjd}
3065168404Spjd
3066168404Spjdstatic nvlist_t *
3067168404Spjdzpool_get_vdev_by_name(nvlist_t *nv, char *name)
3068168404Spjd{
3069168404Spjd	nvlist_t **child;
3070168404Spjd	uint_t c, children;
3071168404Spjd	nvlist_t *match;
3072168404Spjd	char *path;
3073168404Spjd
3074168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
3075168404Spjd	    &child, &children) != 0) {
3076168404Spjd		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
3077219089Spjd		if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
3078219089Spjd			name += sizeof(_PATH_DEV) - 1;
3079219089Spjd		if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
3080219089Spjd			path += sizeof(_PATH_DEV) - 1;
3081168404Spjd		if (strcmp(name, path) == 0)
3082168404Spjd			return (nv);
3083168404Spjd		return (NULL);
3084168404Spjd	}
3085168404Spjd
3086168404Spjd	for (c = 0; c < children; c++)
3087168404Spjd		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
3088168404Spjd			return (match);
3089168404Spjd
3090168404Spjd	return (NULL);
3091168404Spjd}
3092168404Spjd
3093168404Spjdstatic int
3094168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing)
3095168404Spjd{
3096168404Spjd	boolean_t force = B_FALSE;
3097168404Spjd	int c;
3098168404Spjd	nvlist_t *nvroot;
3099168404Spjd	char *poolname, *old_disk, *new_disk;
3100168404Spjd	zpool_handle_t *zhp;
3101168404Spjd	int ret;
3102168404Spjd
3103168404Spjd	/* check options */
3104168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
3105168404Spjd		switch (c) {
3106168404Spjd		case 'f':
3107168404Spjd			force = B_TRUE;
3108168404Spjd			break;
3109168404Spjd		case '?':
3110168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3111168404Spjd			    optopt);
3112168404Spjd			usage(B_FALSE);
3113168404Spjd		}
3114168404Spjd	}
3115168404Spjd
3116168404Spjd	argc -= optind;
3117168404Spjd	argv += optind;
3118168404Spjd
3119168404Spjd	/* get pool name and check number of arguments */
3120168404Spjd	if (argc < 1) {
3121168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
3122168404Spjd		usage(B_FALSE);
3123168404Spjd	}
3124168404Spjd
3125168404Spjd	poolname = argv[0];
3126168404Spjd
3127168404Spjd	if (argc < 2) {
3128168404Spjd		(void) fprintf(stderr,
3129168404Spjd		    gettext("missing <device> specification\n"));
3130168404Spjd		usage(B_FALSE);
3131168404Spjd	}
3132168404Spjd
3133168404Spjd	old_disk = argv[1];
3134168404Spjd
3135168404Spjd	if (argc < 3) {
3136168404Spjd		if (!replacing) {
3137168404Spjd			(void) fprintf(stderr,
3138168404Spjd			    gettext("missing <new_device> specification\n"));
3139168404Spjd			usage(B_FALSE);
3140168404Spjd		}
3141168404Spjd		new_disk = old_disk;
3142168404Spjd		argc -= 1;
3143168404Spjd		argv += 1;
3144168404Spjd	} else {
3145168404Spjd		new_disk = argv[2];
3146168404Spjd		argc -= 2;
3147168404Spjd		argv += 2;
3148168404Spjd	}
3149168404Spjd
3150168404Spjd	if (argc > 1) {
3151168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
3152168404Spjd		usage(B_FALSE);
3153168404Spjd	}
3154168404Spjd
3155168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3156168404Spjd		return (1);
3157168404Spjd
3158185029Spjd	if (zpool_get_config(zhp, NULL) == NULL) {
3159168404Spjd		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
3160168404Spjd		    poolname);
3161168404Spjd		zpool_close(zhp);
3162168404Spjd		return (1);
3163168404Spjd	}
3164168404Spjd
3165185029Spjd	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
3166185029Spjd	    argc, argv);
3167168404Spjd	if (nvroot == NULL) {
3168168404Spjd		zpool_close(zhp);
3169168404Spjd		return (1);
3170168404Spjd	}
3171168404Spjd
3172168404Spjd	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
3173168404Spjd
3174168404Spjd	nvlist_free(nvroot);
3175168404Spjd	zpool_close(zhp);
3176168404Spjd
3177168404Spjd	return (ret);
3178168404Spjd}
3179168404Spjd
3180168404Spjd/*
3181168404Spjd * zpool replace [-f] <pool> <device> <new_device>
3182168404Spjd *
3183168404Spjd *	-f	Force attach, even if <new_device> appears to be in use.
3184168404Spjd *
3185168404Spjd * Replace <device> with <new_device>.
3186168404Spjd */
3187168404Spjd/* ARGSUSED */
3188168404Spjdint
3189168404Spjdzpool_do_replace(int argc, char **argv)
3190168404Spjd{
3191168404Spjd	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
3192168404Spjd}
3193168404Spjd
3194168404Spjd/*
3195168404Spjd * zpool attach [-f] <pool> <device> <new_device>
3196168404Spjd *
3197168404Spjd *	-f	Force attach, even if <new_device> appears to be in use.
3198168404Spjd *
3199168404Spjd * Attach <new_device> to the mirror containing <device>.  If <device> is not
3200168404Spjd * part of a mirror, then <device> will be transformed into a mirror of
3201168404Spjd * <device> and <new_device>.  In either case, <new_device> will begin life
3202168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself.
3203168404Spjd */
3204168404Spjdint
3205168404Spjdzpool_do_attach(int argc, char **argv)
3206168404Spjd{
3207168404Spjd	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
3208168404Spjd}
3209168404Spjd
3210168404Spjd/*
3211168404Spjd * zpool detach [-f] <pool> <device>
3212168404Spjd *
3213168404Spjd *	-f	Force detach of <device>, even if DTLs argue against it
3214168404Spjd *		(not supported yet)
3215168404Spjd *
3216168404Spjd * Detach a device from a mirror.  The operation will be refused if <device>
3217168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device
3218168404Spjd * has the only valid copy of some data.
3219168404Spjd */
3220168404Spjd/* ARGSUSED */
3221168404Spjdint
3222168404Spjdzpool_do_detach(int argc, char **argv)
3223168404Spjd{
3224168404Spjd	int c;
3225168404Spjd	char *poolname, *path;
3226168404Spjd	zpool_handle_t *zhp;
3227168404Spjd	int ret;
3228168404Spjd
3229168404Spjd	/* check options */
3230168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
3231168404Spjd		switch (c) {
3232168404Spjd		case 'f':
3233168404Spjd		case '?':
3234168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3235168404Spjd			    optopt);
3236168404Spjd			usage(B_FALSE);
3237168404Spjd		}
3238168404Spjd	}
3239168404Spjd
3240168404Spjd	argc -= optind;
3241168404Spjd	argv += optind;
3242168404Spjd
3243168404Spjd	/* get pool name and check number of arguments */
3244168404Spjd	if (argc < 1) {
3245168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
3246168404Spjd		usage(B_FALSE);
3247168404Spjd	}
3248168404Spjd
3249168404Spjd	if (argc < 2) {
3250168404Spjd		(void) fprintf(stderr,
3251168404Spjd		    gettext("missing <device> specification\n"));
3252168404Spjd		usage(B_FALSE);
3253168404Spjd	}
3254168404Spjd
3255168404Spjd	poolname = argv[0];
3256168404Spjd	path = argv[1];
3257168404Spjd
3258168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3259168404Spjd		return (1);
3260168404Spjd
3261168404Spjd	ret = zpool_vdev_detach(zhp, path);
3262168404Spjd
3263168404Spjd	zpool_close(zhp);
3264168404Spjd
3265168404Spjd	return (ret);
3266168404Spjd}
3267168404Spjd
3268168404Spjd/*
3269219089Spjd * zpool split [-n] [-o prop=val] ...
3270219089Spjd *		[-o mntopt] ...
3271219089Spjd *		[-R altroot] <pool> <newpool> [<device> ...]
3272219089Spjd *
3273219089Spjd *	-n	Do not split the pool, but display the resulting layout if
3274219089Spjd *		it were to be split.
3275219089Spjd *	-o	Set property=value, or set mount options.
3276219089Spjd *	-R	Mount the split-off pool under an alternate root.
3277219089Spjd *
3278219089Spjd * Splits the named pool and gives it the new pool name.  Devices to be split
3279219089Spjd * off may be listed, provided that no more than one device is specified
3280219089Spjd * per top-level vdev mirror.  The newly split pool is left in an exported
3281219089Spjd * state unless -R is specified.
3282219089Spjd *
3283219089Spjd * Restrictions: the top-level of the pool pool must only be made up of
3284219089Spjd * mirrors; all devices in the pool must be healthy; no device may be
3285219089Spjd * undergoing a resilvering operation.
3286219089Spjd */
3287219089Spjdint
3288219089Spjdzpool_do_split(int argc, char **argv)
3289219089Spjd{
3290219089Spjd	char *srcpool, *newpool, *propval;
3291219089Spjd	char *mntopts = NULL;
3292219089Spjd	splitflags_t flags;
3293219089Spjd	int c, ret = 0;
3294219089Spjd	zpool_handle_t *zhp;
3295219089Spjd	nvlist_t *config, *props = NULL;
3296219089Spjd
3297219089Spjd	flags.dryrun = B_FALSE;
3298219089Spjd	flags.import = B_FALSE;
3299219089Spjd
3300219089Spjd	/* check options */
3301219089Spjd	while ((c = getopt(argc, argv, ":R:no:")) != -1) {
3302219089Spjd		switch (c) {
3303219089Spjd		case 'R':
3304219089Spjd			flags.import = B_TRUE;
3305219089Spjd			if (add_prop_list(
3306219089Spjd			    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
3307219089Spjd			    &props, B_TRUE) != 0) {
3308219089Spjd				if (props)
3309219089Spjd					nvlist_free(props);
3310219089Spjd				usage(B_FALSE);
3311219089Spjd			}
3312219089Spjd			break;
3313219089Spjd		case 'n':
3314219089Spjd			flags.dryrun = B_TRUE;
3315219089Spjd			break;
3316219089Spjd		case 'o':
3317219089Spjd			if ((propval = strchr(optarg, '=')) != NULL) {
3318219089Spjd				*propval = '\0';
3319219089Spjd				propval++;
3320219089Spjd				if (add_prop_list(optarg, propval,
3321219089Spjd				    &props, B_TRUE) != 0) {
3322219089Spjd					if (props)
3323219089Spjd						nvlist_free(props);
3324219089Spjd					usage(B_FALSE);
3325219089Spjd				}
3326219089Spjd			} else {
3327219089Spjd				mntopts = optarg;
3328219089Spjd			}
3329219089Spjd			break;
3330219089Spjd		case ':':
3331219089Spjd			(void) fprintf(stderr, gettext("missing argument for "
3332219089Spjd			    "'%c' option\n"), optopt);
3333219089Spjd			usage(B_FALSE);
3334219089Spjd			break;
3335219089Spjd		case '?':
3336219089Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3337219089Spjd			    optopt);
3338219089Spjd			usage(B_FALSE);
3339219089Spjd			break;
3340219089Spjd		}
3341219089Spjd	}
3342219089Spjd
3343219089Spjd	if (!flags.import && mntopts != NULL) {
3344219089Spjd		(void) fprintf(stderr, gettext("setting mntopts is only "
3345219089Spjd		    "valid when importing the pool\n"));
3346219089Spjd		usage(B_FALSE);
3347219089Spjd	}
3348219089Spjd
3349219089Spjd	argc -= optind;
3350219089Spjd	argv += optind;
3351219089Spjd
3352219089Spjd	if (argc < 1) {
3353219089Spjd		(void) fprintf(stderr, gettext("Missing pool name\n"));
3354219089Spjd		usage(B_FALSE);
3355219089Spjd	}
3356219089Spjd	if (argc < 2) {
3357219089Spjd		(void) fprintf(stderr, gettext("Missing new pool name\n"));
3358219089Spjd		usage(B_FALSE);
3359219089Spjd	}
3360219089Spjd
3361219089Spjd	srcpool = argv[0];
3362219089Spjd	newpool = argv[1];
3363219089Spjd
3364219089Spjd	argc -= 2;
3365219089Spjd	argv += 2;
3366219089Spjd
3367219089Spjd	if ((zhp = zpool_open(g_zfs, srcpool)) == NULL)
3368219089Spjd		return (1);
3369219089Spjd
3370219089Spjd	config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
3371219089Spjd	if (config == NULL) {
3372219089Spjd		ret = 1;
3373219089Spjd	} else {
3374219089Spjd		if (flags.dryrun) {
3375219089Spjd			(void) printf(gettext("would create '%s' with the "
3376219089Spjd			    "following layout:\n\n"), newpool);
3377219089Spjd			print_vdev_tree(NULL, newpool, config, 0, B_FALSE);
3378219089Spjd		}
3379219089Spjd		nvlist_free(config);
3380219089Spjd	}
3381219089Spjd
3382219089Spjd	zpool_close(zhp);
3383219089Spjd
3384219089Spjd	if (ret != 0 || flags.dryrun || !flags.import)
3385219089Spjd		return (ret);
3386219089Spjd
3387219089Spjd	/*
3388219089Spjd	 * The split was successful. Now we need to open the new
3389219089Spjd	 * pool and import it.
3390219089Spjd	 */
3391219089Spjd	if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
3392219089Spjd		return (1);
3393219089Spjd	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
3394219089Spjd	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
3395219089Spjd		ret = 1;
3396219089Spjd		(void) fprintf(stderr, gettext("Split was succssful, but "
3397219089Spjd		    "the datasets could not all be mounted\n"));
3398219089Spjd		(void) fprintf(stderr, gettext("Try doing '%s' with a "
3399219089Spjd		    "different altroot\n"), "zpool import");
3400219089Spjd	}
3401219089Spjd	zpool_close(zhp);
3402219089Spjd
3403219089Spjd	return (ret);
3404219089Spjd}
3405219089Spjd
3406219089Spjd
3407219089Spjd
3408219089Spjd/*
3409168404Spjd * zpool online <pool> <device> ...
3410168404Spjd */
3411168404Spjdint
3412168404Spjdzpool_do_online(int argc, char **argv)
3413168404Spjd{
3414168404Spjd	int c, i;
3415168404Spjd	char *poolname;
3416168404Spjd	zpool_handle_t *zhp;
3417168404Spjd	int ret = 0;
3418185029Spjd	vdev_state_t newstate;
3419219089Spjd	int flags = 0;
3420168404Spjd
3421168404Spjd	/* check options */
3422219089Spjd	while ((c = getopt(argc, argv, "et")) != -1) {
3423168404Spjd		switch (c) {
3424219089Spjd		case 'e':
3425219089Spjd			flags |= ZFS_ONLINE_EXPAND;
3426219089Spjd			break;
3427168404Spjd		case 't':
3428168404Spjd		case '?':
3429168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3430168404Spjd			    optopt);
3431168404Spjd			usage(B_FALSE);
3432168404Spjd		}
3433168404Spjd	}
3434168404Spjd
3435168404Spjd	argc -= optind;
3436168404Spjd	argv += optind;
3437168404Spjd
3438168404Spjd	/* get pool name and check number of arguments */
3439168404Spjd	if (argc < 1) {
3440168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
3441168404Spjd		usage(B_FALSE);
3442168404Spjd	}
3443168404Spjd	if (argc < 2) {
3444168404Spjd		(void) fprintf(stderr, gettext("missing device name\n"));
3445168404Spjd		usage(B_FALSE);
3446168404Spjd	}
3447168404Spjd
3448168404Spjd	poolname = argv[0];
3449168404Spjd
3450168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3451168404Spjd		return (1);
3452168404Spjd
3453185029Spjd	for (i = 1; i < argc; i++) {
3454219089Spjd		if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
3455185029Spjd			if (newstate != VDEV_STATE_HEALTHY) {
3456185029Spjd				(void) printf(gettext("warning: device '%s' "
3457185029Spjd				    "onlined, but remains in faulted state\n"),
3458185029Spjd				    argv[i]);
3459185029Spjd				if (newstate == VDEV_STATE_FAULTED)
3460185029Spjd					(void) printf(gettext("use 'zpool "
3461185029Spjd					    "clear' to restore a faulted "
3462185029Spjd					    "device\n"));
3463185029Spjd				else
3464185029Spjd					(void) printf(gettext("use 'zpool "
3465185029Spjd					    "replace' to replace devices "
3466185029Spjd					    "that are no longer present\n"));
3467185029Spjd			}
3468185029Spjd		} else {
3469168404Spjd			ret = 1;
3470185029Spjd		}
3471185029Spjd	}
3472168404Spjd
3473168404Spjd	zpool_close(zhp);
3474168404Spjd
3475168404Spjd	return (ret);
3476168404Spjd}
3477168404Spjd
3478168404Spjd/*
3479168404Spjd * zpool offline [-ft] <pool> <device> ...
3480168404Spjd *
3481168404Spjd *	-f	Force the device into the offline state, even if doing
3482168404Spjd *		so would appear to compromise pool availability.
3483168404Spjd *		(not supported yet)
3484168404Spjd *
3485168404Spjd *	-t	Only take the device off-line temporarily.  The offline
3486168404Spjd *		state will not be persistent across reboots.
3487168404Spjd */
3488168404Spjd/* ARGSUSED */
3489168404Spjdint
3490168404Spjdzpool_do_offline(int argc, char **argv)
3491168404Spjd{
3492168404Spjd	int c, i;
3493168404Spjd	char *poolname;
3494168404Spjd	zpool_handle_t *zhp;
3495168404Spjd	int ret = 0;
3496168404Spjd	boolean_t istmp = B_FALSE;
3497168404Spjd
3498168404Spjd	/* check options */
3499168404Spjd	while ((c = getopt(argc, argv, "ft")) != -1) {
3500168404Spjd		switch (c) {
3501168404Spjd		case 't':
3502168404Spjd			istmp = B_TRUE;
3503168404Spjd			break;
3504168404Spjd		case 'f':
3505168404Spjd		case '?':
3506168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3507168404Spjd			    optopt);
3508168404Spjd			usage(B_FALSE);
3509168404Spjd		}
3510168404Spjd	}
3511168404Spjd
3512168404Spjd	argc -= optind;
3513168404Spjd	argv += optind;
3514168404Spjd
3515168404Spjd	/* get pool name and check number of arguments */
3516168404Spjd	if (argc < 1) {
3517168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
3518168404Spjd		usage(B_FALSE);
3519168404Spjd	}
3520168404Spjd	if (argc < 2) {
3521168404Spjd		(void) fprintf(stderr, gettext("missing device name\n"));
3522168404Spjd		usage(B_FALSE);
3523168404Spjd	}
3524168404Spjd
3525168404Spjd	poolname = argv[0];
3526168404Spjd
3527168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3528168404Spjd		return (1);
3529168404Spjd
3530185029Spjd	for (i = 1; i < argc; i++) {
3531185029Spjd		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
3532168404Spjd			ret = 1;
3533185029Spjd	}
3534168404Spjd
3535168404Spjd	zpool_close(zhp);
3536168404Spjd
3537168404Spjd	return (ret);
3538168404Spjd}
3539168404Spjd
3540168404Spjd/*
3541168404Spjd * zpool clear <pool> [device]
3542168404Spjd *
3543168404Spjd * Clear all errors associated with a pool or a particular device.
3544168404Spjd */
3545168404Spjdint
3546168404Spjdzpool_do_clear(int argc, char **argv)
3547168404Spjd{
3548219089Spjd	int c;
3549168404Spjd	int ret = 0;
3550219089Spjd	boolean_t dryrun = B_FALSE;
3551219089Spjd	boolean_t do_rewind = B_FALSE;
3552219089Spjd	boolean_t xtreme_rewind = B_FALSE;
3553219089Spjd	uint32_t rewind_policy = ZPOOL_NO_REWIND;
3554219089Spjd	nvlist_t *policy = NULL;
3555168404Spjd	zpool_handle_t *zhp;
3556168404Spjd	char *pool, *device;
3557168404Spjd
3558219089Spjd	/* check options */
3559219089Spjd	while ((c = getopt(argc, argv, "FnX")) != -1) {
3560219089Spjd		switch (c) {
3561219089Spjd		case 'F':
3562219089Spjd			do_rewind = B_TRUE;
3563219089Spjd			break;
3564219089Spjd		case 'n':
3565219089Spjd			dryrun = B_TRUE;
3566219089Spjd			break;
3567219089Spjd		case 'X':
3568219089Spjd			xtreme_rewind = B_TRUE;
3569219089Spjd			break;
3570219089Spjd		case '?':
3571219089Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3572219089Spjd			    optopt);
3573219089Spjd			usage(B_FALSE);
3574219089Spjd		}
3575219089Spjd	}
3576219089Spjd
3577219089Spjd	argc -= optind;
3578219089Spjd	argv += optind;
3579219089Spjd
3580219089Spjd	if (argc < 1) {
3581168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
3582168404Spjd		usage(B_FALSE);
3583168404Spjd	}
3584168404Spjd
3585219089Spjd	if (argc > 2) {
3586168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
3587168404Spjd		usage(B_FALSE);
3588168404Spjd	}
3589168404Spjd
3590219089Spjd	if ((dryrun || xtreme_rewind) && !do_rewind) {
3591219089Spjd		(void) fprintf(stderr,
3592219089Spjd		    gettext("-n or -X only meaningful with -F\n"));
3593219089Spjd		usage(B_FALSE);
3594219089Spjd	}
3595219089Spjd	if (dryrun)
3596219089Spjd		rewind_policy = ZPOOL_TRY_REWIND;
3597219089Spjd	else if (do_rewind)
3598219089Spjd		rewind_policy = ZPOOL_DO_REWIND;
3599219089Spjd	if (xtreme_rewind)
3600219089Spjd		rewind_policy |= ZPOOL_EXTREME_REWIND;
3601168404Spjd
3602219089Spjd	/* In future, further rewind policy choices can be passed along here */
3603219089Spjd	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
3604219089Spjd	    nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
3605168404Spjd		return (1);
3606168404Spjd
3607219089Spjd	pool = argv[0];
3608219089Spjd	device = argc == 2 ? argv[1] : NULL;
3609219089Spjd
3610219089Spjd	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
3611219089Spjd		nvlist_free(policy);
3612219089Spjd		return (1);
3613219089Spjd	}
3614219089Spjd
3615219089Spjd	if (zpool_clear(zhp, device, policy) != 0)
3616168404Spjd		ret = 1;
3617168404Spjd
3618168404Spjd	zpool_close(zhp);
3619168404Spjd
3620219089Spjd	nvlist_free(policy);
3621219089Spjd
3622168404Spjd	return (ret);
3623168404Spjd}
3624168404Spjd
3625228103Smm/*
3626228103Smm * zpool reguid <pool>
3627228103Smm */
3628228103Smmint
3629228103Smmzpool_do_reguid(int argc, char **argv)
3630228103Smm{
3631228103Smm	int c;
3632228103Smm	char *poolname;
3633228103Smm	zpool_handle_t *zhp;
3634228103Smm	int ret = 0;
3635228103Smm
3636228103Smm	/* check options */
3637228103Smm	while ((c = getopt(argc, argv, "")) != -1) {
3638228103Smm		switch (c) {
3639228103Smm		case '?':
3640228103Smm			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3641228103Smm			    optopt);
3642228103Smm			usage(B_FALSE);
3643228103Smm		}
3644228103Smm	}
3645228103Smm
3646228103Smm	argc -= optind;
3647228103Smm	argv += optind;
3648228103Smm
3649228103Smm	/* get pool name and check number of arguments */
3650228103Smm	if (argc < 1) {
3651228103Smm		(void) fprintf(stderr, gettext("missing pool name\n"));
3652228103Smm		usage(B_FALSE);
3653228103Smm	}
3654228103Smm
3655228103Smm	if (argc > 1) {
3656228103Smm		(void) fprintf(stderr, gettext("too many arguments\n"));
3657228103Smm		usage(B_FALSE);
3658228103Smm	}
3659228103Smm
3660228103Smm	poolname = argv[0];
3661228103Smm	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3662228103Smm		return (1);
3663228103Smm
3664228103Smm	ret = zpool_reguid(zhp);
3665228103Smm
3666228103Smm	zpool_close(zhp);
3667228103Smm	return (ret);
3668228103Smm}
3669228103Smm
3670228103Smm
3671236155Smm/*
3672236155Smm * zpool reopen <pool>
3673236155Smm *
3674236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs.
3675236155Smm *
3676236155Smm * NOTE: This command is currently undocumented.  If the command is ever
3677236155Smm * exposed then the appropriate usage() messages will need to be made.
3678236155Smm */
3679236155Smmint
3680236155Smmzpool_do_reopen(int argc, char **argv)
3681236155Smm{
3682236155Smm	int ret = 0;
3683236155Smm	zpool_handle_t *zhp;
3684236155Smm	char *pool;
3685236155Smm
3686236155Smm	argc--;
3687236155Smm	argv++;
3688236155Smm
3689236155Smm	if (argc != 1)
3690236155Smm		return (2);
3691236155Smm
3692236155Smm	pool = argv[0];
3693236155Smm	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
3694236155Smm		return (1);
3695236155Smm
3696236155Smm	ret = zpool_reopen(zhp);
3697236155Smm	zpool_close(zhp);
3698236155Smm	return (ret);
3699236155Smm}
3700236155Smm
3701168404Spjdtypedef struct scrub_cbdata {
3702168404Spjd	int	cb_type;
3703168404Spjd	int	cb_argc;
3704168404Spjd	char	**cb_argv;
3705168404Spjd} scrub_cbdata_t;
3706168404Spjd
3707168404Spjdint
3708168404Spjdscrub_callback(zpool_handle_t *zhp, void *data)
3709168404Spjd{
3710168404Spjd	scrub_cbdata_t *cb = data;
3711168404Spjd	int err;
3712168404Spjd
3713168404Spjd	/*
3714168404Spjd	 * Ignore faulted pools.
3715168404Spjd	 */
3716168404Spjd	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
3717168404Spjd		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
3718168404Spjd		    "currently unavailable\n"), zpool_get_name(zhp));
3719168404Spjd		return (1);
3720168404Spjd	}
3721168404Spjd
3722219089Spjd	err = zpool_scan(zhp, cb->cb_type);
3723168404Spjd
3724168404Spjd	return (err != 0);
3725168404Spjd}
3726168404Spjd
3727168404Spjd/*
3728168404Spjd * zpool scrub [-s] <pool> ...
3729168404Spjd *
3730168404Spjd *	-s	Stop.  Stops any in-progress scrub.
3731168404Spjd */
3732168404Spjdint
3733168404Spjdzpool_do_scrub(int argc, char **argv)
3734168404Spjd{
3735168404Spjd	int c;
3736168404Spjd	scrub_cbdata_t cb;
3737168404Spjd
3738219089Spjd	cb.cb_type = POOL_SCAN_SCRUB;
3739168404Spjd
3740168404Spjd	/* check options */
3741168404Spjd	while ((c = getopt(argc, argv, "s")) != -1) {
3742168404Spjd		switch (c) {
3743168404Spjd		case 's':
3744219089Spjd			cb.cb_type = POOL_SCAN_NONE;
3745168404Spjd			break;
3746168404Spjd		case '?':
3747168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3748168404Spjd			    optopt);
3749168404Spjd			usage(B_FALSE);
3750168404Spjd		}
3751168404Spjd	}
3752168404Spjd
3753168404Spjd	cb.cb_argc = argc;
3754168404Spjd	cb.cb_argv = argv;
3755168404Spjd	argc -= optind;
3756168404Spjd	argv += optind;
3757168404Spjd
3758168404Spjd	if (argc < 1) {
3759168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
3760168404Spjd		usage(B_FALSE);
3761168404Spjd	}
3762168404Spjd
3763168404Spjd	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
3764168404Spjd}
3765168404Spjd
3766168404Spjdtypedef struct status_cbdata {
3767168404Spjd	int		cb_count;
3768168404Spjd	boolean_t	cb_allpools;
3769168404Spjd	boolean_t	cb_verbose;
3770168404Spjd	boolean_t	cb_explain;
3771168404Spjd	boolean_t	cb_first;
3772219089Spjd	boolean_t	cb_dedup_stats;
3773168404Spjd} status_cbdata_t;
3774168404Spjd
3775168404Spjd/*
3776168404Spjd * Print out detailed scrub status.
3777168404Spjd */
3778168404Spjdvoid
3779219089Spjdprint_scan_status(pool_scan_stat_t *ps)
3780168404Spjd{
3781219089Spjd	time_t start, end;
3782219089Spjd	uint64_t elapsed, mins_left, hours_left;
3783219089Spjd	uint64_t pass_exam, examined, total;
3784219089Spjd	uint_t rate;
3785168404Spjd	double fraction_done;
3786219089Spjd	char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
3787168404Spjd
3788226583Spjd	(void) printf(gettext("  scan: "));
3789168404Spjd
3790219089Spjd	/* If there's never been a scan, there's not much to say. */
3791219089Spjd	if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
3792219089Spjd	    ps->pss_func >= POOL_SCAN_FUNCS) {
3793168404Spjd		(void) printf(gettext("none requested\n"));
3794168404Spjd		return;
3795168404Spjd	}
3796168404Spjd
3797219089Spjd	start = ps->pss_start_time;
3798219089Spjd	end = ps->pss_end_time;
3799219089Spjd	zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
3800168404Spjd
3801219089Spjd	assert(ps->pss_func == POOL_SCAN_SCRUB ||
3802219089Spjd	    ps->pss_func == POOL_SCAN_RESILVER);
3803219089Spjd	/*
3804219089Spjd	 * Scan is finished or canceled.
3805219089Spjd	 */
3806219089Spjd	if (ps->pss_state == DSS_FINISHED) {
3807219089Spjd		uint64_t minutes_taken = (end - start) / 60;
3808219089Spjd		char *fmt;
3809168404Spjd
3810219089Spjd		if (ps->pss_func == POOL_SCAN_SCRUB) {
3811219089Spjd			fmt = gettext("scrub repaired %s in %lluh%um with "
3812219089Spjd			    "%llu errors on %s");
3813219089Spjd		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
3814219089Spjd			fmt = gettext("resilvered %s in %lluh%um with "
3815219089Spjd			    "%llu errors on %s");
3816219089Spjd		}
3817219089Spjd		/* LINTED */
3818219089Spjd		(void) printf(fmt, processed_buf,
3819185029Spjd		    (u_longlong_t)(minutes_taken / 60),
3820185029Spjd		    (uint_t)(minutes_taken % 60),
3821219089Spjd		    (u_longlong_t)ps->pss_errors,
3822219089Spjd		    ctime((time_t *)&end));
3823168404Spjd		return;
3824219089Spjd	} else if (ps->pss_state == DSS_CANCELED) {
3825219089Spjd		if (ps->pss_func == POOL_SCAN_SCRUB) {
3826219089Spjd			(void) printf(gettext("scrub canceled on %s"),
3827219089Spjd			    ctime(&end));
3828219089Spjd		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
3829219089Spjd			(void) printf(gettext("resilver canceled on %s"),
3830219089Spjd			    ctime(&end));
3831219089Spjd		}
3832219089Spjd		return;
3833168404Spjd	}
3834168404Spjd
3835219089Spjd	assert(ps->pss_state == DSS_SCANNING);
3836168404Spjd
3837219089Spjd	/*
3838219089Spjd	 * Scan is in progress.
3839219089Spjd	 */
3840219089Spjd	if (ps->pss_func == POOL_SCAN_SCRUB) {
3841219089Spjd		(void) printf(gettext("scrub in progress since %s"),
3842219089Spjd		    ctime(&start));
3843219089Spjd	} else if (ps->pss_func == POOL_SCAN_RESILVER) {
3844219089Spjd		(void) printf(gettext("resilver in progress since %s"),
3845219089Spjd		    ctime(&start));
3846219089Spjd	}
3847219089Spjd
3848219089Spjd	examined = ps->pss_examined ? ps->pss_examined : 1;
3849219089Spjd	total = ps->pss_to_examine;
3850168404Spjd	fraction_done = (double)examined / total;
3851168404Spjd
3852219089Spjd	/* elapsed time for this pass */
3853219089Spjd	elapsed = time(NULL) - ps->pss_pass_start;
3854219089Spjd	elapsed = elapsed ? elapsed : 1;
3855219089Spjd	pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1;
3856219089Spjd	rate = pass_exam / elapsed;
3857219089Spjd	rate = rate ? rate : 1;
3858219089Spjd	mins_left = ((total - examined) / rate) / 60;
3859219089Spjd	hours_left = mins_left / 60;
3860219089Spjd
3861219089Spjd	zfs_nicenum(examined, examined_buf, sizeof (examined_buf));
3862219089Spjd	zfs_nicenum(total, total_buf, sizeof (total_buf));
3863219089Spjd	zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
3864219089Spjd
3865219089Spjd	/*
3866219089Spjd	 * do not print estimated time if hours_left is more than 30 days
3867219089Spjd	 */
3868226583Spjd	(void) printf(gettext("        %s scanned out of %s at %s/s"),
3869219089Spjd	    examined_buf, total_buf, rate_buf);
3870219089Spjd	if (hours_left < (30 * 24)) {
3871219089Spjd		(void) printf(gettext(", %lluh%um to go\n"),
3872219089Spjd		    (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
3873219089Spjd	} else {
3874219089Spjd		(void) printf(gettext(
3875219089Spjd		    ", (scan is slow, no estimated time)\n"));
3876219089Spjd	}
3877219089Spjd
3878219089Spjd	if (ps->pss_func == POOL_SCAN_RESILVER) {
3879226583Spjd		(void) printf(gettext("        %s resilvered, %.2f%% done\n"),
3880219089Spjd		    processed_buf, 100 * fraction_done);
3881219089Spjd	} else if (ps->pss_func == POOL_SCAN_SCRUB) {
3882226583Spjd		(void) printf(gettext("        %s repaired, %.2f%% done\n"),
3883219089Spjd		    processed_buf, 100 * fraction_done);
3884219089Spjd	}
3885168404Spjd}
3886168404Spjd
3887168404Spjdstatic void
3888168404Spjdprint_error_log(zpool_handle_t *zhp)
3889168404Spjd{
3890185029Spjd	nvlist_t *nverrlist = NULL;
3891168404Spjd	nvpair_t *elem;
3892168404Spjd	char *pathname;
3893168404Spjd	size_t len = MAXPATHLEN * 2;
3894168404Spjd
3895168404Spjd	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
3896168404Spjd		(void) printf("errors: List of errors unavailable "
3897168404Spjd		    "(insufficient privileges)\n");
3898168404Spjd		return;
3899168404Spjd	}
3900168404Spjd
3901168404Spjd	(void) printf("errors: Permanent errors have been "
3902168404Spjd	    "detected in the following files:\n\n");
3903168404Spjd
3904168404Spjd	pathname = safe_malloc(len);
3905168404Spjd	elem = NULL;
3906168404Spjd	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
3907168404Spjd		nvlist_t *nv;
3908168404Spjd		uint64_t dsobj, obj;
3909168404Spjd
3910168404Spjd		verify(nvpair_value_nvlist(elem, &nv) == 0);
3911168404Spjd		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
3912168404Spjd		    &dsobj) == 0);
3913168404Spjd		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
3914168404Spjd		    &obj) == 0);
3915168404Spjd		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
3916168404Spjd		(void) printf("%7s %s\n", "", pathname);
3917168404Spjd	}
3918168404Spjd	free(pathname);
3919168404Spjd	nvlist_free(nverrlist);
3920168404Spjd}
3921168404Spjd
3922168404Spjdstatic void
3923168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
3924168404Spjd    int namewidth)
3925168404Spjd{
3926168404Spjd	uint_t i;
3927168404Spjd	char *name;
3928168404Spjd
3929168404Spjd	if (nspares == 0)
3930168404Spjd		return;
3931168404Spjd
3932168404Spjd	(void) printf(gettext("\tspares\n"));
3933168404Spjd
3934168404Spjd	for (i = 0; i < nspares; i++) {
3935219089Spjd		name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE);
3936168404Spjd		print_status_config(zhp, name, spares[i],
3937209962Smm		    namewidth, 2, B_TRUE);
3938168404Spjd		free(name);
3939168404Spjd	}
3940168404Spjd}
3941168404Spjd
3942185029Spjdstatic void
3943185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
3944185029Spjd    int namewidth)
3945185029Spjd{
3946185029Spjd	uint_t i;
3947185029Spjd	char *name;
3948185029Spjd
3949185029Spjd	if (nl2cache == 0)
3950185029Spjd		return;
3951185029Spjd
3952185029Spjd	(void) printf(gettext("\tcache\n"));
3953185029Spjd
3954185029Spjd	for (i = 0; i < nl2cache; i++) {
3955219089Spjd		name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE);
3956185029Spjd		print_status_config(zhp, name, l2cache[i],
3957209962Smm		    namewidth, 2, B_FALSE);
3958185029Spjd		free(name);
3959185029Spjd	}
3960185029Spjd}
3961185029Spjd
3962219089Spjdstatic void
3963219089Spjdprint_dedup_stats(nvlist_t *config)
3964219089Spjd{
3965219089Spjd	ddt_histogram_t *ddh;
3966219089Spjd	ddt_stat_t *dds;
3967219089Spjd	ddt_object_t *ddo;
3968219089Spjd	uint_t c;
3969219089Spjd
3970219089Spjd	/*
3971219089Spjd	 * If the pool was faulted then we may not have been able to
3972219089Spjd	 * obtain the config. Otherwise, if have anything in the dedup
3973219089Spjd	 * table continue processing the stats.
3974219089Spjd	 */
3975219089Spjd	if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
3976227497Smm	    (uint64_t **)&ddo, &c) != 0)
3977219089Spjd		return;
3978219089Spjd
3979219089Spjd	(void) printf("\n");
3980227497Smm	(void) printf(gettext(" dedup: "));
3981227497Smm	if (ddo->ddo_count == 0) {
3982227497Smm		(void) printf(gettext("no DDT entries\n"));
3983227497Smm		return;
3984227497Smm	}
3985227497Smm
3986219089Spjd	(void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
3987219089Spjd	    (u_longlong_t)ddo->ddo_count,
3988219089Spjd	    (u_longlong_t)ddo->ddo_dspace,
3989219089Spjd	    (u_longlong_t)ddo->ddo_mspace);
3990219089Spjd
3991219089Spjd	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
3992219089Spjd	    (uint64_t **)&dds, &c) == 0);
3993219089Spjd	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
3994219089Spjd	    (uint64_t **)&ddh, &c) == 0);
3995219089Spjd	zpool_dump_ddt(dds, ddh);
3996219089Spjd}
3997219089Spjd
3998168404Spjd/*
3999168404Spjd * Display a summary of pool status.  Displays a summary such as:
4000168404Spjd *
4001168404Spjd *        pool: tank
4002168404Spjd *	status: DEGRADED
4003168404Spjd *	reason: One or more devices ...
4004236146Smm *         see: http://illumos.org/msg/ZFS-xxxx-01
4005168404Spjd *	config:
4006168404Spjd *		mirror		DEGRADED
4007168404Spjd *                c1t0d0	OK
4008168404Spjd *                c2t0d0	UNAVAIL
4009168404Spjd *
4010168404Spjd * When given the '-v' option, we print out the complete config.  If the '-e'
4011168404Spjd * option is specified, then we print out error rate information as well.
4012168404Spjd */
4013168404Spjdint
4014168404Spjdstatus_callback(zpool_handle_t *zhp, void *data)
4015168404Spjd{
4016168404Spjd	status_cbdata_t *cbp = data;
4017168404Spjd	nvlist_t *config, *nvroot;
4018168404Spjd	char *msgid;
4019168404Spjd	int reason;
4020168404Spjd	const char *health;
4021168404Spjd	uint_t c;
4022168404Spjd	vdev_stat_t *vs;
4023168404Spjd
4024168404Spjd	config = zpool_get_config(zhp, NULL);
4025168404Spjd	reason = zpool_get_status(zhp, &msgid);
4026168404Spjd
4027168404Spjd	cbp->cb_count++;
4028168404Spjd
4029168404Spjd	/*
4030168404Spjd	 * If we were given 'zpool status -x', only report those pools with
4031168404Spjd	 * problems.
4032168404Spjd	 */
4033168404Spjd	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
4034168404Spjd		if (!cbp->cb_allpools) {
4035168404Spjd			(void) printf(gettext("pool '%s' is healthy\n"),
4036168404Spjd			    zpool_get_name(zhp));
4037168404Spjd			if (cbp->cb_first)
4038168404Spjd				cbp->cb_first = B_FALSE;
4039168404Spjd		}
4040168404Spjd		return (0);
4041168404Spjd	}
4042168404Spjd
4043168404Spjd	if (cbp->cb_first)
4044168404Spjd		cbp->cb_first = B_FALSE;
4045168404Spjd	else
4046168404Spjd		(void) printf("\n");
4047168404Spjd
4048168404Spjd	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
4049168404Spjd	    &nvroot) == 0);
4050219089Spjd	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
4051168404Spjd	    (uint64_t **)&vs, &c) == 0);
4052185029Spjd	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
4053168404Spjd
4054168404Spjd	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
4055168404Spjd	(void) printf(gettext(" state: %s\n"), health);
4056168404Spjd
4057168404Spjd	switch (reason) {
4058168404Spjd	case ZPOOL_STATUS_MISSING_DEV_R:
4059168404Spjd		(void) printf(gettext("status: One or more devices could not "
4060168404Spjd		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
4061168404Spjd		    "continue functioning in a degraded state.\n"));
4062168404Spjd		(void) printf(gettext("action: Attach the missing device and "
4063168404Spjd		    "online it using 'zpool online'.\n"));
4064168404Spjd		break;
4065168404Spjd
4066168404Spjd	case ZPOOL_STATUS_MISSING_DEV_NR:
4067168404Spjd		(void) printf(gettext("status: One or more devices could not "
4068168404Spjd		    "be opened.  There are insufficient\n\treplicas for the "
4069168404Spjd		    "pool to continue functioning.\n"));
4070168404Spjd		(void) printf(gettext("action: Attach the missing device and "
4071168404Spjd		    "online it using 'zpool online'.\n"));
4072168404Spjd		break;
4073168404Spjd
4074168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_R:
4075168404Spjd		(void) printf(gettext("status: One or more devices could not "
4076168404Spjd		    "be used because the label is missing or\n\tinvalid.  "
4077168404Spjd		    "Sufficient replicas exist for the pool to continue\n\t"
4078168404Spjd		    "functioning in a degraded state.\n"));
4079168404Spjd		(void) printf(gettext("action: Replace the device using "
4080168404Spjd		    "'zpool replace'.\n"));
4081168404Spjd		break;
4082168404Spjd
4083168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
4084168404Spjd		(void) printf(gettext("status: One or more devices could not "
4085168404Spjd		    "be used because the label is missing \n\tor invalid.  "
4086168404Spjd		    "There are insufficient replicas for the pool to "
4087168404Spjd		    "continue\n\tfunctioning.\n"));
4088219089Spjd		zpool_explain_recover(zpool_get_handle(zhp),
4089219089Spjd		    zpool_get_name(zhp), reason, config);
4090168404Spjd		break;
4091168404Spjd
4092168404Spjd	case ZPOOL_STATUS_FAILING_DEV:
4093168404Spjd		(void) printf(gettext("status: One or more devices has "
4094168404Spjd		    "experienced an unrecoverable error.  An\n\tattempt was "
4095168404Spjd		    "made to correct the error.  Applications are "
4096168404Spjd		    "unaffected.\n"));
4097168404Spjd		(void) printf(gettext("action: Determine if the device needs "
4098168404Spjd		    "to be replaced, and clear the errors\n\tusing "
4099168404Spjd		    "'zpool clear' or replace the device with 'zpool "
4100168404Spjd		    "replace'.\n"));
4101168404Spjd		break;
4102168404Spjd
4103168404Spjd	case ZPOOL_STATUS_OFFLINE_DEV:
4104168404Spjd		(void) printf(gettext("status: One or more devices has "
4105168404Spjd		    "been taken offline by the administrator.\n\tSufficient "
4106168404Spjd		    "replicas exist for the pool to continue functioning in "
4107168404Spjd		    "a\n\tdegraded state.\n"));
4108168404Spjd		(void) printf(gettext("action: Online the device using "
4109168404Spjd		    "'zpool online' or replace the device with\n\t'zpool "
4110168404Spjd		    "replace'.\n"));
4111168404Spjd		break;
4112168404Spjd
4113219089Spjd	case ZPOOL_STATUS_REMOVED_DEV:
4114219089Spjd		(void) printf(gettext("status: One or more devices has "
4115219089Spjd		    "been removed by the administrator.\n\tSufficient "
4116219089Spjd		    "replicas exist for the pool to continue functioning in "
4117219089Spjd		    "a\n\tdegraded state.\n"));
4118219089Spjd		(void) printf(gettext("action: Online the device using "
4119219089Spjd		    "'zpool online' or replace the device with\n\t'zpool "
4120219089Spjd		    "replace'.\n"));
4121219089Spjd		break;
4122219089Spjd
4123168404Spjd	case ZPOOL_STATUS_RESILVERING:
4124168404Spjd		(void) printf(gettext("status: One or more devices is "
4125168404Spjd		    "currently being resilvered.  The pool will\n\tcontinue "
4126168404Spjd		    "to function, possibly in a degraded state.\n"));
4127168404Spjd		(void) printf(gettext("action: Wait for the resilver to "
4128168404Spjd		    "complete.\n"));
4129168404Spjd		break;
4130168404Spjd
4131168404Spjd	case ZPOOL_STATUS_CORRUPT_DATA:
4132168404Spjd		(void) printf(gettext("status: One or more devices has "
4133168404Spjd		    "experienced an error resulting in data\n\tcorruption.  "
4134168404Spjd		    "Applications may be affected.\n"));
4135168404Spjd		(void) printf(gettext("action: Restore the file in question "
4136168404Spjd		    "if possible.  Otherwise restore the\n\tentire pool from "
4137168404Spjd		    "backup.\n"));
4138168404Spjd		break;
4139168404Spjd
4140168404Spjd	case ZPOOL_STATUS_CORRUPT_POOL:
4141168404Spjd		(void) printf(gettext("status: The pool metadata is corrupted "
4142168404Spjd		    "and the pool cannot be opened.\n"));
4143219089Spjd		zpool_explain_recover(zpool_get_handle(zhp),
4144219089Spjd		    zpool_get_name(zhp), reason, config);
4145168404Spjd		break;
4146168404Spjd
4147168404Spjd	case ZPOOL_STATUS_VERSION_OLDER:
4148238926Smm		(void) printf(gettext("status: The pool is formatted using a "
4149238926Smm		    "legacy on-disk format.  The pool can\n\tstill be used, "
4150238926Smm		    "but some features are unavailable.\n"));
4151168404Spjd		(void) printf(gettext("action: Upgrade the pool using 'zpool "
4152168404Spjd		    "upgrade'.  Once this is done, the\n\tpool will no longer "
4153238926Smm		    "be accessible on software that does not support feature\n"
4154238926Smm		    "\tflags.\n"));
4155168404Spjd		break;
4156168404Spjd
4157168404Spjd	case ZPOOL_STATUS_VERSION_NEWER:
4158168404Spjd		(void) printf(gettext("status: The pool has been upgraded to a "
4159168404Spjd		    "newer, incompatible on-disk version.\n\tThe pool cannot "
4160168404Spjd		    "be accessed on this system.\n"));
4161168404Spjd		(void) printf(gettext("action: Access the pool from a system "
4162168404Spjd		    "running more recent software, or\n\trestore the pool from "
4163168404Spjd		    "backup.\n"));
4164168404Spjd		break;
4165168404Spjd
4166238926Smm	case ZPOOL_STATUS_FEAT_DISABLED:
4167238926Smm		(void) printf(gettext("status: Some supported features are not "
4168238926Smm		    "enabled on the pool. The pool can\n\tstill be used, but "
4169238926Smm		    "some features are unavailable.\n"));
4170238926Smm		(void) printf(gettext("action: Enable all features using "
4171238926Smm		    "'zpool upgrade'. Once this is done,\n\tthe pool may no "
4172238926Smm		    "longer be accessible by software that does not support\n\t"
4173238926Smm		    "the features. See zpool-features(5) for details.\n"));
4174238926Smm		break;
4175238926Smm
4176236884Smm	case ZPOOL_STATUS_UNSUP_FEAT_READ:
4177236884Smm		(void) printf(gettext("status: The pool cannot be accessed on "
4178236884Smm		    "this system because it uses the\n\tfollowing feature(s) "
4179236884Smm		    "not supported on this system:\n"));
4180236884Smm		zpool_print_unsup_feat(config);
4181236884Smm		(void) printf("\n");
4182236884Smm		(void) printf(gettext("action: Access the pool from a system "
4183236884Smm		    "that supports the required feature(s),\n\tor restore the "
4184236884Smm		    "pool from backup.\n"));
4185236884Smm		break;
4186236884Smm
4187236884Smm	case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
4188236884Smm		(void) printf(gettext("status: The pool can only be accessed "
4189236884Smm		    "in read-only mode on this system. It\n\tcannot be "
4190236884Smm		    "accessed in read-write mode because it uses the "
4191236884Smm		    "following\n\tfeature(s) not supported on this system:\n"));
4192236884Smm		zpool_print_unsup_feat(config);
4193236884Smm		(void) printf("\n");
4194236884Smm		(void) printf(gettext("action: The pool cannot be accessed in "
4195236884Smm		    "read-write mode. Import the pool with\n"
4196236884Smm		    "\t\"-o readonly=on\", access the pool from a system that "
4197236884Smm		    "supports the\n\trequired feature(s), or restore the "
4198236884Smm		    "pool from backup.\n"));
4199236884Smm		break;
4200236884Smm
4201185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_R:
4202185029Spjd		(void) printf(gettext("status: One or more devices are "
4203185029Spjd		    "faulted in response to persistent errors.\n\tSufficient "
4204185029Spjd		    "replicas exist for the pool to continue functioning "
4205185029Spjd		    "in a\n\tdegraded state.\n"));
4206185029Spjd		(void) printf(gettext("action: Replace the faulted device, "
4207185029Spjd		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
4208185029Spjd		break;
4209185029Spjd
4210185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_NR:
4211185029Spjd		(void) printf(gettext("status: One or more devices are "
4212185029Spjd		    "faulted in response to persistent errors.  There are "
4213185029Spjd		    "insufficient replicas for the pool to\n\tcontinue "
4214185029Spjd		    "functioning.\n"));
4215185029Spjd		(void) printf(gettext("action: Destroy and re-create the pool "
4216185029Spjd		    "from a backup source.  Manually marking the device\n"
4217185029Spjd		    "\trepaired using 'zpool clear' may allow some data "
4218185029Spjd		    "to be recovered.\n"));
4219185029Spjd		break;
4220185029Spjd
4221185029Spjd	case ZPOOL_STATUS_IO_FAILURE_WAIT:
4222185029Spjd	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
4223185029Spjd		(void) printf(gettext("status: One or more devices are "
4224185029Spjd		    "faulted in response to IO failures.\n"));
4225185029Spjd		(void) printf(gettext("action: Make sure the affected devices "
4226185029Spjd		    "are connected, then run 'zpool clear'.\n"));
4227185029Spjd		break;
4228185029Spjd
4229185029Spjd	case ZPOOL_STATUS_BAD_LOG:
4230185029Spjd		(void) printf(gettext("status: An intent log record "
4231185029Spjd		    "could not be read.\n"
4232185029Spjd		    "\tWaiting for adminstrator intervention to fix the "
4233185029Spjd		    "faulted pool.\n"));
4234185029Spjd		(void) printf(gettext("action: Either restore the affected "
4235185029Spjd		    "device(s) and run 'zpool online',\n"
4236185029Spjd		    "\tor ignore the intent log records by running "
4237185029Spjd		    "'zpool clear'.\n"));
4238185029Spjd		break;
4239185029Spjd
4240168404Spjd	default:
4241168404Spjd		/*
4242168404Spjd		 * The remaining errors can't actually be generated, yet.
4243168404Spjd		 */
4244168404Spjd		assert(reason == ZPOOL_STATUS_OK);
4245168404Spjd	}
4246168404Spjd
4247168404Spjd	if (msgid != NULL)
4248236146Smm		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
4249168404Spjd		    msgid);
4250168404Spjd
4251168404Spjd	if (config != NULL) {
4252168404Spjd		int namewidth;
4253168404Spjd		uint64_t nerr;
4254185029Spjd		nvlist_t **spares, **l2cache;
4255185029Spjd		uint_t nspares, nl2cache;
4256219089Spjd		pool_scan_stat_t *ps = NULL;
4257168404Spjd
4258219089Spjd		(void) nvlist_lookup_uint64_array(nvroot,
4259219089Spjd		    ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
4260219089Spjd		print_scan_status(ps);
4261168404Spjd
4262168404Spjd		namewidth = max_width(zhp, nvroot, 0, 0);
4263168404Spjd		if (namewidth < 10)
4264168404Spjd			namewidth = 10;
4265168404Spjd
4266168404Spjd		(void) printf(gettext("config:\n\n"));
4267168404Spjd		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
4268168404Spjd		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
4269168404Spjd		print_status_config(zhp, zpool_get_name(zhp), nvroot,
4270209962Smm		    namewidth, 0, B_FALSE);
4271209962Smm
4272185029Spjd		if (num_logs(nvroot) > 0)
4273213197Smm			print_logs(zhp, nvroot, namewidth, B_TRUE);
4274185029Spjd		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
4275185029Spjd		    &l2cache, &nl2cache) == 0)
4276185029Spjd			print_l2cache(zhp, l2cache, nl2cache, namewidth);
4277185029Spjd
4278168404Spjd		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
4279168404Spjd		    &spares, &nspares) == 0)
4280168404Spjd			print_spares(zhp, spares, nspares, namewidth);
4281168404Spjd
4282168404Spjd		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
4283168404Spjd		    &nerr) == 0) {
4284168404Spjd			nvlist_t *nverrlist = NULL;
4285168404Spjd
4286168404Spjd			/*
4287168404Spjd			 * If the approximate error count is small, get a
4288168404Spjd			 * precise count by fetching the entire log and
4289168404Spjd			 * uniquifying the results.
4290168404Spjd			 */
4291185029Spjd			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
4292168404Spjd			    zpool_get_errlog(zhp, &nverrlist) == 0) {
4293168404Spjd				nvpair_t *elem;
4294168404Spjd
4295168404Spjd				elem = NULL;
4296168404Spjd				nerr = 0;
4297168404Spjd				while ((elem = nvlist_next_nvpair(nverrlist,
4298168404Spjd				    elem)) != NULL) {
4299168404Spjd					nerr++;
4300168404Spjd				}
4301168404Spjd			}
4302168404Spjd			nvlist_free(nverrlist);
4303168404Spjd
4304168404Spjd			(void) printf("\n");
4305168404Spjd
4306168404Spjd			if (nerr == 0)
4307168404Spjd				(void) printf(gettext("errors: No known data "
4308168404Spjd				    "errors\n"));
4309168404Spjd			else if (!cbp->cb_verbose)
4310168404Spjd				(void) printf(gettext("errors: %llu data "
4311168404Spjd				    "errors, use '-v' for a list\n"),
4312168404Spjd				    (u_longlong_t)nerr);
4313168404Spjd			else
4314168404Spjd				print_error_log(zhp);
4315168404Spjd		}
4316219089Spjd
4317219089Spjd		if (cbp->cb_dedup_stats)
4318219089Spjd			print_dedup_stats(config);
4319168404Spjd	} else {
4320168404Spjd		(void) printf(gettext("config: The configuration cannot be "
4321168404Spjd		    "determined.\n"));
4322168404Spjd	}
4323168404Spjd
4324168404Spjd	return (0);
4325168404Spjd}
4326168404Spjd
4327168404Spjd/*
4328219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]]
4329168404Spjd *
4330168404Spjd *	-v	Display complete error logs
4331168404Spjd *	-x	Display only pools with potential problems
4332219089Spjd *	-D	Display dedup status (undocumented)
4333219089Spjd *	-T	Display a timestamp in date(1) or Unix format
4334168404Spjd *
4335168404Spjd * Describes the health status of all pools or some subset.
4336168404Spjd */
4337168404Spjdint
4338168404Spjdzpool_do_status(int argc, char **argv)
4339168404Spjd{
4340168404Spjd	int c;
4341168404Spjd	int ret;
4342219089Spjd	unsigned long interval = 0, count = 0;
4343168404Spjd	status_cbdata_t cb = { 0 };
4344168404Spjd
4345168404Spjd	/* check options */
4346219089Spjd	while ((c = getopt(argc, argv, "vxDT:")) != -1) {
4347168404Spjd		switch (c) {
4348168404Spjd		case 'v':
4349168404Spjd			cb.cb_verbose = B_TRUE;
4350168404Spjd			break;
4351168404Spjd		case 'x':
4352168404Spjd			cb.cb_explain = B_TRUE;
4353168404Spjd			break;
4354219089Spjd		case 'D':
4355219089Spjd			cb.cb_dedup_stats = B_TRUE;
4356219089Spjd			break;
4357219089Spjd		case 'T':
4358219089Spjd			get_timestamp_arg(*optarg);
4359219089Spjd			break;
4360168404Spjd		case '?':
4361168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4362168404Spjd			    optopt);
4363168404Spjd			usage(B_FALSE);
4364168404Spjd		}
4365168404Spjd	}
4366168404Spjd
4367168404Spjd	argc -= optind;
4368168404Spjd	argv += optind;
4369168404Spjd
4370219089Spjd	get_interval_count(&argc, argv, &interval, &count);
4371168404Spjd
4372168404Spjd	if (argc == 0)
4373168404Spjd		cb.cb_allpools = B_TRUE;
4374168404Spjd
4375219089Spjd	cb.cb_first = B_TRUE;
4376168404Spjd
4377219089Spjd	for (;;) {
4378219089Spjd		if (timestamp_fmt != NODATE)
4379219089Spjd			print_timestamp(timestamp_fmt);
4380168404Spjd
4381219089Spjd		ret = for_each_pool(argc, argv, B_TRUE, NULL,
4382219089Spjd		    status_callback, &cb);
4383219089Spjd
4384219089Spjd		if (argc == 0 && cb.cb_count == 0)
4385219089Spjd			(void) printf(gettext("no pools available\n"));
4386219089Spjd		else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
4387219089Spjd			(void) printf(gettext("all pools are healthy\n"));
4388219089Spjd
4389219089Spjd		if (ret != 0)
4390219089Spjd			return (ret);
4391219089Spjd
4392219089Spjd		if (interval == 0)
4393219089Spjd			break;
4394219089Spjd
4395219089Spjd		if (count != 0 && --count == 0)
4396219089Spjd			break;
4397219089Spjd
4398219089Spjd		(void) sleep(interval);
4399219089Spjd	}
4400219089Spjd
4401219089Spjd	return (0);
4402168404Spjd}
4403168404Spjd
4404168404Spjdtypedef struct upgrade_cbdata {
4405168404Spjd	int	cb_first;
4406212050Spjd	char	cb_poolname[ZPOOL_MAXNAMELEN];
4407168404Spjd	int	cb_argc;
4408185029Spjd	uint64_t cb_version;
4409168404Spjd	char	**cb_argv;
4410168404Spjd} upgrade_cbdata_t;
4411168404Spjd
4412168404Spjdstatic int
4413212050Spjdis_root_pool(zpool_handle_t *zhp)
4414212050Spjd{
4415212050Spjd	static struct statfs sfs;
4416212050Spjd	static char *poolname = NULL;
4417212050Spjd	static boolean_t stated = B_FALSE;
4418212050Spjd	char *slash;
4419212050Spjd
4420212067Spjd	if (!stated) {
4421212050Spjd		stated = B_TRUE;
4422212050Spjd		if (statfs("/", &sfs) == -1) {
4423212050Spjd			(void) fprintf(stderr,
4424212050Spjd			    "Unable to stat root file system: %s.\n",
4425212050Spjd			    strerror(errno));
4426212067Spjd			return (0);
4427212050Spjd		}
4428212050Spjd		if (strcmp(sfs.f_fstypename, "zfs") != 0)
4429212067Spjd			return (0);
4430212050Spjd		poolname = sfs.f_mntfromname;
4431212050Spjd		if ((slash = strchr(poolname, '/')) != NULL)
4432212050Spjd			*slash = '\0';
4433212050Spjd	}
4434212050Spjd	return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0);
4435212050Spjd}
4436212050Spjd
4437212050Spjdstatic int
4438238926Smmupgrade_version(zpool_handle_t *zhp, uint64_t version)
4439238926Smm{
4440238926Smm	int ret;
4441238926Smm	nvlist_t *config;
4442238926Smm	uint64_t oldversion;
4443238926Smm
4444238926Smm	config = zpool_get_config(zhp, NULL);
4445238926Smm	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
4446238926Smm	    &oldversion) == 0);
4447238926Smm
4448238926Smm	assert(SPA_VERSION_IS_SUPPORTED(oldversion));
4449238926Smm	assert(oldversion < version);
4450238926Smm
4451238926Smm	ret = zpool_upgrade(zhp, version);
4452238926Smm	if (ret != 0)
4453238926Smm		return (ret);
4454238926Smm
4455238926Smm	if (version >= SPA_VERSION_FEATURES) {
4456238926Smm		(void) printf(gettext("Successfully upgraded "
4457238926Smm		    "'%s' from version %llu to feature flags.\n"),
4458238926Smm		    zpool_get_name(zhp), oldversion);
4459238926Smm	} else {
4460238926Smm		(void) printf(gettext("Successfully upgraded "
4461238926Smm		    "'%s' from version %llu to version %llu.\n"),
4462238926Smm		    zpool_get_name(zhp), oldversion, version);
4463238926Smm	}
4464238926Smm
4465238926Smm	return (0);
4466238926Smm}
4467238926Smm
4468238926Smmstatic int
4469238926Smmupgrade_enable_all(zpool_handle_t *zhp, int *countp)
4470238926Smm{
4471238926Smm	int i, ret, count;
4472238926Smm	boolean_t firstff = B_TRUE;
4473238926Smm	nvlist_t *enabled = zpool_get_features(zhp);
4474238926Smm
4475238926Smm	count = 0;
4476238926Smm	for (i = 0; i < SPA_FEATURES; i++) {
4477238926Smm		const char *fname = spa_feature_table[i].fi_uname;
4478238926Smm		const char *fguid = spa_feature_table[i].fi_guid;
4479238926Smm		if (!nvlist_exists(enabled, fguid)) {
4480238926Smm			char *propname;
4481238926Smm			verify(-1 != asprintf(&propname, "feature@%s", fname));
4482238926Smm			ret = zpool_set_prop(zhp, propname,
4483238926Smm			    ZFS_FEATURE_ENABLED);
4484238926Smm			if (ret != 0) {
4485238926Smm				free(propname);
4486238926Smm				return (ret);
4487238926Smm			}
4488238926Smm			count++;
4489238926Smm
4490238926Smm			if (firstff) {
4491238926Smm				(void) printf(gettext("Enabled the "
4492238926Smm				    "following features on '%s':\n"),
4493238926Smm				    zpool_get_name(zhp));
4494238926Smm				firstff = B_FALSE;
4495238926Smm			}
4496238926Smm			(void) printf(gettext("  %s\n"), fname);
4497238926Smm			free(propname);
4498238926Smm		}
4499238926Smm	}
4500238926Smm
4501238926Smm	if (countp != NULL)
4502238926Smm		*countp = count;
4503238926Smm	return (0);
4504238926Smm}
4505238926Smm
4506238926Smmstatic int
4507168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg)
4508168404Spjd{
4509168404Spjd	upgrade_cbdata_t *cbp = arg;
4510168404Spjd	nvlist_t *config;
4511168404Spjd	uint64_t version;
4512238926Smm	boolean_t printnl = B_FALSE;
4513238926Smm	int ret;
4514168404Spjd
4515168404Spjd	config = zpool_get_config(zhp, NULL);
4516168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
4517168404Spjd	    &version) == 0);
4518168404Spjd
4519238926Smm	assert(SPA_VERSION_IS_SUPPORTED(version));
4520168404Spjd
4521238926Smm	if (version < cbp->cb_version) {
4522238926Smm		cbp->cb_first = B_FALSE;
4523238926Smm		ret = upgrade_version(zhp, cbp->cb_version);
4524238926Smm		if (ret != 0)
4525238926Smm			return (ret);
4526238926Smm#ifdef __FreeBSD__
4527238926Smm		if (cbp->cb_poolname[0] == '\0' &&
4528238926Smm		    is_root_pool(zhp)) {
4529238926Smm			(void) strlcpy(cbp->cb_poolname,
4530238926Smm			    zpool_get_name(zhp),
4531238926Smm			    sizeof(cbp->cb_poolname));
4532238926Smm		}
4533238926Smm#endif	/* ___FreeBSD__ */
4534238926Smm		printnl = B_TRUE;
4535238926Smm
4536238926Smm#ifdef illumos
4537238926Smm		/*
4538238926Smm		 * If they did "zpool upgrade -a", then we could
4539238926Smm		 * be doing ioctls to different pools.  We need
4540238926Smm		 * to log this history once to each pool, and bypass
4541238926Smm		 * the normal history logging that happens in main().
4542238926Smm		 */
4543238926Smm		(void) zpool_log_history(g_zfs, history_str);
4544238926Smm		log_history = B_FALSE;
4545238926Smm#endif
4546238926Smm	}
4547238926Smm
4548238926Smm	if (cbp->cb_version >= SPA_VERSION_FEATURES) {
4549238926Smm		int count;
4550238926Smm		ret = upgrade_enable_all(zhp, &count);
4551238926Smm		if (ret != 0)
4552238926Smm			return (ret);
4553238926Smm
4554238926Smm		if (count > 0) {
4555168404Spjd			cbp->cb_first = B_FALSE;
4556238926Smm			printnl = B_TRUE;
4557168404Spjd		}
4558238926Smm	}
4559168404Spjd
4560238926Smm	if (printnl) {
4561238926Smm		(void) printf(gettext("\n"));
4562238926Smm	}
4563238926Smm
4564238926Smm	return (0);
4565238926Smm}
4566238926Smm
4567238926Smmstatic int
4568238926Smmupgrade_list_older_cb(zpool_handle_t *zhp, void *arg)
4569238926Smm{
4570238926Smm	upgrade_cbdata_t *cbp = arg;
4571238926Smm	nvlist_t *config;
4572238926Smm	uint64_t version;
4573238926Smm
4574238926Smm	config = zpool_get_config(zhp, NULL);
4575238926Smm	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
4576238926Smm	    &version) == 0);
4577238926Smm
4578238926Smm	assert(SPA_VERSION_IS_SUPPORTED(version));
4579238926Smm
4580238926Smm	if (version < SPA_VERSION_FEATURES) {
4581168404Spjd		if (cbp->cb_first) {
4582168404Spjd			(void) printf(gettext("The following pools are "
4583238926Smm			    "formatted with legacy version numbers and can\n"
4584238926Smm			    "be upgraded to use feature flags.  After "
4585238926Smm			    "being upgraded, these pools\nwill no "
4586238926Smm			    "longer be accessible by software that does not "
4587238926Smm			    "support feature\nflags.\n\n"));
4588168404Spjd			(void) printf(gettext("VER  POOL\n"));
4589168404Spjd			(void) printf(gettext("---  ------------\n"));
4590168404Spjd			cbp->cb_first = B_FALSE;
4591168404Spjd		}
4592168404Spjd
4593168404Spjd		(void) printf("%2llu   %s\n", (u_longlong_t)version,
4594168404Spjd		    zpool_get_name(zhp));
4595168404Spjd	}
4596168404Spjd
4597238926Smm	return (0);
4598168404Spjd}
4599168404Spjd
4600238926Smmstatic int
4601238926Smmupgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg)
4602238926Smm{
4603238926Smm	upgrade_cbdata_t *cbp = arg;
4604238926Smm	nvlist_t *config;
4605238926Smm	uint64_t version;
4606238926Smm
4607238926Smm	config = zpool_get_config(zhp, NULL);
4608238926Smm	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
4609238926Smm	    &version) == 0);
4610238926Smm
4611238926Smm	if (version >= SPA_VERSION_FEATURES) {
4612238926Smm		int i;
4613238926Smm		boolean_t poolfirst = B_TRUE;
4614238926Smm		nvlist_t *enabled = zpool_get_features(zhp);
4615238926Smm
4616238926Smm		for (i = 0; i < SPA_FEATURES; i++) {
4617238926Smm			const char *fguid = spa_feature_table[i].fi_guid;
4618238926Smm			const char *fname = spa_feature_table[i].fi_uname;
4619238926Smm			if (!nvlist_exists(enabled, fguid)) {
4620238926Smm				if (cbp->cb_first) {
4621238926Smm					(void) printf(gettext("\nSome "
4622238926Smm					    "supported features are not "
4623238926Smm					    "enabled on the following pools. "
4624238926Smm					    "Once a\nfeature is enabled the "
4625238926Smm					    "pool may become incompatible with "
4626238926Smm					    "software\nthat does not support "
4627238926Smm					    "the feature. See "
4628238926Smm					    "zpool-features(5) for "
4629238926Smm					    "details.\n\n"));
4630238926Smm					(void) printf(gettext("POOL  "
4631238926Smm					    "FEATURE\n"));
4632238926Smm					(void) printf(gettext("------"
4633238926Smm					    "---------\n"));
4634238926Smm					cbp->cb_first = B_FALSE;
4635238926Smm				}
4636238926Smm
4637238926Smm				if (poolfirst) {
4638238926Smm					(void) printf(gettext("%s\n"),
4639238926Smm					    zpool_get_name(zhp));
4640238926Smm					poolfirst = B_FALSE;
4641238926Smm				}
4642238926Smm
4643238926Smm				(void) printf(gettext("      %s\n"), fname);
4644238926Smm			}
4645238926Smm		}
4646238926Smm	}
4647238926Smm
4648238926Smm	return (0);
4649238926Smm}
4650238926Smm
4651168404Spjd/* ARGSUSED */
4652168404Spjdstatic int
4653168404Spjdupgrade_one(zpool_handle_t *zhp, void *data)
4654168404Spjd{
4655238926Smm	boolean_t printnl = B_FALSE;
4656185029Spjd	upgrade_cbdata_t *cbp = data;
4657185029Spjd	uint64_t cur_version;
4658168404Spjd	int ret;
4659168404Spjd
4660185029Spjd	if (strcmp("log", zpool_get_name(zhp)) == 0) {
4661185029Spjd		(void) printf(gettext("'log' is now a reserved word\n"
4662185029Spjd		    "Pool 'log' must be renamed using export and import"
4663185029Spjd		    " to upgrade.\n"));
4664185029Spjd		return (1);
4665185029Spjd	}
4666168404Spjd
4667185029Spjd	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
4668185029Spjd	if (cur_version > cbp->cb_version) {
4669168404Spjd		(void) printf(gettext("Pool '%s' is already formatted "
4670238926Smm		    "using more current version '%llu'.\n\n"),
4671185029Spjd		    zpool_get_name(zhp), cur_version);
4672185029Spjd		return (0);
4673185029Spjd	}
4674238926Smm
4675238926Smm	if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) {
4676185029Spjd		(void) printf(gettext("Pool '%s' is already formatted "
4677238926Smm		    "using version %llu.\n\n"), zpool_get_name(zhp),
4678238926Smm		    cbp->cb_version);
4679168404Spjd		return (0);
4680168404Spjd	}
4681168404Spjd
4682238926Smm	if (cur_version != cbp->cb_version) {
4683238926Smm		printnl = B_TRUE;
4684238926Smm		ret = upgrade_version(zhp, cbp->cb_version);
4685238926Smm		if (ret != 0) {
4686238926Smm#ifdef __FreeBSD__
4687238926Smm			if (cbp->cb_poolname[0] == '\0' &&
4688238926Smm			    is_root_pool(zhp)) {
4689238926Smm				(void) strlcpy(cbp->cb_poolname,
4690238926Smm				    zpool_get_name(zhp),
4691238926Smm				    sizeof(cbp->cb_poolname));
4692238926Smm			}
4693238926Smm#endif	/* ___FreeBSD__ */
4694238926Smm			return (ret);
4695238926Smm		}
4696238926Smm	}
4697168404Spjd
4698238926Smm	if (cbp->cb_version >= SPA_VERSION_FEATURES) {
4699238926Smm		int count = 0;
4700238926Smm		ret = upgrade_enable_all(zhp, &count);
4701238926Smm		if (ret != 0)
4702238926Smm			return (ret);
4703238926Smm
4704238926Smm		if (count != 0) {
4705238926Smm			printnl = B_TRUE;
4706238926Smm		} else if (cur_version == SPA_VERSION) {
4707238926Smm			(void) printf(gettext("Pool '%s' already has all "
4708238926Smm			    "supported features enabled.\n"),
4709238926Smm			    zpool_get_name(zhp));
4710238926Smm		}
4711212050Spjd		if (cbp->cb_poolname[0] == '\0' && is_root_pool(zhp)) {
4712212050Spjd			(void) strlcpy(cbp->cb_poolname, zpool_get_name(zhp),
4713212050Spjd			    sizeof(cbp->cb_poolname));
4714212050Spjd		}
4715168404Spjd	}
4716168404Spjd
4717238926Smm	if (printnl) {
4718238926Smm		(void) printf(gettext("\n"));
4719238926Smm	}
4720238926Smm
4721238926Smm	return (0);
4722168404Spjd}
4723168404Spjd
4724168404Spjd/*
4725168404Spjd * zpool upgrade
4726168404Spjd * zpool upgrade -v
4727185029Spjd * zpool upgrade [-V version] <-a | pool ...>
4728168404Spjd *
4729168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade.
4730168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will
4731168404Spjd * upgrade all pools.
4732168404Spjd */
4733168404Spjdint
4734168404Spjdzpool_do_upgrade(int argc, char **argv)
4735168404Spjd{
4736168404Spjd	int c;
4737168404Spjd	upgrade_cbdata_t cb = { 0 };
4738168404Spjd	int ret = 0;
4739168404Spjd	boolean_t showversions = B_FALSE;
4740238926Smm	boolean_t upgradeall = B_FALSE;
4741185029Spjd	char *end;
4742168404Spjd
4743185029Spjd
4744168404Spjd	/* check options */
4745219089Spjd	while ((c = getopt(argc, argv, ":avV:")) != -1) {
4746168404Spjd		switch (c) {
4747168404Spjd		case 'a':
4748238926Smm			upgradeall = B_TRUE;
4749168404Spjd			break;
4750168404Spjd		case 'v':
4751168404Spjd			showversions = B_TRUE;
4752168404Spjd			break;
4753185029Spjd		case 'V':
4754185029Spjd			cb.cb_version = strtoll(optarg, &end, 10);
4755236884Smm			if (*end != '\0' ||
4756236884Smm			    !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) {
4757185029Spjd				(void) fprintf(stderr,
4758185029Spjd				    gettext("invalid version '%s'\n"), optarg);
4759185029Spjd				usage(B_FALSE);
4760185029Spjd			}
4761185029Spjd			break;
4762219089Spjd		case ':':
4763219089Spjd			(void) fprintf(stderr, gettext("missing argument for "
4764219089Spjd			    "'%c' option\n"), optopt);
4765219089Spjd			usage(B_FALSE);
4766219089Spjd			break;
4767168404Spjd		case '?':
4768168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4769168404Spjd			    optopt);
4770168404Spjd			usage(B_FALSE);
4771168404Spjd		}
4772168404Spjd	}
4773168404Spjd
4774168404Spjd	cb.cb_argc = argc;
4775168404Spjd	cb.cb_argv = argv;
4776168404Spjd	argc -= optind;
4777168404Spjd	argv += optind;
4778168404Spjd
4779185029Spjd	if (cb.cb_version == 0) {
4780185029Spjd		cb.cb_version = SPA_VERSION;
4781238926Smm	} else if (!upgradeall && argc == 0) {
4782185029Spjd		(void) fprintf(stderr, gettext("-V option is "
4783185029Spjd		    "incompatible with other arguments\n"));
4784185029Spjd		usage(B_FALSE);
4785185029Spjd	}
4786185029Spjd
4787168404Spjd	if (showversions) {
4788238926Smm		if (upgradeall || argc != 0) {
4789168404Spjd			(void) fprintf(stderr, gettext("-v option is "
4790168404Spjd			    "incompatible with other arguments\n"));
4791168404Spjd			usage(B_FALSE);
4792168404Spjd		}
4793238926Smm	} else if (upgradeall) {
4794168404Spjd		if (argc != 0) {
4795185029Spjd			(void) fprintf(stderr, gettext("-a option should not "
4796185029Spjd			    "be used along with a pool name\n"));
4797168404Spjd			usage(B_FALSE);
4798168404Spjd		}
4799168404Spjd	}
4800168404Spjd
4801236884Smm	(void) printf(gettext("This system supports ZFS pool feature "
4802236884Smm	    "flags.\n\n"));
4803168404Spjd	if (showversions) {
4804238926Smm		int i;
4805238926Smm
4806238926Smm		(void) printf(gettext("The following features are "
4807168404Spjd		    "supported:\n\n"));
4808238926Smm		(void) printf(gettext("FEAT DESCRIPTION\n"));
4809238926Smm		(void) printf("----------------------------------------------"
4810238926Smm		    "---------------\n");
4811238926Smm		for (i = 0; i < SPA_FEATURES; i++) {
4812238926Smm			zfeature_info_t *fi = &spa_feature_table[i];
4813238926Smm			const char *ro = fi->fi_can_readonly ?
4814238926Smm			    " (read-only compatible)" : "";
4815238926Smm
4816238926Smm			(void) printf("%-37s%s\n", fi->fi_uname, ro);
4817238926Smm			(void) printf("     %s\n", fi->fi_desc);
4818238926Smm		}
4819238926Smm		(void) printf("\n");
4820238926Smm
4821238926Smm		(void) printf(gettext("The following legacy versions are also "
4822238926Smm		    "supported:\n\n"));
4823168404Spjd		(void) printf(gettext("VER  DESCRIPTION\n"));
4824168404Spjd		(void) printf("---  -----------------------------------------"
4825168404Spjd		    "---------------\n");
4826168404Spjd		(void) printf(gettext(" 1   Initial ZFS version\n"));
4827168404Spjd		(void) printf(gettext(" 2   Ditto blocks "
4828168404Spjd		    "(replicated metadata)\n"));
4829168404Spjd		(void) printf(gettext(" 3   Hot spares and double parity "
4830168404Spjd		    "RAID-Z\n"));
4831168404Spjd		(void) printf(gettext(" 4   zpool history\n"));
4832168404Spjd		(void) printf(gettext(" 5   Compression using the gzip "
4833168404Spjd		    "algorithm\n"));
4834185029Spjd		(void) printf(gettext(" 6   bootfs pool property\n"));
4835185029Spjd		(void) printf(gettext(" 7   Separate intent log devices\n"));
4836185029Spjd		(void) printf(gettext(" 8   Delegated administration\n"));
4837185029Spjd		(void) printf(gettext(" 9   refquota and refreservation "
4838185029Spjd		    "properties\n"));
4839185029Spjd		(void) printf(gettext(" 10  Cache devices\n"));
4840185029Spjd		(void) printf(gettext(" 11  Improved scrub performance\n"));
4841185029Spjd		(void) printf(gettext(" 12  Snapshot properties\n"));
4842185029Spjd		(void) printf(gettext(" 13  snapused property\n"));
4843209962Smm		(void) printf(gettext(" 14  passthrough-x aclinherit\n"));
4844209962Smm		(void) printf(gettext(" 15  user/group space accounting\n"));
4845219089Spjd		(void) printf(gettext(" 16  stmf property support\n"));
4846219089Spjd		(void) printf(gettext(" 17  Triple-parity RAID-Z\n"));
4847219089Spjd		(void) printf(gettext(" 18  Snapshot user holds\n"));
4848219089Spjd		(void) printf(gettext(" 19  Log device removal\n"));
4849219089Spjd		(void) printf(gettext(" 20  Compression using zle "
4850219089Spjd		    "(zero-length encoding)\n"));
4851219089Spjd		(void) printf(gettext(" 21  Deduplication\n"));
4852219089Spjd		(void) printf(gettext(" 22  Received properties\n"));
4853219089Spjd		(void) printf(gettext(" 23  Slim ZIL\n"));
4854219089Spjd		(void) printf(gettext(" 24  System attributes\n"));
4855219089Spjd		(void) printf(gettext(" 25  Improved scrub stats\n"));
4856219089Spjd		(void) printf(gettext(" 26  Improved snapshot deletion "
4857219089Spjd		    "performance\n"));
4858219089Spjd		(void) printf(gettext(" 27  Improved snapshot creation "
4859219089Spjd		    "performance\n"));
4860219089Spjd		(void) printf(gettext(" 28  Multiple vdev replacements\n"));
4861219089Spjd		(void) printf(gettext("\nFor more information on a particular "
4862219089Spjd		    "version, including supported releases,\n"));
4863219089Spjd		(void) printf(gettext("see the ZFS Administration Guide.\n\n"));
4864238926Smm	} else if (argc == 0 && upgradeall) {
4865238926Smm		cb.cb_first = B_TRUE;
4866168404Spjd		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
4867238926Smm		if (ret == 0 && cb.cb_first) {
4868238926Smm			if (cb.cb_version == SPA_VERSION) {
4869238926Smm				(void) printf(gettext("All pools are already "
4870238926Smm				    "formatted using feature flags.\n\n"));
4871238926Smm				(void) printf(gettext("Every feature flags "
4872238926Smm				    "pool already has all supported features "
4873238926Smm				    "enabled.\n"));
4874238926Smm			} else {
4875238926Smm				(void) printf(gettext("All pools are already "
4876238926Smm				    "formatted with version %llu or higher.\n"),
4877238926Smm				    cb.cb_version);
4878168404Spjd			}
4879168404Spjd		}
4880238926Smm	} else if (argc == 0) {
4881238926Smm		cb.cb_first = B_TRUE;
4882238926Smm		ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb);
4883238926Smm		assert(ret == 0);
4884168404Spjd
4885238926Smm		if (cb.cb_first) {
4886238926Smm			(void) printf(gettext("All pools are formatted "
4887238926Smm			    "using feature flags.\n\n"));
4888238926Smm		} else {
4889238926Smm			(void) printf(gettext("\nUse 'zpool upgrade -v' "
4890238926Smm			    "for a list of available legacy versions.\n"));
4891168404Spjd		}
4892238926Smm
4893238926Smm		cb.cb_first = B_TRUE;
4894238926Smm		ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb);
4895238926Smm		assert(ret == 0);
4896238926Smm
4897238926Smm		if (cb.cb_first) {
4898238926Smm			(void) printf(gettext("Every feature flags pool has "
4899238926Smm			    "all supported features enabled.\n"));
4900238926Smm		} else {
4901238926Smm			(void) printf(gettext("\n"));
4902238926Smm		}
4903168404Spjd	} else {
4904168404Spjd		ret = for_each_pool(argc, argv, B_FALSE, NULL,
4905168404Spjd		    upgrade_one, &cb);
4906168404Spjd	}
4907168404Spjd
4908212050Spjd	if (cb.cb_poolname[0] != '\0') {
4909212050Spjd		(void) printf(
4910212050Spjd		    "If you boot from pool '%s', don't forget to update boot code.\n"
4911212050Spjd		    "Assuming you use GPT partitioning and da0 is your boot disk\n"
4912212050Spjd		    "the following command will do it:\n"
4913212050Spjd		    "\n"
4914212050Spjd		    "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n",
4915212050Spjd		    cb.cb_poolname);
4916212050Spjd	}
4917212050Spjd
4918168404Spjd	return (ret);
4919168404Spjd}
4920168404Spjd
4921185029Spjdtypedef struct hist_cbdata {
4922185029Spjd	boolean_t first;
4923185029Spjd	int longfmt;
4924185029Spjd	int internal;
4925185029Spjd} hist_cbdata_t;
4926185029Spjd
4927168404Spjd/*
4928168404Spjd * Print out the command history for a specific pool.
4929168404Spjd */
4930168404Spjdstatic int
4931168404Spjdget_history_one(zpool_handle_t *zhp, void *data)
4932168404Spjd{
4933168404Spjd	nvlist_t *nvhis;
4934168404Spjd	nvlist_t **records;
4935168404Spjd	uint_t numrecords;
4936168404Spjd	char *cmdstr;
4937185029Spjd	char *pathstr;
4938168404Spjd	uint64_t dst_time;
4939168404Spjd	time_t tsec;
4940168404Spjd	struct tm t;
4941168404Spjd	char tbuf[30];
4942168404Spjd	int ret, i;
4943185029Spjd	uint64_t who;
4944185029Spjd	struct passwd *pwd;
4945185029Spjd	char *hostname;
4946185029Spjd	char *zonename;
4947185029Spjd	char internalstr[MAXPATHLEN];
4948185029Spjd	hist_cbdata_t *cb = (hist_cbdata_t *)data;
4949185029Spjd	uint64_t txg;
4950185029Spjd	uint64_t ievent;
4951168404Spjd
4952185029Spjd	cb->first = B_FALSE;
4953168404Spjd
4954168404Spjd	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
4955168404Spjd
4956168404Spjd	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
4957168404Spjd		return (ret);
4958168404Spjd
4959168404Spjd	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
4960168404Spjd	    &records, &numrecords) == 0);
4961168404Spjd	for (i = 0; i < numrecords; i++) {
4962168404Spjd		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
4963185029Spjd		    &dst_time) != 0)
4964185029Spjd			continue;
4965185029Spjd
4966185029Spjd		/* is it an internal event or a standard event? */
4967185029Spjd		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
4968185029Spjd		    &cmdstr) != 0) {
4969185029Spjd			if (cb->internal == 0)
4970185029Spjd				continue;
4971185029Spjd
4972185029Spjd			if (nvlist_lookup_uint64(records[i],
4973185029Spjd			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
4974185029Spjd				continue;
4975185029Spjd			verify(nvlist_lookup_uint64(records[i],
4976185029Spjd			    ZPOOL_HIST_TXG, &txg) == 0);
4977185029Spjd			verify(nvlist_lookup_string(records[i],
4978185029Spjd			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
4979185029Spjd			if (ievent >= LOG_END)
4980185029Spjd				continue;
4981185029Spjd			(void) snprintf(internalstr,
4982185029Spjd			    sizeof (internalstr),
4983185029Spjd			    "[internal %s txg:%lld] %s",
4984219089Spjd			    zfs_history_event_names[ievent], txg,
4985185029Spjd			    pathstr);
4986185029Spjd			cmdstr = internalstr;
4987168404Spjd		}
4988185029Spjd		tsec = dst_time;
4989185029Spjd		(void) localtime_r(&tsec, &t);
4990185029Spjd		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
4991185029Spjd		(void) printf("%s %s", tbuf, cmdstr);
4992185029Spjd
4993185029Spjd		if (!cb->longfmt) {
4994185029Spjd			(void) printf("\n");
4995185029Spjd			continue;
4996185029Spjd		}
4997185029Spjd		(void) printf(" [");
4998185029Spjd		if (nvlist_lookup_uint64(records[i],
4999185029Spjd		    ZPOOL_HIST_WHO, &who) == 0) {
5000185029Spjd			pwd = getpwuid((uid_t)who);
5001185029Spjd			if (pwd)
5002185029Spjd				(void) printf("user %s on",
5003185029Spjd				    pwd->pw_name);
5004185029Spjd			else
5005185029Spjd				(void) printf("user %d on",
5006185029Spjd				    (int)who);
5007185029Spjd		} else {
5008185029Spjd			(void) printf(gettext("no info]\n"));
5009185029Spjd			continue;
5010185029Spjd		}
5011185029Spjd		if (nvlist_lookup_string(records[i],
5012185029Spjd		    ZPOOL_HIST_HOST, &hostname) == 0) {
5013185029Spjd			(void) printf(" %s", hostname);
5014185029Spjd		}
5015185029Spjd		if (nvlist_lookup_string(records[i],
5016185029Spjd		    ZPOOL_HIST_ZONE, &zonename) == 0) {
5017185029Spjd			(void) printf(":%s", zonename);
5018185029Spjd		}
5019185029Spjd
5020185029Spjd		(void) printf("]");
5021185029Spjd		(void) printf("\n");
5022168404Spjd	}
5023168404Spjd	(void) printf("\n");
5024168404Spjd	nvlist_free(nvhis);
5025168404Spjd
5026168404Spjd	return (ret);
5027168404Spjd}
5028168404Spjd
5029168404Spjd/*
5030168404Spjd * zpool history <pool>
5031168404Spjd *
5032168404Spjd * Displays the history of commands that modified pools.
5033168404Spjd */
5034185029Spjd
5035185029Spjd
5036168404Spjdint
5037168404Spjdzpool_do_history(int argc, char **argv)
5038168404Spjd{
5039185029Spjd	hist_cbdata_t cbdata = { 0 };
5040168404Spjd	int ret;
5041185029Spjd	int c;
5042168404Spjd
5043185029Spjd	cbdata.first = B_TRUE;
5044185029Spjd	/* check options */
5045185029Spjd	while ((c = getopt(argc, argv, "li")) != -1) {
5046185029Spjd		switch (c) {
5047185029Spjd		case 'l':
5048185029Spjd			cbdata.longfmt = 1;
5049185029Spjd			break;
5050185029Spjd		case 'i':
5051185029Spjd			cbdata.internal = 1;
5052185029Spjd			break;
5053185029Spjd		case '?':
5054185029Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5055185029Spjd			    optopt);
5056185029Spjd			usage(B_FALSE);
5057185029Spjd		}
5058185029Spjd	}
5059168404Spjd	argc -= optind;
5060168404Spjd	argv += optind;
5061168404Spjd
5062168404Spjd	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
5063185029Spjd	    &cbdata);
5064168404Spjd
5065185029Spjd	if (argc == 0 && cbdata.first == B_TRUE) {
5066168404Spjd		(void) printf(gettext("no pools available\n"));
5067168404Spjd		return (0);
5068168404Spjd	}
5069168404Spjd
5070168404Spjd	return (ret);
5071168404Spjd}
5072168404Spjd
5073168404Spjdstatic int
5074168404Spjdget_callback(zpool_handle_t *zhp, void *data)
5075168404Spjd{
5076185029Spjd	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
5077168404Spjd	char value[MAXNAMELEN];
5078185029Spjd	zprop_source_t srctype;
5079185029Spjd	zprop_list_t *pl;
5080168404Spjd
5081168404Spjd	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
5082168404Spjd
5083168404Spjd		/*
5084185029Spjd		 * Skip the special fake placeholder. This will also skip
5085185029Spjd		 * over the name property when 'all' is specified.
5086168404Spjd		 */
5087185029Spjd		if (pl->pl_prop == ZPOOL_PROP_NAME &&
5088168404Spjd		    pl == cbp->cb_proplist)
5089168404Spjd			continue;
5090168404Spjd
5091236884Smm		if (pl->pl_prop == ZPROP_INVAL &&
5092236884Smm		    (zpool_prop_feature(pl->pl_user_prop) ||
5093236884Smm		    zpool_prop_unsupported(pl->pl_user_prop))) {
5094236884Smm			srctype = ZPROP_SRC_LOCAL;
5095168404Spjd
5096236884Smm			if (zpool_prop_get_feature(zhp, pl->pl_user_prop,
5097236884Smm			    value, sizeof (value)) == 0) {
5098236884Smm				zprop_print_one_property(zpool_get_name(zhp),
5099236884Smm				    cbp, pl->pl_user_prop, value, srctype,
5100236884Smm				    NULL, NULL);
5101236884Smm			}
5102236884Smm		} else {
5103236884Smm			if (zpool_get_prop(zhp, pl->pl_prop, value,
5104236884Smm			    sizeof (value), &srctype) != 0)
5105236884Smm				continue;
5106236884Smm
5107236884Smm			zprop_print_one_property(zpool_get_name(zhp), cbp,
5108236884Smm			    zpool_prop_to_name(pl->pl_prop), value, srctype,
5109236884Smm			    NULL, NULL);
5110236884Smm		}
5111168404Spjd	}
5112168404Spjd	return (0);
5113168404Spjd}
5114168404Spjd
5115168404Spjdint
5116168404Spjdzpool_do_get(int argc, char **argv)
5117168404Spjd{
5118185029Spjd	zprop_get_cbdata_t cb = { 0 };
5119185029Spjd	zprop_list_t fake_name = { 0 };
5120168404Spjd	int ret;
5121168404Spjd
5122236884Smm	if (argc < 2) {
5123236884Smm		(void) fprintf(stderr, gettext("missing property "
5124236884Smm		    "argument\n"));
5125168404Spjd		usage(B_FALSE);
5126236884Smm	}
5127168404Spjd
5128168404Spjd	cb.cb_first = B_TRUE;
5129185029Spjd	cb.cb_sources = ZPROP_SRC_ALL;
5130168404Spjd	cb.cb_columns[0] = GET_COL_NAME;
5131168404Spjd	cb.cb_columns[1] = GET_COL_PROPERTY;
5132168404Spjd	cb.cb_columns[2] = GET_COL_VALUE;
5133168404Spjd	cb.cb_columns[3] = GET_COL_SOURCE;
5134185029Spjd	cb.cb_type = ZFS_TYPE_POOL;
5135168404Spjd
5136236884Smm	if (zprop_get_list(g_zfs, argv[1], &cb.cb_proplist,
5137185029Spjd	    ZFS_TYPE_POOL) != 0)
5138168404Spjd		usage(B_FALSE);
5139168404Spjd
5140168404Spjd	if (cb.cb_proplist != NULL) {
5141185029Spjd		fake_name.pl_prop = ZPOOL_PROP_NAME;
5142168404Spjd		fake_name.pl_width = strlen(gettext("NAME"));
5143168404Spjd		fake_name.pl_next = cb.cb_proplist;
5144168404Spjd		cb.cb_proplist = &fake_name;
5145168404Spjd	}
5146168404Spjd
5147168404Spjd	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
5148168404Spjd	    get_callback, &cb);
5149168404Spjd
5150168404Spjd	if (cb.cb_proplist == &fake_name)
5151185029Spjd		zprop_free_list(fake_name.pl_next);
5152168404Spjd	else
5153185029Spjd		zprop_free_list(cb.cb_proplist);
5154168404Spjd
5155168404Spjd	return (ret);
5156168404Spjd}
5157168404Spjd
5158168404Spjdtypedef struct set_cbdata {
5159168404Spjd	char *cb_propname;
5160168404Spjd	char *cb_value;
5161168404Spjd	boolean_t cb_any_successful;
5162168404Spjd} set_cbdata_t;
5163168404Spjd
5164168404Spjdint
5165168404Spjdset_callback(zpool_handle_t *zhp, void *data)
5166168404Spjd{
5167168404Spjd	int error;
5168168404Spjd	set_cbdata_t *cb = (set_cbdata_t *)data;
5169168404Spjd
5170168404Spjd	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
5171168404Spjd
5172168404Spjd	if (!error)
5173168404Spjd		cb->cb_any_successful = B_TRUE;
5174168404Spjd
5175168404Spjd	return (error);
5176168404Spjd}
5177168404Spjd
5178168404Spjdint
5179168404Spjdzpool_do_set(int argc, char **argv)
5180168404Spjd{
5181168404Spjd	set_cbdata_t cb = { 0 };
5182168404Spjd	int error;
5183168404Spjd
5184168404Spjd	if (argc > 1 && argv[1][0] == '-') {
5185168404Spjd		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5186168404Spjd		    argv[1][1]);
5187168404Spjd		usage(B_FALSE);
5188168404Spjd	}
5189168404Spjd
5190168404Spjd	if (argc < 2) {
5191168404Spjd		(void) fprintf(stderr, gettext("missing property=value "
5192168404Spjd		    "argument\n"));
5193168404Spjd		usage(B_FALSE);
5194168404Spjd	}
5195168404Spjd
5196168404Spjd	if (argc < 3) {
5197168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
5198168404Spjd		usage(B_FALSE);
5199168404Spjd	}
5200168404Spjd
5201168404Spjd	if (argc > 3) {
5202168404Spjd		(void) fprintf(stderr, gettext("too many pool names\n"));
5203168404Spjd		usage(B_FALSE);
5204168404Spjd	}
5205168404Spjd
5206168404Spjd	cb.cb_propname = argv[1];
5207168404Spjd	cb.cb_value = strchr(cb.cb_propname, '=');
5208168404Spjd	if (cb.cb_value == NULL) {
5209168404Spjd		(void) fprintf(stderr, gettext("missing value in "
5210168404Spjd		    "property=value argument\n"));
5211168404Spjd		usage(B_FALSE);
5212168404Spjd	}
5213168404Spjd
5214168404Spjd	*(cb.cb_value) = '\0';
5215168404Spjd	cb.cb_value++;
5216168404Spjd
5217168404Spjd	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
5218168404Spjd	    set_callback, &cb);
5219168404Spjd
5220168404Spjd	return (error);
5221168404Spjd}
5222168404Spjd
5223168404Spjdstatic int
5224168404Spjdfind_command_idx(char *command, int *idx)
5225168404Spjd{
5226168404Spjd	int i;
5227168404Spjd
5228168404Spjd	for (i = 0; i < NCOMMAND; i++) {
5229168404Spjd		if (command_table[i].name == NULL)
5230168404Spjd			continue;
5231168404Spjd
5232168404Spjd		if (strcmp(command, command_table[i].name) == 0) {
5233168404Spjd			*idx = i;
5234168404Spjd			return (0);
5235168404Spjd		}
5236168404Spjd	}
5237168404Spjd	return (1);
5238168404Spjd}
5239168404Spjd
5240168404Spjdint
5241168404Spjdmain(int argc, char **argv)
5242168404Spjd{
5243168404Spjd	int ret;
5244168404Spjd	int i;
5245168404Spjd	char *cmdname;
5246168404Spjd
5247168404Spjd	(void) setlocale(LC_ALL, "");
5248168404Spjd	(void) textdomain(TEXT_DOMAIN);
5249168404Spjd
5250168404Spjd	if ((g_zfs = libzfs_init()) == NULL) {
5251168404Spjd		(void) fprintf(stderr, gettext("internal error: failed to "
5252168404Spjd		    "initialize ZFS library\n"));
5253168404Spjd		return (1);
5254168404Spjd	}
5255168404Spjd
5256168404Spjd	libzfs_print_on_error(g_zfs, B_TRUE);
5257168404Spjd
5258168404Spjd	opterr = 0;
5259168404Spjd
5260168404Spjd	/*
5261168404Spjd	 * Make sure the user has specified some command.
5262168404Spjd	 */
5263168404Spjd	if (argc < 2) {
5264168404Spjd		(void) fprintf(stderr, gettext("missing command\n"));
5265168404Spjd		usage(B_FALSE);
5266168404Spjd	}
5267168404Spjd
5268168404Spjd	cmdname = argv[1];
5269168404Spjd
5270168404Spjd	/*
5271168404Spjd	 * Special case '-?'
5272168404Spjd	 */
5273168404Spjd	if (strcmp(cmdname, "-?") == 0)
5274168404Spjd		usage(B_TRUE);
5275168404Spjd
5276185029Spjd	zpool_set_history_str("zpool", argc, argv, history_str);
5277185029Spjd	verify(zpool_stage_history(g_zfs, history_str) == 0);
5278185029Spjd
5279168404Spjd	/*
5280168404Spjd	 * Run the appropriate command.
5281168404Spjd	 */
5282168404Spjd	if (find_command_idx(cmdname, &i) == 0) {
5283168404Spjd		current_command = &command_table[i];
5284168404Spjd		ret = command_table[i].func(argc - 1, argv + 1);
5285185029Spjd	} else if (strchr(cmdname, '=')) {
5286185029Spjd		verify(find_command_idx("set", &i) == 0);
5287185029Spjd		current_command = &command_table[i];
5288185029Spjd		ret = command_table[i].func(argc, argv);
5289185029Spjd	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
5290185029Spjd		/*
5291185029Spjd		 * 'freeze' is a vile debugging abomination, so we treat
5292185029Spjd		 * it as such.
5293185029Spjd		 */
5294168404Spjd		char buf[16384];
5295168404Spjd		int fd = open(ZFS_DEV, O_RDWR);
5296168404Spjd		(void) strcpy((void *)buf, argv[2]);
5297168404Spjd		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
5298185029Spjd	} else {
5299168404Spjd		(void) fprintf(stderr, gettext("unrecognized "
5300168404Spjd		    "command '%s'\n"), cmdname);
5301168404Spjd		usage(B_FALSE);
5302168404Spjd	}
5303168404Spjd
5304168404Spjd	libzfs_fini(g_zfs);
5305168404Spjd
5306168404Spjd	/*
5307168404Spjd	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
5308168404Spjd	 * for the purposes of running ::findleaks.
5309168404Spjd	 */
5310168404Spjd	if (getenv("ZFS_ABORT") != NULL) {
5311168404Spjd		(void) printf("dumping core by request\n");
5312168404Spjd		abort();
5313168404Spjd	}
5314168404Spjd
5315168404Spjd	return (ret);
5316168404Spjd}
5317