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.
24332525Smav * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
25236145Smm * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
26236155Smm * Copyright (c) 2012 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
27254758Sdelphij * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
28296537Smav * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
29297763Smav * Copyright 2016 Nexenta Systems, Inc.
30324010Savg * Copyright (c) 2017 Datto Inc.
31168404Spjd */
32168404Spjd
33168404Spjd#include <solaris.h>
34168404Spjd#include <assert.h>
35168404Spjd#include <ctype.h>
36168404Spjd#include <dirent.h>
37168404Spjd#include <errno.h>
38168404Spjd#include <fcntl.h>
39332547Smav#include <getopt.h>
40168404Spjd#include <libgen.h>
41168404Spjd#include <libintl.h>
42168404Spjd#include <libuutil.h>
43168404Spjd#include <locale.h>
44168404Spjd#include <stdio.h>
45168404Spjd#include <stdlib.h>
46168404Spjd#include <string.h>
47168404Spjd#include <strings.h>
48168404Spjd#include <unistd.h>
49168404Spjd#include <priv.h>
50185029Spjd#include <pwd.h>
51185029Spjd#include <zone.h>
52168404Spjd#include <sys/time.h>
53236155Smm#include <zfs_prop.h>
54168404Spjd#include <sys/fs/zfs.h>
55168404Spjd#include <sys/stat.h>
56168404Spjd
57168404Spjd#include <libzfs.h>
58168404Spjd
59168404Spjd#include "zpool_util.h"
60185029Spjd#include "zfs_comutil.h"
61236884Smm#include "zfeature_common.h"
62168404Spjd
63219089Spjd#include "statcommon.h"
64219089Spjd
65359754Skevanslibzfs_handle_t *g_zfs;
66359754Skevans
67168404Spjdstatic int zpool_do_create(int, char **);
68168404Spjdstatic int zpool_do_destroy(int, char **);
69168404Spjd
70168404Spjdstatic int zpool_do_add(int, char **);
71168404Spjdstatic int zpool_do_remove(int, char **);
72224171Sgibbsstatic int zpool_do_labelclear(int, char **);
73168404Spjd
74332547Smavstatic int zpool_do_checkpoint(int, char **);
75332547Smav
76168404Spjdstatic int zpool_do_list(int, char **);
77168404Spjdstatic int zpool_do_iostat(int, char **);
78168404Spjdstatic int zpool_do_status(int, char **);
79168404Spjd
80168404Spjdstatic int zpool_do_online(int, char **);
81168404Spjdstatic int zpool_do_offline(int, char **);
82168404Spjdstatic int zpool_do_clear(int, char **);
83236155Smmstatic int zpool_do_reopen(int, char **);
84168404Spjd
85228103Smmstatic int zpool_do_reguid(int, char **);
86228103Smm
87168404Spjdstatic int zpool_do_attach(int, char **);
88168404Spjdstatic int zpool_do_detach(int, char **);
89168404Spjdstatic int zpool_do_replace(int, char **);
90219089Spjdstatic int zpool_do_split(int, char **);
91168404Spjd
92339111Smavstatic int zpool_do_initialize(int, char **);
93168404Spjdstatic int zpool_do_scrub(int, char **);
94168404Spjd
95168404Spjdstatic int zpool_do_import(int, char **);
96168404Spjdstatic int zpool_do_export(int, char **);
97168404Spjd
98168404Spjdstatic int zpool_do_upgrade(int, char **);
99168404Spjd
100168404Spjdstatic int zpool_do_history(int, char **);
101168404Spjd
102168404Spjdstatic int zpool_do_get(int, char **);
103168404Spjdstatic int zpool_do_set(int, char **);
104168404Spjd
105168404Spjd/*
106168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's
107168404Spjd * debugging facilities.
108168404Spjd */
109185029Spjd
110185029Spjd#ifdef DEBUG
111168404Spjdconst char *
112168404Spjd_umem_debug_init(void)
113168404Spjd{
114168404Spjd	return ("default,verbose"); /* $UMEM_DEBUG setting */
115168404Spjd}
116168404Spjd
117168404Spjdconst char *
118168404Spjd_umem_logging_init(void)
119168404Spjd{
120168404Spjd	return ("fail,contents"); /* $UMEM_LOGGING setting */
121168404Spjd}
122185029Spjd#endif
123168404Spjd
124168404Spjdtypedef enum {
125168404Spjd	HELP_ADD,
126168404Spjd	HELP_ATTACH,
127168404Spjd	HELP_CLEAR,
128168404Spjd	HELP_CREATE,
129332547Smav	HELP_CHECKPOINT,
130168404Spjd	HELP_DESTROY,
131168404Spjd	HELP_DETACH,
132168404Spjd	HELP_EXPORT,
133168404Spjd	HELP_HISTORY,
134168404Spjd	HELP_IMPORT,
135168404Spjd	HELP_IOSTAT,
136224171Sgibbs	HELP_LABELCLEAR,
137168404Spjd	HELP_LIST,
138168404Spjd	HELP_OFFLINE,
139168404Spjd	HELP_ONLINE,
140168404Spjd	HELP_REPLACE,
141168404Spjd	HELP_REMOVE,
142339111Smav	HELP_INITIALIZE,
143168404Spjd	HELP_SCRUB,
144168404Spjd	HELP_STATUS,
145168404Spjd	HELP_UPGRADE,
146168404Spjd	HELP_GET,
147219089Spjd	HELP_SET,
148228103Smm	HELP_SPLIT,
149236155Smm	HELP_REGUID,
150236155Smm	HELP_REOPEN
151168404Spjd} zpool_help_t;
152168404Spjd
153168404Spjd
154168404Spjdtypedef struct zpool_command {
155168404Spjd	const char	*name;
156168404Spjd	int		(*func)(int, char **);
157168404Spjd	zpool_help_t	usage;
158168404Spjd} zpool_command_t;
159168404Spjd
160168404Spjd/*
161168404Spjd * Master command table.  Each ZFS command has a name, associated function, and
162168404Spjd * usage message.  The usage messages need to be internationalized, so we have
163168404Spjd * to have a function to return the usage message based on a command index.
164168404Spjd *
165168404Spjd * These commands are organized according to how they are displayed in the usage
166168404Spjd * message.  An empty command (one with a NULL name) indicates an empty line in
167168404Spjd * the generic usage message.
168168404Spjd */
169168404Spjdstatic zpool_command_t command_table[] = {
170168404Spjd	{ "create",	zpool_do_create,	HELP_CREATE		},
171168404Spjd	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
172168404Spjd	{ NULL },
173168404Spjd	{ "add",	zpool_do_add,		HELP_ADD		},
174168404Spjd	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
175168404Spjd	{ NULL },
176224171Sgibbs	{ "labelclear",	zpool_do_labelclear,	HELP_LABELCLEAR		},
177224171Sgibbs	{ NULL },
178332547Smav	{ "checkpoint",	zpool_do_checkpoint,	HELP_CHECKPOINT		},
179332547Smav	{ NULL },
180168404Spjd	{ "list",	zpool_do_list,		HELP_LIST		},
181168404Spjd	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
182168404Spjd	{ "status",	zpool_do_status,	HELP_STATUS		},
183168404Spjd	{ NULL },
184168404Spjd	{ "online",	zpool_do_online,	HELP_ONLINE		},
185168404Spjd	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
186168404Spjd	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
187236155Smm	{ "reopen",	zpool_do_reopen,	HELP_REOPEN		},
188168404Spjd	{ NULL },
189168404Spjd	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
190168404Spjd	{ "detach",	zpool_do_detach,	HELP_DETACH		},
191168404Spjd	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
192219089Spjd	{ "split",	zpool_do_split,		HELP_SPLIT		},
193168404Spjd	{ NULL },
194339111Smav	{ "initialize",	zpool_do_initialize,	HELP_INITIALIZE		},
195168404Spjd	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
196168404Spjd	{ NULL },
197168404Spjd	{ "import",	zpool_do_import,	HELP_IMPORT		},
198168404Spjd	{ "export",	zpool_do_export,	HELP_EXPORT		},
199168404Spjd	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
200228103Smm	{ "reguid",	zpool_do_reguid,	HELP_REGUID		},
201168404Spjd	{ NULL },
202168404Spjd	{ "history",	zpool_do_history,	HELP_HISTORY		},
203168404Spjd	{ "get",	zpool_do_get,		HELP_GET		},
204168404Spjd	{ "set",	zpool_do_set,		HELP_SET		},
205168404Spjd};
206168404Spjd
207168404Spjd#define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
208168404Spjd
209248571Smmstatic zpool_command_t *current_command;
210185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN];
211248571Smmstatic boolean_t log_history = B_TRUE;
212219089Spjdstatic uint_t timestamp_fmt = NODATE;
213219089Spjd
214168404Spjdstatic const char *
215289562Smavget_usage(zpool_help_t idx)
216289562Smav{
217168404Spjd	switch (idx) {
218168404Spjd	case HELP_ADD:
219168404Spjd		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
220168404Spjd	case HELP_ATTACH:
221168404Spjd		return (gettext("\tattach [-f] <pool> <device> "
222185029Spjd		    "<new-device>\n"));
223168404Spjd	case HELP_CLEAR:
224219089Spjd		return (gettext("\tclear [-nF] <pool> [device]\n"));
225168404Spjd	case HELP_CREATE:
226331395Smav		return (gettext("\tcreate [-fnd] [-B] "
227331395Smav		    "[-o property=value] ... \n"
228333194Savg		    "\t    [-O file-system-property=value] ...\n"
229333194Savg		    "\t    [-m mountpoint] [-R root] [-t tempname] "
230333194Savg		    "<pool> <vdev> ...\n"));
231332547Smav	case HELP_CHECKPOINT:
232332547Smav		return (gettext("\tcheckpoint [--discard] <pool> ...\n"));
233168404Spjd	case HELP_DESTROY:
234168404Spjd		return (gettext("\tdestroy [-f] <pool>\n"));
235168404Spjd	case HELP_DETACH:
236168404Spjd		return (gettext("\tdetach <pool> <device>\n"));
237168404Spjd	case HELP_EXPORT:
238168404Spjd		return (gettext("\texport [-f] <pool> ...\n"));
239168404Spjd	case HELP_HISTORY:
240185029Spjd		return (gettext("\thistory [-il] [<pool>] ...\n"));
241168404Spjd	case HELP_IMPORT:
242168404Spjd		return (gettext("\timport [-d dir] [-D]\n"
243185029Spjd		    "\timport [-o mntopts] [-o property=value] ... \n"
244219089Spjd		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
245219089Spjd		    "[-R root] [-F [-n]] -a\n"
246185029Spjd		    "\timport [-o mntopts] [-o property=value] ... \n"
247219089Spjd		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
248333194Savg		    "[-R root] [-F [-n]] [-t]\n"
249332547Smav		    "\t    [--rewind-to-checkpoint] <pool | id> [newpool]\n"));
250168404Spjd	case HELP_IOSTAT:
251219089Spjd		return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
252168404Spjd		    "[count]]\n"));
253224171Sgibbs	case HELP_LABELCLEAR:
254224171Sgibbs		return (gettext("\tlabelclear [-f] <vdev>\n"));
255168404Spjd	case HELP_LIST:
256263889Sdelphij		return (gettext("\tlist [-Hpv] [-o property[,...]] "
257219089Spjd		    "[-T d|u] [pool] ... [interval [count]]\n"));
258168404Spjd	case HELP_OFFLINE:
259168404Spjd		return (gettext("\toffline [-t] <pool> <device> ...\n"));
260168404Spjd	case HELP_ONLINE:
261228020Smm		return (gettext("\tonline [-e] <pool> <device> ...\n"));
262168404Spjd	case HELP_REPLACE:
263168404Spjd		return (gettext("\treplace [-f] <pool> <device> "
264185029Spjd		    "[new-device]\n"));
265168404Spjd	case HELP_REMOVE:
266332525Smav		return (gettext("\tremove [-nps] <pool> <device> ...\n"));
267236155Smm	case HELP_REOPEN:
268260138Sdelphij		return (gettext("\treopen <pool>\n"));
269339111Smav	case HELP_INITIALIZE:
270339111Smav		return (gettext("\tinitialize [-cs] <pool> [<device> ...]\n"));
271168404Spjd	case HELP_SCRUB:
272324010Savg		return (gettext("\tscrub [-s | -p] <pool> ...\n"));
273168404Spjd	case HELP_STATUS:
274219089Spjd		return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
275219089Spjd		    "[count]]\n"));
276168404Spjd	case HELP_UPGRADE:
277228020Smm		return (gettext("\tupgrade [-v]\n"
278185029Spjd		    "\tupgrade [-V version] <-a | pool ...>\n"));
279168404Spjd	case HELP_GET:
280263889Sdelphij		return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] "
281263889Sdelphij		    "<\"all\" | property[,...]> <pool> ...\n"));
282168404Spjd	case HELP_SET:
283168404Spjd		return (gettext("\tset <property=value> <pool> \n"));
284219089Spjd	case HELP_SPLIT:
285219089Spjd		return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
286219089Spjd		    "\t    [-o property=value] <pool> <newpool> "
287219089Spjd		    "[<device> ...]\n"));
288228103Smm	case HELP_REGUID:
289228103Smm		return (gettext("\treguid <pool>\n"));
290168404Spjd	}
291168404Spjd
292168404Spjd	abort();
293168404Spjd	/* NOTREACHED */
294168404Spjd}
295168404Spjd
296168404Spjd
297168404Spjd/*
298168404Spjd * Callback routine that will print out a pool property value.
299168404Spjd */
300185029Spjdstatic int
301185029Spjdprint_prop_cb(int prop, void *cb)
302168404Spjd{
303168404Spjd	FILE *fp = cb;
304168404Spjd
305219089Spjd	(void) fprintf(fp, "\t%-15s  ", zpool_prop_to_name(prop));
306168404Spjd
307185029Spjd	if (zpool_prop_readonly(prop))
308185029Spjd		(void) fprintf(fp, "  NO   ");
309185029Spjd	else
310219089Spjd		(void) fprintf(fp, " YES   ");
311185029Spjd
312168404Spjd	if (zpool_prop_values(prop) == NULL)
313168404Spjd		(void) fprintf(fp, "-\n");
314168404Spjd	else
315168404Spjd		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
316168404Spjd
317185029Spjd	return (ZPROP_CONT);
318168404Spjd}
319168404Spjd
320168404Spjd/*
321168404Spjd * Display usage message.  If we're inside a command, display only the usage for
322168404Spjd * that command.  Otherwise, iterate over the entire command table and display
323168404Spjd * a complete usage message.
324168404Spjd */
325168404Spjdvoid
326168404Spjdusage(boolean_t requested)
327168404Spjd{
328168404Spjd	FILE *fp = requested ? stdout : stderr;
329168404Spjd
330168404Spjd	if (current_command == NULL) {
331168404Spjd		int i;
332168404Spjd
333168404Spjd		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
334168404Spjd		(void) fprintf(fp,
335168404Spjd		    gettext("where 'command' is one of the following:\n\n"));
336168404Spjd
337168404Spjd		for (i = 0; i < NCOMMAND; i++) {
338168404Spjd			if (command_table[i].name == NULL)
339168404Spjd				(void) fprintf(fp, "\n");
340168404Spjd			else
341168404Spjd				(void) fprintf(fp, "%s",
342168404Spjd				    get_usage(command_table[i].usage));
343168404Spjd		}
344168404Spjd	} else {
345168404Spjd		(void) fprintf(fp, gettext("usage:\n"));
346168404Spjd		(void) fprintf(fp, "%s", get_usage(current_command->usage));
347168404Spjd	}
348168404Spjd
349168404Spjd	if (current_command != NULL &&
350168404Spjd	    ((strcmp(current_command->name, "set") == 0) ||
351185029Spjd	    (strcmp(current_command->name, "get") == 0) ||
352185029Spjd	    (strcmp(current_command->name, "list") == 0))) {
353168404Spjd
354168404Spjd		(void) fprintf(fp,
355168404Spjd		    gettext("\nthe following properties are supported:\n"));
356168404Spjd
357219089Spjd		(void) fprintf(fp, "\n\t%-15s  %s   %s\n\n",
358185029Spjd		    "PROPERTY", "EDIT", "VALUES");
359168404Spjd
360168404Spjd		/* Iterate over all properties */
361185029Spjd		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
362185029Spjd		    ZFS_TYPE_POOL);
363236884Smm
364236884Smm		(void) fprintf(fp, "\t%-15s   ", "feature@...");
365236884Smm		(void) fprintf(fp, "YES   disabled | enabled | active\n");
366236884Smm
367236884Smm		(void) fprintf(fp, gettext("\nThe feature@ properties must be "
368243014Smm		    "appended with a feature name.\nSee zpool-features(7).\n"));
369168404Spjd	}
370168404Spjd
371168404Spjd	/*
372168404Spjd	 * See comments at end of main().
373168404Spjd	 */
374168404Spjd	if (getenv("ZFS_ABORT") != NULL) {
375168404Spjd		(void) printf("dumping core by request\n");
376168404Spjd		abort();
377168404Spjd	}
378168404Spjd
379168404Spjd	exit(requested ? 0 : 2);
380168404Spjd}
381168404Spjd
382168404Spjdvoid
383185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
384185029Spjd    boolean_t print_logs)
385168404Spjd{
386168404Spjd	nvlist_t **child;
387168404Spjd	uint_t c, children;
388168404Spjd	char *vname;
389168404Spjd
390168404Spjd	if (name != NULL)
391168404Spjd		(void) printf("\t%*s%s\n", indent, "", name);
392168404Spjd
393168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
394168404Spjd	    &child, &children) != 0)
395168404Spjd		return;
396168404Spjd
397168404Spjd	for (c = 0; c < children; c++) {
398185029Spjd		uint64_t is_log = B_FALSE;
399185029Spjd
400185029Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
401185029Spjd		    &is_log);
402185029Spjd		if ((is_log && !print_logs) || (!is_log && print_logs))
403185029Spjd			continue;
404185029Spjd
405219089Spjd		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
406185029Spjd		print_vdev_tree(zhp, vname, child[c], indent + 2,
407185029Spjd		    B_FALSE);
408168404Spjd		free(vname);
409168404Spjd	}
410168404Spjd}
411168404Spjd
412238926Smmstatic boolean_t
413238926Smmprop_list_contains_feature(nvlist_t *proplist)
414238926Smm{
415238926Smm	nvpair_t *nvp;
416238926Smm	for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp;
417238926Smm	    nvp = nvlist_next_nvpair(proplist, nvp)) {
418238926Smm		if (zpool_prop_feature(nvpair_name(nvp)))
419238926Smm			return (B_TRUE);
420238926Smm	}
421238926Smm	return (B_FALSE);
422238926Smm}
423238926Smm
424168404Spjd/*
425185029Spjd * Add a property pair (name, string-value) into a property nvlist.
426185029Spjd */
427185029Spjdstatic int
428185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props,
429185029Spjd    boolean_t poolprop)
430185029Spjd{
431185029Spjd	zpool_prop_t prop = ZPROP_INVAL;
432185029Spjd	zfs_prop_t fprop;
433185029Spjd	nvlist_t *proplist;
434185029Spjd	const char *normnm;
435185029Spjd	char *strval;
436185029Spjd
437185029Spjd	if (*props == NULL &&
438185029Spjd	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
439185029Spjd		(void) fprintf(stderr,
440185029Spjd		    gettext("internal error: out of memory\n"));
441185029Spjd		return (1);
442185029Spjd	}
443185029Spjd
444185029Spjd	proplist = *props;
445185029Spjd
446185029Spjd	if (poolprop) {
447238926Smm		const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
448238926Smm
449236884Smm		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
450236884Smm		    !zpool_prop_feature(propname)) {
451185029Spjd			(void) fprintf(stderr, gettext("property '%s' is "
452185029Spjd			    "not a valid pool property\n"), propname);
453185029Spjd			return (2);
454185029Spjd		}
455238926Smm
456238926Smm		/*
457238926Smm		 * feature@ properties and version should not be specified
458238926Smm		 * at the same time.
459238926Smm		 */
460329493Smav		if ((prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname) &&
461238926Smm		    nvlist_exists(proplist, vname)) ||
462238926Smm		    (prop == ZPOOL_PROP_VERSION &&
463238926Smm		    prop_list_contains_feature(proplist))) {
464238926Smm			(void) fprintf(stderr, gettext("'feature@' and "
465238926Smm			    "'version' properties cannot be specified "
466238926Smm			    "together\n"));
467238926Smm			return (2);
468238926Smm		}
469238926Smm
470238926Smm
471236884Smm		if (zpool_prop_feature(propname))
472236884Smm			normnm = propname;
473236884Smm		else
474236884Smm			normnm = zpool_prop_to_name(prop);
475185029Spjd	} else {
476209962Smm		if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
477209962Smm			normnm = zfs_prop_to_name(fprop);
478209962Smm		} else {
479209962Smm			normnm = propname;
480185029Spjd		}
481185029Spjd	}
482185029Spjd
483185029Spjd	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
484185029Spjd	    prop != ZPOOL_PROP_CACHEFILE) {
485185029Spjd		(void) fprintf(stderr, gettext("property '%s' "
486185029Spjd		    "specified multiple times\n"), propname);
487185029Spjd		return (2);
488185029Spjd	}
489185029Spjd
490185029Spjd	if (nvlist_add_string(proplist, normnm, propval) != 0) {
491185029Spjd		(void) fprintf(stderr, gettext("internal "
492185029Spjd		    "error: out of memory\n"));
493185029Spjd		return (1);
494185029Spjd	}
495185029Spjd
496185029Spjd	return (0);
497185029Spjd}
498185029Spjd
499185029Spjd/*
500333194Savg * Set a default property pair (name, string-value) in a property nvlist
501333194Savg */
502333194Savgstatic int
503333194Savgadd_prop_list_default(const char *propname, char *propval, nvlist_t **props,
504333194Savg    boolean_t poolprop)
505333194Savg{
506333194Savg	char *pval;
507333194Savg
508333194Savg	if (nvlist_lookup_string(*props, propname, &pval) == 0)
509333194Savg		return (0);
510333194Savg
511333194Savg	return (add_prop_list(propname, propval, props, poolprop));
512333194Savg}
513333194Savg
514333194Savg/*
515168404Spjd * zpool add [-fn] <pool> <vdev> ...
516168404Spjd *
517168404Spjd *	-f	Force addition of devices, even if they appear in use
518168404Spjd *	-n	Do not add the devices, but display the resulting layout if
519168404Spjd *		they were to be added.
520168404Spjd *
521168404Spjd * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
522168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
523168404Spjd * libzfs.
524168404Spjd */
525168404Spjdint
526168404Spjdzpool_do_add(int argc, char **argv)
527168404Spjd{
528168404Spjd	boolean_t force = B_FALSE;
529168404Spjd	boolean_t dryrun = B_FALSE;
530168404Spjd	int c;
531168404Spjd	nvlist_t *nvroot;
532168404Spjd	char *poolname;
533331395Smav	zpool_boot_label_t boot_type;
534331395Smav	uint64_t boot_size;
535168404Spjd	int ret;
536168404Spjd	zpool_handle_t *zhp;
537168404Spjd	nvlist_t *config;
538168404Spjd
539168404Spjd	/* check options */
540168404Spjd	while ((c = getopt(argc, argv, "fn")) != -1) {
541168404Spjd		switch (c) {
542168404Spjd		case 'f':
543168404Spjd			force = B_TRUE;
544168404Spjd			break;
545168404Spjd		case 'n':
546168404Spjd			dryrun = B_TRUE;
547168404Spjd			break;
548168404Spjd		case '?':
549168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
550168404Spjd			    optopt);
551168404Spjd			usage(B_FALSE);
552168404Spjd		}
553168404Spjd	}
554168404Spjd
555168404Spjd	argc -= optind;
556168404Spjd	argv += optind;
557168404Spjd
558168404Spjd	/* get pool name and check number of arguments */
559168404Spjd	if (argc < 1) {
560168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
561168404Spjd		usage(B_FALSE);
562168404Spjd	}
563168404Spjd	if (argc < 2) {
564168404Spjd		(void) fprintf(stderr, gettext("missing vdev specification\n"));
565168404Spjd		usage(B_FALSE);
566168404Spjd	}
567168404Spjd
568168404Spjd	poolname = argv[0];
569168404Spjd
570168404Spjd	argc--;
571168404Spjd	argv++;
572168404Spjd
573168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
574168404Spjd		return (1);
575168404Spjd
576168404Spjd	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
577168404Spjd		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
578168404Spjd		    poolname);
579168404Spjd		zpool_close(zhp);
580168404Spjd		return (1);
581168404Spjd	}
582168404Spjd
583331395Smav	if (zpool_is_bootable(zhp))
584331395Smav		boot_type = ZPOOL_COPY_BOOT_LABEL;
585331395Smav	else
586331395Smav		boot_type = ZPOOL_NO_BOOT_LABEL;
587331395Smav
588168404Spjd	/* pass off to get_vdev_spec for processing */
589331395Smav	boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
590185029Spjd	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
591331395Smav	    boot_type, boot_size, argc, argv);
592168404Spjd	if (nvroot == NULL) {
593168404Spjd		zpool_close(zhp);
594168404Spjd		return (1);
595168404Spjd	}
596168404Spjd
597168404Spjd	if (dryrun) {
598168404Spjd		nvlist_t *poolnvroot;
599168404Spjd
600168404Spjd		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
601168404Spjd		    &poolnvroot) == 0);
602168404Spjd
603168404Spjd		(void) printf(gettext("would update '%s' to the following "
604168404Spjd		    "configuration:\n"), zpool_get_name(zhp));
605168404Spjd
606185029Spjd		/* print original main pool and new tree */
607185029Spjd		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
608185029Spjd		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
609168404Spjd
610185029Spjd		/* Do the same for the logs */
611185029Spjd		if (num_logs(poolnvroot) > 0) {
612185029Spjd			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
613185029Spjd			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
614185029Spjd		} else if (num_logs(nvroot) > 0) {
615185029Spjd			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
616185029Spjd		}
617185029Spjd
618168404Spjd		ret = 0;
619168404Spjd	} else {
620168404Spjd		ret = (zpool_add(zhp, nvroot) != 0);
621168404Spjd	}
622168404Spjd
623168404Spjd	nvlist_free(nvroot);
624168404Spjd	zpool_close(zhp);
625168404Spjd
626168404Spjd	return (ret);
627168404Spjd}
628168404Spjd
629168404Spjd/*
630219089Spjd * zpool remove  <pool> <vdev> ...
631168404Spjd *
632332525Smav * Removes the given vdev from the pool.
633168404Spjd */
634168404Spjdint
635168404Spjdzpool_do_remove(int argc, char **argv)
636168404Spjd{
637168404Spjd	char *poolname;
638185029Spjd	int i, ret = 0;
639168404Spjd	zpool_handle_t *zhp;
640332525Smav	boolean_t stop = B_FALSE;
641332525Smav	boolean_t noop = B_FALSE;
642332525Smav	boolean_t parsable = B_FALSE;
643332525Smav	char c;
644168404Spjd
645332525Smav	/* check options */
646332525Smav	while ((c = getopt(argc, argv, "nps")) != -1) {
647332525Smav		switch (c) {
648332525Smav		case 'n':
649332525Smav			noop = B_TRUE;
650332525Smav			break;
651332525Smav		case 'p':
652332525Smav			parsable = B_TRUE;
653332525Smav			break;
654332525Smav		case 's':
655332525Smav			stop = B_TRUE;
656332525Smav			break;
657332525Smav		case '?':
658332525Smav			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
659332525Smav			    optopt);
660332525Smav			usage(B_FALSE);
661332525Smav		}
662332525Smav	}
663168404Spjd
664332525Smav	argc -= optind;
665332525Smav	argv += optind;
666332525Smav
667168404Spjd	/* get pool name and check number of arguments */
668168404Spjd	if (argc < 1) {
669168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
670168404Spjd		usage(B_FALSE);
671168404Spjd	}
672168404Spjd
673168404Spjd	poolname = argv[0];
674168404Spjd
675168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
676168404Spjd		return (1);
677168404Spjd
678332525Smav	if (stop && noop) {
679332525Smav		(void) fprintf(stderr, gettext("stop request ignored\n"));
680332525Smav		return (0);
681332525Smav	}
682332525Smav
683332525Smav	if (stop) {
684332525Smav		if (argc > 1) {
685332525Smav			(void) fprintf(stderr, gettext("too many arguments\n"));
686332525Smav			usage(B_FALSE);
687332525Smav		}
688332525Smav		if (zpool_vdev_remove_cancel(zhp) != 0)
689185029Spjd			ret = 1;
690332525Smav	} else {
691332525Smav		if (argc < 2) {
692332525Smav			(void) fprintf(stderr, gettext("missing device\n"));
693332525Smav			usage(B_FALSE);
694332525Smav		}
695332525Smav
696332525Smav		for (i = 1; i < argc; i++) {
697332525Smav			if (noop) {
698332525Smav				uint64_t size;
699332525Smav
700332525Smav				if (zpool_vdev_indirect_size(zhp, argv[i],
701332525Smav				    &size) != 0) {
702332525Smav					ret = 1;
703332525Smav					break;
704332525Smav				}
705332525Smav				if (parsable) {
706332525Smav					(void) printf("%s %llu\n",
707332525Smav					    argv[i], size);
708332525Smav				} else {
709332525Smav					char valstr[32];
710332525Smav					zfs_nicenum(size, valstr,
711332525Smav					    sizeof (valstr));
712332525Smav					(void) printf("Memory that will be "
713332525Smav					    "used after removing %s: %s\n",
714332525Smav					    argv[i], valstr);
715332525Smav				}
716332525Smav			} else {
717332525Smav				if (zpool_vdev_remove(zhp, argv[i]) != 0)
718332525Smav					ret = 1;
719332525Smav			}
720332525Smav		}
721168404Spjd	}
722168404Spjd
723168404Spjd	return (ret);
724168404Spjd}
725168404Spjd
726168404Spjd/*
727297763Smav * zpool labelclear [-f] <vdev>
728224171Sgibbs *
729297763Smav *	-f	Force clearing the label for the vdevs which are members of
730297763Smav *		the exported or foreign pools.
731297763Smav *
732224171Sgibbs * Verifies that the vdev is not active and zeros out the label information
733224171Sgibbs * on the device.
734224171Sgibbs */
735224171Sgibbsint
736224171Sgibbszpool_do_labelclear(int argc, char **argv)
737224171Sgibbs{
738297763Smav	char vdev[MAXPATHLEN];
739297763Smav	char *name = NULL;
740297763Smav	struct stat st;
741297763Smav	int c, fd, ret = 0;
742297763Smav	nvlist_t *config;
743224171Sgibbs	pool_state_t state;
744224171Sgibbs	boolean_t inuse = B_FALSE;
745224171Sgibbs	boolean_t force = B_FALSE;
746224171Sgibbs
747224171Sgibbs	/* check options */
748224171Sgibbs	while ((c = getopt(argc, argv, "f")) != -1) {
749224171Sgibbs		switch (c) {
750224171Sgibbs		case 'f':
751224171Sgibbs			force = B_TRUE;
752224171Sgibbs			break;
753224171Sgibbs		default:
754224171Sgibbs			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
755224171Sgibbs			    optopt);
756224171Sgibbs			usage(B_FALSE);
757224171Sgibbs		}
758224171Sgibbs	}
759224171Sgibbs
760224171Sgibbs	argc -= optind;
761224171Sgibbs	argv += optind;
762224171Sgibbs
763224171Sgibbs	/* get vdev name */
764224171Sgibbs	if (argc < 1) {
765297763Smav		(void) fprintf(stderr, gettext("missing vdev name\n"));
766224171Sgibbs		usage(B_FALSE);
767224171Sgibbs	}
768297763Smav	if (argc > 1) {
769297763Smav		(void) fprintf(stderr, gettext("too many arguments\n"));
770297763Smav		usage(B_FALSE);
771297763Smav	}
772224171Sgibbs
773297763Smav	/*
774297763Smav	 * Check if we were given absolute path and use it as is.
775297763Smav	 * Otherwise if the provided vdev name doesn't point to a file,
776297763Smav	 * try prepending dsk path and appending s0.
777297763Smav	 */
778297763Smav	(void) strlcpy(vdev, argv[0], sizeof (vdev));
779297763Smav	if (vdev[0] != '/' && stat(vdev, &st) != 0) {
780297763Smav		char *s;
781297763Smav
782297763Smav		(void) snprintf(vdev, sizeof (vdev), "%s/%s",
783297763Smav#ifdef illumos
784297763Smav		    ZFS_DISK_ROOT, argv[0]);
785297763Smav		if ((s = strrchr(argv[0], 's')) == NULL ||
786297763Smav		    !isdigit(*(s + 1)))
787297763Smav			(void) strlcat(vdev, "s0", sizeof (vdev));
788297763Smav#else
789297763Smav		    "/dev", argv[0]);
790297763Smav#endif
791297763Smav		if (stat(vdev, &st) != 0) {
792297763Smav			(void) fprintf(stderr, gettext(
793297763Smav			    "failed to find device %s, try specifying absolute "
794297763Smav			    "path instead\n"), argv[0]);
795297763Smav			return (1);
796297763Smav		}
797297763Smav	}
798297763Smav
799224171Sgibbs	if ((fd = open(vdev, O_RDWR)) < 0) {
800297763Smav		(void) fprintf(stderr, gettext("failed to open %s: %s\n"),
801297763Smav		    vdev, strerror(errno));
802297763Smav		return (1);
803224171Sgibbs	}
804224171Sgibbs
805324255Savg	if (zpool_read_label(fd, &config) != 0) {
806224171Sgibbs		(void) fprintf(stderr,
807297763Smav		    gettext("failed to read label from %s\n"), vdev);
808297763Smav		return (1);
809297763Smav	}
810297763Smav	nvlist_free(config);
811224171Sgibbs
812297763Smav	ret = zpool_in_use(g_zfs, fd, &state, &name, &inuse);
813297763Smav	if (ret != 0) {
814297763Smav		(void) fprintf(stderr,
815297763Smav		    gettext("failed to check state for %s\n"), vdev);
816224171Sgibbs		return (1);
817224171Sgibbs	}
818224171Sgibbs
819297763Smav	if (!inuse)
820297763Smav		goto wipe_label;
821224171Sgibbs
822297763Smav	switch (state) {
823297763Smav	default:
824297763Smav	case POOL_STATE_ACTIVE:
825297763Smav	case POOL_STATE_SPARE:
826297763Smav	case POOL_STATE_L2CACHE:
827297763Smav		(void) fprintf(stderr, gettext(
828297763Smav		    "%s is a member (%s) of pool \"%s\"\n"),
829297763Smav		    vdev, zpool_pool_state_to_name(state), name);
830297763Smav		ret = 1;
831297763Smav		goto errout;
832224171Sgibbs
833297763Smav	case POOL_STATE_EXPORTED:
834297763Smav		if (force)
835297763Smav			break;
836297763Smav		(void) fprintf(stderr, gettext(
837297763Smav		    "use '-f' to override the following error:\n"
838297763Smav		    "%s is a member of exported pool \"%s\"\n"),
839297763Smav		    vdev, name);
840297763Smav		ret = 1;
841297763Smav		goto errout;
842224171Sgibbs
843297763Smav	case POOL_STATE_POTENTIALLY_ACTIVE:
844297763Smav		if (force)
845297763Smav			break;
846297763Smav		(void) fprintf(stderr, gettext(
847297763Smav		    "use '-f' to override the following error:\n"
848297763Smav		    "%s is a member of potentially active pool \"%s\"\n"),
849297763Smav		    vdev, name);
850297763Smav		ret = 1;
851297763Smav		goto errout;
852224171Sgibbs
853297763Smav	case POOL_STATE_DESTROYED:
854297763Smav		/* inuse should never be set for a destroyed pool */
855297763Smav		assert(0);
856297763Smav		break;
857224171Sgibbs	}
858224171Sgibbs
859224171Sgibbswipe_label:
860297763Smav	ret = zpool_clear_label(fd);
861297763Smav	if (ret != 0) {
862224171Sgibbs		(void) fprintf(stderr,
863297763Smav		    gettext("failed to clear label for %s\n"), vdev);
864224171Sgibbs	}
865224171Sgibbs
866224171Sgibbserrout:
867297763Smav	free(name);
868297763Smav	(void) close(fd);
869224171Sgibbs
870224171Sgibbs	return (ret);
871224171Sgibbs}
872224171Sgibbs
873224171Sgibbs/*
874331395Smav * zpool create [-fnd] [-B] [-o property=value] ...
875185029Spjd *		[-O file-system-property=value] ...
876333194Savg *		[-R root] [-m mountpoint] [-t tempname] <pool> <dev> ...
877168404Spjd *
878331395Smav *	-B	Create boot partition.
879168404Spjd *	-f	Force creation, even if devices appear in use
880168404Spjd *	-n	Do not create the pool, but display the resulting layout if it
881168404Spjd *		were to be created.
882333194Savg *	-R	Create a pool under an alternate root
883333194Savg *	-m	Set default mountpoint for the root dataset.  By default it's
884236884Smm *		'/<pool>'
885333194Savg *	-t	Use the temporary name until the pool is exported.
886185029Spjd *	-o	Set property=value.
887236884Smm *	-d	Don't automatically enable all supported pool features
888236884Smm *		(individual features can be enabled with -o).
889185029Spjd *	-O	Set fsproperty=value in the pool's root file system
890168404Spjd *
891168404Spjd * Creates the named pool according to the given vdev specification.  The
892168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
893168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents
894168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation.
895168404Spjd */
896331395Smav
897331395Smav#define	SYSTEM256	(256 * 1024 * 1024)
898168404Spjdint
899168404Spjdzpool_do_create(int argc, char **argv)
900168404Spjd{
901168404Spjd	boolean_t force = B_FALSE;
902168404Spjd	boolean_t dryrun = B_FALSE;
903236884Smm	boolean_t enable_all_pool_feat = B_TRUE;
904331395Smav	zpool_boot_label_t boot_type = ZPOOL_NO_BOOT_LABEL;
905331395Smav	uint64_t boot_size = 0;
906168404Spjd	int c;
907185029Spjd	nvlist_t *nvroot = NULL;
908168404Spjd	char *poolname;
909333194Savg	char *tname = NULL;
910185029Spjd	int ret = 1;
911168404Spjd	char *altroot = NULL;
912168404Spjd	char *mountpoint = NULL;
913185029Spjd	nvlist_t *fsprops = NULL;
914185029Spjd	nvlist_t *props = NULL;
915185029Spjd	char *propval;
916168404Spjd
917168404Spjd	/* check options */
918333194Savg	while ((c = getopt(argc, argv, ":fndBR:m:o:O:t:")) != -1) {
919168404Spjd		switch (c) {
920168404Spjd		case 'f':
921168404Spjd			force = B_TRUE;
922168404Spjd			break;
923168404Spjd		case 'n':
924168404Spjd			dryrun = B_TRUE;
925168404Spjd			break;
926236884Smm		case 'd':
927236884Smm			enable_all_pool_feat = B_FALSE;
928236884Smm			break;
929331395Smav		case 'B':
930331395Smav#ifdef illumos
931331395Smav			/*
932331395Smav			 * We should create the system partition.
933331395Smav			 * Also make sure the size is set.
934331395Smav			 */
935331395Smav			boot_type = ZPOOL_CREATE_BOOT_LABEL;
936331395Smav			if (boot_size == 0)
937331395Smav				boot_size = SYSTEM256;
938331395Smav			break;
939331395Smav#else
940331395Smav			(void) fprintf(stderr,
941331395Smav			    gettext("option '%c' is not supported\n"),
942331395Smav			    optopt);
943331395Smav			goto badusage;
944331395Smav#endif
945168404Spjd		case 'R':
946168404Spjd			altroot = optarg;
947185029Spjd			if (add_prop_list(zpool_prop_to_name(
948185029Spjd			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
949185029Spjd				goto errout;
950333194Savg			if (add_prop_list_default(zpool_prop_to_name(
951185029Spjd			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
952185029Spjd				goto errout;
953168404Spjd			break;
954168404Spjd		case 'm':
955251634Sdelphij			/* Equivalent to -O mountpoint=optarg */
956168404Spjd			mountpoint = optarg;
957168404Spjd			break;
958185029Spjd		case 'o':
959185029Spjd			if ((propval = strchr(optarg, '=')) == NULL) {
960185029Spjd				(void) fprintf(stderr, gettext("missing "
961185029Spjd				    "'=' for -o option\n"));
962185029Spjd				goto errout;
963185029Spjd			}
964185029Spjd			*propval = '\0';
965185029Spjd			propval++;
966185029Spjd
967185029Spjd			if (add_prop_list(optarg, propval, &props, B_TRUE))
968185029Spjd				goto errout;
969236884Smm
970236884Smm			/*
971331395Smav			 * Get bootsize value for make_root_vdev().
972331395Smav			 */
973331395Smav			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_BOOTSIZE) {
974331395Smav				if (zfs_nicestrtonum(g_zfs, propval,
975331395Smav				    &boot_size) < 0 || boot_size == 0) {
976331395Smav					(void) fprintf(stderr,
977331395Smav					    gettext("bad boot partition size "
978331395Smav					    "'%s': %s\n"),  propval,
979331395Smav					    libzfs_error_description(g_zfs));
980331395Smav					goto errout;
981331395Smav				}
982331395Smav			}
983331395Smav
984331395Smav			/*
985236884Smm			 * If the user is creating a pool that doesn't support
986236884Smm			 * feature flags, don't enable any features.
987236884Smm			 */
988236884Smm			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) {
989236884Smm				char *end;
990236884Smm				u_longlong_t ver;
991236884Smm
992236884Smm				ver = strtoull(propval, &end, 10);
993236884Smm				if (*end == '\0' &&
994236884Smm				    ver < SPA_VERSION_FEATURES) {
995236884Smm					enable_all_pool_feat = B_FALSE;
996236884Smm				}
997236884Smm			}
998279366Sdelphij			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT)
999279366Sdelphij				altroot = propval;
1000185029Spjd			break;
1001185029Spjd		case 'O':
1002185029Spjd			if ((propval = strchr(optarg, '=')) == NULL) {
1003185029Spjd				(void) fprintf(stderr, gettext("missing "
1004185029Spjd				    "'=' for -O option\n"));
1005185029Spjd				goto errout;
1006185029Spjd			}
1007185029Spjd			*propval = '\0';
1008185029Spjd			propval++;
1009185029Spjd
1010251634Sdelphij			/*
1011251634Sdelphij			 * Mountpoints are checked and then added later.
1012251634Sdelphij			 * Uniquely among properties, they can be specified
1013251634Sdelphij			 * more than once, to avoid conflict with -m.
1014251634Sdelphij			 */
1015251634Sdelphij			if (0 == strcmp(optarg,
1016251634Sdelphij			    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) {
1017251634Sdelphij				mountpoint = propval;
1018251634Sdelphij			} else if (add_prop_list(optarg, propval, &fsprops,
1019251634Sdelphij			    B_FALSE)) {
1020185029Spjd				goto errout;
1021251634Sdelphij			}
1022185029Spjd			break;
1023333194Savg		case 't':
1024333194Savg			/*
1025333194Savg			 * Sanity check temporary pool name.
1026333194Savg			 */
1027333194Savg			if (strchr(optarg, '/') != NULL) {
1028333194Savg				(void) fprintf(stderr, gettext("cannot create "
1029333194Savg				    "'%s': invalid character '/' in temporary "
1030333194Savg				    "name\n"), optarg);
1031333194Savg				(void) fprintf(stderr, gettext("use 'zfs "
1032333194Savg				    "create' to create a dataset\n"));
1033333194Savg				goto errout;
1034333194Savg			}
1035333194Savg
1036333194Savg			if (add_prop_list(zpool_prop_to_name(
1037333194Savg			    ZPOOL_PROP_TNAME), optarg, &props, B_TRUE))
1038333194Savg				goto errout;
1039333194Savg			if (add_prop_list_default(zpool_prop_to_name(
1040333194Savg			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1041333194Savg				goto errout;
1042333194Savg			tname = optarg;
1043333194Savg			break;
1044168404Spjd		case ':':
1045168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
1046168404Spjd			    "'%c' option\n"), optopt);
1047185029Spjd			goto badusage;
1048168404Spjd		case '?':
1049168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1050168404Spjd			    optopt);
1051185029Spjd			goto badusage;
1052168404Spjd		}
1053168404Spjd	}
1054168404Spjd
1055168404Spjd	argc -= optind;
1056168404Spjd	argv += optind;
1057168404Spjd
1058168404Spjd	/* get pool name and check number of arguments */
1059168404Spjd	if (argc < 1) {
1060168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
1061185029Spjd		goto badusage;
1062168404Spjd	}
1063168404Spjd	if (argc < 2) {
1064168404Spjd		(void) fprintf(stderr, gettext("missing vdev specification\n"));
1065185029Spjd		goto badusage;
1066168404Spjd	}
1067168404Spjd
1068168404Spjd	poolname = argv[0];
1069168404Spjd
1070168404Spjd	/*
1071168404Spjd	 * As a special case, check for use of '/' in the name, and direct the
1072168404Spjd	 * user to use 'zfs create' instead.
1073168404Spjd	 */
1074168404Spjd	if (strchr(poolname, '/') != NULL) {
1075168404Spjd		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
1076168404Spjd		    "character '/' in pool name\n"), poolname);
1077168404Spjd		(void) fprintf(stderr, gettext("use 'zfs create' to "
1078168404Spjd		    "create a dataset\n"));
1079185029Spjd		goto errout;
1080168404Spjd	}
1081168404Spjd
1082331395Smav	/*
1083331395Smav	 * Make sure the bootsize is set when ZPOOL_CREATE_BOOT_LABEL is used,
1084331395Smav	 * and not set otherwise.
1085331395Smav	 */
1086331395Smav	if (boot_type == ZPOOL_CREATE_BOOT_LABEL) {
1087331395Smav		const char *propname;
1088331395Smav		char *strptr, *buf = NULL;
1089331395Smav		int rv;
1090331395Smav
1091331395Smav		propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE);
1092331395Smav		if (nvlist_lookup_string(props, propname, &strptr) != 0) {
1093331395Smav			(void) asprintf(&buf, "%" PRIu64, boot_size);
1094331395Smav			if (buf == NULL) {
1095331395Smav				(void) fprintf(stderr,
1096331395Smav				    gettext("internal error: out of memory\n"));
1097331395Smav				goto errout;
1098331395Smav			}
1099331395Smav			rv = add_prop_list(propname, buf, &props, B_TRUE);
1100331395Smav			free(buf);
1101331395Smav			if (rv != 0)
1102331395Smav				goto errout;
1103331395Smav		}
1104331395Smav	} else {
1105331395Smav		const char *propname;
1106331395Smav		char *strptr;
1107331395Smav
1108331395Smav		propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE);
1109331395Smav		if (nvlist_lookup_string(props, propname, &strptr) == 0) {
1110331395Smav			(void) fprintf(stderr, gettext("error: setting boot "
1111331395Smav			    "partition size requires option '-B'\n"));
1112331395Smav			goto errout;
1113331395Smav		}
1114331395Smav	}
1115331395Smav
1116168404Spjd	/* pass off to get_vdev_spec for bulk processing */
1117185029Spjd	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
1118331395Smav	    boot_type, boot_size, argc - 1, argv + 1);
1119168404Spjd	if (nvroot == NULL)
1120185029Spjd		goto errout;
1121168404Spjd
1122168404Spjd	/* make_root_vdev() allows 0 toplevel children if there are spares */
1123185029Spjd	if (!zfs_allocatable_devs(nvroot)) {
1124168404Spjd		(void) fprintf(stderr, gettext("invalid vdev "
1125168404Spjd		    "specification: at least one toplevel vdev must be "
1126168404Spjd		    "specified\n"));
1127185029Spjd		goto errout;
1128168404Spjd	}
1129168404Spjd
1130168404Spjd	if (altroot != NULL && altroot[0] != '/') {
1131168404Spjd		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
1132168404Spjd		    "must be an absolute path\n"), altroot);
1133185029Spjd		goto errout;
1134168404Spjd	}
1135168404Spjd
1136168404Spjd	/*
1137168404Spjd	 * Check the validity of the mountpoint and direct the user to use the
1138168404Spjd	 * '-m' mountpoint option if it looks like its in use.
1139244857Spjd	 * Ignore the checks if the '-f' option is given.
1140168404Spjd	 */
1141244857Spjd	if (!force && (mountpoint == NULL ||
1142168404Spjd	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
1143244857Spjd	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0))) {
1144168404Spjd		char buf[MAXPATHLEN];
1145185029Spjd		DIR *dirp;
1146168404Spjd
1147168404Spjd		if (mountpoint && mountpoint[0] != '/') {
1148168404Spjd			(void) fprintf(stderr, gettext("invalid mountpoint "
1149168404Spjd			    "'%s': must be an absolute path, 'legacy', or "
1150168404Spjd			    "'none'\n"), mountpoint);
1151185029Spjd			goto errout;
1152168404Spjd		}
1153168404Spjd
1154168404Spjd		if (mountpoint == NULL) {
1155168404Spjd			if (altroot != NULL)
1156168404Spjd				(void) snprintf(buf, sizeof (buf), "%s/%s",
1157168404Spjd				    altroot, poolname);
1158168404Spjd			else
1159168404Spjd				(void) snprintf(buf, sizeof (buf), "/%s",
1160168404Spjd				    poolname);
1161168404Spjd		} else {
1162168404Spjd			if (altroot != NULL)
1163168404Spjd				(void) snprintf(buf, sizeof (buf), "%s%s",
1164168404Spjd				    altroot, mountpoint);
1165168404Spjd			else
1166168404Spjd				(void) snprintf(buf, sizeof (buf), "%s",
1167168404Spjd				    mountpoint);
1168168404Spjd		}
1169168404Spjd
1170185029Spjd		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
1171185029Spjd			(void) fprintf(stderr, gettext("mountpoint '%s' : "
1172185029Spjd			    "%s\n"), buf, strerror(errno));
1173185029Spjd			(void) fprintf(stderr, gettext("use '-m' "
1174185029Spjd			    "option to provide a different default\n"));
1175185029Spjd			goto errout;
1176185029Spjd		} else if (dirp) {
1177185029Spjd			int count = 0;
1178185029Spjd
1179185029Spjd			while (count < 3 && readdir(dirp) != NULL)
1180185029Spjd				count++;
1181185029Spjd			(void) closedir(dirp);
1182185029Spjd
1183185029Spjd			if (count > 2) {
1184168404Spjd				(void) fprintf(stderr, gettext("mountpoint "
1185168404Spjd				    "'%s' exists and is not empty\n"), buf);
1186185029Spjd				(void) fprintf(stderr, gettext("use '-m' "
1187185029Spjd				    "option to provide a "
1188185029Spjd				    "different default\n"));
1189185029Spjd				goto errout;
1190185029Spjd			}
1191168404Spjd		}
1192168404Spjd	}
1193168404Spjd
1194251634Sdelphij	/*
1195251634Sdelphij	 * Now that the mountpoint's validity has been checked, ensure that
1196251634Sdelphij	 * the property is set appropriately prior to creating the pool.
1197251634Sdelphij	 */
1198251634Sdelphij	if (mountpoint != NULL) {
1199251634Sdelphij		ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1200251634Sdelphij		    mountpoint, &fsprops, B_FALSE);
1201251634Sdelphij		if (ret != 0)
1202251634Sdelphij			goto errout;
1203251634Sdelphij	}
1204251634Sdelphij
1205251634Sdelphij	ret = 1;
1206168404Spjd	if (dryrun) {
1207168404Spjd		/*
1208168404Spjd		 * For a dry run invocation, print out a basic message and run
1209168404Spjd		 * through all the vdevs in the list and print out in an
1210168404Spjd		 * appropriate hierarchy.
1211168404Spjd		 */
1212168404Spjd		(void) printf(gettext("would create '%s' with the "
1213168404Spjd		    "following layout:\n\n"), poolname);
1214168404Spjd
1215185029Spjd		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
1216185029Spjd		if (num_logs(nvroot) > 0)
1217185029Spjd			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
1218168404Spjd
1219168404Spjd		ret = 0;
1220168404Spjd	} else {
1221168404Spjd		/*
1222168404Spjd		 * Hand off to libzfs.
1223168404Spjd		 */
1224236884Smm		if (enable_all_pool_feat) {
1225259813Sdelphij			spa_feature_t i;
1226236884Smm			for (i = 0; i < SPA_FEATURES; i++) {
1227236884Smm				char propname[MAXPATHLEN];
1228236884Smm				zfeature_info_t *feat = &spa_feature_table[i];
1229236884Smm
1230236884Smm				(void) snprintf(propname, sizeof (propname),
1231236884Smm				    "feature@%s", feat->fi_uname);
1232236884Smm
1233236884Smm				/*
1234236884Smm				 * Skip feature if user specified it manually
1235236884Smm				 * on the command line.
1236236884Smm				 */
1237236884Smm				if (nvlist_exists(props, propname))
1238236884Smm					continue;
1239236884Smm
1240251634Sdelphij				ret = add_prop_list(propname,
1241251634Sdelphij				    ZFS_FEATURE_ENABLED, &props, B_TRUE);
1242251634Sdelphij				if (ret != 0)
1243236884Smm					goto errout;
1244236884Smm			}
1245236884Smm		}
1246251634Sdelphij
1247251634Sdelphij		ret = 1;
1248185029Spjd		if (zpool_create(g_zfs, poolname,
1249185029Spjd		    nvroot, props, fsprops) == 0) {
1250333194Savg			zfs_handle_t *pool = zfs_open(g_zfs,
1251333194Savg			    tname ? tname : poolname, ZFS_TYPE_FILESYSTEM);
1252168404Spjd			if (pool != NULL) {
1253168404Spjd				if (zfs_mount(pool, NULL, 0) == 0)
1254185029Spjd					ret = zfs_shareall(pool);
1255168404Spjd				zfs_close(pool);
1256168404Spjd			}
1257168404Spjd		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
1258168404Spjd			(void) fprintf(stderr, gettext("pool name may have "
1259168404Spjd			    "been omitted\n"));
1260168404Spjd		}
1261168404Spjd	}
1262168404Spjd
1263185029Spjderrout:
1264168404Spjd	nvlist_free(nvroot);
1265185029Spjd	nvlist_free(fsprops);
1266185029Spjd	nvlist_free(props);
1267168404Spjd	return (ret);
1268185029Spjdbadusage:
1269185029Spjd	nvlist_free(fsprops);
1270185029Spjd	nvlist_free(props);
1271185029Spjd	usage(B_FALSE);
1272185029Spjd	return (2);
1273168404Spjd}
1274168404Spjd
1275168404Spjd/*
1276168404Spjd * zpool destroy <pool>
1277168404Spjd *
1278342941Savg *	-f	Forcefully unmount any datasets
1279168404Spjd *
1280168404Spjd * Destroy the given pool.  Automatically unmounts any datasets in the pool.
1281168404Spjd */
1282168404Spjdint
1283168404Spjdzpool_do_destroy(int argc, char **argv)
1284168404Spjd{
1285168404Spjd	boolean_t force = B_FALSE;
1286168404Spjd	int c;
1287168404Spjd	char *pool;
1288168404Spjd	zpool_handle_t *zhp;
1289168404Spjd	int ret;
1290168404Spjd
1291168404Spjd	/* check options */
1292168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
1293168404Spjd		switch (c) {
1294168404Spjd		case 'f':
1295168404Spjd			force = B_TRUE;
1296168404Spjd			break;
1297168404Spjd		case '?':
1298168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1299168404Spjd			    optopt);
1300168404Spjd			usage(B_FALSE);
1301168404Spjd		}
1302168404Spjd	}
1303168404Spjd
1304168404Spjd	argc -= optind;
1305168404Spjd	argv += optind;
1306168404Spjd
1307168404Spjd	/* check arguments */
1308168404Spjd	if (argc < 1) {
1309168404Spjd		(void) fprintf(stderr, gettext("missing pool argument\n"));
1310168404Spjd		usage(B_FALSE);
1311168404Spjd	}
1312168404Spjd	if (argc > 1) {
1313168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
1314168404Spjd		usage(B_FALSE);
1315168404Spjd	}
1316168404Spjd
1317168404Spjd	pool = argv[0];
1318168404Spjd
1319168404Spjd	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
1320168404Spjd		/*
1321168404Spjd		 * As a special case, check for use of '/' in the name, and
1322168404Spjd		 * direct the user to use 'zfs destroy' instead.
1323168404Spjd		 */
1324168404Spjd		if (strchr(pool, '/') != NULL)
1325168404Spjd			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
1326168404Spjd			    "destroy a dataset\n"));
1327168404Spjd		return (1);
1328168404Spjd	}
1329168404Spjd
1330168404Spjd	if (zpool_disable_datasets(zhp, force) != 0) {
1331168404Spjd		(void) fprintf(stderr, gettext("could not destroy '%s': "
1332168404Spjd		    "could not unmount datasets\n"), zpool_get_name(zhp));
1333168404Spjd		return (1);
1334168404Spjd	}
1335168404Spjd
1336248571Smm	/* The history must be logged as part of the export */
1337248571Smm	log_history = B_FALSE;
1338168404Spjd
1339248571Smm	ret = (zpool_destroy(zhp, history_str) != 0);
1340248571Smm
1341168404Spjd	zpool_close(zhp);
1342168404Spjd
1343168404Spjd	return (ret);
1344168404Spjd}
1345168404Spjd
1346168404Spjd/*
1347168404Spjd * zpool export [-f] <pool> ...
1348168404Spjd *
1349168404Spjd *	-f	Forcefully unmount datasets
1350168404Spjd *
1351168404Spjd * Export the given pools.  By default, the command will attempt to cleanly
1352168404Spjd * unmount any active datasets within the pool.  If the '-f' flag is specified,
1353168404Spjd * then the datasets will be forcefully unmounted.
1354168404Spjd */
1355168404Spjdint
1356168404Spjdzpool_do_export(int argc, char **argv)
1357168404Spjd{
1358168404Spjd	boolean_t force = B_FALSE;
1359207670Smm	boolean_t hardforce = B_FALSE;
1360168404Spjd	int c;
1361168404Spjd	zpool_handle_t *zhp;
1362168404Spjd	int ret;
1363168404Spjd	int i;
1364168404Spjd
1365168404Spjd	/* check options */
1366207670Smm	while ((c = getopt(argc, argv, "fF")) != -1) {
1367168404Spjd		switch (c) {
1368168404Spjd		case 'f':
1369168404Spjd			force = B_TRUE;
1370168404Spjd			break;
1371207670Smm		case 'F':
1372207670Smm			hardforce = B_TRUE;
1373207670Smm			break;
1374168404Spjd		case '?':
1375168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1376168404Spjd			    optopt);
1377168404Spjd			usage(B_FALSE);
1378168404Spjd		}
1379168404Spjd	}
1380168404Spjd
1381168404Spjd	argc -= optind;
1382168404Spjd	argv += optind;
1383168404Spjd
1384168404Spjd	/* check arguments */
1385168404Spjd	if (argc < 1) {
1386168404Spjd		(void) fprintf(stderr, gettext("missing pool argument\n"));
1387168404Spjd		usage(B_FALSE);
1388168404Spjd	}
1389168404Spjd
1390168404Spjd	ret = 0;
1391168404Spjd	for (i = 0; i < argc; i++) {
1392168404Spjd		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
1393168404Spjd			ret = 1;
1394168404Spjd			continue;
1395168404Spjd		}
1396168404Spjd
1397168404Spjd		if (zpool_disable_datasets(zhp, force) != 0) {
1398168404Spjd			ret = 1;
1399168404Spjd			zpool_close(zhp);
1400168404Spjd			continue;
1401168404Spjd		}
1402168404Spjd
1403248571Smm		/* The history must be logged as part of the export */
1404248571Smm		log_history = B_FALSE;
1405248571Smm
1406207670Smm		if (hardforce) {
1407248571Smm			if (zpool_export_force(zhp, history_str) != 0)
1408207670Smm				ret = 1;
1409248571Smm		} else if (zpool_export(zhp, force, history_str) != 0) {
1410168404Spjd			ret = 1;
1411207670Smm		}
1412168404Spjd
1413168404Spjd		zpool_close(zhp);
1414168404Spjd	}
1415168404Spjd
1416168404Spjd	return (ret);
1417168404Spjd}
1418168404Spjd
1419168404Spjd/*
1420168404Spjd * Given a vdev configuration, determine the maximum width needed for the device
1421168404Spjd * name column.
1422168404Spjd */
1423168404Spjdstatic int
1424168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
1425168404Spjd{
1426219089Spjd	char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
1427168404Spjd	nvlist_t **child;
1428168404Spjd	uint_t c, children;
1429168404Spjd	int ret;
1430168404Spjd
1431168404Spjd	if (strlen(name) + depth > max)
1432168404Spjd		max = strlen(name) + depth;
1433168404Spjd
1434168404Spjd	free(name);
1435168404Spjd
1436168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1437168404Spjd	    &child, &children) == 0) {
1438168404Spjd		for (c = 0; c < children; c++)
1439168404Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
1440168404Spjd			    max)) > max)
1441168404Spjd				max = ret;
1442168404Spjd	}
1443168404Spjd
1444185029Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1445185029Spjd	    &child, &children) == 0) {
1446185029Spjd		for (c = 0; c < children; c++)
1447185029Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
1448185029Spjd			    max)) > max)
1449185029Spjd				max = ret;
1450185029Spjd	}
1451185029Spjd
1452168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1453168404Spjd	    &child, &children) == 0) {
1454168404Spjd		for (c = 0; c < children; c++)
1455168404Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
1456168404Spjd			    max)) > max)
1457168404Spjd				max = ret;
1458168404Spjd	}
1459168404Spjd
1460168404Spjd
1461168404Spjd	return (max);
1462168404Spjd}
1463168404Spjd
1464213197Smmtypedef struct spare_cbdata {
1465213197Smm	uint64_t	cb_guid;
1466213197Smm	zpool_handle_t	*cb_zhp;
1467213197Smm} spare_cbdata_t;
1468168404Spjd
1469213197Smmstatic boolean_t
1470213197Smmfind_vdev(nvlist_t *nv, uint64_t search)
1471213197Smm{
1472213197Smm	uint64_t guid;
1473213197Smm	nvlist_t **child;
1474213197Smm	uint_t c, children;
1475213197Smm
1476213197Smm	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
1477213197Smm	    search == guid)
1478213197Smm		return (B_TRUE);
1479213197Smm
1480213197Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1481213197Smm	    &child, &children) == 0) {
1482213197Smm		for (c = 0; c < children; c++)
1483213197Smm			if (find_vdev(child[c], search))
1484213197Smm				return (B_TRUE);
1485213197Smm	}
1486213197Smm
1487213197Smm	return (B_FALSE);
1488213197Smm}
1489213197Smm
1490213197Smmstatic int
1491213197Smmfind_spare(zpool_handle_t *zhp, void *data)
1492213197Smm{
1493213197Smm	spare_cbdata_t *cbp = data;
1494213197Smm	nvlist_t *config, *nvroot;
1495213197Smm
1496213197Smm	config = zpool_get_config(zhp, NULL);
1497213197Smm	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1498213197Smm	    &nvroot) == 0);
1499213197Smm
1500213197Smm	if (find_vdev(nvroot, cbp->cb_guid)) {
1501213197Smm		cbp->cb_zhp = zhp;
1502213197Smm		return (1);
1503213197Smm	}
1504213197Smm
1505213197Smm	zpool_close(zhp);
1506213197Smm	return (0);
1507213197Smm}
1508213197Smm
1509168404Spjd/*
1510213197Smm * Print out configuration state as requested by status_callback.
1511213197Smm */
1512213197Smmvoid
1513213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
1514213197Smm    int namewidth, int depth, boolean_t isspare)
1515213197Smm{
1516213197Smm	nvlist_t **child;
1517254591Sgibbs	uint_t c, vsc, children;
1518219089Spjd	pool_scan_stat_t *ps = NULL;
1519213197Smm	vdev_stat_t *vs;
1520219089Spjd	char rbuf[6], wbuf[6], cbuf[6];
1521213197Smm	char *vname;
1522213197Smm	uint64_t notpresent;
1523254591Sgibbs	uint64_t ashift;
1524213197Smm	spare_cbdata_t cb;
1525224169Sgibbs	const char *state;
1526332525Smav	char *type;
1527213197Smm
1528213197Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1529213197Smm	    &child, &children) != 0)
1530213197Smm		children = 0;
1531213197Smm
1532219089Spjd	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1533254591Sgibbs	    (uint64_t **)&vs, &vsc) == 0);
1534219089Spjd
1535332525Smav	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
1536332525Smav
1537332525Smav	if (strcmp(type, VDEV_TYPE_INDIRECT) == 0)
1538332525Smav		return;
1539332525Smav
1540213197Smm	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1541213197Smm	if (isspare) {
1542213197Smm		/*
1543213197Smm		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
1544213197Smm		 * online drives.
1545213197Smm		 */
1546213197Smm		if (vs->vs_aux == VDEV_AUX_SPARED)
1547213197Smm			state = "INUSE";
1548213197Smm		else if (vs->vs_state == VDEV_STATE_HEALTHY)
1549213197Smm			state = "AVAIL";
1550213197Smm	}
1551213197Smm
1552213197Smm	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
1553213197Smm	    name, state);
1554213197Smm
1555213197Smm	if (!isspare) {
1556213197Smm		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
1557213197Smm		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
1558213197Smm		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
1559213197Smm		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
1560213197Smm	}
1561213197Smm
1562213197Smm	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1563224170Sgibbs	    &notpresent) == 0 ||
1564224170Sgibbs	    vs->vs_state <= VDEV_STATE_CANT_OPEN) {
1565213197Smm		char *path;
1566224170Sgibbs		if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0)
1567224170Sgibbs			(void) printf("  was %s", path);
1568213197Smm	} else if (vs->vs_aux != 0) {
1569213197Smm		(void) printf("  ");
1570213197Smm
1571213197Smm		switch (vs->vs_aux) {
1572213197Smm		case VDEV_AUX_OPEN_FAILED:
1573213197Smm			(void) printf(gettext("cannot open"));
1574213197Smm			break;
1575213197Smm
1576213197Smm		case VDEV_AUX_BAD_GUID_SUM:
1577213197Smm			(void) printf(gettext("missing device"));
1578213197Smm			break;
1579213197Smm
1580213197Smm		case VDEV_AUX_NO_REPLICAS:
1581213197Smm			(void) printf(gettext("insufficient replicas"));
1582213197Smm			break;
1583213197Smm
1584213197Smm		case VDEV_AUX_VERSION_NEWER:
1585213197Smm			(void) printf(gettext("newer version"));
1586213197Smm			break;
1587213197Smm
1588236884Smm		case VDEV_AUX_UNSUP_FEAT:
1589236884Smm			(void) printf(gettext("unsupported feature(s)"));
1590236884Smm			break;
1591236884Smm
1592254591Sgibbs		case VDEV_AUX_ASHIFT_TOO_BIG:
1593254591Sgibbs			(void) printf(gettext("unsupported minimum blocksize"));
1594254591Sgibbs			break;
1595254591Sgibbs
1596213197Smm		case VDEV_AUX_SPARED:
1597213197Smm			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1598213197Smm			    &cb.cb_guid) == 0);
1599213197Smm			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
1600213197Smm				if (strcmp(zpool_get_name(cb.cb_zhp),
1601213197Smm				    zpool_get_name(zhp)) == 0)
1602213197Smm					(void) printf(gettext("currently in "
1603213197Smm					    "use"));
1604213197Smm				else
1605213197Smm					(void) printf(gettext("in use by "
1606213197Smm					    "pool '%s'"),
1607213197Smm					    zpool_get_name(cb.cb_zhp));
1608213197Smm				zpool_close(cb.cb_zhp);
1609213197Smm			} else {
1610213197Smm				(void) printf(gettext("currently in use"));
1611213197Smm			}
1612213197Smm			break;
1613213197Smm
1614213197Smm		case VDEV_AUX_ERR_EXCEEDED:
1615213197Smm			(void) printf(gettext("too many errors"));
1616213197Smm			break;
1617213197Smm
1618213197Smm		case VDEV_AUX_IO_FAILURE:
1619213197Smm			(void) printf(gettext("experienced I/O failures"));
1620213197Smm			break;
1621213197Smm
1622213197Smm		case VDEV_AUX_BAD_LOG:
1623213197Smm			(void) printf(gettext("bad intent log"));
1624213197Smm			break;
1625213197Smm
1626219089Spjd		case VDEV_AUX_EXTERNAL:
1627219089Spjd			(void) printf(gettext("external device fault"));
1628219089Spjd			break;
1629219089Spjd
1630219089Spjd		case VDEV_AUX_SPLIT_POOL:
1631219089Spjd			(void) printf(gettext("split into new pool"));
1632219089Spjd			break;
1633219089Spjd
1634332536Smav		case VDEV_AUX_CHILDREN_OFFLINE:
1635332536Smav			(void) printf(gettext("all children offline"));
1636332536Smav			break;
1637332536Smav
1638213197Smm		default:
1639213197Smm			(void) printf(gettext("corrupted data"));
1640213197Smm			break;
1641213197Smm		}
1642254591Sgibbs	} else if (children == 0 && !isspare &&
1643254591Sgibbs	    VDEV_STAT_VALID(vs_physical_ashift, vsc) &&
1644254591Sgibbs	    vs->vs_configured_ashift < vs->vs_physical_ashift) {
1645254591Sgibbs		(void) printf(
1646254591Sgibbs		    gettext("  block size: %dB configured, %dB native"),
1647254591Sgibbs		    1 << vs->vs_configured_ashift, 1 << vs->vs_physical_ashift);
1648213197Smm	}
1649213197Smm
1650219089Spjd	(void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS,
1651219089Spjd	    (uint64_t **)&ps, &c);
1652219089Spjd
1653339034Ssef	if (ps != NULL && ps->pss_state == DSS_SCANNING &&
1654219089Spjd	    vs->vs_scan_processed != 0 && children == 0) {
1655219089Spjd		(void) printf(gettext("  (%s)"),
1656219089Spjd		    (ps->pss_func == POOL_SCAN_RESILVER) ?
1657219089Spjd		    "resilvering" : "repairing");
1658219089Spjd	}
1659219089Spjd
1660339111Smav	if ((vs->vs_initialize_state == VDEV_INITIALIZE_ACTIVE ||
1661339111Smav	    vs->vs_initialize_state == VDEV_INITIALIZE_SUSPENDED ||
1662339111Smav	    vs->vs_initialize_state == VDEV_INITIALIZE_COMPLETE) &&
1663339111Smav	    !vs->vs_scan_removing) {
1664339111Smav		char zbuf[1024];
1665339111Smav		char tbuf[256];
1666339111Smav		struct tm zaction_ts;
1667339111Smav
1668339111Smav		time_t t = vs->vs_initialize_action_time;
1669339111Smav		int initialize_pct = 100;
1670339111Smav		if (vs->vs_initialize_state != VDEV_INITIALIZE_COMPLETE) {
1671339111Smav			initialize_pct = (vs->vs_initialize_bytes_done * 100 /
1672339111Smav			    (vs->vs_initialize_bytes_est + 1));
1673339111Smav		}
1674339111Smav
1675339111Smav		(void) localtime_r(&t, &zaction_ts);
1676339111Smav		(void) strftime(tbuf, sizeof (tbuf), "%c", &zaction_ts);
1677339111Smav
1678339111Smav		switch (vs->vs_initialize_state) {
1679339111Smav		case VDEV_INITIALIZE_SUSPENDED:
1680339111Smav			(void) snprintf(zbuf, sizeof (zbuf),
1681339111Smav			    ", suspended, started at %s", tbuf);
1682339111Smav			break;
1683339111Smav		case VDEV_INITIALIZE_ACTIVE:
1684339111Smav			(void) snprintf(zbuf, sizeof (zbuf),
1685339111Smav			    ", started at %s", tbuf);
1686339111Smav			break;
1687339111Smav		case VDEV_INITIALIZE_COMPLETE:
1688339111Smav			(void) snprintf(zbuf, sizeof (zbuf),
1689339111Smav			    ", completed at %s", tbuf);
1690339111Smav			break;
1691339111Smav		}
1692339111Smav
1693339111Smav		(void) printf(gettext("  (%d%% initialized%s)"),
1694339111Smav		    initialize_pct, zbuf);
1695339111Smav	}
1696339111Smav
1697213197Smm	(void) printf("\n");
1698213197Smm
1699213197Smm	for (c = 0; c < children; c++) {
1700219089Spjd		uint64_t islog = B_FALSE, ishole = B_FALSE;
1701213197Smm
1702219089Spjd		/* Don't print logs or holes here */
1703213197Smm		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1704219089Spjd		    &islog);
1705219089Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
1706219089Spjd		    &ishole);
1707219089Spjd		if (islog || ishole)
1708213197Smm			continue;
1709219089Spjd		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1710213197Smm		print_status_config(zhp, vname, child[c],
1711213197Smm		    namewidth, depth + 2, isspare);
1712213197Smm		free(vname);
1713213197Smm	}
1714213197Smm}
1715213197Smm
1716213197Smm
1717213197Smm/*
1718168404Spjd * Print the configuration of an exported pool.  Iterate over all vdevs in the
1719168404Spjd * pool, printing out the name and status for each one.
1720168404Spjd */
1721168404Spjdvoid
1722213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
1723168404Spjd{
1724168404Spjd	nvlist_t **child;
1725168404Spjd	uint_t c, children;
1726168404Spjd	vdev_stat_t *vs;
1727168404Spjd	char *type, *vname;
1728168404Spjd
1729168404Spjd	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
1730219089Spjd	if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
1731219089Spjd	    strcmp(type, VDEV_TYPE_HOLE) == 0)
1732168404Spjd		return;
1733168404Spjd
1734219089Spjd	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1735168404Spjd	    (uint64_t **)&vs, &c) == 0);
1736168404Spjd
1737168404Spjd	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
1738185029Spjd	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1739168404Spjd
1740168404Spjd	if (vs->vs_aux != 0) {
1741185029Spjd		(void) printf("  ");
1742168404Spjd
1743168404Spjd		switch (vs->vs_aux) {
1744168404Spjd		case VDEV_AUX_OPEN_FAILED:
1745168404Spjd			(void) printf(gettext("cannot open"));
1746168404Spjd			break;
1747168404Spjd
1748168404Spjd		case VDEV_AUX_BAD_GUID_SUM:
1749168404Spjd			(void) printf(gettext("missing device"));
1750168404Spjd			break;
1751168404Spjd
1752168404Spjd		case VDEV_AUX_NO_REPLICAS:
1753168404Spjd			(void) printf(gettext("insufficient replicas"));
1754168404Spjd			break;
1755168404Spjd
1756168404Spjd		case VDEV_AUX_VERSION_NEWER:
1757168404Spjd			(void) printf(gettext("newer version"));
1758168404Spjd			break;
1759168404Spjd
1760236884Smm		case VDEV_AUX_UNSUP_FEAT:
1761236884Smm			(void) printf(gettext("unsupported feature(s)"));
1762236884Smm			break;
1763236884Smm
1764185029Spjd		case VDEV_AUX_ERR_EXCEEDED:
1765185029Spjd			(void) printf(gettext("too many errors"));
1766185029Spjd			break;
1767185029Spjd
1768332536Smav		case VDEV_AUX_CHILDREN_OFFLINE:
1769332536Smav			(void) printf(gettext("all children offline"));
1770332536Smav			break;
1771332536Smav
1772168404Spjd		default:
1773168404Spjd			(void) printf(gettext("corrupted data"));
1774168404Spjd			break;
1775168404Spjd		}
1776168404Spjd	}
1777168404Spjd	(void) printf("\n");
1778168404Spjd
1779168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1780168404Spjd	    &child, &children) != 0)
1781168404Spjd		return;
1782168404Spjd
1783168404Spjd	for (c = 0; c < children; c++) {
1784185029Spjd		uint64_t is_log = B_FALSE;
1785185029Spjd
1786185029Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1787185029Spjd		    &is_log);
1788213197Smm		if (is_log)
1789185029Spjd			continue;
1790185029Spjd
1791219089Spjd		vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
1792213197Smm		print_import_config(vname, child[c], namewidth, depth + 2);
1793168404Spjd		free(vname);
1794168404Spjd	}
1795168404Spjd
1796185029Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1797185029Spjd	    &child, &children) == 0) {
1798185029Spjd		(void) printf(gettext("\tcache\n"));
1799185029Spjd		for (c = 0; c < children; c++) {
1800219089Spjd			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1801185029Spjd			(void) printf("\t  %s\n", vname);
1802185029Spjd			free(vname);
1803185029Spjd		}
1804185029Spjd	}
1805185029Spjd
1806168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1807185029Spjd	    &child, &children) == 0) {
1808185029Spjd		(void) printf(gettext("\tspares\n"));
1809185029Spjd		for (c = 0; c < children; c++) {
1810219089Spjd			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1811185029Spjd			(void) printf("\t  %s\n", vname);
1812185029Spjd			free(vname);
1813185029Spjd		}
1814168404Spjd	}
1815168404Spjd}
1816168404Spjd
1817168404Spjd/*
1818213197Smm * Print log vdevs.
1819213197Smm * Logs are recorded as top level vdevs in the main pool child array
1820213197Smm * but with "is_log" set to 1. We use either print_status_config() or
1821213197Smm * print_import_config() to print the top level logs then any log
1822213197Smm * children (eg mirrored slogs) are printed recursively - which
1823213197Smm * works because only the top level vdev is marked "is_log"
1824213197Smm */
1825213197Smmstatic void
1826213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
1827213197Smm{
1828213197Smm	uint_t c, children;
1829213197Smm	nvlist_t **child;
1830213197Smm
1831213197Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1832213197Smm	    &children) != 0)
1833213197Smm		return;
1834213197Smm
1835213197Smm	(void) printf(gettext("\tlogs\n"));
1836213197Smm
1837213197Smm	for (c = 0; c < children; c++) {
1838213197Smm		uint64_t is_log = B_FALSE;
1839213197Smm		char *name;
1840213197Smm
1841213197Smm		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1842213197Smm		    &is_log);
1843213197Smm		if (!is_log)
1844213197Smm			continue;
1845219089Spjd		name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1846213197Smm		if (verbose)
1847213197Smm			print_status_config(zhp, name, child[c], namewidth,
1848213197Smm			    2, B_FALSE);
1849213197Smm		else
1850213197Smm			print_import_config(name, child[c], namewidth, 2);
1851213197Smm		free(name);
1852213197Smm	}
1853213197Smm}
1854219089Spjd
1855213197Smm/*
1856168404Spjd * Display the status for the given pool.
1857168404Spjd */
1858168404Spjdstatic void
1859168404Spjdshow_import(nvlist_t *config)
1860168404Spjd{
1861168404Spjd	uint64_t pool_state;
1862168404Spjd	vdev_stat_t *vs;
1863168404Spjd	char *name;
1864168404Spjd	uint64_t guid;
1865168404Spjd	char *msgid;
1866168404Spjd	nvlist_t *nvroot;
1867168404Spjd	int reason;
1868168404Spjd	const char *health;
1869168404Spjd	uint_t vsc;
1870168404Spjd	int namewidth;
1871228103Smm	char *comment;
1872168404Spjd
1873168404Spjd	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1874168404Spjd	    &name) == 0);
1875168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1876168404Spjd	    &guid) == 0);
1877168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1878168404Spjd	    &pool_state) == 0);
1879168404Spjd	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1880168404Spjd	    &nvroot) == 0);
1881168404Spjd
1882219089Spjd	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
1883168404Spjd	    (uint64_t **)&vs, &vsc) == 0);
1884185029Spjd	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1885168404Spjd
1886168404Spjd	reason = zpool_import_status(config, &msgid);
1887168404Spjd
1888228103Smm	(void) printf(gettext("   pool: %s\n"), name);
1889228103Smm	(void) printf(gettext("     id: %llu\n"), (u_longlong_t)guid);
1890228103Smm	(void) printf(gettext("  state: %s"), health);
1891168404Spjd	if (pool_state == POOL_STATE_DESTROYED)
1892168404Spjd		(void) printf(gettext(" (DESTROYED)"));
1893168404Spjd	(void) printf("\n");
1894168404Spjd
1895168404Spjd	switch (reason) {
1896168404Spjd	case ZPOOL_STATUS_MISSING_DEV_R:
1897168404Spjd	case ZPOOL_STATUS_MISSING_DEV_NR:
1898168404Spjd	case ZPOOL_STATUS_BAD_GUID_SUM:
1899228103Smm		(void) printf(gettext(" status: One or more devices are "
1900228103Smm		    "missing from the system.\n"));
1901168404Spjd		break;
1902168404Spjd
1903168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1904168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1905228103Smm		(void) printf(gettext(" status: One or more devices contains "
1906168404Spjd		    "corrupted data.\n"));
1907168404Spjd		break;
1908168404Spjd
1909168404Spjd	case ZPOOL_STATUS_CORRUPT_DATA:
1910228103Smm		(void) printf(
1911228103Smm		    gettext(" status: The pool data is corrupted.\n"));
1912168404Spjd		break;
1913168404Spjd
1914168404Spjd	case ZPOOL_STATUS_OFFLINE_DEV:
1915228103Smm		(void) printf(gettext(" status: One or more devices "
1916168404Spjd		    "are offlined.\n"));
1917168404Spjd		break;
1918168404Spjd
1919168404Spjd	case ZPOOL_STATUS_CORRUPT_POOL:
1920228103Smm		(void) printf(gettext(" status: The pool metadata is "
1921168404Spjd		    "corrupted.\n"));
1922168404Spjd		break;
1923168404Spjd
1924168404Spjd	case ZPOOL_STATUS_VERSION_OLDER:
1925238926Smm		(void) printf(gettext(" status: The pool is formatted using a "
1926238926Smm		    "legacy on-disk version.\n"));
1927168404Spjd		break;
1928168404Spjd
1929168404Spjd	case ZPOOL_STATUS_VERSION_NEWER:
1930228103Smm		(void) printf(gettext(" status: The pool is formatted using an "
1931168404Spjd		    "incompatible version.\n"));
1932168404Spjd		break;
1933168404Spjd
1934238926Smm	case ZPOOL_STATUS_FEAT_DISABLED:
1935238926Smm		(void) printf(gettext(" status: Some supported features are "
1936238926Smm		    "not enabled on the pool.\n"));
1937238926Smm		break;
1938238926Smm
1939236884Smm	case ZPOOL_STATUS_UNSUP_FEAT_READ:
1940236884Smm		(void) printf(gettext("status: The pool uses the following "
1941332542Smav		    "feature(s) not supported on this system:\n"));
1942236884Smm		zpool_print_unsup_feat(config);
1943236884Smm		break;
1944236884Smm
1945236884Smm	case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
1946236884Smm		(void) printf(gettext("status: The pool can only be accessed "
1947236884Smm		    "in read-only mode on this system. It\n\tcannot be "
1948236884Smm		    "accessed in read-write mode because it uses the "
1949236884Smm		    "following\n\tfeature(s) not supported on this system:\n"));
1950236884Smm		zpool_print_unsup_feat(config);
1951236884Smm		break;
1952236884Smm
1953168498Spjd	case ZPOOL_STATUS_HOSTID_MISMATCH:
1954228103Smm		(void) printf(gettext(" status: The pool was last accessed by "
1955168498Spjd		    "another system.\n"));
1956168498Spjd		break;
1957185029Spjd
1958185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_R:
1959185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_NR:
1960228103Smm		(void) printf(gettext(" status: One or more devices are "
1961185029Spjd		    "faulted.\n"));
1962185029Spjd		break;
1963185029Spjd
1964185029Spjd	case ZPOOL_STATUS_BAD_LOG:
1965228103Smm		(void) printf(gettext(" status: An intent log record cannot be "
1966185029Spjd		    "read.\n"));
1967185029Spjd		break;
1968185029Spjd
1969219089Spjd	case ZPOOL_STATUS_RESILVERING:
1970228103Smm		(void) printf(gettext(" status: One or more devices were being "
1971219089Spjd		    "resilvered.\n"));
1972219089Spjd		break;
1973219089Spjd
1974259131Sdelphij	case ZPOOL_STATUS_NON_NATIVE_ASHIFT:
1975259131Sdelphij		(void) printf(gettext("status: One or more devices were "
1976259131Sdelphij		    "configured to use a non-native block size.\n"
1977259131Sdelphij		    "\tExpect reduced performance.\n"));
1978259131Sdelphij		break;
1979259131Sdelphij
1980168404Spjd	default:
1981168404Spjd		/*
1982168404Spjd		 * No other status can be seen when importing pools.
1983168404Spjd		 */
1984168404Spjd		assert(reason == ZPOOL_STATUS_OK);
1985168404Spjd	}
1986168404Spjd
1987168404Spjd	/*
1988168404Spjd	 * Print out an action according to the overall state of the pool.
1989168404Spjd	 */
1990168404Spjd	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1991238926Smm		if (reason == ZPOOL_STATUS_VERSION_OLDER ||
1992238926Smm		    reason == ZPOOL_STATUS_FEAT_DISABLED) {
1993228103Smm			(void) printf(gettext(" action: The pool can be "
1994168404Spjd			    "imported using its name or numeric identifier, "
1995168404Spjd			    "though\n\tsome features will not be available "
1996168404Spjd			    "without an explicit 'zpool upgrade'.\n"));
1997238926Smm		} else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) {
1998228103Smm			(void) printf(gettext(" action: The pool can be "
1999168498Spjd			    "imported using its name or numeric "
2000168498Spjd			    "identifier and\n\tthe '-f' flag.\n"));
2001238926Smm		} else {
2002228103Smm			(void) printf(gettext(" action: The pool can be "
2003168404Spjd			    "imported using its name or numeric "
2004168404Spjd			    "identifier.\n"));
2005238926Smm		}
2006168404Spjd	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
2007228103Smm		(void) printf(gettext(" action: The pool can be imported "
2008168404Spjd		    "despite missing or damaged devices.  The\n\tfault "
2009168404Spjd		    "tolerance of the pool may be compromised if imported.\n"));
2010168404Spjd	} else {
2011168404Spjd		switch (reason) {
2012168404Spjd		case ZPOOL_STATUS_VERSION_NEWER:
2013228103Smm			(void) printf(gettext(" action: The pool cannot be "
2014168404Spjd			    "imported.  Access the pool on a system running "
2015168404Spjd			    "newer\n\tsoftware, or recreate the pool from "
2016168404Spjd			    "backup.\n"));
2017168404Spjd			break;
2018236884Smm		case ZPOOL_STATUS_UNSUP_FEAT_READ:
2019236884Smm			(void) printf(gettext("action: The pool cannot be "
2020236884Smm			    "imported. Access the pool on a system that "
2021236884Smm			    "supports\n\tthe required feature(s), or recreate "
2022236884Smm			    "the pool from backup.\n"));
2023236884Smm			break;
2024236884Smm		case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
2025236884Smm			(void) printf(gettext("action: The pool cannot be "
2026236884Smm			    "imported in read-write mode. Import the pool "
2027236884Smm			    "with\n"
2028236884Smm			    "\t\"-o readonly=on\", access the pool on a system "
2029236884Smm			    "that supports the\n\trequired feature(s), or "
2030236884Smm			    "recreate the pool from backup.\n"));
2031236884Smm			break;
2032168404Spjd		case ZPOOL_STATUS_MISSING_DEV_R:
2033168404Spjd		case ZPOOL_STATUS_MISSING_DEV_NR:
2034168404Spjd		case ZPOOL_STATUS_BAD_GUID_SUM:
2035228103Smm			(void) printf(gettext(" action: The pool cannot be "
2036168404Spjd			    "imported. Attach the missing\n\tdevices and try "
2037168404Spjd			    "again.\n"));
2038168404Spjd			break;
2039168404Spjd		default:
2040228103Smm			(void) printf(gettext(" action: The pool cannot be "
2041168404Spjd			    "imported due to damaged devices or data.\n"));
2042168404Spjd		}
2043168404Spjd	}
2044168404Spjd
2045228103Smm	/* Print the comment attached to the pool. */
2046228103Smm	if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
2047228103Smm		(void) printf(gettext("comment: %s\n"), comment);
2048228103Smm
2049168404Spjd	/*
2050168404Spjd	 * If the state is "closed" or "can't open", and the aux state
2051168404Spjd	 * is "corrupt data":
2052168404Spjd	 */
2053168404Spjd	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
2054168404Spjd	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
2055168404Spjd	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
2056168404Spjd		if (pool_state == POOL_STATE_DESTROYED)
2057168404Spjd			(void) printf(gettext("\tThe pool was destroyed, "
2058168404Spjd			    "but can be imported using the '-Df' flags.\n"));
2059168404Spjd		else if (pool_state != POOL_STATE_EXPORTED)
2060168404Spjd			(void) printf(gettext("\tThe pool may be active on "
2061185029Spjd			    "another system, but can be imported using\n\t"
2062168404Spjd			    "the '-f' flag.\n"));
2063168404Spjd	}
2064168404Spjd
2065168404Spjd	if (msgid != NULL)
2066236146Smm		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
2067168404Spjd		    msgid);
2068168404Spjd
2069228103Smm	(void) printf(gettext(" config:\n\n"));
2070168404Spjd
2071168404Spjd	namewidth = max_width(NULL, nvroot, 0, 0);
2072168404Spjd	if (namewidth < 10)
2073168404Spjd		namewidth = 10;
2074168404Spjd
2075213197Smm	print_import_config(name, nvroot, namewidth, 0);
2076213197Smm	if (num_logs(nvroot) > 0)
2077213197Smm		print_logs(NULL, nvroot, namewidth, B_FALSE);
2078185029Spjd
2079168404Spjd	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
2080168404Spjd		(void) printf(gettext("\n\tAdditional devices are known to "
2081168404Spjd		    "be part of this pool, though their\n\texact "
2082168404Spjd		    "configuration cannot be determined.\n"));
2083168404Spjd	}
2084168404Spjd}
2085168404Spjd
2086168404Spjd/*
2087168404Spjd * Perform the import for the given configuration.  This passes the heavy
2088185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained
2089185029Spjd * within the pool.
2090168404Spjd */
2091168404Spjdstatic int
2092168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts,
2093219089Spjd    nvlist_t *props, int flags)
2094168404Spjd{
2095168404Spjd	zpool_handle_t *zhp;
2096168404Spjd	char *name;
2097168404Spjd	uint64_t state;
2098168404Spjd	uint64_t version;
2099168404Spjd
2100168404Spjd	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
2101168404Spjd	    &name) == 0);
2102168404Spjd
2103168404Spjd	verify(nvlist_lookup_uint64(config,
2104168404Spjd	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
2105168404Spjd	verify(nvlist_lookup_uint64(config,
2106168404Spjd	    ZPOOL_CONFIG_VERSION, &version) == 0);
2107236884Smm	if (!SPA_VERSION_IS_SUPPORTED(version)) {
2108168404Spjd		(void) fprintf(stderr, gettext("cannot import '%s': pool "
2109236884Smm		    "is formatted using an unsupported ZFS version\n"), name);
2110168404Spjd		return (1);
2111219089Spjd	} else if (state != POOL_STATE_EXPORTED &&
2112219089Spjd	    !(flags & ZFS_IMPORT_ANY_HOST)) {
2113168498Spjd		uint64_t hostid;
2114168498Spjd
2115168498Spjd		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
2116168498Spjd		    &hostid) == 0) {
2117168498Spjd			if ((unsigned long)hostid != gethostid()) {
2118168498Spjd				char *hostname;
2119168498Spjd				uint64_t timestamp;
2120168498Spjd				time_t t;
2121168498Spjd
2122168498Spjd				verify(nvlist_lookup_string(config,
2123168498Spjd				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
2124168498Spjd				verify(nvlist_lookup_uint64(config,
2125168498Spjd				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
2126168498Spjd				t = timestamp;
2127168498Spjd				(void) fprintf(stderr, gettext("cannot import "
2128168498Spjd				    "'%s': pool may be in use from other "
2129168498Spjd				    "system, it was last accessed by %s "
2130168498Spjd				    "(hostid: 0x%lx) on %s"), name, hostname,
2131168498Spjd				    (unsigned long)hostid,
2132168498Spjd				    asctime(localtime(&t)));
2133168498Spjd				(void) fprintf(stderr, gettext("use '-f' to "
2134168498Spjd				    "import anyway\n"));
2135168498Spjd				return (1);
2136168498Spjd			}
2137168498Spjd		} else {
2138168498Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
2139168498Spjd			    "pool may be in use from other system\n"), name);
2140168498Spjd			(void) fprintf(stderr, gettext("use '-f' to import "
2141168498Spjd			    "anyway\n"));
2142168498Spjd			return (1);
2143168498Spjd		}
2144168404Spjd	}
2145168404Spjd
2146219089Spjd	if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
2147168404Spjd		return (1);
2148168404Spjd
2149168404Spjd	if (newname != NULL)
2150168404Spjd		name = (char *)newname;
2151168404Spjd
2152209962Smm	if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
2153209962Smm		return (1);
2154168404Spjd
2155209962Smm	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
2156219089Spjd	    !(flags & ZFS_IMPORT_ONLY) &&
2157209962Smm	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
2158168404Spjd		zpool_close(zhp);
2159168404Spjd		return (1);
2160168404Spjd	}
2161168404Spjd
2162168404Spjd	zpool_close(zhp);
2163219089Spjd	return (0);
2164168404Spjd}
2165168404Spjd
2166168404Spjd/*
2167332547Smav * zpool checkpoint <pool>
2168332547Smav *       checkpoint --discard <pool>
2169332547Smav *
2170342941Savg *	-d	Discard the checkpoint from a checkpointed
2171342941Savg *	--discard  pool.
2172332547Smav *
2173332547Smav * Checkpoints the specified pool, by taking a "snapshot" of its
2174332547Smav * current state. A pool can only have one checkpoint at a time.
2175332547Smav */
2176332547Smavint
2177332547Smavzpool_do_checkpoint(int argc, char **argv)
2178332547Smav{
2179332547Smav	boolean_t discard;
2180332547Smav	char *pool;
2181332547Smav	zpool_handle_t *zhp;
2182332547Smav	int c, err;
2183332547Smav
2184332547Smav	struct option long_options[] = {
2185332547Smav		{"discard", no_argument, NULL, 'd'},
2186332547Smav		{0, 0, 0, 0}
2187332547Smav	};
2188332547Smav
2189332547Smav	discard = B_FALSE;
2190332547Smav	while ((c = getopt_long(argc, argv, ":d", long_options, NULL)) != -1) {
2191332547Smav		switch (c) {
2192332547Smav		case 'd':
2193332547Smav			discard = B_TRUE;
2194332547Smav			break;
2195332547Smav		case '?':
2196332547Smav			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2197332547Smav			    optopt);
2198332547Smav			usage(B_FALSE);
2199332547Smav		}
2200332547Smav	}
2201332547Smav
2202332547Smav	argc -= optind;
2203332547Smav	argv += optind;
2204332547Smav
2205332547Smav	if (argc < 1) {
2206332547Smav		(void) fprintf(stderr, gettext("missing pool argument\n"));
2207332547Smav		usage(B_FALSE);
2208332547Smav	}
2209332547Smav
2210332547Smav	if (argc > 1) {
2211332547Smav		(void) fprintf(stderr, gettext("too many arguments\n"));
2212332547Smav		usage(B_FALSE);
2213332547Smav	}
2214332547Smav
2215332547Smav	pool = argv[0];
2216332547Smav
2217332547Smav	if ((zhp = zpool_open(g_zfs, pool)) == NULL) {
2218332547Smav		/* As a special case, check for use of '/' in the name */
2219332547Smav		if (strchr(pool, '/') != NULL)
2220332547Smav			(void) fprintf(stderr, gettext("'zpool checkpoint' "
2221332547Smav			    "doesn't work on datasets. To save the state "
2222332547Smav			    "of a dataset from a specific point in time "
2223332547Smav			    "please use 'zfs snapshot'\n"));
2224332547Smav		return (1);
2225332547Smav	}
2226332547Smav
2227332547Smav	if (discard)
2228332547Smav		err = (zpool_discard_checkpoint(zhp) != 0);
2229332547Smav	else
2230332547Smav		err = (zpool_checkpoint(zhp) != 0);
2231332547Smav
2232332547Smav	zpool_close(zhp);
2233332547Smav
2234332547Smav	return (err);
2235332547Smav}
2236332547Smav
2237332547Smav#define	CHECKPOINT_OPT	1024
2238332547Smav
2239332547Smav/*
2240168404Spjd * zpool import [-d dir] [-D]
2241185029Spjd *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
2242185029Spjd *              [-d dir | -c cachefile] [-f] -a
2243185029Spjd *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
2244333194Savg *              [-d dir | -c cachefile] [-f] [-n] [-F] [-t]
2245333194Savg *              <pool | id> [newpool]
2246168404Spjd *
2247342941Savg *	-c	Read pool information from a cachefile instead of searching
2248185029Spjd *		devices.
2249185029Spjd *
2250342941Savg *	-d	Scan in a specific directory, other than /dev/dsk.  More than
2251168404Spjd *		one directory can be specified using multiple '-d' options.
2252168404Spjd *
2253342941Savg *	-D	Scan for previously destroyed pools or import all or only
2254342941Savg *		specified destroyed pools.
2255168404Spjd *
2256342941Savg *	-R	Temporarily import the pool, with all mountpoints relative to
2257168404Spjd *		the given root.  The pool will remain exported when the machine
2258168404Spjd *		is rebooted.
2259168404Spjd *
2260342941Savg *	-V	Import even in the presence of faulted vdevs.  This is an
2261342941Savg *		intentionally undocumented option for testing purposes, and
2262342941Savg *		treats the pool configuration as complete, leaving any bad
2263209962Smm *		vdevs in the FAULTED state. In other words, it does verbatim
2264209962Smm *		import.
2265185029Spjd *
2266342941Savg *	-f	Force import, even if it appears that the pool is active.
2267219089Spjd *
2268342941Savg *	-F	Attempt rewind if necessary.
2269219089Spjd *
2270342941Savg *	-n	See if rewind would work, but don't actually rewind.
2271219089Spjd *
2272342941Savg *	-N	Import the pool but don't mount datasets.
2273219089Spjd *
2274342941Savg *	-t	Use newpool as a temporary pool name instead of renaming
2275342941Savg *		the pool.
2276333194Savg *
2277342941Savg *	-T	Specify a starting txg to use for import. This option is
2278342941Savg *		intentionally undocumented option for testing purposes.
2279219089Spjd *
2280342941Savg *	-a	Import all pools found.
2281168404Spjd *
2282342941Savg *	-o	Set property=value and/or temporary mount options (without '=').
2283185029Spjd *
2284342941Savg *	--rewind-to-checkpoint
2285342941Savg *		Import the pool and revert back to the checkpoint.
2286332547Smav *
2287168404Spjd * The import command scans for pools to import, and import pools based on pool
2288168404Spjd * name and GUID.  The pool can also be renamed as part of the import process.
2289168404Spjd */
2290168404Spjdint
2291168404Spjdzpool_do_import(int argc, char **argv)
2292168404Spjd{
2293168404Spjd	char **searchdirs = NULL;
2294168404Spjd	int nsearch = 0;
2295168404Spjd	int c;
2296219089Spjd	int err = 0;
2297185029Spjd	nvlist_t *pools = NULL;
2298168404Spjd	boolean_t do_all = B_FALSE;
2299168404Spjd	boolean_t do_destroyed = B_FALSE;
2300168404Spjd	char *mntopts = NULL;
2301168404Spjd	nvpair_t *elem;
2302168404Spjd	nvlist_t *config;
2303185029Spjd	uint64_t searchguid = 0;
2304185029Spjd	char *searchname = NULL;
2305185029Spjd	char *propval;
2306168404Spjd	nvlist_t *found_config;
2307219089Spjd	nvlist_t *policy = NULL;
2308185029Spjd	nvlist_t *props = NULL;
2309168404Spjd	boolean_t first;
2310219089Spjd	int flags = ZFS_IMPORT_NORMAL;
2311219089Spjd	uint32_t rewind_policy = ZPOOL_NO_REWIND;
2312219089Spjd	boolean_t dryrun = B_FALSE;
2313219089Spjd	boolean_t do_rewind = B_FALSE;
2314219089Spjd	boolean_t xtreme_rewind = B_FALSE;
2315219089Spjd	uint64_t pool_state, txg = -1ULL;
2316185029Spjd	char *cachefile = NULL;
2317219089Spjd	importargs_t idata = { 0 };
2318219089Spjd	char *endptr;
2319168404Spjd
2320332547Smav
2321332547Smav	struct option long_options[] = {
2322332547Smav		{"rewind-to-checkpoint", no_argument, NULL, CHECKPOINT_OPT},
2323332547Smav		{0, 0, 0, 0}
2324332547Smav	};
2325332547Smav
2326168404Spjd	/* check options */
2327333194Savg	while ((c = getopt_long(argc, argv, ":aCc:d:DEfFmnNo:rR:tT:VX",
2328332547Smav	    long_options, NULL)) != -1) {
2329168404Spjd		switch (c) {
2330168404Spjd		case 'a':
2331168404Spjd			do_all = B_TRUE;
2332168404Spjd			break;
2333185029Spjd		case 'c':
2334185029Spjd			cachefile = optarg;
2335185029Spjd			break;
2336168404Spjd		case 'd':
2337168404Spjd			if (searchdirs == NULL) {
2338168404Spjd				searchdirs = safe_malloc(sizeof (char *));
2339168404Spjd			} else {
2340168404Spjd				char **tmp = safe_malloc((nsearch + 1) *
2341168404Spjd				    sizeof (char *));
2342168404Spjd				bcopy(searchdirs, tmp, nsearch *
2343168404Spjd				    sizeof (char *));
2344168404Spjd				free(searchdirs);
2345168404Spjd				searchdirs = tmp;
2346168404Spjd			}
2347168404Spjd			searchdirs[nsearch++] = optarg;
2348168404Spjd			break;
2349168404Spjd		case 'D':
2350168404Spjd			do_destroyed = B_TRUE;
2351168404Spjd			break;
2352168404Spjd		case 'f':
2353219089Spjd			flags |= ZFS_IMPORT_ANY_HOST;
2354168404Spjd			break;
2355185029Spjd		case 'F':
2356219089Spjd			do_rewind = B_TRUE;
2357185029Spjd			break;
2358219089Spjd		case 'm':
2359219089Spjd			flags |= ZFS_IMPORT_MISSING_LOG;
2360219089Spjd			break;
2361219089Spjd		case 'n':
2362219089Spjd			dryrun = B_TRUE;
2363219089Spjd			break;
2364219089Spjd		case 'N':
2365219089Spjd			flags |= ZFS_IMPORT_ONLY;
2366219089Spjd			break;
2367168404Spjd		case 'o':
2368185029Spjd			if ((propval = strchr(optarg, '=')) != NULL) {
2369185029Spjd				*propval = '\0';
2370185029Spjd				propval++;
2371185029Spjd				if (add_prop_list(optarg, propval,
2372185029Spjd				    &props, B_TRUE))
2373185029Spjd					goto error;
2374185029Spjd			} else {
2375185029Spjd				mntopts = optarg;
2376185029Spjd			}
2377168404Spjd			break;
2378168404Spjd		case 'R':
2379185029Spjd			if (add_prop_list(zpool_prop_to_name(
2380185029Spjd			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
2381185029Spjd				goto error;
2382333194Savg			if (add_prop_list_default(zpool_prop_to_name(
2383185029Spjd			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
2384185029Spjd				goto error;
2385168404Spjd			break;
2386333194Savg		case 't':
2387333194Savg			flags |= ZFS_IMPORT_TEMP_NAME;
2388333194Savg			if (add_prop_list_default(zpool_prop_to_name(
2389333194Savg			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
2390333194Savg				goto error;
2391333194Savg			break;
2392219089Spjd		case 'T':
2393219089Spjd			errno = 0;
2394268720Sdelphij			txg = strtoull(optarg, &endptr, 0);
2395219089Spjd			if (errno != 0 || *endptr != '\0') {
2396219089Spjd				(void) fprintf(stderr,
2397219089Spjd				    gettext("invalid txg value\n"));
2398219089Spjd				usage(B_FALSE);
2399219089Spjd			}
2400219089Spjd			rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
2401219089Spjd			break;
2402219089Spjd		case 'V':
2403219089Spjd			flags |= ZFS_IMPORT_VERBATIM;
2404219089Spjd			break;
2405219089Spjd		case 'X':
2406219089Spjd			xtreme_rewind = B_TRUE;
2407219089Spjd			break;
2408332547Smav		case CHECKPOINT_OPT:
2409332547Smav			flags |= ZFS_IMPORT_CHECKPOINT;
2410332547Smav			break;
2411168404Spjd		case ':':
2412168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
2413168404Spjd			    "'%c' option\n"), optopt);
2414168404Spjd			usage(B_FALSE);
2415168404Spjd			break;
2416168404Spjd		case '?':
2417168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2418168404Spjd			    optopt);
2419168404Spjd			usage(B_FALSE);
2420168404Spjd		}
2421168404Spjd	}
2422168404Spjd
2423168404Spjd	argc -= optind;
2424168404Spjd	argv += optind;
2425168404Spjd
2426185029Spjd	if (cachefile && nsearch != 0) {
2427185029Spjd		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
2428185029Spjd		usage(B_FALSE);
2429185029Spjd	}
2430185029Spjd
2431219089Spjd	if ((dryrun || xtreme_rewind) && !do_rewind) {
2432219089Spjd		(void) fprintf(stderr,
2433219089Spjd		    gettext("-n or -X only meaningful with -F\n"));
2434219089Spjd		usage(B_FALSE);
2435219089Spjd	}
2436219089Spjd	if (dryrun)
2437219089Spjd		rewind_policy = ZPOOL_TRY_REWIND;
2438219089Spjd	else if (do_rewind)
2439219089Spjd		rewind_policy = ZPOOL_DO_REWIND;
2440219089Spjd	if (xtreme_rewind)
2441219089Spjd		rewind_policy |= ZPOOL_EXTREME_REWIND;
2442219089Spjd
2443219089Spjd	/* In the future, we can capture further policy and include it here */
2444219089Spjd	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
2445332550Smav	    nvlist_add_uint64(policy, ZPOOL_LOAD_REQUEST_TXG, txg) != 0 ||
2446332550Smav	    nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY,
2447332550Smav	    rewind_policy) != 0)
2448219089Spjd		goto error;
2449219089Spjd
2450168404Spjd	if (searchdirs == NULL) {
2451168404Spjd		searchdirs = safe_malloc(sizeof (char *));
2452235478Savg		searchdirs[0] = "/dev";
2453168404Spjd		nsearch = 1;
2454168404Spjd	}
2455168404Spjd
2456168404Spjd	/* check argument count */
2457168404Spjd	if (do_all) {
2458168404Spjd		if (argc != 0) {
2459168404Spjd			(void) fprintf(stderr, gettext("too many arguments\n"));
2460168404Spjd			usage(B_FALSE);
2461168404Spjd		}
2462168404Spjd	} else {
2463168404Spjd		if (argc > 2) {
2464168404Spjd			(void) fprintf(stderr, gettext("too many arguments\n"));
2465168404Spjd			usage(B_FALSE);
2466168404Spjd		}
2467168404Spjd
2468168404Spjd		/*
2469168404Spjd		 * Check for the SYS_CONFIG privilege.  We do this explicitly
2470168404Spjd		 * here because otherwise any attempt to discover pools will
2471168404Spjd		 * silently fail.
2472168404Spjd		 */
2473168404Spjd		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
2474168404Spjd			(void) fprintf(stderr, gettext("cannot "
2475168404Spjd			    "discover pools: permission denied\n"));
2476168404Spjd			free(searchdirs);
2477219089Spjd			nvlist_free(policy);
2478168404Spjd			return (1);
2479168404Spjd		}
2480168404Spjd	}
2481168404Spjd
2482168404Spjd	/*
2483168404Spjd	 * Depending on the arguments given, we do one of the following:
2484168404Spjd	 *
2485168404Spjd	 *	<none>	Iterate through all pools and display information about
2486168404Spjd	 *		each one.
2487168404Spjd	 *
2488168404Spjd	 *	-a	Iterate through all pools and try to import each one.
2489168404Spjd	 *
2490168404Spjd	 *	<id>	Find the pool that corresponds to the given GUID/pool
2491168404Spjd	 *		name and import that one.
2492168404Spjd	 *
2493168404Spjd	 *	-D	Above options applies only to destroyed pools.
2494168404Spjd	 */
2495168404Spjd	if (argc != 0) {
2496168404Spjd		char *endptr;
2497168404Spjd
2498168404Spjd		errno = 0;
2499168404Spjd		searchguid = strtoull(argv[0], &endptr, 10);
2500254758Sdelphij		if (errno != 0 || *endptr != '\0') {
2501168404Spjd			searchname = argv[0];
2502254758Sdelphij			searchguid = 0;
2503254758Sdelphij		}
2504168404Spjd		found_config = NULL;
2505168404Spjd
2506185029Spjd		/*
2507219089Spjd		 * User specified a name or guid.  Ensure it's unique.
2508185029Spjd		 */
2509219089Spjd		idata.unique = B_TRUE;
2510185029Spjd	}
2511185029Spjd
2512219089Spjd
2513219089Spjd	idata.path = searchdirs;
2514219089Spjd	idata.paths = nsearch;
2515219089Spjd	idata.poolname = searchname;
2516219089Spjd	idata.guid = searchguid;
2517219089Spjd	idata.cachefile = cachefile;
2518332536Smav	idata.policy = policy;
2519219089Spjd
2520219089Spjd	pools = zpool_search_import(g_zfs, &idata);
2521219089Spjd
2522219089Spjd	if (pools != NULL && idata.exists &&
2523219089Spjd	    (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
2524219089Spjd		(void) fprintf(stderr, gettext("cannot import '%s': "
2525219089Spjd		    "a pool with that name already exists\n"),
2526219089Spjd		    argv[0]);
2527333194Savg		(void) fprintf(stderr, gettext("use the form 'zpool import "
2528333194Savg		    "[-t] <pool | id> <newpool>' to give it a new temporary "
2529333194Savg		    "or permanent name\n"));
2530219089Spjd		err = 1;
2531219089Spjd	} else if (pools == NULL && idata.exists) {
2532219089Spjd		(void) fprintf(stderr, gettext("cannot import '%s': "
2533219089Spjd		    "a pool with that name is already created/imported,\n"),
2534219089Spjd		    argv[0]);
2535219089Spjd		(void) fprintf(stderr, gettext("and no additional pools "
2536219089Spjd		    "with that name were found\n"));
2537219089Spjd		err = 1;
2538219089Spjd	} else if (pools == NULL) {
2539185029Spjd		if (argc != 0) {
2540185029Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
2541185029Spjd			    "no such pool available\n"), argv[0]);
2542185029Spjd		}
2543219089Spjd		err = 1;
2544219089Spjd	}
2545219089Spjd
2546219089Spjd	if (err == 1) {
2547185029Spjd		free(searchdirs);
2548219089Spjd		nvlist_free(policy);
2549185029Spjd		return (1);
2550185029Spjd	}
2551185029Spjd
2552185029Spjd	/*
2553185029Spjd	 * At this point we have a list of import candidate configs. Even if
2554185029Spjd	 * we were searching by pool name or guid, we still need to
2555185029Spjd	 * post-process the list to deal with pool state and possible
2556185029Spjd	 * duplicate names.
2557185029Spjd	 */
2558168404Spjd	err = 0;
2559168404Spjd	elem = NULL;
2560168404Spjd	first = B_TRUE;
2561168404Spjd	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
2562168404Spjd
2563168404Spjd		verify(nvpair_value_nvlist(elem, &config) == 0);
2564168404Spjd
2565168404Spjd		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
2566168404Spjd		    &pool_state) == 0);
2567168404Spjd		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
2568168404Spjd			continue;
2569168404Spjd		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
2570168404Spjd			continue;
2571168404Spjd
2572332550Smav		verify(nvlist_add_nvlist(config, ZPOOL_LOAD_POLICY,
2573219089Spjd		    policy) == 0);
2574219089Spjd
2575168404Spjd		if (argc == 0) {
2576168404Spjd			if (first)
2577168404Spjd				first = B_FALSE;
2578168404Spjd			else if (!do_all)
2579168404Spjd				(void) printf("\n");
2580168404Spjd
2581219089Spjd			if (do_all) {
2582168404Spjd				err |= do_import(config, NULL, mntopts,
2583219089Spjd				    props, flags);
2584219089Spjd			} else {
2585168404Spjd				show_import(config);
2586219089Spjd			}
2587168404Spjd		} else if (searchname != NULL) {
2588168404Spjd			char *name;
2589168404Spjd
2590168404Spjd			/*
2591168404Spjd			 * We are searching for a pool based on name.
2592168404Spjd			 */
2593168404Spjd			verify(nvlist_lookup_string(config,
2594168404Spjd			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
2595168404Spjd
2596168404Spjd			if (strcmp(name, searchname) == 0) {
2597168404Spjd				if (found_config != NULL) {
2598168404Spjd					(void) fprintf(stderr, gettext(
2599168404Spjd					    "cannot import '%s': more than "
2600168404Spjd					    "one matching pool\n"), searchname);
2601168404Spjd					(void) fprintf(stderr, gettext(
2602168404Spjd					    "import by numeric ID instead\n"));
2603168404Spjd					err = B_TRUE;
2604168404Spjd				}
2605168404Spjd				found_config = config;
2606168404Spjd			}
2607168404Spjd		} else {
2608168404Spjd			uint64_t guid;
2609168404Spjd
2610168404Spjd			/*
2611168404Spjd			 * Search for a pool by guid.
2612168404Spjd			 */
2613168404Spjd			verify(nvlist_lookup_uint64(config,
2614168404Spjd			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
2615168404Spjd
2616168404Spjd			if (guid == searchguid)
2617168404Spjd				found_config = config;
2618168404Spjd		}
2619168404Spjd	}
2620168404Spjd
2621168404Spjd	/*
2622168404Spjd	 * If we were searching for a specific pool, verify that we found a
2623168404Spjd	 * pool, and then do the import.
2624168404Spjd	 */
2625168404Spjd	if (argc != 0 && err == 0) {
2626168404Spjd		if (found_config == NULL) {
2627168404Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
2628168404Spjd			    "no such pool available\n"), argv[0]);
2629168404Spjd			err = B_TRUE;
2630168404Spjd		} else {
2631168404Spjd			err |= do_import(found_config, argc == 1 ? NULL :
2632219089Spjd			    argv[1], mntopts, props, flags);
2633168404Spjd		}
2634168404Spjd	}
2635168404Spjd
2636168404Spjd	/*
2637168404Spjd	 * If we were just looking for pools, report an error if none were
2638168404Spjd	 * found.
2639168404Spjd	 */
2640168404Spjd	if (argc == 0 && first)
2641168404Spjd		(void) fprintf(stderr,
2642168404Spjd		    gettext("no pools available to import\n"));
2643168404Spjd
2644185029Spjderror:
2645185029Spjd	nvlist_free(props);
2646168404Spjd	nvlist_free(pools);
2647219089Spjd	nvlist_free(policy);
2648168404Spjd	free(searchdirs);
2649168404Spjd
2650168404Spjd	return (err ? 1 : 0);
2651168404Spjd}
2652168404Spjd
2653168404Spjdtypedef struct iostat_cbdata {
2654236155Smm	boolean_t cb_verbose;
2655236155Smm	int cb_namewidth;
2656236155Smm	int cb_iteration;
2657168404Spjd	zpool_list_t *cb_list;
2658168404Spjd} iostat_cbdata_t;
2659168404Spjd
2660168404Spjdstatic void
2661168404Spjdprint_iostat_separator(iostat_cbdata_t *cb)
2662168404Spjd{
2663168404Spjd	int i = 0;
2664168404Spjd
2665168404Spjd	for (i = 0; i < cb->cb_namewidth; i++)
2666168404Spjd		(void) printf("-");
2667168404Spjd	(void) printf("  -----  -----  -----  -----  -----  -----\n");
2668168404Spjd}
2669168404Spjd
2670168404Spjdstatic void
2671168404Spjdprint_iostat_header(iostat_cbdata_t *cb)
2672168404Spjd{
2673168404Spjd	(void) printf("%*s     capacity     operations    bandwidth\n",
2674168404Spjd	    cb->cb_namewidth, "");
2675219089Spjd	(void) printf("%-*s  alloc   free   read  write   read  write\n",
2676168404Spjd	    cb->cb_namewidth, "pool");
2677168404Spjd	print_iostat_separator(cb);
2678168404Spjd}
2679168404Spjd
2680168404Spjd/*
2681168404Spjd * Display a single statistic.
2682168404Spjd */
2683185029Spjdstatic void
2684168404Spjdprint_one_stat(uint64_t value)
2685168404Spjd{
2686168404Spjd	char buf[64];
2687168404Spjd
2688168404Spjd	zfs_nicenum(value, buf, sizeof (buf));
2689168404Spjd	(void) printf("  %5s", buf);
2690168404Spjd}
2691168404Spjd
2692168404Spjd/*
2693168404Spjd * Print out all the statistics for the given vdev.  This can either be the
2694168404Spjd * toplevel configuration, or called recursively.  If 'name' is NULL, then this
2695168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats.
2696168404Spjd */
2697168404Spjdvoid
2698168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
2699168404Spjd    nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
2700168404Spjd{
2701168404Spjd	nvlist_t **oldchild, **newchild;
2702168404Spjd	uint_t c, children;
2703168404Spjd	vdev_stat_t *oldvs, *newvs;
2704168404Spjd	vdev_stat_t zerovs = { 0 };
2705168404Spjd	uint64_t tdelta;
2706168404Spjd	double scale;
2707168404Spjd	char *vname;
2708168404Spjd
2709332525Smav	if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
2710332525Smav		return;
2711332525Smav
2712168404Spjd	if (oldnv != NULL) {
2713219089Spjd		verify(nvlist_lookup_uint64_array(oldnv,
2714219089Spjd		    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
2715168404Spjd	} else {
2716168404Spjd		oldvs = &zerovs;
2717168404Spjd	}
2718168404Spjd
2719219089Spjd	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
2720168404Spjd	    (uint64_t **)&newvs, &c) == 0);
2721168404Spjd
2722168404Spjd	if (strlen(name) + depth > cb->cb_namewidth)
2723168404Spjd		(void) printf("%*s%s", depth, "", name);
2724168404Spjd	else
2725168404Spjd		(void) printf("%*s%s%*s", depth, "", name,
2726168404Spjd		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
2727168404Spjd
2728168404Spjd	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
2729168404Spjd
2730168404Spjd	if (tdelta == 0)
2731168404Spjd		scale = 1.0;
2732168404Spjd	else
2733168404Spjd		scale = (double)NANOSEC / tdelta;
2734168404Spjd
2735168404Spjd	/* only toplevel vdevs have capacity stats */
2736168404Spjd	if (newvs->vs_space == 0) {
2737168404Spjd		(void) printf("      -      -");
2738168404Spjd	} else {
2739168404Spjd		print_one_stat(newvs->vs_alloc);
2740168404Spjd		print_one_stat(newvs->vs_space - newvs->vs_alloc);
2741168404Spjd	}
2742168404Spjd
2743168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
2744168404Spjd	    oldvs->vs_ops[ZIO_TYPE_READ])));
2745168404Spjd
2746168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
2747168404Spjd	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
2748168404Spjd
2749168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
2750168404Spjd	    oldvs->vs_bytes[ZIO_TYPE_READ])));
2751168404Spjd
2752168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
2753168404Spjd	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
2754168404Spjd
2755168404Spjd	(void) printf("\n");
2756168404Spjd
2757168404Spjd	if (!cb->cb_verbose)
2758168404Spjd		return;
2759168404Spjd
2760168404Spjd	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
2761168404Spjd	    &newchild, &children) != 0)
2762168404Spjd		return;
2763168404Spjd
2764168404Spjd	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
2765168404Spjd	    &oldchild, &c) != 0)
2766168404Spjd		return;
2767168404Spjd
2768168404Spjd	for (c = 0; c < children; c++) {
2769227497Smm		uint64_t ishole = B_FALSE, islog = B_FALSE;
2770219089Spjd
2771227497Smm		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
2772227497Smm		    &ishole);
2773227497Smm
2774227497Smm		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
2775227497Smm		    &islog);
2776227497Smm
2777227497Smm		if (ishole || islog)
2778219089Spjd			continue;
2779219089Spjd
2780219089Spjd		vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
2781168404Spjd		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2782168404Spjd		    newchild[c], cb, depth + 2);
2783168404Spjd		free(vname);
2784168404Spjd	}
2785185029Spjd
2786185029Spjd	/*
2787227497Smm	 * Log device section
2788227497Smm	 */
2789227497Smm
2790227497Smm	if (num_logs(newnv) > 0) {
2791227497Smm		(void) printf("%-*s      -      -      -      -      -      "
2792227497Smm		    "-\n", cb->cb_namewidth, "logs");
2793227497Smm
2794227497Smm		for (c = 0; c < children; c++) {
2795227497Smm			uint64_t islog = B_FALSE;
2796227497Smm			(void) nvlist_lookup_uint64(newchild[c],
2797227497Smm			    ZPOOL_CONFIG_IS_LOG, &islog);
2798227497Smm
2799227497Smm			if (islog) {
2800227497Smm				vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
2801227497Smm				    B_FALSE);
2802227497Smm				print_vdev_stats(zhp, vname, oldnv ?
2803227497Smm				    oldchild[c] : NULL, newchild[c],
2804227497Smm				    cb, depth + 2);
2805227497Smm				free(vname);
2806227497Smm			}
2807227497Smm		}
2808227497Smm
2809227497Smm	}
2810227497Smm
2811227497Smm	/*
2812185029Spjd	 * Include level 2 ARC devices in iostat output
2813185029Spjd	 */
2814185029Spjd	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
2815185029Spjd	    &newchild, &children) != 0)
2816185029Spjd		return;
2817185029Spjd
2818185029Spjd	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
2819185029Spjd	    &oldchild, &c) != 0)
2820185029Spjd		return;
2821185029Spjd
2822185029Spjd	if (children > 0) {
2823185029Spjd		(void) printf("%-*s      -      -      -      -      -      "
2824185029Spjd		    "-\n", cb->cb_namewidth, "cache");
2825185029Spjd		for (c = 0; c < children; c++) {
2826219089Spjd			vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
2827219089Spjd			    B_FALSE);
2828185029Spjd			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2829185029Spjd			    newchild[c], cb, depth + 2);
2830185029Spjd			free(vname);
2831185029Spjd		}
2832185029Spjd	}
2833168404Spjd}
2834168404Spjd
2835168404Spjdstatic int
2836168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data)
2837168404Spjd{
2838168404Spjd	iostat_cbdata_t *cb = data;
2839168404Spjd	boolean_t missing;
2840168404Spjd
2841168404Spjd	/*
2842168404Spjd	 * If the pool has disappeared, remove it from the list and continue.
2843168404Spjd	 */
2844168404Spjd	if (zpool_refresh_stats(zhp, &missing) != 0)
2845168404Spjd		return (-1);
2846168404Spjd
2847168404Spjd	if (missing)
2848168404Spjd		pool_list_remove(cb->cb_list, zhp);
2849168404Spjd
2850168404Spjd	return (0);
2851168404Spjd}
2852168404Spjd
2853168404Spjd/*
2854168404Spjd * Callback to print out the iostats for the given pool.
2855168404Spjd */
2856168404Spjdint
2857168404Spjdprint_iostat(zpool_handle_t *zhp, void *data)
2858168404Spjd{
2859168404Spjd	iostat_cbdata_t *cb = data;
2860168404Spjd	nvlist_t *oldconfig, *newconfig;
2861168404Spjd	nvlist_t *oldnvroot, *newnvroot;
2862168404Spjd
2863168404Spjd	newconfig = zpool_get_config(zhp, &oldconfig);
2864168404Spjd
2865168404Spjd	if (cb->cb_iteration == 1)
2866168404Spjd		oldconfig = NULL;
2867168404Spjd
2868168404Spjd	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
2869168404Spjd	    &newnvroot) == 0);
2870168404Spjd
2871168404Spjd	if (oldconfig == NULL)
2872168404Spjd		oldnvroot = NULL;
2873168404Spjd	else
2874168404Spjd		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
2875168404Spjd		    &oldnvroot) == 0);
2876168404Spjd
2877168404Spjd	/*
2878168404Spjd	 * Print out the statistics for the pool.
2879168404Spjd	 */
2880168404Spjd	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
2881168404Spjd
2882168404Spjd	if (cb->cb_verbose)
2883168404Spjd		print_iostat_separator(cb);
2884168404Spjd
2885168404Spjd	return (0);
2886168404Spjd}
2887168404Spjd
2888168404Spjdint
2889168404Spjdget_namewidth(zpool_handle_t *zhp, void *data)
2890168404Spjd{
2891168404Spjd	iostat_cbdata_t *cb = data;
2892168404Spjd	nvlist_t *config, *nvroot;
2893168404Spjd
2894168404Spjd	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
2895168404Spjd		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2896168404Spjd		    &nvroot) == 0);
2897168404Spjd		if (!cb->cb_verbose)
2898168404Spjd			cb->cb_namewidth = strlen(zpool_get_name(zhp));
2899168404Spjd		else
2900236145Smm			cb->cb_namewidth = max_width(zhp, nvroot, 0,
2901236145Smm			    cb->cb_namewidth);
2902168404Spjd	}
2903168404Spjd
2904168404Spjd	/*
2905168404Spjd	 * The width must fall into the range [10,38].  The upper limit is the
2906168404Spjd	 * maximum we can have and still fit in 80 columns.
2907168404Spjd	 */
2908168404Spjd	if (cb->cb_namewidth < 10)
2909168404Spjd		cb->cb_namewidth = 10;
2910168404Spjd	if (cb->cb_namewidth > 38)
2911168404Spjd		cb->cb_namewidth = 38;
2912168404Spjd
2913168404Spjd	return (0);
2914168404Spjd}
2915168404Spjd
2916168404Spjd/*
2917219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one.
2918168404Spjd */
2919219089Spjdstatic void
2920219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv,
2921219089Spjd    unsigned long *cnt)
2922168404Spjd{
2923168404Spjd	unsigned long interval = 0, count = 0;
2924219089Spjd	int argc = *argcp, errno;
2925168404Spjd
2926168404Spjd	/*
2927168404Spjd	 * Determine if the last argument is an integer or a pool name
2928168404Spjd	 */
2929168404Spjd	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2930168404Spjd		char *end;
2931168404Spjd
2932168404Spjd		errno = 0;
2933168404Spjd		interval = strtoul(argv[argc - 1], &end, 10);
2934168404Spjd
2935168404Spjd		if (*end == '\0' && errno == 0) {
2936168404Spjd			if (interval == 0) {
2937168404Spjd				(void) fprintf(stderr, gettext("interval "
2938168404Spjd				    "cannot be zero\n"));
2939168404Spjd				usage(B_FALSE);
2940168404Spjd			}
2941168404Spjd			/*
2942168404Spjd			 * Ignore the last parameter
2943168404Spjd			 */
2944168404Spjd			argc--;
2945168404Spjd		} else {
2946168404Spjd			/*
2947168404Spjd			 * If this is not a valid number, just plow on.  The
2948168404Spjd			 * user will get a more informative error message later
2949168404Spjd			 * on.
2950168404Spjd			 */
2951168404Spjd			interval = 0;
2952168404Spjd		}
2953168404Spjd	}
2954168404Spjd
2955168404Spjd	/*
2956168404Spjd	 * If the last argument is also an integer, then we have both a count
2957219089Spjd	 * and an interval.
2958168404Spjd	 */
2959168404Spjd	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2960168404Spjd		char *end;
2961168404Spjd
2962168404Spjd		errno = 0;
2963168404Spjd		count = interval;
2964168404Spjd		interval = strtoul(argv[argc - 1], &end, 10);
2965168404Spjd
2966168404Spjd		if (*end == '\0' && errno == 0) {
2967168404Spjd			if (interval == 0) {
2968168404Spjd				(void) fprintf(stderr, gettext("interval "
2969168404Spjd				    "cannot be zero\n"));
2970168404Spjd				usage(B_FALSE);
2971168404Spjd			}
2972168404Spjd
2973168404Spjd			/*
2974168404Spjd			 * Ignore the last parameter
2975168404Spjd			 */
2976168404Spjd			argc--;
2977168404Spjd		} else {
2978168404Spjd			interval = 0;
2979168404Spjd		}
2980168404Spjd	}
2981168404Spjd
2982219089Spjd	*iv = interval;
2983219089Spjd	*cnt = count;
2984219089Spjd	*argcp = argc;
2985219089Spjd}
2986219089Spjd
2987219089Spjdstatic void
2988219089Spjdget_timestamp_arg(char c)
2989219089Spjd{
2990219089Spjd	if (c == 'u')
2991219089Spjd		timestamp_fmt = UDATE;
2992219089Spjd	else if (c == 'd')
2993219089Spjd		timestamp_fmt = DDATE;
2994219089Spjd	else
2995219089Spjd		usage(B_FALSE);
2996219089Spjd}
2997219089Spjd
2998219089Spjd/*
2999219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]]
3000219089Spjd *
3001219089Spjd *	-v	Display statistics for individual vdevs
3002219089Spjd *	-T	Display a timestamp in date(1) or Unix format
3003219089Spjd *
3004219089Spjd * This command can be tricky because we want to be able to deal with pool
3005219089Spjd * creation/destruction as well as vdev configuration changes.  The bulk of this
3006219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
3007219089Spjd * on pool_list_update() to detect the addition of new pools.  Configuration
3008219089Spjd * changes are all handled within libzfs.
3009219089Spjd */
3010219089Spjdint
3011219089Spjdzpool_do_iostat(int argc, char **argv)
3012219089Spjd{
3013219089Spjd	int c;
3014219089Spjd	int ret;
3015219089Spjd	int npools;
3016219089Spjd	unsigned long interval = 0, count = 0;
3017219089Spjd	zpool_list_t *list;
3018219089Spjd	boolean_t verbose = B_FALSE;
3019219089Spjd	iostat_cbdata_t cb;
3020219089Spjd
3021219089Spjd	/* check options */
3022219089Spjd	while ((c = getopt(argc, argv, "T:v")) != -1) {
3023219089Spjd		switch (c) {
3024219089Spjd		case 'T':
3025219089Spjd			get_timestamp_arg(*optarg);
3026219089Spjd			break;
3027219089Spjd		case 'v':
3028219089Spjd			verbose = B_TRUE;
3029219089Spjd			break;
3030219089Spjd		case '?':
3031219089Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3032219089Spjd			    optopt);
3033219089Spjd			usage(B_FALSE);
3034219089Spjd		}
3035219089Spjd	}
3036219089Spjd
3037219089Spjd	argc -= optind;
3038219089Spjd	argv += optind;
3039219089Spjd
3040219089Spjd	get_interval_count(&argc, argv, &interval, &count);
3041219089Spjd
3042168404Spjd	/*
3043168404Spjd	 * Construct the list of all interesting pools.
3044168404Spjd	 */
3045168404Spjd	ret = 0;
3046168404Spjd	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
3047168404Spjd		return (1);
3048168404Spjd
3049168404Spjd	if (pool_list_count(list) == 0 && argc != 0) {
3050168404Spjd		pool_list_free(list);
3051168404Spjd		return (1);
3052168404Spjd	}
3053168404Spjd
3054168404Spjd	if (pool_list_count(list) == 0 && interval == 0) {
3055168404Spjd		pool_list_free(list);
3056168404Spjd		(void) fprintf(stderr, gettext("no pools available\n"));
3057168404Spjd		return (1);
3058168404Spjd	}
3059168404Spjd
3060168404Spjd	/*
3061168404Spjd	 * Enter the main iostat loop.
3062168404Spjd	 */
3063168404Spjd	cb.cb_list = list;
3064168404Spjd	cb.cb_verbose = verbose;
3065168404Spjd	cb.cb_iteration = 0;
3066168404Spjd	cb.cb_namewidth = 0;
3067168404Spjd
3068168404Spjd	for (;;) {
3069168404Spjd		pool_list_update(list);
3070168404Spjd
3071168404Spjd		if ((npools = pool_list_count(list)) == 0)
3072168404Spjd			break;
3073168404Spjd
3074168404Spjd		/*
3075168404Spjd		 * Refresh all statistics.  This is done as an explicit step
3076168404Spjd		 * before calculating the maximum name width, so that any
3077168404Spjd		 * configuration changes are properly accounted for.
3078168404Spjd		 */
3079168404Spjd		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
3080168404Spjd
3081168404Spjd		/*
3082168404Spjd		 * Iterate over all pools to determine the maximum width
3083168404Spjd		 * for the pool / device name column across all pools.
3084168404Spjd		 */
3085168404Spjd		cb.cb_namewidth = 0;
3086168404Spjd		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
3087168404Spjd
3088219089Spjd		if (timestamp_fmt != NODATE)
3089219089Spjd			print_timestamp(timestamp_fmt);
3090219089Spjd
3091168404Spjd		/*
3092168404Spjd		 * If it's the first time, or verbose mode, print the header.
3093168404Spjd		 */
3094168404Spjd		if (++cb.cb_iteration == 1 || verbose)
3095168404Spjd			print_iostat_header(&cb);
3096168404Spjd
3097168404Spjd		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
3098168404Spjd
3099168404Spjd		/*
3100168404Spjd		 * If there's more than one pool, and we're not in verbose mode
3101168404Spjd		 * (which prints a separator for us), then print a separator.
3102168404Spjd		 */
3103168404Spjd		if (npools > 1 && !verbose)
3104168404Spjd			print_iostat_separator(&cb);
3105168404Spjd
3106168404Spjd		if (verbose)
3107168404Spjd			(void) printf("\n");
3108168404Spjd
3109168404Spjd		/*
3110168404Spjd		 * Flush the output so that redirection to a file isn't buffered
3111168404Spjd		 * indefinitely.
3112168404Spjd		 */
3113168404Spjd		(void) fflush(stdout);
3114168404Spjd
3115168404Spjd		if (interval == 0)
3116168404Spjd			break;
3117168404Spjd
3118168404Spjd		if (count != 0 && --count == 0)
3119168404Spjd			break;
3120168404Spjd
3121168404Spjd		(void) sleep(interval);
3122168404Spjd	}
3123168404Spjd
3124168404Spjd	pool_list_free(list);
3125168404Spjd
3126168404Spjd	return (ret);
3127168404Spjd}
3128168404Spjd
3129168404Spjdtypedef struct list_cbdata {
3130236155Smm	boolean_t	cb_verbose;
3131236155Smm	int		cb_namewidth;
3132168404Spjd	boolean_t	cb_scripted;
3133185029Spjd	zprop_list_t	*cb_proplist;
3134263889Sdelphij	boolean_t	cb_literal;
3135168404Spjd} list_cbdata_t;
3136168404Spjd
3137168404Spjd/*
3138168404Spjd * Given a list of columns to display, output appropriate headers for each one.
3139168404Spjd */
3140185029Spjdstatic void
3141236155Smmprint_header(list_cbdata_t *cb)
3142168404Spjd{
3143236155Smm	zprop_list_t *pl = cb->cb_proplist;
3144236884Smm	char headerbuf[ZPOOL_MAXPROPLEN];
3145185029Spjd	const char *header;
3146185029Spjd	boolean_t first = B_TRUE;
3147185029Spjd	boolean_t right_justify;
3148236155Smm	size_t width = 0;
3149168404Spjd
3150185029Spjd	for (; pl != NULL; pl = pl->pl_next) {
3151236155Smm		width = pl->pl_width;
3152236155Smm		if (first && cb->cb_verbose) {
3153236155Smm			/*
3154236155Smm			 * Reset the width to accommodate the verbose listing
3155236155Smm			 * of devices.
3156236155Smm			 */
3157236155Smm			width = cb->cb_namewidth;
3158236155Smm		}
3159236155Smm
3160185029Spjd		if (!first)
3161168404Spjd			(void) printf("  ");
3162168404Spjd		else
3163185029Spjd			first = B_FALSE;
3164168404Spjd
3165236884Smm		right_justify = B_FALSE;
3166236884Smm		if (pl->pl_prop != ZPROP_INVAL) {
3167236884Smm			header = zpool_prop_column_name(pl->pl_prop);
3168236884Smm			right_justify = zpool_prop_align_right(pl->pl_prop);
3169236884Smm		} else {
3170236884Smm			int i;
3171185029Spjd
3172236884Smm			for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
3173236884Smm				headerbuf[i] = toupper(pl->pl_user_prop[i]);
3174236884Smm			headerbuf[i] = '\0';
3175236884Smm			header = headerbuf;
3176236884Smm		}
3177236884Smm
3178185029Spjd		if (pl->pl_next == NULL && !right_justify)
3179185029Spjd			(void) printf("%s", header);
3180185029Spjd		else if (right_justify)
3181236155Smm			(void) printf("%*s", width, header);
3182185029Spjd		else
3183236155Smm			(void) printf("%-*s", width, header);
3184236155Smm
3185168404Spjd	}
3186168404Spjd
3187168404Spjd	(void) printf("\n");
3188168404Spjd}
3189168404Spjd
3190185029Spjd/*
3191185029Spjd * Given a pool and a list of properties, print out all the properties according
3192185029Spjd * to the described layout.
3193185029Spjd */
3194185029Spjdstatic void
3195236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
3196168404Spjd{
3197236155Smm	zprop_list_t *pl = cb->cb_proplist;
3198185029Spjd	boolean_t first = B_TRUE;
3199185029Spjd	char property[ZPOOL_MAXPROPLEN];
3200185029Spjd	char *propstr;
3201185029Spjd	boolean_t right_justify;
3202236155Smm	size_t width;
3203168404Spjd
3204185029Spjd	for (; pl != NULL; pl = pl->pl_next) {
3205236155Smm
3206236155Smm		width = pl->pl_width;
3207236155Smm		if (first && cb->cb_verbose) {
3208236155Smm			/*
3209236155Smm			 * Reset the width to accommodate the verbose listing
3210236155Smm			 * of devices.
3211236155Smm			 */
3212236155Smm			width = cb->cb_namewidth;
3213236155Smm		}
3214236155Smm
3215185029Spjd		if (!first) {
3216236155Smm			if (cb->cb_scripted)
3217168404Spjd				(void) printf("\t");
3218168404Spjd			else
3219168404Spjd				(void) printf("  ");
3220185029Spjd		} else {
3221185029Spjd			first = B_FALSE;
3222168404Spjd		}
3223168404Spjd
3224185029Spjd		right_justify = B_FALSE;
3225185029Spjd		if (pl->pl_prop != ZPROP_INVAL) {
3226272502Sdelphij			if (zpool_get_prop(zhp, pl->pl_prop, property,
3227263889Sdelphij			    sizeof (property), NULL, cb->cb_literal) != 0)
3228185029Spjd				propstr = "-";
3229168404Spjd			else
3230185029Spjd				propstr = property;
3231168404Spjd
3232185029Spjd			right_justify = zpool_prop_align_right(pl->pl_prop);
3233236884Smm		} else if ((zpool_prop_feature(pl->pl_user_prop) ||
3234236884Smm		    zpool_prop_unsupported(pl->pl_user_prop)) &&
3235236884Smm		    zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
3236236884Smm		    sizeof (property)) == 0) {
3237236884Smm			propstr = property;
3238185029Spjd		} else {
3239185029Spjd			propstr = "-";
3240185029Spjd		}
3241168404Spjd
3242168404Spjd
3243185029Spjd		/*
3244185029Spjd		 * If this is being called in scripted mode, or if this is the
3245185029Spjd		 * last column and it is left-justified, don't include a width
3246185029Spjd		 * format specifier.
3247185029Spjd		 */
3248236155Smm		if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
3249185029Spjd			(void) printf("%s", propstr);
3250185029Spjd		else if (right_justify)
3251185029Spjd			(void) printf("%*s", width, propstr);
3252185029Spjd		else
3253185029Spjd			(void) printf("%-*s", width, propstr);
3254185029Spjd	}
3255168404Spjd
3256185029Spjd	(void) printf("\n");
3257185029Spjd}
3258168404Spjd
3259236155Smmstatic void
3260272502Sdelphijprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted,
3261272502Sdelphij    boolean_t valid)
3262236155Smm{
3263236155Smm	char propval[64];
3264236155Smm	boolean_t fixed;
3265236155Smm	size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
3266236155Smm
3267272502Sdelphij	switch (prop) {
3268272502Sdelphij	case ZPOOL_PROP_EXPANDSZ:
3269332547Smav	case ZPOOL_PROP_CHECKPOINT:
3270272502Sdelphij		if (value == 0)
3271272502Sdelphij			(void) strlcpy(propval, "-", sizeof (propval));
3272272502Sdelphij		else
3273272502Sdelphij			zfs_nicenum(value, propval, sizeof (propval));
3274272502Sdelphij		break;
3275272502Sdelphij	case ZPOOL_PROP_FRAGMENTATION:
3276272502Sdelphij		if (value == ZFS_FRAG_INVALID) {
3277272502Sdelphij			(void) strlcpy(propval, "-", sizeof (propval));
3278272502Sdelphij		} else {
3279272502Sdelphij			(void) snprintf(propval, sizeof (propval), "%llu%%",
3280272502Sdelphij			    value);
3281272502Sdelphij		}
3282272502Sdelphij		break;
3283272502Sdelphij	case ZPOOL_PROP_CAPACITY:
3284269118Sdelphij		(void) snprintf(propval, sizeof (propval), "%llu%%", value);
3285272502Sdelphij		break;
3286272502Sdelphij	default:
3287269118Sdelphij		zfs_nicenum(value, propval, sizeof (propval));
3288272502Sdelphij	}
3289236155Smm
3290272502Sdelphij	if (!valid)
3291272502Sdelphij		(void) strlcpy(propval, "-", sizeof (propval));
3292272502Sdelphij
3293236155Smm	if (scripted)
3294236155Smm		(void) printf("\t%s", propval);
3295236155Smm	else
3296236155Smm		(void) printf("  %*s", width, propval);
3297236155Smm}
3298236155Smm
3299236155Smmvoid
3300236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
3301236155Smm    list_cbdata_t *cb, int depth)
3302236155Smm{
3303236155Smm	nvlist_t **child;
3304236155Smm	vdev_stat_t *vs;
3305236155Smm	uint_t c, children;
3306236155Smm	char *vname;
3307236155Smm	boolean_t scripted = cb->cb_scripted;
3308289536Smav	uint64_t islog = B_FALSE;
3309289536Smav	boolean_t haslog = B_FALSE;
3310289536Smav	char *dashes = "%-*s      -      -      -         -      -      -\n";
3311236155Smm
3312236155Smm	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
3313236155Smm	    (uint64_t **)&vs, &c) == 0);
3314236155Smm
3315236155Smm	if (name != NULL) {
3316272502Sdelphij		boolean_t toplevel = (vs->vs_space != 0);
3317272502Sdelphij		uint64_t cap;
3318272502Sdelphij
3319332525Smav		if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
3320332525Smav			return;
3321332525Smav
3322236155Smm		if (scripted)
3323236155Smm			(void) printf("\t%s", name);
3324236155Smm		else if (strlen(name) + depth > cb->cb_namewidth)
3325236155Smm			(void) printf("%*s%s", depth, "", name);
3326236155Smm		else
3327236155Smm			(void) printf("%*s%s%*s", depth, "", name,
3328236155Smm			    (int)(cb->cb_namewidth - strlen(name) - depth), "");
3329236155Smm
3330272502Sdelphij		/*
3331272502Sdelphij		 * Print the properties for the individual vdevs. Some
3332272502Sdelphij		 * properties are only applicable to toplevel vdevs. The
3333272502Sdelphij		 * 'toplevel' boolean value is passed to the print_one_column()
3334272502Sdelphij		 * to indicate that the value is valid.
3335272502Sdelphij		 */
3336272502Sdelphij		print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted,
3337272502Sdelphij		    toplevel);
3338272502Sdelphij		print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted,
3339272502Sdelphij		    toplevel);
3340272502Sdelphij		print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc,
3341272502Sdelphij		    scripted, toplevel);
3342332547Smav		print_one_column(ZPOOL_PROP_CHECKPOINT,
3343332547Smav		    vs->vs_checkpoint_space, scripted, toplevel);
3344272502Sdelphij		print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted,
3345272502Sdelphij		    B_TRUE);
3346272502Sdelphij		print_one_column(ZPOOL_PROP_FRAGMENTATION,
3347272502Sdelphij		    vs->vs_fragmentation, scripted,
3348272502Sdelphij		    (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel));
3349272502Sdelphij		cap = (vs->vs_space == 0) ? 0 :
3350272502Sdelphij		    (vs->vs_alloc * 100 / vs->vs_space);
3351272502Sdelphij		print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel);
3352236155Smm		(void) printf("\n");
3353236155Smm	}
3354236155Smm
3355236155Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
3356236155Smm	    &child, &children) != 0)
3357236155Smm		return;
3358236155Smm
3359236155Smm	for (c = 0; c < children; c++) {
3360236155Smm		uint64_t ishole = B_FALSE;
3361236155Smm
3362236155Smm		if (nvlist_lookup_uint64(child[c],
3363236155Smm		    ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
3364236155Smm			continue;
3365236155Smm
3366289536Smav		if (nvlist_lookup_uint64(child[c],
3367289536Smav		    ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) {
3368289536Smav			haslog = B_TRUE;
3369289536Smav			continue;
3370289536Smav		}
3371289536Smav
3372236155Smm		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
3373236155Smm		print_list_stats(zhp, vname, child[c], cb, depth + 2);
3374236155Smm		free(vname);
3375236155Smm	}
3376236155Smm
3377289536Smav	if (haslog == B_TRUE) {
3378289536Smav		/* LINTED E_SEC_PRINTF_VAR_FMT */
3379289536Smav		(void) printf(dashes, cb->cb_namewidth, "log");
3380289536Smav		for (c = 0; c < children; c++) {
3381289536Smav			if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3382289536Smav			    &islog) != 0 || !islog)
3383289536Smav				continue;
3384289536Smav			vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
3385289536Smav			print_list_stats(zhp, vname, child[c], cb, depth + 2);
3386289536Smav			free(vname);
3387289536Smav		}
3388289536Smav	}
3389289536Smav
3390236155Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
3391289536Smav	    &child, &children) == 0 && children > 0) {
3392289536Smav		/* LINTED E_SEC_PRINTF_VAR_FMT */
3393289536Smav		(void) printf(dashes, cb->cb_namewidth, "cache");
3394289536Smav		for (c = 0; c < children; c++) {
3395289536Smav			vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
3396289536Smav			print_list_stats(zhp, vname, child[c], cb, depth + 2);
3397289536Smav			free(vname);
3398289536Smav		}
3399289536Smav	}
3400236155Smm
3401289536Smav	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child,
3402289536Smav	    &children) == 0 && children > 0) {
3403289536Smav		/* LINTED E_SEC_PRINTF_VAR_FMT */
3404289536Smav		(void) printf(dashes, cb->cb_namewidth, "spare");
3405236155Smm		for (c = 0; c < children; c++) {
3406289536Smav			vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
3407236155Smm			print_list_stats(zhp, vname, child[c], cb, depth + 2);
3408236155Smm			free(vname);
3409236155Smm		}
3410236155Smm	}
3411236155Smm}
3412236155Smm
3413236155Smm
3414185029Spjd/*
3415185029Spjd * Generic callback function to list a pool.
3416185029Spjd */
3417185029Spjdint
3418185029Spjdlist_callback(zpool_handle_t *zhp, void *data)
3419185029Spjd{
3420185029Spjd	list_cbdata_t *cbp = data;
3421236155Smm	nvlist_t *config;
3422236155Smm	nvlist_t *nvroot;
3423168404Spjd
3424236155Smm	config = zpool_get_config(zhp, NULL);
3425168404Spjd
3426236155Smm	print_pool(zhp, cbp);
3427236155Smm	if (!cbp->cb_verbose)
3428236155Smm		return (0);
3429168404Spjd
3430236155Smm	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
3431236155Smm	    &nvroot) == 0);
3432236155Smm	print_list_stats(zhp, NULL, nvroot, cbp, 0);
3433236155Smm
3434168404Spjd	return (0);
3435168404Spjd}
3436168404Spjd
3437168404Spjd/*
3438263889Sdelphij * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
3439168404Spjd *
3440185029Spjd *	-H	Scripted mode.  Don't display headers, and separate properties
3441185029Spjd *		by a single tab.
3442185029Spjd *	-o	List of properties to display.  Defaults to
3443272502Sdelphij *		"name,size,allocated,free,expandsize,fragmentation,capacity,"
3444272502Sdelphij *		"dedupratio,health,altroot"
3445342941Savg *	-p	Diplay values in parsable (exact) format.
3446219089Spjd *	-T	Display a timestamp in date(1) or Unix format
3447168404Spjd *
3448168404Spjd * List all pools in the system, whether or not they're healthy.  Output space
3449168404Spjd * statistics for each one, as well as health status summary.
3450168404Spjd */
3451168404Spjdint
3452168404Spjdzpool_do_list(int argc, char **argv)
3453168404Spjd{
3454168404Spjd	int c;
3455168404Spjd	int ret;
3456168404Spjd	list_cbdata_t cb = { 0 };
3457185029Spjd	static char default_props[] =
3458332547Smav	    "name,size,allocated,free,checkpoint,expandsize,fragmentation,"
3459332547Smav	    "capacity,dedupratio,health,altroot";
3460185029Spjd	char *props = default_props;
3461219089Spjd	unsigned long interval = 0, count = 0;
3462236155Smm	zpool_list_t *list;
3463236155Smm	boolean_t first = B_TRUE;
3464168404Spjd
3465168404Spjd	/* check options */
3466263889Sdelphij	while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) {
3467168404Spjd		switch (c) {
3468168404Spjd		case 'H':
3469168404Spjd			cb.cb_scripted = B_TRUE;
3470168404Spjd			break;
3471168404Spjd		case 'o':
3472185029Spjd			props = optarg;
3473168404Spjd			break;
3474263889Sdelphij		case 'p':
3475263889Sdelphij			cb.cb_literal = B_TRUE;
3476263889Sdelphij			break;
3477219089Spjd		case 'T':
3478219089Spjd			get_timestamp_arg(*optarg);
3479219089Spjd			break;
3480236155Smm		case 'v':
3481236155Smm			cb.cb_verbose = B_TRUE;
3482236155Smm			break;
3483168404Spjd		case ':':
3484168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
3485168404Spjd			    "'%c' option\n"), optopt);
3486168404Spjd			usage(B_FALSE);
3487168404Spjd			break;
3488168404Spjd		case '?':
3489168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3490168404Spjd			    optopt);
3491168404Spjd			usage(B_FALSE);
3492168404Spjd		}
3493168404Spjd	}
3494168404Spjd
3495168404Spjd	argc -= optind;
3496168404Spjd	argv += optind;
3497168404Spjd
3498219089Spjd	get_interval_count(&argc, argv, &interval, &count);
3499219089Spjd
3500185029Spjd	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
3501185029Spjd		usage(B_FALSE);
3502168404Spjd
3503219089Spjd	for (;;) {
3504268470Sdelphij		if ((list = pool_list_get(argc, argv, &cb.cb_proplist,
3505268470Sdelphij		    &ret)) == NULL)
3506268470Sdelphij			return (1);
3507168404Spjd
3508236155Smm		if (pool_list_count(list) == 0)
3509236155Smm			break;
3510236155Smm
3511236155Smm		cb.cb_namewidth = 0;
3512236155Smm		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
3513236155Smm
3514219089Spjd		if (timestamp_fmt != NODATE)
3515219089Spjd			print_timestamp(timestamp_fmt);
3516168404Spjd
3517236155Smm		if (!cb.cb_scripted && (first || cb.cb_verbose)) {
3518236155Smm			print_header(&cb);
3519236155Smm			first = B_FALSE;
3520219089Spjd		}
3521236155Smm		ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
3522219089Spjd
3523219089Spjd		if (interval == 0)
3524219089Spjd			break;
3525219089Spjd
3526219089Spjd		if (count != 0 && --count == 0)
3527219089Spjd			break;
3528219089Spjd
3529268470Sdelphij		pool_list_free(list);
3530219089Spjd		(void) sleep(interval);
3531168404Spjd	}
3532168404Spjd
3533268470Sdelphij	if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
3534268470Sdelphij		(void) printf(gettext("no pools available\n"));
3535268470Sdelphij		ret = 0;
3536268470Sdelphij	}
3537268470Sdelphij
3538268470Sdelphij	pool_list_free(list);
3539219089Spjd	zprop_free_list(cb.cb_proplist);
3540168404Spjd	return (ret);
3541168404Spjd}
3542168404Spjd
3543168404Spjdstatic int
3544168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing)
3545168404Spjd{
3546168404Spjd	boolean_t force = B_FALSE;
3547168404Spjd	int c;
3548168404Spjd	nvlist_t *nvroot;
3549168404Spjd	char *poolname, *old_disk, *new_disk;
3550168404Spjd	zpool_handle_t *zhp;
3551331395Smav	zpool_boot_label_t boot_type;
3552331395Smav	uint64_t boot_size;
3553168404Spjd	int ret;
3554168404Spjd
3555168404Spjd	/* check options */
3556168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
3557168404Spjd		switch (c) {
3558168404Spjd		case 'f':
3559168404Spjd			force = B_TRUE;
3560168404Spjd			break;
3561168404Spjd		case '?':
3562168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3563168404Spjd			    optopt);
3564168404Spjd			usage(B_FALSE);
3565168404Spjd		}
3566168404Spjd	}
3567168404Spjd
3568168404Spjd	argc -= optind;
3569168404Spjd	argv += optind;
3570168404Spjd
3571168404Spjd	/* get pool name and check number of arguments */
3572168404Spjd	if (argc < 1) {
3573168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
3574168404Spjd		usage(B_FALSE);
3575168404Spjd	}
3576168404Spjd
3577168404Spjd	poolname = argv[0];
3578168404Spjd
3579168404Spjd	if (argc < 2) {
3580168404Spjd		(void) fprintf(stderr,
3581168404Spjd		    gettext("missing <device> specification\n"));
3582168404Spjd		usage(B_FALSE);
3583168404Spjd	}
3584168404Spjd
3585168404Spjd	old_disk = argv[1];
3586168404Spjd
3587168404Spjd	if (argc < 3) {
3588168404Spjd		if (!replacing) {
3589168404Spjd			(void) fprintf(stderr,
3590168404Spjd			    gettext("missing <new_device> specification\n"));
3591168404Spjd			usage(B_FALSE);
3592168404Spjd		}
3593168404Spjd		new_disk = old_disk;
3594168404Spjd		argc -= 1;
3595168404Spjd		argv += 1;
3596168404Spjd	} else {
3597168404Spjd		new_disk = argv[2];
3598168404Spjd		argc -= 2;
3599168404Spjd		argv += 2;
3600168404Spjd	}
3601168404Spjd
3602168404Spjd	if (argc > 1) {
3603168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
3604168404Spjd		usage(B_FALSE);
3605168404Spjd	}
3606168404Spjd
3607168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3608168404Spjd		return (1);
3609168404Spjd
3610185029Spjd	if (zpool_get_config(zhp, NULL) == NULL) {
3611168404Spjd		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
3612168404Spjd		    poolname);
3613168404Spjd		zpool_close(zhp);
3614168404Spjd		return (1);
3615168404Spjd	}
3616168404Spjd
3617331395Smav	if (zpool_is_bootable(zhp))
3618331395Smav		boot_type = ZPOOL_COPY_BOOT_LABEL;
3619331395Smav	else
3620331395Smav		boot_type = ZPOOL_NO_BOOT_LABEL;
3621331395Smav
3622331395Smav	boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
3623185029Spjd	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
3624331395Smav	    boot_type, boot_size, argc, argv);
3625168404Spjd	if (nvroot == NULL) {
3626168404Spjd		zpool_close(zhp);
3627168404Spjd		return (1);
3628168404Spjd	}
3629168404Spjd
3630168404Spjd	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
3631168404Spjd
3632168404Spjd	nvlist_free(nvroot);
3633168404Spjd	zpool_close(zhp);
3634168404Spjd
3635168404Spjd	return (ret);
3636168404Spjd}
3637168404Spjd
3638168404Spjd/*
3639168404Spjd * zpool replace [-f] <pool> <device> <new_device>
3640168404Spjd *
3641168404Spjd *	-f	Force attach, even if <new_device> appears to be in use.
3642168404Spjd *
3643168404Spjd * Replace <device> with <new_device>.
3644168404Spjd */
3645168404Spjd/* ARGSUSED */
3646168404Spjdint
3647168404Spjdzpool_do_replace(int argc, char **argv)
3648168404Spjd{
3649168404Spjd	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
3650168404Spjd}
3651168404Spjd
3652168404Spjd/*
3653168404Spjd * zpool attach [-f] <pool> <device> <new_device>
3654168404Spjd *
3655168404Spjd *	-f	Force attach, even if <new_device> appears to be in use.
3656168404Spjd *
3657168404Spjd * Attach <new_device> to the mirror containing <device>.  If <device> is not
3658168404Spjd * part of a mirror, then <device> will be transformed into a mirror of
3659168404Spjd * <device> and <new_device>.  In either case, <new_device> will begin life
3660168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself.
3661168404Spjd */
3662168404Spjdint
3663168404Spjdzpool_do_attach(int argc, char **argv)
3664168404Spjd{
3665168404Spjd	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
3666168404Spjd}
3667168404Spjd
3668168404Spjd/*
3669168404Spjd * zpool detach [-f] <pool> <device>
3670168404Spjd *
3671168404Spjd *	-f	Force detach of <device>, even if DTLs argue against it
3672168404Spjd *		(not supported yet)
3673168404Spjd *
3674168404Spjd * Detach a device from a mirror.  The operation will be refused if <device>
3675168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device
3676168404Spjd * has the only valid copy of some data.
3677168404Spjd */
3678168404Spjd/* ARGSUSED */
3679168404Spjdint
3680168404Spjdzpool_do_detach(int argc, char **argv)
3681168404Spjd{
3682168404Spjd	int c;
3683168404Spjd	char *poolname, *path;
3684168404Spjd	zpool_handle_t *zhp;
3685168404Spjd	int ret;
3686168404Spjd
3687168404Spjd	/* check options */
3688168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
3689168404Spjd		switch (c) {
3690168404Spjd		case 'f':
3691168404Spjd		case '?':
3692168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3693168404Spjd			    optopt);
3694168404Spjd			usage(B_FALSE);
3695168404Spjd		}
3696168404Spjd	}
3697168404Spjd
3698168404Spjd	argc -= optind;
3699168404Spjd	argv += optind;
3700168404Spjd
3701168404Spjd	/* get pool name and check number of arguments */
3702168404Spjd	if (argc < 1) {
3703168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
3704168404Spjd		usage(B_FALSE);
3705168404Spjd	}
3706168404Spjd
3707168404Spjd	if (argc < 2) {
3708168404Spjd		(void) fprintf(stderr,
3709168404Spjd		    gettext("missing <device> specification\n"));
3710168404Spjd		usage(B_FALSE);
3711168404Spjd	}
3712168404Spjd
3713168404Spjd	poolname = argv[0];
3714168404Spjd	path = argv[1];
3715168404Spjd
3716168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3717168404Spjd		return (1);
3718168404Spjd
3719168404Spjd	ret = zpool_vdev_detach(zhp, path);
3720168404Spjd
3721168404Spjd	zpool_close(zhp);
3722168404Spjd
3723168404Spjd	return (ret);
3724168404Spjd}
3725168404Spjd
3726168404Spjd/*
3727219089Spjd * zpool split [-n] [-o prop=val] ...
3728219089Spjd *		[-o mntopt] ...
3729219089Spjd *		[-R altroot] <pool> <newpool> [<device> ...]
3730219089Spjd *
3731219089Spjd *	-n	Do not split the pool, but display the resulting layout if
3732219089Spjd *		it were to be split.
3733219089Spjd *	-o	Set property=value, or set mount options.
3734219089Spjd *	-R	Mount the split-off pool under an alternate root.
3735219089Spjd *
3736219089Spjd * Splits the named pool and gives it the new pool name.  Devices to be split
3737219089Spjd * off may be listed, provided that no more than one device is specified
3738219089Spjd * per top-level vdev mirror.  The newly split pool is left in an exported
3739219089Spjd * state unless -R is specified.
3740219089Spjd *
3741219089Spjd * Restrictions: the top-level of the pool pool must only be made up of
3742219089Spjd * mirrors; all devices in the pool must be healthy; no device may be
3743219089Spjd * undergoing a resilvering operation.
3744219089Spjd */
3745219089Spjdint
3746219089Spjdzpool_do_split(int argc, char **argv)
3747219089Spjd{
3748219089Spjd	char *srcpool, *newpool, *propval;
3749219089Spjd	char *mntopts = NULL;
3750219089Spjd	splitflags_t flags;
3751219089Spjd	int c, ret = 0;
3752219089Spjd	zpool_handle_t *zhp;
3753219089Spjd	nvlist_t *config, *props = NULL;
3754219089Spjd
3755219089Spjd	flags.dryrun = B_FALSE;
3756219089Spjd	flags.import = B_FALSE;
3757219089Spjd
3758219089Spjd	/* check options */
3759219089Spjd	while ((c = getopt(argc, argv, ":R:no:")) != -1) {
3760219089Spjd		switch (c) {
3761219089Spjd		case 'R':
3762219089Spjd			flags.import = B_TRUE;
3763219089Spjd			if (add_prop_list(
3764219089Spjd			    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
3765219089Spjd			    &props, B_TRUE) != 0) {
3766296528Smav				nvlist_free(props);
3767219089Spjd				usage(B_FALSE);
3768219089Spjd			}
3769219089Spjd			break;
3770219089Spjd		case 'n':
3771219089Spjd			flags.dryrun = B_TRUE;
3772219089Spjd			break;
3773219089Spjd		case 'o':
3774219089Spjd			if ((propval = strchr(optarg, '=')) != NULL) {
3775219089Spjd				*propval = '\0';
3776219089Spjd				propval++;
3777219089Spjd				if (add_prop_list(optarg, propval,
3778219089Spjd				    &props, B_TRUE) != 0) {
3779296528Smav					nvlist_free(props);
3780219089Spjd					usage(B_FALSE);
3781219089Spjd				}
3782219089Spjd			} else {
3783219089Spjd				mntopts = optarg;
3784219089Spjd			}
3785219089Spjd			break;
3786219089Spjd		case ':':
3787219089Spjd			(void) fprintf(stderr, gettext("missing argument for "
3788219089Spjd			    "'%c' option\n"), optopt);
3789219089Spjd			usage(B_FALSE);
3790219089Spjd			break;
3791219089Spjd		case '?':
3792219089Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3793219089Spjd			    optopt);
3794219089Spjd			usage(B_FALSE);
3795219089Spjd			break;
3796219089Spjd		}
3797219089Spjd	}
3798219089Spjd
3799219089Spjd	if (!flags.import && mntopts != NULL) {
3800219089Spjd		(void) fprintf(stderr, gettext("setting mntopts is only "
3801219089Spjd		    "valid when importing the pool\n"));
3802219089Spjd		usage(B_FALSE);
3803219089Spjd	}
3804219089Spjd
3805219089Spjd	argc -= optind;
3806219089Spjd	argv += optind;
3807219089Spjd
3808219089Spjd	if (argc < 1) {
3809219089Spjd		(void) fprintf(stderr, gettext("Missing pool name\n"));
3810219089Spjd		usage(B_FALSE);
3811219089Spjd	}
3812219089Spjd	if (argc < 2) {
3813219089Spjd		(void) fprintf(stderr, gettext("Missing new pool name\n"));
3814219089Spjd		usage(B_FALSE);
3815219089Spjd	}
3816219089Spjd
3817219089Spjd	srcpool = argv[0];
3818219089Spjd	newpool = argv[1];
3819219089Spjd
3820219089Spjd	argc -= 2;
3821219089Spjd	argv += 2;
3822219089Spjd
3823219089Spjd	if ((zhp = zpool_open(g_zfs, srcpool)) == NULL)
3824219089Spjd		return (1);
3825219089Spjd
3826219089Spjd	config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
3827219089Spjd	if (config == NULL) {
3828219089Spjd		ret = 1;
3829219089Spjd	} else {
3830219089Spjd		if (flags.dryrun) {
3831219089Spjd			(void) printf(gettext("would create '%s' with the "
3832219089Spjd			    "following layout:\n\n"), newpool);
3833219089Spjd			print_vdev_tree(NULL, newpool, config, 0, B_FALSE);
3834219089Spjd		}
3835219089Spjd		nvlist_free(config);
3836219089Spjd	}
3837219089Spjd
3838219089Spjd	zpool_close(zhp);
3839219089Spjd
3840219089Spjd	if (ret != 0 || flags.dryrun || !flags.import)
3841219089Spjd		return (ret);
3842219089Spjd
3843219089Spjd	/*
3844219089Spjd	 * The split was successful. Now we need to open the new
3845219089Spjd	 * pool and import it.
3846219089Spjd	 */
3847219089Spjd	if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
3848219089Spjd		return (1);
3849219089Spjd	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
3850219089Spjd	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
3851219089Spjd		ret = 1;
3852240415Smm		(void) fprintf(stderr, gettext("Split was successful, but "
3853219089Spjd		    "the datasets could not all be mounted\n"));
3854219089Spjd		(void) fprintf(stderr, gettext("Try doing '%s' with a "
3855219089Spjd		    "different altroot\n"), "zpool import");
3856219089Spjd	}
3857219089Spjd	zpool_close(zhp);
3858219089Spjd
3859219089Spjd	return (ret);
3860219089Spjd}
3861219089Spjd
3862219089Spjd
3863219089Spjd
3864219089Spjd/*
3865168404Spjd * zpool online <pool> <device> ...
3866168404Spjd */
3867168404Spjdint
3868168404Spjdzpool_do_online(int argc, char **argv)
3869168404Spjd{
3870168404Spjd	int c, i;
3871168404Spjd	char *poolname;
3872168404Spjd	zpool_handle_t *zhp;
3873168404Spjd	int ret = 0;
3874185029Spjd	vdev_state_t newstate;
3875219089Spjd	int flags = 0;
3876168404Spjd
3877168404Spjd	/* check options */
3878219089Spjd	while ((c = getopt(argc, argv, "et")) != -1) {
3879168404Spjd		switch (c) {
3880219089Spjd		case 'e':
3881219089Spjd			flags |= ZFS_ONLINE_EXPAND;
3882219089Spjd			break;
3883168404Spjd		case 't':
3884168404Spjd		case '?':
3885168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3886168404Spjd			    optopt);
3887168404Spjd			usage(B_FALSE);
3888168404Spjd		}
3889168404Spjd	}
3890168404Spjd
3891168404Spjd	argc -= optind;
3892168404Spjd	argv += optind;
3893168404Spjd
3894168404Spjd	/* get pool name and check number of arguments */
3895168404Spjd	if (argc < 1) {
3896168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
3897168404Spjd		usage(B_FALSE);
3898168404Spjd	}
3899168404Spjd	if (argc < 2) {
3900168404Spjd		(void) fprintf(stderr, gettext("missing device name\n"));
3901168404Spjd		usage(B_FALSE);
3902168404Spjd	}
3903168404Spjd
3904168404Spjd	poolname = argv[0];
3905168404Spjd
3906168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3907168404Spjd		return (1);
3908168404Spjd
3909185029Spjd	for (i = 1; i < argc; i++) {
3910219089Spjd		if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
3911185029Spjd			if (newstate != VDEV_STATE_HEALTHY) {
3912185029Spjd				(void) printf(gettext("warning: device '%s' "
3913185029Spjd				    "onlined, but remains in faulted state\n"),
3914185029Spjd				    argv[i]);
3915185029Spjd				if (newstate == VDEV_STATE_FAULTED)
3916185029Spjd					(void) printf(gettext("use 'zpool "
3917185029Spjd					    "clear' to restore a faulted "
3918185029Spjd					    "device\n"));
3919185029Spjd				else
3920185029Spjd					(void) printf(gettext("use 'zpool "
3921185029Spjd					    "replace' to replace devices "
3922185029Spjd					    "that are no longer present\n"));
3923185029Spjd			}
3924185029Spjd		} else {
3925168404Spjd			ret = 1;
3926185029Spjd		}
3927185029Spjd	}
3928168404Spjd
3929168404Spjd	zpool_close(zhp);
3930168404Spjd
3931168404Spjd	return (ret);
3932168404Spjd}
3933168404Spjd
3934168404Spjd/*
3935168404Spjd * zpool offline [-ft] <pool> <device> ...
3936168404Spjd *
3937168404Spjd *	-f	Force the device into the offline state, even if doing
3938168404Spjd *		so would appear to compromise pool availability.
3939168404Spjd *		(not supported yet)
3940168404Spjd *
3941168404Spjd *	-t	Only take the device off-line temporarily.  The offline
3942168404Spjd *		state will not be persistent across reboots.
3943168404Spjd */
3944168404Spjd/* ARGSUSED */
3945168404Spjdint
3946168404Spjdzpool_do_offline(int argc, char **argv)
3947168404Spjd{
3948168404Spjd	int c, i;
3949168404Spjd	char *poolname;
3950168404Spjd	zpool_handle_t *zhp;
3951168404Spjd	int ret = 0;
3952168404Spjd	boolean_t istmp = B_FALSE;
3953168404Spjd
3954168404Spjd	/* check options */
3955168404Spjd	while ((c = getopt(argc, argv, "ft")) != -1) {
3956168404Spjd		switch (c) {
3957168404Spjd		case 't':
3958168404Spjd			istmp = B_TRUE;
3959168404Spjd			break;
3960168404Spjd		case 'f':
3961168404Spjd		case '?':
3962168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3963168404Spjd			    optopt);
3964168404Spjd			usage(B_FALSE);
3965168404Spjd		}
3966168404Spjd	}
3967168404Spjd
3968168404Spjd	argc -= optind;
3969168404Spjd	argv += optind;
3970168404Spjd
3971168404Spjd	/* get pool name and check number of arguments */
3972168404Spjd	if (argc < 1) {
3973168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
3974168404Spjd		usage(B_FALSE);
3975168404Spjd	}
3976168404Spjd	if (argc < 2) {
3977168404Spjd		(void) fprintf(stderr, gettext("missing device name\n"));
3978168404Spjd		usage(B_FALSE);
3979168404Spjd	}
3980168404Spjd
3981168404Spjd	poolname = argv[0];
3982168404Spjd
3983168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3984168404Spjd		return (1);
3985168404Spjd
3986185029Spjd	for (i = 1; i < argc; i++) {
3987185029Spjd		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
3988168404Spjd			ret = 1;
3989185029Spjd	}
3990168404Spjd
3991168404Spjd	zpool_close(zhp);
3992168404Spjd
3993168404Spjd	return (ret);
3994168404Spjd}
3995168404Spjd
3996168404Spjd/*
3997168404Spjd * zpool clear <pool> [device]
3998168404Spjd *
3999168404Spjd * Clear all errors associated with a pool or a particular device.
4000168404Spjd */
4001168404Spjdint
4002168404Spjdzpool_do_clear(int argc, char **argv)
4003168404Spjd{
4004219089Spjd	int c;
4005168404Spjd	int ret = 0;
4006219089Spjd	boolean_t dryrun = B_FALSE;
4007219089Spjd	boolean_t do_rewind = B_FALSE;
4008219089Spjd	boolean_t xtreme_rewind = B_FALSE;
4009219089Spjd	uint32_t rewind_policy = ZPOOL_NO_REWIND;
4010219089Spjd	nvlist_t *policy = NULL;
4011168404Spjd	zpool_handle_t *zhp;
4012168404Spjd	char *pool, *device;
4013168404Spjd
4014219089Spjd	/* check options */
4015219089Spjd	while ((c = getopt(argc, argv, "FnX")) != -1) {
4016219089Spjd		switch (c) {
4017219089Spjd		case 'F':
4018219089Spjd			do_rewind = B_TRUE;
4019219089Spjd			break;
4020219089Spjd		case 'n':
4021219089Spjd			dryrun = B_TRUE;
4022219089Spjd			break;
4023219089Spjd		case 'X':
4024219089Spjd			xtreme_rewind = B_TRUE;
4025219089Spjd			break;
4026219089Spjd		case '?':
4027219089Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4028219089Spjd			    optopt);
4029219089Spjd			usage(B_FALSE);
4030219089Spjd		}
4031219089Spjd	}
4032219089Spjd
4033219089Spjd	argc -= optind;
4034219089Spjd	argv += optind;
4035219089Spjd
4036219089Spjd	if (argc < 1) {
4037168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
4038168404Spjd		usage(B_FALSE);
4039168404Spjd	}
4040168404Spjd
4041219089Spjd	if (argc > 2) {
4042168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
4043168404Spjd		usage(B_FALSE);
4044168404Spjd	}
4045168404Spjd
4046219089Spjd	if ((dryrun || xtreme_rewind) && !do_rewind) {
4047219089Spjd		(void) fprintf(stderr,
4048219089Spjd		    gettext("-n or -X only meaningful with -F\n"));
4049219089Spjd		usage(B_FALSE);
4050219089Spjd	}
4051219089Spjd	if (dryrun)
4052219089Spjd		rewind_policy = ZPOOL_TRY_REWIND;
4053219089Spjd	else if (do_rewind)
4054219089Spjd		rewind_policy = ZPOOL_DO_REWIND;
4055219089Spjd	if (xtreme_rewind)
4056219089Spjd		rewind_policy |= ZPOOL_EXTREME_REWIND;
4057168404Spjd
4058219089Spjd	/* In future, further rewind policy choices can be passed along here */
4059219089Spjd	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
4060332550Smav	    nvlist_add_uint32(policy, ZPOOL_LOAD_REWIND_POLICY,
4061332550Smav	    rewind_policy) != 0) {
4062168404Spjd		return (1);
4063332550Smav	}
4064168404Spjd
4065219089Spjd	pool = argv[0];
4066219089Spjd	device = argc == 2 ? argv[1] : NULL;
4067219089Spjd
4068219089Spjd	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
4069219089Spjd		nvlist_free(policy);
4070219089Spjd		return (1);
4071219089Spjd	}
4072219089Spjd
4073219089Spjd	if (zpool_clear(zhp, device, policy) != 0)
4074168404Spjd		ret = 1;
4075168404Spjd
4076168404Spjd	zpool_close(zhp);
4077168404Spjd
4078219089Spjd	nvlist_free(policy);
4079219089Spjd
4080168404Spjd	return (ret);
4081168404Spjd}
4082168404Spjd
4083228103Smm/*
4084228103Smm * zpool reguid <pool>
4085228103Smm */
4086228103Smmint
4087228103Smmzpool_do_reguid(int argc, char **argv)
4088228103Smm{
4089228103Smm	int c;
4090228103Smm	char *poolname;
4091228103Smm	zpool_handle_t *zhp;
4092228103Smm	int ret = 0;
4093228103Smm
4094228103Smm	/* check options */
4095228103Smm	while ((c = getopt(argc, argv, "")) != -1) {
4096228103Smm		switch (c) {
4097228103Smm		case '?':
4098228103Smm			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4099228103Smm			    optopt);
4100228103Smm			usage(B_FALSE);
4101228103Smm		}
4102228103Smm	}
4103228103Smm
4104228103Smm	argc -= optind;
4105228103Smm	argv += optind;
4106228103Smm
4107228103Smm	/* get pool name and check number of arguments */
4108228103Smm	if (argc < 1) {
4109228103Smm		(void) fprintf(stderr, gettext("missing pool name\n"));
4110228103Smm		usage(B_FALSE);
4111228103Smm	}
4112228103Smm
4113228103Smm	if (argc > 1) {
4114228103Smm		(void) fprintf(stderr, gettext("too many arguments\n"));
4115228103Smm		usage(B_FALSE);
4116228103Smm	}
4117228103Smm
4118228103Smm	poolname = argv[0];
4119228103Smm	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
4120228103Smm		return (1);
4121228103Smm
4122228103Smm	ret = zpool_reguid(zhp);
4123228103Smm
4124228103Smm	zpool_close(zhp);
4125228103Smm	return (ret);
4126228103Smm}
4127228103Smm
4128228103Smm
4129236155Smm/*
4130236155Smm * zpool reopen <pool>
4131236155Smm *
4132236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs.
4133236155Smm */
4134236155Smmint
4135236155Smmzpool_do_reopen(int argc, char **argv)
4136236155Smm{
4137260138Sdelphij	int c;
4138236155Smm	int ret = 0;
4139236155Smm	zpool_handle_t *zhp;
4140236155Smm	char *pool;
4141236155Smm
4142260138Sdelphij	/* check options */
4143260138Sdelphij	while ((c = getopt(argc, argv, "")) != -1) {
4144260138Sdelphij		switch (c) {
4145260138Sdelphij		case '?':
4146260138Sdelphij			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4147260138Sdelphij			    optopt);
4148260138Sdelphij			usage(B_FALSE);
4149260138Sdelphij		}
4150260138Sdelphij	}
4151260138Sdelphij
4152236155Smm	argc--;
4153236155Smm	argv++;
4154236155Smm
4155260138Sdelphij	if (argc < 1) {
4156260138Sdelphij		(void) fprintf(stderr, gettext("missing pool name\n"));
4157260138Sdelphij		usage(B_FALSE);
4158260138Sdelphij	}
4159236155Smm
4160260138Sdelphij	if (argc > 1) {
4161260138Sdelphij		(void) fprintf(stderr, gettext("too many arguments\n"));
4162260138Sdelphij		usage(B_FALSE);
4163260138Sdelphij	}
4164260138Sdelphij
4165236155Smm	pool = argv[0];
4166236155Smm	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
4167236155Smm		return (1);
4168236155Smm
4169236155Smm	ret = zpool_reopen(zhp);
4170236155Smm	zpool_close(zhp);
4171236155Smm	return (ret);
4172236155Smm}
4173236155Smm
4174168404Spjdtypedef struct scrub_cbdata {
4175168404Spjd	int	cb_type;
4176168404Spjd	int	cb_argc;
4177168404Spjd	char	**cb_argv;
4178324010Savg	pool_scrub_cmd_t cb_scrub_cmd;
4179168404Spjd} scrub_cbdata_t;
4180168404Spjd
4181332547Smavstatic boolean_t
4182332547Smavzpool_has_checkpoint(zpool_handle_t *zhp)
4183332547Smav{
4184332547Smav	nvlist_t *config, *nvroot;
4185332547Smav
4186332547Smav	config = zpool_get_config(zhp, NULL);
4187332547Smav
4188332547Smav	if (config != NULL) {
4189332547Smav		pool_checkpoint_stat_t *pcs = NULL;
4190332547Smav		uint_t c;
4191332547Smav
4192332547Smav		nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
4193332547Smav		(void) nvlist_lookup_uint64_array(nvroot,
4194332547Smav		    ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c);
4195332547Smav
4196332547Smav		if (pcs == NULL || pcs->pcs_state == CS_NONE)
4197332547Smav			return (B_FALSE);
4198332547Smav
4199332547Smav		assert(pcs->pcs_state == CS_CHECKPOINT_EXISTS ||
4200332547Smav		    pcs->pcs_state == CS_CHECKPOINT_DISCARDING);
4201332547Smav		return (B_TRUE);
4202332547Smav	}
4203332547Smav
4204332547Smav	return (B_FALSE);
4205332547Smav}
4206332547Smav
4207168404Spjdint
4208168404Spjdscrub_callback(zpool_handle_t *zhp, void *data)
4209168404Spjd{
4210168404Spjd	scrub_cbdata_t *cb = data;
4211168404Spjd	int err;
4212168404Spjd
4213168404Spjd	/*
4214168404Spjd	 * Ignore faulted pools.
4215168404Spjd	 */
4216168404Spjd	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
4217168404Spjd		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
4218168404Spjd		    "currently unavailable\n"), zpool_get_name(zhp));
4219168404Spjd		return (1);
4220168404Spjd	}
4221168404Spjd
4222324010Savg	err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd);
4223168404Spjd
4224332547Smav	if (err == 0 && zpool_has_checkpoint(zhp) &&
4225332547Smav	    cb->cb_type == POOL_SCAN_SCRUB) {
4226332547Smav		(void) printf(gettext("warning: will not scrub state that "
4227332547Smav		    "belongs to the checkpoint of pool '%s'\n"),
4228332547Smav		    zpool_get_name(zhp));
4229332547Smav	}
4230332547Smav
4231168404Spjd	return (err != 0);
4232168404Spjd}
4233168404Spjd
4234168404Spjd/*
4235324010Savg * zpool scrub [-s | -p] <pool> ...
4236168404Spjd *
4237168404Spjd *	-s	Stop.  Stops any in-progress scrub.
4238324010Savg *	-p	Pause. Pause in-progress scrub.
4239168404Spjd */
4240168404Spjdint
4241168404Spjdzpool_do_scrub(int argc, char **argv)
4242168404Spjd{
4243168404Spjd	int c;
4244168404Spjd	scrub_cbdata_t cb;
4245168404Spjd
4246219089Spjd	cb.cb_type = POOL_SCAN_SCRUB;
4247324010Savg	cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
4248168404Spjd
4249168404Spjd	/* check options */
4250324010Savg	while ((c = getopt(argc, argv, "sp")) != -1) {
4251168404Spjd		switch (c) {
4252168404Spjd		case 's':
4253219089Spjd			cb.cb_type = POOL_SCAN_NONE;
4254168404Spjd			break;
4255324010Savg		case 'p':
4256324010Savg			cb.cb_scrub_cmd = POOL_SCRUB_PAUSE;
4257324010Savg			break;
4258168404Spjd		case '?':
4259168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4260168404Spjd			    optopt);
4261168404Spjd			usage(B_FALSE);
4262168404Spjd		}
4263168404Spjd	}
4264168404Spjd
4265324010Savg	if (cb.cb_type == POOL_SCAN_NONE &&
4266324010Savg	    cb.cb_scrub_cmd == POOL_SCRUB_PAUSE) {
4267324010Savg		(void) fprintf(stderr, gettext("invalid option combination: "
4268324010Savg		    "-s and -p are mutually exclusive\n"));
4269324010Savg		usage(B_FALSE);
4270324010Savg	}
4271324010Savg
4272168404Spjd	cb.cb_argc = argc;
4273168404Spjd	cb.cb_argv = argv;
4274168404Spjd	argc -= optind;
4275168404Spjd	argv += optind;
4276168404Spjd
4277168404Spjd	if (argc < 1) {
4278168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
4279168404Spjd		usage(B_FALSE);
4280168404Spjd	}
4281168404Spjd
4282168404Spjd	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
4283168404Spjd}
4284168404Spjd
4285339111Smavstatic void
4286339111Smavzpool_collect_leaves(zpool_handle_t *zhp, nvlist_t *nvroot, nvlist_t *res)
4287339111Smav{
4288339111Smav	uint_t children = 0;
4289339111Smav	nvlist_t **child;
4290339111Smav	uint_t i;
4291339111Smav
4292339111Smav	(void) nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
4293339111Smav	    &child, &children);
4294339111Smav
4295339111Smav	if (children == 0) {
4296339111Smav		char *path = zpool_vdev_name(g_zfs, zhp, nvroot, B_FALSE);
4297339111Smav		fnvlist_add_boolean(res, path);
4298339111Smav		free(path);
4299339111Smav		return;
4300339111Smav	}
4301339111Smav
4302339111Smav	for (i = 0; i < children; i++) {
4303339111Smav		zpool_collect_leaves(zhp, child[i], res);
4304339111Smav	}
4305339111Smav}
4306339111Smav
4307339111Smav/*
4308339111Smav * zpool initialize [-cs] <pool> [<vdev> ...]
4309339111Smav * Initialize all unused blocks in the specified vdevs, or all vdevs in the pool
4310339111Smav * if none specified.
4311339111Smav *
4312339111Smav *	-c	Cancel. Ends active initializing.
4313339111Smav *	-s	Suspend. Initializing can then be restarted with no flags.
4314339111Smav */
4315339111Smavint
4316339111Smavzpool_do_initialize(int argc, char **argv)
4317339111Smav{
4318339111Smav	int c;
4319339111Smav	char *poolname;
4320339111Smav	zpool_handle_t *zhp;
4321339111Smav	nvlist_t *vdevs;
4322339111Smav	int err = 0;
4323339111Smav
4324339111Smav	struct option long_options[] = {
4325339111Smav		{"cancel",	no_argument,		NULL, 'c'},
4326339111Smav		{"suspend",	no_argument,		NULL, 's'},
4327339111Smav		{0, 0, 0, 0}
4328339111Smav	};
4329339111Smav
4330339111Smav	pool_initialize_func_t cmd_type = POOL_INITIALIZE_DO;
4331339111Smav	while ((c = getopt_long(argc, argv, "cs", long_options, NULL)) != -1) {
4332339111Smav		switch (c) {
4333339111Smav		case 'c':
4334339111Smav			if (cmd_type != POOL_INITIALIZE_DO) {
4335339111Smav				(void) fprintf(stderr, gettext("-c cannot be "
4336339111Smav				    "combined with other options\n"));
4337339111Smav				usage(B_FALSE);
4338339111Smav			}
4339339111Smav			cmd_type = POOL_INITIALIZE_CANCEL;
4340339111Smav			break;
4341339111Smav		case 's':
4342339111Smav			if (cmd_type != POOL_INITIALIZE_DO) {
4343339111Smav				(void) fprintf(stderr, gettext("-s cannot be "
4344339111Smav				    "combined with other options\n"));
4345339111Smav				usage(B_FALSE);
4346339111Smav			}
4347339111Smav			cmd_type = POOL_INITIALIZE_SUSPEND;
4348339111Smav			break;
4349339111Smav		case '?':
4350339111Smav			if (optopt != 0) {
4351339111Smav				(void) fprintf(stderr,
4352339111Smav				    gettext("invalid option '%c'\n"), optopt);
4353339111Smav			} else {
4354339111Smav				(void) fprintf(stderr,
4355339111Smav				    gettext("invalid option '%s'\n"),
4356339111Smav				    argv[optind - 1]);
4357339111Smav			}
4358339111Smav			usage(B_FALSE);
4359339111Smav		}
4360339111Smav	}
4361339111Smav
4362339111Smav	argc -= optind;
4363339111Smav	argv += optind;
4364339111Smav
4365339111Smav	if (argc < 1) {
4366339111Smav		(void) fprintf(stderr, gettext("missing pool name argument\n"));
4367339111Smav		usage(B_FALSE);
4368339111Smav		return (-1);
4369339111Smav	}
4370339111Smav
4371339111Smav	poolname = argv[0];
4372339111Smav	zhp = zpool_open(g_zfs, poolname);
4373339111Smav	if (zhp == NULL)
4374339111Smav		return (-1);
4375339111Smav
4376339111Smav	vdevs = fnvlist_alloc();
4377339111Smav	if (argc == 1) {
4378339111Smav		/* no individual leaf vdevs specified, so add them all */
4379339111Smav		nvlist_t *config = zpool_get_config(zhp, NULL);
4380339111Smav		nvlist_t *nvroot = fnvlist_lookup_nvlist(config,
4381339111Smav		    ZPOOL_CONFIG_VDEV_TREE);
4382339111Smav		zpool_collect_leaves(zhp, nvroot, vdevs);
4383339111Smav	} else {
4384339111Smav		int i;
4385339111Smav		for (i = 1; i < argc; i++) {
4386339111Smav			fnvlist_add_boolean(vdevs, argv[i]);
4387339111Smav		}
4388339111Smav	}
4389339111Smav
4390339111Smav	err = zpool_initialize(zhp, cmd_type, vdevs);
4391339111Smav
4392339111Smav	fnvlist_free(vdevs);
4393339111Smav	zpool_close(zhp);
4394339111Smav
4395339111Smav	return (err);
4396339111Smav}
4397339111Smav
4398168404Spjdtypedef struct status_cbdata {
4399168404Spjd	int		cb_count;
4400168404Spjd	boolean_t	cb_allpools;
4401168404Spjd	boolean_t	cb_verbose;
4402168404Spjd	boolean_t	cb_explain;
4403168404Spjd	boolean_t	cb_first;
4404219089Spjd	boolean_t	cb_dedup_stats;
4405168404Spjd} status_cbdata_t;
4406168404Spjd
4407168404Spjd/*
4408168404Spjd * Print out detailed scrub status.
4409168404Spjd */
4410332525Smavstatic void
4411219089Spjdprint_scan_status(pool_scan_stat_t *ps)
4412168404Spjd{
4413324010Savg	time_t start, end, pause;
4414339034Ssef	uint64_t total_secs_left;
4415339034Ssef	uint64_t elapsed, secs_left, mins_left, hours_left, days_left;
4416339034Ssef	uint64_t pass_scanned, scanned, pass_issued, issued, total;
4417339034Ssef	uint_t scan_rate, issue_rate;
4418168404Spjd	double fraction_done;
4419339034Ssef	char processed_buf[7], scanned_buf[7], issued_buf[7], total_buf[7];
4420339034Ssef	char srate_buf[7], irate_buf[7];
4421168404Spjd
4422226583Spjd	(void) printf(gettext("  scan: "));
4423168404Spjd
4424219089Spjd	/* If there's never been a scan, there's not much to say. */
4425219089Spjd	if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
4426219089Spjd	    ps->pss_func >= POOL_SCAN_FUNCS) {
4427168404Spjd		(void) printf(gettext("none requested\n"));
4428168404Spjd		return;
4429168404Spjd	}
4430168404Spjd
4431219089Spjd	start = ps->pss_start_time;
4432219089Spjd	end = ps->pss_end_time;
4433324010Savg	pause = ps->pss_pass_scrub_pause;
4434339034Ssef
4435219089Spjd	zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
4436168404Spjd
4437219089Spjd	assert(ps->pss_func == POOL_SCAN_SCRUB ||
4438219089Spjd	    ps->pss_func == POOL_SCAN_RESILVER);
4439339034Ssef
4440339034Ssef	/* Scan is finished or canceled. */
4441219089Spjd	if (ps->pss_state == DSS_FINISHED) {
4442339034Ssef		total_secs_left = end - start;
4443339034Ssef		days_left = total_secs_left / 60 / 60 / 24;
4444339034Ssef		hours_left = (total_secs_left / 60 / 60) % 24;
4445339034Ssef		mins_left = (total_secs_left / 60) % 60;
4446339034Ssef		secs_left = (total_secs_left % 60);
4447339034Ssef
4448219089Spjd		if (ps->pss_func == POOL_SCAN_SCRUB) {
4449339034Ssef			(void) printf(gettext("scrub repaired %s "
4450339034Ssef                            "in %llu days %02llu:%02llu:%02llu "
4451339034Ssef			    "with %llu errors on %s"), processed_buf,
4452339034Ssef                            (u_longlong_t)days_left, (u_longlong_t)hours_left,
4453339034Ssef                            (u_longlong_t)mins_left, (u_longlong_t)secs_left,
4454339034Ssef                            (u_longlong_t)ps->pss_errors, ctime(&end));
4455219089Spjd		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
4456339034Ssef                       (void) printf(gettext("resilvered %s "
4457339034Ssef                           "in %llu days %02llu:%02llu:%02llu "
4458339034Ssef                           "with %llu errors on %s"), processed_buf,
4459339034Ssef                           (u_longlong_t)days_left, (u_longlong_t)hours_left,
4460339034Ssef                           (u_longlong_t)mins_left, (u_longlong_t)secs_left,
4461339034Ssef                           (u_longlong_t)ps->pss_errors, ctime(&end));
4462339034Ssef
4463219089Spjd		}
4464339034Ssef
4465168404Spjd		return;
4466219089Spjd	} else if (ps->pss_state == DSS_CANCELED) {
4467219089Spjd		if (ps->pss_func == POOL_SCAN_SCRUB) {
4468219089Spjd			(void) printf(gettext("scrub canceled on %s"),
4469219089Spjd			    ctime(&end));
4470219089Spjd		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
4471219089Spjd			(void) printf(gettext("resilver canceled on %s"),
4472219089Spjd			    ctime(&end));
4473219089Spjd		}
4474219089Spjd		return;
4475168404Spjd	}
4476168404Spjd
4477219089Spjd	assert(ps->pss_state == DSS_SCANNING);
4478168404Spjd
4479339034Ssef	/* Scan is in progress. Resilvers can't be paused. */
4480219089Spjd	if (ps->pss_func == POOL_SCAN_SCRUB) {
4481324010Savg		if (pause == 0) {
4482324010Savg			(void) printf(gettext("scrub in progress since %s"),
4483324010Savg			    ctime(&start));
4484324010Savg		} else {
4485339034Ssef			(void) printf(gettext("scrub paused since %s"),
4486339034Ssef			    ctime(&pause));
4487339034Ssef			(void) printf(gettext("\tscrub started on %s"),
4488324010Savg			    ctime(&start));
4489324010Savg		}
4490219089Spjd	} else if (ps->pss_func == POOL_SCAN_RESILVER) {
4491219089Spjd		(void) printf(gettext("resilver in progress since %s"),
4492219089Spjd		    ctime(&start));
4493219089Spjd	}
4494219089Spjd
4495339034Ssef	scanned = ps->pss_examined;
4496339034Ssef	pass_scanned = ps->pss_pass_exam;
4497339034Ssef	issued = ps->pss_issued;
4498339034Ssef	pass_issued = ps->pss_pass_issued;
4499219089Spjd	total = ps->pss_to_examine;
4500168404Spjd
4501339034Ssef	/* we are only done with a block once we have issued the IO for it */
4502339034Ssef	fraction_done = (double)issued / total;
4503339034Ssef
4504339034Ssef	/* elapsed time for this pass, rounding up to 1 if it's 0 */
4505219089Spjd	elapsed = time(NULL) - ps->pss_pass_start;
4506324010Savg	elapsed -= ps->pss_pass_scrub_spent_paused;
4507339034Ssef	elapsed = (elapsed != 0) ? elapsed : 1;
4508219089Spjd
4509339034Ssef	scan_rate = pass_scanned / elapsed;
4510339034Ssef	issue_rate = pass_issued / elapsed;
4511339034Ssef	total_secs_left = (issue_rate != 0) ?
4512339034Ssef	    ((total - issued) / issue_rate) : UINT64_MAX;
4513339034Ssef
4514339034Ssef	days_left = total_secs_left / 60 / 60 / 24;
4515339034Ssef	hours_left = (total_secs_left / 60 / 60) % 24;
4516339034Ssef	mins_left = (total_secs_left / 60) % 60;
4517339034Ssef	secs_left = (total_secs_left % 60);
4518339034Ssef
4519339034Ssef	/* format all of the numbers we will be reporting */
4520339034Ssef	zfs_nicenum(scanned, scanned_buf, sizeof (scanned_buf));
4521339034Ssef	zfs_nicenum(issued, issued_buf, sizeof (issued_buf));
4522219089Spjd	zfs_nicenum(total, total_buf, sizeof (total_buf));
4523339034Ssef	zfs_nicenum(scan_rate, srate_buf, sizeof (srate_buf));
4524339034Ssef	zfs_nicenum(issue_rate, irate_buf, sizeof (irate_buf));
4525219089Spjd
4526339034Ssef	/* doo not print estimated time if we have a paused scrub */
4527324010Savg	if (pause == 0) {
4528339034Ssef		(void) printf(gettext("\t%s scanned at %s/s, "
4529339034Ssef		    "%s issued at %s/s, %s total\n"),
4530339034Ssef		    scanned_buf, srate_buf, issued_buf, irate_buf, total_buf);
4531219089Spjd	} else {
4532339034Ssef		(void) printf(gettext("\t%s scanned, %s issued, %s total\n"),
4533339034Ssef                    scanned_buf, issued_buf, total_buf);
4534219089Spjd	}
4535219089Spjd
4536219089Spjd	if (ps->pss_func == POOL_SCAN_RESILVER) {
4537339034Ssef		(void) printf(gettext("\t%s resilvered, %.2f%% done"),
4538219089Spjd		    processed_buf, 100 * fraction_done);
4539219089Spjd	} else if (ps->pss_func == POOL_SCAN_SCRUB) {
4540339034Ssef		(void) printf(gettext("\t%s repaired, %.2f%% done"),
4541219089Spjd		    processed_buf, 100 * fraction_done);
4542219089Spjd	}
4543339034Ssef
4544339034Ssef	if (pause == 0) {
4545339034Ssef		if (issue_rate >= 10 * 1024 * 1024) {
4546339034Ssef			(void) printf(gettext(", %llu days "
4547339034Ssef                            "%02llu:%02llu:%02llu to go\n"),
4548339034Ssef                            (u_longlong_t)days_left, (u_longlong_t)hours_left,
4549339034Ssef                            (u_longlong_t)mins_left, (u_longlong_t)secs_left);
4550339034Ssef		} else {
4551339034Ssef			(void) printf(gettext(", no estimated "
4552339034Ssef                            "completion time\n"));
4553339034Ssef		}
4554339034Ssef	} else {
4555339034Ssef		(void) printf(gettext("\n"));
4556339034Ssef	}
4557168404Spjd}
4558168404Spjd
4559332525Smav/*
4560332547Smav * As we don't scrub checkpointed blocks, we want to warn the
4561332547Smav * user that we skipped scanning some blocks if a checkpoint exists
4562332547Smav * or existed at any time during the scan.
4563332547Smav */
4564332547Smavstatic void
4565332547Smavprint_checkpoint_scan_warning(pool_scan_stat_t *ps, pool_checkpoint_stat_t *pcs)
4566332547Smav{
4567332547Smav	if (ps == NULL || pcs == NULL)
4568332547Smav		return;
4569332547Smav
4570332547Smav	if (pcs->pcs_state == CS_NONE ||
4571332547Smav	    pcs->pcs_state == CS_CHECKPOINT_DISCARDING)
4572332547Smav		return;
4573332547Smav
4574332547Smav	assert(pcs->pcs_state == CS_CHECKPOINT_EXISTS);
4575332547Smav
4576332547Smav	if (ps->pss_state == DSS_NONE)
4577332547Smav		return;
4578332547Smav
4579332547Smav	if ((ps->pss_state == DSS_FINISHED || ps->pss_state == DSS_CANCELED) &&
4580332547Smav	    ps->pss_end_time < pcs->pcs_start_time)
4581332547Smav		return;
4582332547Smav
4583332547Smav	if (ps->pss_state == DSS_FINISHED || ps->pss_state == DSS_CANCELED) {
4584332547Smav		(void) printf(gettext("    scan warning: skipped blocks "
4585332547Smav		    "that are only referenced by the checkpoint.\n"));
4586332547Smav	} else {
4587332547Smav		assert(ps->pss_state == DSS_SCANNING);
4588332547Smav		(void) printf(gettext("    scan warning: skipping blocks "
4589332547Smav		    "that are only referenced by the checkpoint.\n"));
4590332547Smav	}
4591332547Smav}
4592332547Smav
4593332547Smav/*
4594332525Smav * Print out detailed removal status.
4595332525Smav */
4596168404Spjdstatic void
4597332525Smavprint_removal_status(zpool_handle_t *zhp, pool_removal_stat_t *prs)
4598332525Smav{
4599332525Smav	char copied_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
4600332525Smav	time_t start, end;
4601332525Smav	nvlist_t *config, *nvroot;
4602332525Smav	nvlist_t **child;
4603332525Smav	uint_t children;
4604332525Smav	char *vdev_name;
4605332525Smav
4606332525Smav	if (prs == NULL || prs->prs_state == DSS_NONE)
4607332525Smav		return;
4608332525Smav
4609332525Smav	/*
4610332525Smav	 * Determine name of vdev.
4611332525Smav	 */
4612332525Smav	config = zpool_get_config(zhp, NULL);
4613332525Smav	nvroot = fnvlist_lookup_nvlist(config,
4614332525Smav	    ZPOOL_CONFIG_VDEV_TREE);
4615332525Smav	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
4616332525Smav	    &child, &children) == 0);
4617332525Smav	assert(prs->prs_removing_vdev < children);
4618332525Smav	vdev_name = zpool_vdev_name(g_zfs, zhp,
4619332525Smav	    child[prs->prs_removing_vdev], B_TRUE);
4620332525Smav
4621332525Smav	(void) printf(gettext("remove: "));
4622332525Smav
4623332525Smav	start = prs->prs_start_time;
4624332525Smav	end = prs->prs_end_time;
4625332525Smav	zfs_nicenum(prs->prs_copied, copied_buf, sizeof (copied_buf));
4626332525Smav
4627332525Smav	/*
4628332525Smav	 * Removal is finished or canceled.
4629332525Smav	 */
4630332525Smav	if (prs->prs_state == DSS_FINISHED) {
4631332525Smav		uint64_t minutes_taken = (end - start) / 60;
4632332525Smav
4633332525Smav		(void) printf(gettext("Removal of vdev %llu copied %s "
4634332525Smav		    "in %lluh%um, completed on %s"),
4635332525Smav		    (longlong_t)prs->prs_removing_vdev,
4636332525Smav		    copied_buf,
4637332525Smav		    (u_longlong_t)(minutes_taken / 60),
4638332525Smav		    (uint_t)(minutes_taken % 60),
4639332525Smav		    ctime((time_t *)&end));
4640332525Smav	} else if (prs->prs_state == DSS_CANCELED) {
4641332525Smav		(void) printf(gettext("Removal of %s canceled on %s"),
4642332525Smav		    vdev_name, ctime(&end));
4643332525Smav	} else {
4644332525Smav		uint64_t copied, total, elapsed, mins_left, hours_left;
4645332525Smav		double fraction_done;
4646332525Smav		uint_t rate;
4647332525Smav
4648332525Smav		assert(prs->prs_state == DSS_SCANNING);
4649332525Smav
4650332525Smav		/*
4651332525Smav		 * Removal is in progress.
4652332525Smav		 */
4653332525Smav		(void) printf(gettext(
4654332525Smav		    "Evacuation of %s in progress since %s"),
4655332525Smav		    vdev_name, ctime(&start));
4656332525Smav
4657332525Smav		copied = prs->prs_copied > 0 ? prs->prs_copied : 1;
4658332525Smav		total = prs->prs_to_copy;
4659332525Smav		fraction_done = (double)copied / total;
4660332525Smav
4661332525Smav		/* elapsed time for this pass */
4662332525Smav		elapsed = time(NULL) - prs->prs_start_time;
4663332525Smav		elapsed = elapsed > 0 ? elapsed : 1;
4664332525Smav		rate = copied / elapsed;
4665332525Smav		rate = rate > 0 ? rate : 1;
4666332525Smav		mins_left = ((total - copied) / rate) / 60;
4667332525Smav		hours_left = mins_left / 60;
4668332525Smav
4669332525Smav		zfs_nicenum(copied, examined_buf, sizeof (examined_buf));
4670332525Smav		zfs_nicenum(total, total_buf, sizeof (total_buf));
4671332525Smav		zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
4672332525Smav
4673332525Smav		/*
4674332525Smav		 * do not print estimated time if hours_left is more than
4675332525Smav		 * 30 days
4676332525Smav		 */
4677332525Smav		(void) printf(gettext("    %s copied out of %s at %s/s, "
4678332525Smav		    "%.2f%% done"),
4679332525Smav		    examined_buf, total_buf, rate_buf, 100 * fraction_done);
4680332525Smav		if (hours_left < (30 * 24)) {
4681332525Smav			(void) printf(gettext(", %lluh%um to go\n"),
4682332525Smav			    (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
4683332525Smav		} else {
4684332525Smav			(void) printf(gettext(
4685332525Smav			    ", (copy is slow, no estimated time)\n"));
4686332525Smav		}
4687332525Smav	}
4688332525Smav
4689332525Smav	if (prs->prs_mapping_memory > 0) {
4690332525Smav		char mem_buf[7];
4691332525Smav		zfs_nicenum(prs->prs_mapping_memory, mem_buf, sizeof (mem_buf));
4692332525Smav		(void) printf(gettext("    %s memory used for "
4693332525Smav		    "removed device mappings\n"),
4694332525Smav		    mem_buf);
4695332525Smav	}
4696332525Smav}
4697332525Smav
4698332525Smavstatic void
4699332547Smavprint_checkpoint_status(pool_checkpoint_stat_t *pcs)
4700332547Smav{
4701332547Smav	time_t start;
4702332547Smav	char space_buf[7];
4703332547Smav
4704332547Smav	if (pcs == NULL || pcs->pcs_state == CS_NONE)
4705332547Smav		return;
4706332547Smav
4707332547Smav	(void) printf(gettext("checkpoint: "));
4708332547Smav
4709332547Smav	start = pcs->pcs_start_time;
4710332547Smav	zfs_nicenum(pcs->pcs_space, space_buf, sizeof (space_buf));
4711332547Smav
4712332547Smav	if (pcs->pcs_state == CS_CHECKPOINT_EXISTS) {
4713332547Smav		char *date = ctime(&start);
4714332547Smav
4715332547Smav		/*
4716332547Smav		 * ctime() adds a newline at the end of the generated
4717332547Smav		 * string, thus the weird format specifier and the
4718332547Smav		 * strlen() call used to chop it off from the output.
4719332547Smav		 */
4720332547Smav		(void) printf(gettext("created %.*s, consumes %s\n"),
4721332547Smav		    strlen(date) - 1, date, space_buf);
4722332547Smav		return;
4723332547Smav	}
4724332547Smav
4725332547Smav	assert(pcs->pcs_state == CS_CHECKPOINT_DISCARDING);
4726332547Smav
4727332547Smav	(void) printf(gettext("discarding, %s remaining.\n"),
4728332547Smav	    space_buf);
4729332547Smav}
4730332547Smav
4731332547Smavstatic void
4732168404Spjdprint_error_log(zpool_handle_t *zhp)
4733168404Spjd{
4734185029Spjd	nvlist_t *nverrlist = NULL;
4735168404Spjd	nvpair_t *elem;
4736168404Spjd	char *pathname;
4737168404Spjd	size_t len = MAXPATHLEN * 2;
4738168404Spjd
4739168404Spjd	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
4740168404Spjd		(void) printf("errors: List of errors unavailable "
4741168404Spjd		    "(insufficient privileges)\n");
4742168404Spjd		return;
4743168404Spjd	}
4744168404Spjd
4745168404Spjd	(void) printf("errors: Permanent errors have been "
4746168404Spjd	    "detected in the following files:\n\n");
4747168404Spjd
4748168404Spjd	pathname = safe_malloc(len);
4749168404Spjd	elem = NULL;
4750168404Spjd	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
4751168404Spjd		nvlist_t *nv;
4752168404Spjd		uint64_t dsobj, obj;
4753168404Spjd
4754168404Spjd		verify(nvpair_value_nvlist(elem, &nv) == 0);
4755168404Spjd		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
4756168404Spjd		    &dsobj) == 0);
4757168404Spjd		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
4758168404Spjd		    &obj) == 0);
4759168404Spjd		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
4760168404Spjd		(void) printf("%7s %s\n", "", pathname);
4761168404Spjd	}
4762168404Spjd	free(pathname);
4763168404Spjd	nvlist_free(nverrlist);
4764168404Spjd}
4765168404Spjd
4766168404Spjdstatic void
4767168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
4768168404Spjd    int namewidth)
4769168404Spjd{
4770168404Spjd	uint_t i;
4771168404Spjd	char *name;
4772168404Spjd
4773168404Spjd	if (nspares == 0)
4774168404Spjd		return;
4775168404Spjd
4776168404Spjd	(void) printf(gettext("\tspares\n"));
4777168404Spjd
4778168404Spjd	for (i = 0; i < nspares; i++) {
4779219089Spjd		name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE);
4780168404Spjd		print_status_config(zhp, name, spares[i],
4781209962Smm		    namewidth, 2, B_TRUE);
4782168404Spjd		free(name);
4783168404Spjd	}
4784168404Spjd}
4785168404Spjd
4786185029Spjdstatic void
4787185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
4788185029Spjd    int namewidth)
4789185029Spjd{
4790185029Spjd	uint_t i;
4791185029Spjd	char *name;
4792185029Spjd
4793185029Spjd	if (nl2cache == 0)
4794185029Spjd		return;
4795185029Spjd
4796185029Spjd	(void) printf(gettext("\tcache\n"));
4797185029Spjd
4798185029Spjd	for (i = 0; i < nl2cache; i++) {
4799219089Spjd		name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE);
4800185029Spjd		print_status_config(zhp, name, l2cache[i],
4801209962Smm		    namewidth, 2, B_FALSE);
4802185029Spjd		free(name);
4803185029Spjd	}
4804185029Spjd}
4805185029Spjd
4806219089Spjdstatic void
4807219089Spjdprint_dedup_stats(nvlist_t *config)
4808219089Spjd{
4809219089Spjd	ddt_histogram_t *ddh;
4810219089Spjd	ddt_stat_t *dds;
4811219089Spjd	ddt_object_t *ddo;
4812219089Spjd	uint_t c;
4813219089Spjd
4814219089Spjd	/*
4815219089Spjd	 * If the pool was faulted then we may not have been able to
4816253441Sdelphij	 * obtain the config. Otherwise, if we have anything in the dedup
4817219089Spjd	 * table continue processing the stats.
4818219089Spjd	 */
4819219089Spjd	if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
4820227497Smm	    (uint64_t **)&ddo, &c) != 0)
4821219089Spjd		return;
4822219089Spjd
4823219089Spjd	(void) printf("\n");
4824227497Smm	(void) printf(gettext(" dedup: "));
4825227497Smm	if (ddo->ddo_count == 0) {
4826227497Smm		(void) printf(gettext("no DDT entries\n"));
4827227497Smm		return;
4828227497Smm	}
4829227497Smm
4830219089Spjd	(void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
4831219089Spjd	    (u_longlong_t)ddo->ddo_count,
4832219089Spjd	    (u_longlong_t)ddo->ddo_dspace,
4833219089Spjd	    (u_longlong_t)ddo->ddo_mspace);
4834219089Spjd
4835219089Spjd	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
4836219089Spjd	    (uint64_t **)&dds, &c) == 0);
4837219089Spjd	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
4838219089Spjd	    (uint64_t **)&ddh, &c) == 0);
4839219089Spjd	zpool_dump_ddt(dds, ddh);
4840219089Spjd}
4841219089Spjd
4842168404Spjd/*
4843168404Spjd * Display a summary of pool status.  Displays a summary such as:
4844168404Spjd *
4845168404Spjd *        pool: tank
4846168404Spjd *	status: DEGRADED
4847168404Spjd *	reason: One or more devices ...
4848236146Smm *         see: http://illumos.org/msg/ZFS-xxxx-01
4849168404Spjd *	config:
4850168404Spjd *		mirror		DEGRADED
4851168404Spjd *                c1t0d0	OK
4852168404Spjd *                c2t0d0	UNAVAIL
4853168404Spjd *
4854168404Spjd * When given the '-v' option, we print out the complete config.  If the '-e'
4855168404Spjd * option is specified, then we print out error rate information as well.
4856168404Spjd */
4857168404Spjdint
4858168404Spjdstatus_callback(zpool_handle_t *zhp, void *data)
4859168404Spjd{
4860168404Spjd	status_cbdata_t *cbp = data;
4861168404Spjd	nvlist_t *config, *nvroot;
4862168404Spjd	char *msgid;
4863168404Spjd	int reason;
4864168404Spjd	const char *health;
4865168404Spjd	uint_t c;
4866168404Spjd	vdev_stat_t *vs;
4867168404Spjd
4868168404Spjd	config = zpool_get_config(zhp, NULL);
4869168404Spjd	reason = zpool_get_status(zhp, &msgid);
4870168404Spjd
4871168404Spjd	cbp->cb_count++;
4872168404Spjd
4873168404Spjd	/*
4874168404Spjd	 * If we were given 'zpool status -x', only report those pools with
4875168404Spjd	 * problems.
4876168404Spjd	 */
4877248267Smm	if (cbp->cb_explain &&
4878248267Smm	    (reason == ZPOOL_STATUS_OK ||
4879248267Smm	    reason == ZPOOL_STATUS_VERSION_OLDER ||
4880268621Ssmh	    reason == ZPOOL_STATUS_NON_NATIVE_ASHIFT ||
4881248267Smm	    reason == ZPOOL_STATUS_FEAT_DISABLED)) {
4882168404Spjd		if (!cbp->cb_allpools) {
4883168404Spjd			(void) printf(gettext("pool '%s' is healthy\n"),
4884168404Spjd			    zpool_get_name(zhp));
4885168404Spjd			if (cbp->cb_first)
4886168404Spjd				cbp->cb_first = B_FALSE;
4887168404Spjd		}
4888168404Spjd		return (0);
4889168404Spjd	}
4890168404Spjd
4891168404Spjd	if (cbp->cb_first)
4892168404Spjd		cbp->cb_first = B_FALSE;
4893168404Spjd	else
4894168404Spjd		(void) printf("\n");
4895168404Spjd
4896332525Smav	nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
4897219089Spjd	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
4898168404Spjd	    (uint64_t **)&vs, &c) == 0);
4899185029Spjd	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
4900168404Spjd
4901168404Spjd	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
4902168404Spjd	(void) printf(gettext(" state: %s\n"), health);
4903168404Spjd
4904168404Spjd	switch (reason) {
4905168404Spjd	case ZPOOL_STATUS_MISSING_DEV_R:
4906168404Spjd		(void) printf(gettext("status: One or more devices could not "
4907168404Spjd		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
4908168404Spjd		    "continue functioning in a degraded state.\n"));
4909168404Spjd		(void) printf(gettext("action: Attach the missing device and "
4910168404Spjd		    "online it using 'zpool online'.\n"));
4911168404Spjd		break;
4912168404Spjd
4913168404Spjd	case ZPOOL_STATUS_MISSING_DEV_NR:
4914168404Spjd		(void) printf(gettext("status: One or more devices could not "
4915168404Spjd		    "be opened.  There are insufficient\n\treplicas for the "
4916168404Spjd		    "pool to continue functioning.\n"));
4917168404Spjd		(void) printf(gettext("action: Attach the missing device and "
4918168404Spjd		    "online it using 'zpool online'.\n"));
4919168404Spjd		break;
4920168404Spjd
4921168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_R:
4922168404Spjd		(void) printf(gettext("status: One or more devices could not "
4923168404Spjd		    "be used because the label is missing or\n\tinvalid.  "
4924168404Spjd		    "Sufficient replicas exist for the pool to continue\n\t"
4925168404Spjd		    "functioning in a degraded state.\n"));
4926168404Spjd		(void) printf(gettext("action: Replace the device using "
4927168404Spjd		    "'zpool replace'.\n"));
4928168404Spjd		break;
4929168404Spjd
4930168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
4931168404Spjd		(void) printf(gettext("status: One or more devices could not "
4932168404Spjd		    "be used because the label is missing \n\tor invalid.  "
4933168404Spjd		    "There are insufficient replicas for the pool to "
4934168404Spjd		    "continue\n\tfunctioning.\n"));
4935219089Spjd		zpool_explain_recover(zpool_get_handle(zhp),
4936219089Spjd		    zpool_get_name(zhp), reason, config);
4937168404Spjd		break;
4938168404Spjd
4939168404Spjd	case ZPOOL_STATUS_FAILING_DEV:
4940168404Spjd		(void) printf(gettext("status: One or more devices has "
4941168404Spjd		    "experienced an unrecoverable error.  An\n\tattempt was "
4942168404Spjd		    "made to correct the error.  Applications are "
4943168404Spjd		    "unaffected.\n"));
4944168404Spjd		(void) printf(gettext("action: Determine if the device needs "
4945168404Spjd		    "to be replaced, and clear the errors\n\tusing "
4946168404Spjd		    "'zpool clear' or replace the device with 'zpool "
4947168404Spjd		    "replace'.\n"));
4948168404Spjd		break;
4949168404Spjd
4950168404Spjd	case ZPOOL_STATUS_OFFLINE_DEV:
4951168404Spjd		(void) printf(gettext("status: One or more devices has "
4952168404Spjd		    "been taken offline by the administrator.\n\tSufficient "
4953168404Spjd		    "replicas exist for the pool to continue functioning in "
4954168404Spjd		    "a\n\tdegraded state.\n"));
4955168404Spjd		(void) printf(gettext("action: Online the device using "
4956168404Spjd		    "'zpool online' or replace the device with\n\t'zpool "
4957168404Spjd		    "replace'.\n"));
4958168404Spjd		break;
4959168404Spjd
4960219089Spjd	case ZPOOL_STATUS_REMOVED_DEV:
4961219089Spjd		(void) printf(gettext("status: One or more devices has "
4962219089Spjd		    "been removed by the administrator.\n\tSufficient "
4963219089Spjd		    "replicas exist for the pool to continue functioning in "
4964219089Spjd		    "a\n\tdegraded state.\n"));
4965219089Spjd		(void) printf(gettext("action: Online the device using "
4966219089Spjd		    "'zpool online' or replace the device with\n\t'zpool "
4967219089Spjd		    "replace'.\n"));
4968219089Spjd		break;
4969219089Spjd
4970168404Spjd	case ZPOOL_STATUS_RESILVERING:
4971168404Spjd		(void) printf(gettext("status: One or more devices is "
4972168404Spjd		    "currently being resilvered.  The pool will\n\tcontinue "
4973168404Spjd		    "to function, possibly in a degraded state.\n"));
4974168404Spjd		(void) printf(gettext("action: Wait for the resilver to "
4975168404Spjd		    "complete.\n"));
4976168404Spjd		break;
4977168404Spjd
4978168404Spjd	case ZPOOL_STATUS_CORRUPT_DATA:
4979168404Spjd		(void) printf(gettext("status: One or more devices has "
4980168404Spjd		    "experienced an error resulting in data\n\tcorruption.  "
4981168404Spjd		    "Applications may be affected.\n"));
4982168404Spjd		(void) printf(gettext("action: Restore the file in question "
4983168404Spjd		    "if possible.  Otherwise restore the\n\tentire pool from "
4984168404Spjd		    "backup.\n"));
4985168404Spjd		break;
4986168404Spjd
4987168404Spjd	case ZPOOL_STATUS_CORRUPT_POOL:
4988168404Spjd		(void) printf(gettext("status: The pool metadata is corrupted "
4989168404Spjd		    "and the pool cannot be opened.\n"));
4990219089Spjd		zpool_explain_recover(zpool_get_handle(zhp),
4991219089Spjd		    zpool_get_name(zhp), reason, config);
4992168404Spjd		break;
4993168404Spjd
4994168404Spjd	case ZPOOL_STATUS_VERSION_OLDER:
4995238926Smm		(void) printf(gettext("status: The pool is formatted using a "
4996238926Smm		    "legacy on-disk format.  The pool can\n\tstill be used, "
4997238926Smm		    "but some features are unavailable.\n"));
4998168404Spjd		(void) printf(gettext("action: Upgrade the pool using 'zpool "
4999168404Spjd		    "upgrade'.  Once this is done, the\n\tpool will no longer "
5000238926Smm		    "be accessible on software that does not support feature\n"
5001238926Smm		    "\tflags.\n"));
5002168404Spjd		break;
5003168404Spjd
5004168404Spjd	case ZPOOL_STATUS_VERSION_NEWER:
5005168404Spjd		(void) printf(gettext("status: The pool has been upgraded to a "
5006168404Spjd		    "newer, incompatible on-disk version.\n\tThe pool cannot "
5007168404Spjd		    "be accessed on this system.\n"));
5008168404Spjd		(void) printf(gettext("action: Access the pool from a system "
5009168404Spjd		    "running more recent software, or\n\trestore the pool from "
5010168404Spjd		    "backup.\n"));
5011168404Spjd		break;
5012168404Spjd
5013238926Smm	case ZPOOL_STATUS_FEAT_DISABLED:
5014238926Smm		(void) printf(gettext("status: Some supported features are not "
5015238926Smm		    "enabled on the pool. The pool can\n\tstill be used, but "
5016238926Smm		    "some features are unavailable.\n"));
5017238926Smm		(void) printf(gettext("action: Enable all features using "
5018238926Smm		    "'zpool upgrade'. Once this is done,\n\tthe pool may no "
5019238926Smm		    "longer be accessible by software that does not support\n\t"
5020243014Smm		    "the features. See zpool-features(7) for details.\n"));
5021238926Smm		break;
5022238926Smm
5023236884Smm	case ZPOOL_STATUS_UNSUP_FEAT_READ:
5024236884Smm		(void) printf(gettext("status: The pool cannot be accessed on "
5025236884Smm		    "this system because it uses the\n\tfollowing feature(s) "
5026236884Smm		    "not supported on this system:\n"));
5027236884Smm		zpool_print_unsup_feat(config);
5028236884Smm		(void) printf("\n");
5029236884Smm		(void) printf(gettext("action: Access the pool from a system "
5030236884Smm		    "that supports the required feature(s),\n\tor restore the "
5031236884Smm		    "pool from backup.\n"));
5032236884Smm		break;
5033236884Smm
5034236884Smm	case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
5035236884Smm		(void) printf(gettext("status: The pool can only be accessed "
5036236884Smm		    "in read-only mode on this system. It\n\tcannot be "
5037236884Smm		    "accessed in read-write mode because it uses the "
5038236884Smm		    "following\n\tfeature(s) not supported on this system:\n"));
5039236884Smm		zpool_print_unsup_feat(config);
5040236884Smm		(void) printf("\n");
5041236884Smm		(void) printf(gettext("action: The pool cannot be accessed in "
5042236884Smm		    "read-write mode. Import the pool with\n"
5043236884Smm		    "\t\"-o readonly=on\", access the pool from a system that "
5044236884Smm		    "supports the\n\trequired feature(s), or restore the "
5045236884Smm		    "pool from backup.\n"));
5046236884Smm		break;
5047236884Smm
5048185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_R:
5049185029Spjd		(void) printf(gettext("status: One or more devices are "
5050185029Spjd		    "faulted in response to persistent errors.\n\tSufficient "
5051185029Spjd		    "replicas exist for the pool to continue functioning "
5052185029Spjd		    "in a\n\tdegraded state.\n"));
5053185029Spjd		(void) printf(gettext("action: Replace the faulted device, "
5054185029Spjd		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
5055185029Spjd		break;
5056185029Spjd
5057185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_NR:
5058185029Spjd		(void) printf(gettext("status: One or more devices are "
5059185029Spjd		    "faulted in response to persistent errors.  There are "
5060185029Spjd		    "insufficient replicas for the pool to\n\tcontinue "
5061185029Spjd		    "functioning.\n"));
5062185029Spjd		(void) printf(gettext("action: Destroy and re-create the pool "
5063185029Spjd		    "from a backup source.  Manually marking the device\n"
5064185029Spjd		    "\trepaired using 'zpool clear' may allow some data "
5065185029Spjd		    "to be recovered.\n"));
5066185029Spjd		break;
5067185029Spjd
5068185029Spjd	case ZPOOL_STATUS_IO_FAILURE_WAIT:
5069185029Spjd	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
5070185029Spjd		(void) printf(gettext("status: One or more devices are "
5071185029Spjd		    "faulted in response to IO failures.\n"));
5072185029Spjd		(void) printf(gettext("action: Make sure the affected devices "
5073185029Spjd		    "are connected, then run 'zpool clear'.\n"));
5074185029Spjd		break;
5075185029Spjd
5076185029Spjd	case ZPOOL_STATUS_BAD_LOG:
5077185029Spjd		(void) printf(gettext("status: An intent log record "
5078185029Spjd		    "could not be read.\n"
5079185029Spjd		    "\tWaiting for adminstrator intervention to fix the "
5080185029Spjd		    "faulted pool.\n"));
5081185029Spjd		(void) printf(gettext("action: Either restore the affected "
5082185029Spjd		    "device(s) and run 'zpool online',\n"
5083185029Spjd		    "\tor ignore the intent log records by running "
5084185029Spjd		    "'zpool clear'.\n"));
5085185029Spjd		break;
5086185029Spjd
5087254591Sgibbs	case ZPOOL_STATUS_NON_NATIVE_ASHIFT:
5088254591Sgibbs		(void) printf(gettext("status: One or more devices are "
5089254591Sgibbs		    "configured to use a non-native block size.\n"
5090254591Sgibbs		    "\tExpect reduced performance.\n"));
5091254591Sgibbs		(void) printf(gettext("action: Replace affected devices with "
5092254591Sgibbs		    "devices that support the\n\tconfigured block size, or "
5093254591Sgibbs		    "migrate data to a properly configured\n\tpool.\n"));
5094254591Sgibbs		break;
5095254591Sgibbs
5096168404Spjd	default:
5097168404Spjd		/*
5098168404Spjd		 * The remaining errors can't actually be generated, yet.
5099168404Spjd		 */
5100168404Spjd		assert(reason == ZPOOL_STATUS_OK);
5101168404Spjd	}
5102168404Spjd
5103168404Spjd	if (msgid != NULL)
5104236146Smm		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
5105168404Spjd		    msgid);
5106168404Spjd
5107168404Spjd	if (config != NULL) {
5108168404Spjd		int namewidth;
5109168404Spjd		uint64_t nerr;
5110185029Spjd		nvlist_t **spares, **l2cache;
5111185029Spjd		uint_t nspares, nl2cache;
5112332547Smav		pool_checkpoint_stat_t *pcs = NULL;
5113219089Spjd		pool_scan_stat_t *ps = NULL;
5114332525Smav		pool_removal_stat_t *prs = NULL;
5115168404Spjd
5116219089Spjd		(void) nvlist_lookup_uint64_array(nvroot,
5117332547Smav		    ZPOOL_CONFIG_CHECKPOINT_STATS, (uint64_t **)&pcs, &c);
5118332547Smav		(void) nvlist_lookup_uint64_array(nvroot,
5119219089Spjd		    ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
5120332525Smav		(void) nvlist_lookup_uint64_array(nvroot,
5121332525Smav		    ZPOOL_CONFIG_REMOVAL_STATS, (uint64_t **)&prs, &c);
5122332547Smav
5123332547Smav		print_scan_status(ps);
5124332547Smav		print_checkpoint_scan_warning(ps, pcs);
5125332525Smav		print_removal_status(zhp, prs);
5126332547Smav		print_checkpoint_status(pcs);
5127332525Smav
5128168404Spjd		namewidth = max_width(zhp, nvroot, 0, 0);
5129168404Spjd		if (namewidth < 10)
5130168404Spjd			namewidth = 10;
5131168404Spjd
5132168404Spjd		(void) printf(gettext("config:\n\n"));
5133168404Spjd		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
5134168404Spjd		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
5135168404Spjd		print_status_config(zhp, zpool_get_name(zhp), nvroot,
5136209962Smm		    namewidth, 0, B_FALSE);
5137209962Smm
5138185029Spjd		if (num_logs(nvroot) > 0)
5139213197Smm			print_logs(zhp, nvroot, namewidth, B_TRUE);
5140185029Spjd		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
5141185029Spjd		    &l2cache, &nl2cache) == 0)
5142185029Spjd			print_l2cache(zhp, l2cache, nl2cache, namewidth);
5143185029Spjd
5144168404Spjd		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
5145168404Spjd		    &spares, &nspares) == 0)
5146168404Spjd			print_spares(zhp, spares, nspares, namewidth);
5147168404Spjd
5148168404Spjd		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
5149168404Spjd		    &nerr) == 0) {
5150168404Spjd			nvlist_t *nverrlist = NULL;
5151168404Spjd
5152168404Spjd			/*
5153168404Spjd			 * If the approximate error count is small, get a
5154168404Spjd			 * precise count by fetching the entire log and
5155168404Spjd			 * uniquifying the results.
5156168404Spjd			 */
5157185029Spjd			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
5158168404Spjd			    zpool_get_errlog(zhp, &nverrlist) == 0) {
5159168404Spjd				nvpair_t *elem;
5160168404Spjd
5161168404Spjd				elem = NULL;
5162168404Spjd				nerr = 0;
5163168404Spjd				while ((elem = nvlist_next_nvpair(nverrlist,
5164168404Spjd				    elem)) != NULL) {
5165168404Spjd					nerr++;
5166168404Spjd				}
5167168404Spjd			}
5168168404Spjd			nvlist_free(nverrlist);
5169168404Spjd
5170168404Spjd			(void) printf("\n");
5171168404Spjd
5172168404Spjd			if (nerr == 0)
5173168404Spjd				(void) printf(gettext("errors: No known data "
5174168404Spjd				    "errors\n"));
5175168404Spjd			else if (!cbp->cb_verbose)
5176168404Spjd				(void) printf(gettext("errors: %llu data "
5177168404Spjd				    "errors, use '-v' for a list\n"),
5178168404Spjd				    (u_longlong_t)nerr);
5179168404Spjd			else
5180168404Spjd				print_error_log(zhp);
5181168404Spjd		}
5182219089Spjd
5183219089Spjd		if (cbp->cb_dedup_stats)
5184219089Spjd			print_dedup_stats(config);
5185168404Spjd	} else {
5186168404Spjd		(void) printf(gettext("config: The configuration cannot be "
5187168404Spjd		    "determined.\n"));
5188168404Spjd	}
5189168404Spjd
5190168404Spjd	return (0);
5191168404Spjd}
5192168404Spjd
5193168404Spjd/*
5194219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]]
5195168404Spjd *
5196168404Spjd *	-v	Display complete error logs
5197168404Spjd *	-x	Display only pools with potential problems
5198219089Spjd *	-D	Display dedup status (undocumented)
5199219089Spjd *	-T	Display a timestamp in date(1) or Unix format
5200168404Spjd *
5201168404Spjd * Describes the health status of all pools or some subset.
5202168404Spjd */
5203168404Spjdint
5204168404Spjdzpool_do_status(int argc, char **argv)
5205168404Spjd{
5206168404Spjd	int c;
5207168404Spjd	int ret;
5208219089Spjd	unsigned long interval = 0, count = 0;
5209168404Spjd	status_cbdata_t cb = { 0 };
5210168404Spjd
5211168404Spjd	/* check options */
5212219089Spjd	while ((c = getopt(argc, argv, "vxDT:")) != -1) {
5213168404Spjd		switch (c) {
5214168404Spjd		case 'v':
5215168404Spjd			cb.cb_verbose = B_TRUE;
5216168404Spjd			break;
5217168404Spjd		case 'x':
5218168404Spjd			cb.cb_explain = B_TRUE;
5219168404Spjd			break;
5220219089Spjd		case 'D':
5221219089Spjd			cb.cb_dedup_stats = B_TRUE;
5222219089Spjd			break;
5223219089Spjd		case 'T':
5224219089Spjd			get_timestamp_arg(*optarg);
5225219089Spjd			break;
5226168404Spjd		case '?':
5227168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5228168404Spjd			    optopt);
5229168404Spjd			usage(B_FALSE);
5230168404Spjd		}
5231168404Spjd	}
5232168404Spjd
5233168404Spjd	argc -= optind;
5234168404Spjd	argv += optind;
5235168404Spjd
5236219089Spjd	get_interval_count(&argc, argv, &interval, &count);
5237168404Spjd
5238168404Spjd	if (argc == 0)
5239168404Spjd		cb.cb_allpools = B_TRUE;
5240168404Spjd
5241219089Spjd	cb.cb_first = B_TRUE;
5242168404Spjd
5243219089Spjd	for (;;) {
5244219089Spjd		if (timestamp_fmt != NODATE)
5245219089Spjd			print_timestamp(timestamp_fmt);
5246168404Spjd
5247219089Spjd		ret = for_each_pool(argc, argv, B_TRUE, NULL,
5248219089Spjd		    status_callback, &cb);
5249219089Spjd
5250219089Spjd		if (argc == 0 && cb.cb_count == 0)
5251219089Spjd			(void) printf(gettext("no pools available\n"));
5252219089Spjd		else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
5253219089Spjd			(void) printf(gettext("all pools are healthy\n"));
5254219089Spjd
5255219089Spjd		if (ret != 0)
5256219089Spjd			return (ret);
5257219089Spjd
5258219089Spjd		if (interval == 0)
5259219089Spjd			break;
5260219089Spjd
5261219089Spjd		if (count != 0 && --count == 0)
5262219089Spjd			break;
5263219089Spjd
5264219089Spjd		(void) sleep(interval);
5265219089Spjd	}
5266219089Spjd
5267219089Spjd	return (0);
5268168404Spjd}
5269168404Spjd
5270168404Spjdtypedef struct upgrade_cbdata {
5271276226Ssmh	boolean_t	cb_first;
5272276226Ssmh	boolean_t	cb_unavail;
5273307108Smav	char		cb_poolname[ZFS_MAX_DATASET_NAME_LEN];
5274276226Ssmh	int		cb_argc;
5275276226Ssmh	uint64_t	cb_version;
5276276226Ssmh	char		**cb_argv;
5277168404Spjd} upgrade_cbdata_t;
5278168404Spjd
5279238950Smm#ifdef __FreeBSD__
5280168404Spjdstatic int
5281212050Spjdis_root_pool(zpool_handle_t *zhp)
5282212050Spjd{
5283212050Spjd	static struct statfs sfs;
5284212050Spjd	static char *poolname = NULL;
5285212050Spjd	static boolean_t stated = B_FALSE;
5286212050Spjd	char *slash;
5287212050Spjd
5288212067Spjd	if (!stated) {
5289212050Spjd		stated = B_TRUE;
5290212050Spjd		if (statfs("/", &sfs) == -1) {
5291212050Spjd			(void) fprintf(stderr,
5292212050Spjd			    "Unable to stat root file system: %s.\n",
5293212050Spjd			    strerror(errno));
5294212067Spjd			return (0);
5295212050Spjd		}
5296212050Spjd		if (strcmp(sfs.f_fstypename, "zfs") != 0)
5297212067Spjd			return (0);
5298212050Spjd		poolname = sfs.f_mntfromname;
5299212050Spjd		if ((slash = strchr(poolname, '/')) != NULL)
5300212050Spjd			*slash = '\0';
5301212050Spjd	}
5302212050Spjd	return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0);
5303212050Spjd}
5304212050Spjd
5305238950Smmstatic void
5306271934Ssmhroot_pool_upgrade_check(zpool_handle_t *zhp, char *poolname, int size)
5307271934Ssmh{
5308238950Smm
5309238950Smm	if (poolname[0] == '\0' && is_root_pool(zhp))
5310238950Smm		(void) strlcpy(poolname, zpool_get_name(zhp), size);
5311238950Smm}
5312238950Smm#endif	/* FreeBSD */
5313238950Smm
5314212050Spjdstatic int
5315238926Smmupgrade_version(zpool_handle_t *zhp, uint64_t version)
5316238926Smm{
5317238926Smm	int ret;
5318238926Smm	nvlist_t *config;
5319238926Smm	uint64_t oldversion;
5320238926Smm
5321238926Smm	config = zpool_get_config(zhp, NULL);
5322238926Smm	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
5323238926Smm	    &oldversion) == 0);
5324238926Smm
5325238926Smm	assert(SPA_VERSION_IS_SUPPORTED(oldversion));
5326238926Smm	assert(oldversion < version);
5327238926Smm
5328238926Smm	ret = zpool_upgrade(zhp, version);
5329238926Smm	if (ret != 0)
5330238926Smm		return (ret);
5331238926Smm
5332238926Smm	if (version >= SPA_VERSION_FEATURES) {
5333238926Smm		(void) printf(gettext("Successfully upgraded "
5334238926Smm		    "'%s' from version %llu to feature flags.\n"),
5335238926Smm		    zpool_get_name(zhp), oldversion);
5336238926Smm	} else {
5337238926Smm		(void) printf(gettext("Successfully upgraded "
5338238926Smm		    "'%s' from version %llu to version %llu.\n"),
5339238926Smm		    zpool_get_name(zhp), oldversion, version);
5340238926Smm	}
5341238926Smm
5342238926Smm	return (0);
5343238926Smm}
5344238926Smm
5345238926Smmstatic int
5346238926Smmupgrade_enable_all(zpool_handle_t *zhp, int *countp)
5347238926Smm{
5348238926Smm	int i, ret, count;
5349238926Smm	boolean_t firstff = B_TRUE;
5350238926Smm	nvlist_t *enabled = zpool_get_features(zhp);
5351238926Smm
5352238926Smm	count = 0;
5353238926Smm	for (i = 0; i < SPA_FEATURES; i++) {
5354238926Smm		const char *fname = spa_feature_table[i].fi_uname;
5355238926Smm		const char *fguid = spa_feature_table[i].fi_guid;
5356238926Smm		if (!nvlist_exists(enabled, fguid)) {
5357238926Smm			char *propname;
5358238926Smm			verify(-1 != asprintf(&propname, "feature@%s", fname));
5359238926Smm			ret = zpool_set_prop(zhp, propname,
5360238926Smm			    ZFS_FEATURE_ENABLED);
5361238926Smm			if (ret != 0) {
5362238926Smm				free(propname);
5363238926Smm				return (ret);
5364238926Smm			}
5365238926Smm			count++;
5366238926Smm
5367238926Smm			if (firstff) {
5368238926Smm				(void) printf(gettext("Enabled the "
5369238926Smm				    "following features on '%s':\n"),
5370238926Smm				    zpool_get_name(zhp));
5371238926Smm				firstff = B_FALSE;
5372238926Smm			}
5373238926Smm			(void) printf(gettext("  %s\n"), fname);
5374238926Smm			free(propname);
5375238926Smm		}
5376238926Smm	}
5377238926Smm
5378238926Smm	if (countp != NULL)
5379238926Smm		*countp = count;
5380238926Smm	return (0);
5381238926Smm}
5382238926Smm
5383238926Smmstatic int
5384168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg)
5385168404Spjd{
5386168404Spjd	upgrade_cbdata_t *cbp = arg;
5387168404Spjd	nvlist_t *config;
5388168404Spjd	uint64_t version;
5389238926Smm	boolean_t printnl = B_FALSE;
5390238926Smm	int ret;
5391168404Spjd
5392276194Ssmh	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
5393276194Ssmh		(void) fprintf(stderr, gettext("cannot upgrade '%s': pool is "
5394276226Ssmh		    "currently unavailable.\n\n"), zpool_get_name(zhp));
5395276226Ssmh		cbp->cb_unavail = B_TRUE;
5396276194Ssmh		/* Allow iteration to continue. */
5397276194Ssmh		return (0);
5398276194Ssmh	}
5399276194Ssmh
5400168404Spjd	config = zpool_get_config(zhp, NULL);
5401168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
5402168404Spjd	    &version) == 0);
5403168404Spjd
5404238926Smm	assert(SPA_VERSION_IS_SUPPORTED(version));
5405168404Spjd
5406238926Smm	if (version < cbp->cb_version) {
5407238926Smm		cbp->cb_first = B_FALSE;
5408238926Smm		ret = upgrade_version(zhp, cbp->cb_version);
5409238926Smm		if (ret != 0)
5410238926Smm			return (ret);
5411238926Smm#ifdef __FreeBSD__
5412238950Smm		root_pool_upgrade_check(zhp, cbp->cb_poolname,
5413238950Smm		    sizeof(cbp->cb_poolname));
5414271934Ssmh#endif	/* __FreeBSD__ */
5415238926Smm		printnl = B_TRUE;
5416238926Smm
5417238926Smm#ifdef illumos
5418238926Smm		/*
5419238926Smm		 * If they did "zpool upgrade -a", then we could
5420238926Smm		 * be doing ioctls to different pools.  We need
5421238926Smm		 * to log this history once to each pool, and bypass
5422238926Smm		 * the normal history logging that happens in main().
5423238926Smm		 */
5424238926Smm		(void) zpool_log_history(g_zfs, history_str);
5425238926Smm		log_history = B_FALSE;
5426238926Smm#endif
5427238926Smm	}
5428238926Smm
5429238926Smm	if (cbp->cb_version >= SPA_VERSION_FEATURES) {
5430238926Smm		int count;
5431238926Smm		ret = upgrade_enable_all(zhp, &count);
5432238926Smm		if (ret != 0)
5433238926Smm			return (ret);
5434238926Smm
5435238926Smm		if (count > 0) {
5436168404Spjd			cbp->cb_first = B_FALSE;
5437238926Smm			printnl = B_TRUE;
5438271934Ssmh#ifdef __FreeBSD__
5439271934Ssmh			root_pool_upgrade_check(zhp, cbp->cb_poolname,
5440271934Ssmh			    sizeof(cbp->cb_poolname));
5441271934Ssmh#endif	/* __FreeBSD__ */
5442248571Smm			/*
5443248571Smm			 * If they did "zpool upgrade -a", then we could
5444248571Smm			 * be doing ioctls to different pools.  We need
5445248571Smm			 * to log this history once to each pool, and bypass
5446248571Smm			 * the normal history logging that happens in main().
5447248571Smm			 */
5448248571Smm			(void) zpool_log_history(g_zfs, history_str);
5449248571Smm			log_history = B_FALSE;
5450168404Spjd		}
5451238926Smm	}
5452168404Spjd
5453238926Smm	if (printnl) {
5454238926Smm		(void) printf(gettext("\n"));
5455238926Smm	}
5456238926Smm
5457238926Smm	return (0);
5458238926Smm}
5459238926Smm
5460238926Smmstatic int
5461276226Ssmhupgrade_list_unavail(zpool_handle_t *zhp, void *arg)
5462276226Ssmh{
5463276226Ssmh	upgrade_cbdata_t *cbp = arg;
5464276226Ssmh
5465276226Ssmh	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
5466276226Ssmh		if (cbp->cb_first) {
5467276226Ssmh			(void) fprintf(stderr, gettext("The following pools "
5468276226Ssmh			    "are unavailable and cannot be upgraded as this "
5469276226Ssmh			    "time.\n\n"));
5470276226Ssmh			(void) fprintf(stderr, gettext("POOL\n"));
5471276226Ssmh			(void) fprintf(stderr, gettext("------------\n"));
5472276226Ssmh			cbp->cb_first = B_FALSE;
5473276226Ssmh		}
5474276226Ssmh		(void) printf(gettext("%s\n"), zpool_get_name(zhp));
5475276226Ssmh		cbp->cb_unavail = B_TRUE;
5476276226Ssmh	}
5477276226Ssmh	return (0);
5478276226Ssmh}
5479276226Ssmh
5480276226Ssmhstatic int
5481238926Smmupgrade_list_older_cb(zpool_handle_t *zhp, void *arg)
5482238926Smm{
5483238926Smm	upgrade_cbdata_t *cbp = arg;
5484238926Smm	nvlist_t *config;
5485238926Smm	uint64_t version;
5486238926Smm
5487276226Ssmh	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
5488276226Ssmh		/*
5489276226Ssmh		 * This will have been reported by upgrade_list_unavail so
5490276226Ssmh		 * just allow iteration to continue.
5491276226Ssmh		 */
5492276226Ssmh		cbp->cb_unavail = B_TRUE;
5493276226Ssmh		return (0);
5494276226Ssmh	}
5495276226Ssmh
5496238926Smm	config = zpool_get_config(zhp, NULL);
5497238926Smm	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
5498238926Smm	    &version) == 0);
5499238926Smm
5500238926Smm	assert(SPA_VERSION_IS_SUPPORTED(version));
5501238926Smm
5502238926Smm	if (version < SPA_VERSION_FEATURES) {
5503168404Spjd		if (cbp->cb_first) {
5504168404Spjd			(void) printf(gettext("The following pools are "
5505238926Smm			    "formatted with legacy version numbers and can\n"
5506238926Smm			    "be upgraded to use feature flags.  After "
5507238926Smm			    "being upgraded, these pools\nwill no "
5508238926Smm			    "longer be accessible by software that does not "
5509238926Smm			    "support feature\nflags.\n\n"));
5510168404Spjd			(void) printf(gettext("VER  POOL\n"));
5511168404Spjd			(void) printf(gettext("---  ------------\n"));
5512168404Spjd			cbp->cb_first = B_FALSE;
5513168404Spjd		}
5514168404Spjd
5515168404Spjd		(void) printf("%2llu   %s\n", (u_longlong_t)version,
5516168404Spjd		    zpool_get_name(zhp));
5517168404Spjd	}
5518168404Spjd
5519238926Smm	return (0);
5520168404Spjd}
5521168404Spjd
5522238926Smmstatic int
5523238926Smmupgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg)
5524238926Smm{
5525238926Smm	upgrade_cbdata_t *cbp = arg;
5526238926Smm	nvlist_t *config;
5527238926Smm	uint64_t version;
5528238926Smm
5529276194Ssmh	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
5530276226Ssmh		/*
5531276226Ssmh		 * This will have been reported by upgrade_list_unavail so
5532276226Ssmh		 * just allow iteration to continue.
5533276226Ssmh		 */
5534276226Ssmh		cbp->cb_unavail = B_TRUE;
5535276194Ssmh		return (0);
5536276194Ssmh	}
5537276194Ssmh
5538238926Smm	config = zpool_get_config(zhp, NULL);
5539238926Smm	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
5540238926Smm	    &version) == 0);
5541238926Smm
5542238926Smm	if (version >= SPA_VERSION_FEATURES) {
5543238926Smm		int i;
5544238926Smm		boolean_t poolfirst = B_TRUE;
5545238926Smm		nvlist_t *enabled = zpool_get_features(zhp);
5546238926Smm
5547238926Smm		for (i = 0; i < SPA_FEATURES; i++) {
5548238926Smm			const char *fguid = spa_feature_table[i].fi_guid;
5549238926Smm			const char *fname = spa_feature_table[i].fi_uname;
5550238926Smm			if (!nvlist_exists(enabled, fguid)) {
5551238926Smm				if (cbp->cb_first) {
5552238926Smm					(void) printf(gettext("\nSome "
5553238926Smm					    "supported features are not "
5554238926Smm					    "enabled on the following pools. "
5555238926Smm					    "Once a\nfeature is enabled the "
5556238926Smm					    "pool may become incompatible with "
5557238926Smm					    "software\nthat does not support "
5558238926Smm					    "the feature. See "
5559243014Smm					    "zpool-features(7) for "
5560238926Smm					    "details.\n\n"));
5561238926Smm					(void) printf(gettext("POOL  "
5562238926Smm					    "FEATURE\n"));
5563238926Smm					(void) printf(gettext("------"
5564238926Smm					    "---------\n"));
5565238926Smm					cbp->cb_first = B_FALSE;
5566238926Smm				}
5567238926Smm
5568238926Smm				if (poolfirst) {
5569238926Smm					(void) printf(gettext("%s\n"),
5570238926Smm					    zpool_get_name(zhp));
5571238926Smm					poolfirst = B_FALSE;
5572238926Smm				}
5573238926Smm
5574238926Smm				(void) printf(gettext("      %s\n"), fname);
5575238926Smm			}
5576238926Smm		}
5577238926Smm	}
5578238926Smm
5579238926Smm	return (0);
5580238926Smm}
5581238926Smm
5582168404Spjd/* ARGSUSED */
5583168404Spjdstatic int
5584168404Spjdupgrade_one(zpool_handle_t *zhp, void *data)
5585168404Spjd{
5586238926Smm	boolean_t printnl = B_FALSE;
5587185029Spjd	upgrade_cbdata_t *cbp = data;
5588185029Spjd	uint64_t cur_version;
5589168404Spjd	int ret;
5590168404Spjd
5591276226Ssmh	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
5592276226Ssmh		(void) fprintf(stderr, gettext("cannot upgrade '%s': pool is "
5593276226Ssmh		    "is currently unavailable.\n\n"), zpool_get_name(zhp));
5594276226Ssmh		cbp->cb_unavail = B_TRUE;
5595276226Ssmh		return (1);
5596276226Ssmh	}
5597276226Ssmh
5598185029Spjd	if (strcmp("log", zpool_get_name(zhp)) == 0) {
5599185029Spjd		(void) printf(gettext("'log' is now a reserved word\n"
5600185029Spjd		    "Pool 'log' must be renamed using export and import"
5601276226Ssmh		    " to upgrade.\n\n"));
5602185029Spjd		return (1);
5603185029Spjd	}
5604168404Spjd
5605185029Spjd	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
5606185029Spjd	if (cur_version > cbp->cb_version) {
5607168404Spjd		(void) printf(gettext("Pool '%s' is already formatted "
5608238926Smm		    "using more current version '%llu'.\n\n"),
5609185029Spjd		    zpool_get_name(zhp), cur_version);
5610185029Spjd		return (0);
5611185029Spjd	}
5612238926Smm
5613238926Smm	if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) {
5614185029Spjd		(void) printf(gettext("Pool '%s' is already formatted "
5615238926Smm		    "using version %llu.\n\n"), zpool_get_name(zhp),
5616238926Smm		    cbp->cb_version);
5617168404Spjd		return (0);
5618168404Spjd	}
5619168404Spjd
5620238926Smm	if (cur_version != cbp->cb_version) {
5621238926Smm		printnl = B_TRUE;
5622238926Smm		ret = upgrade_version(zhp, cbp->cb_version);
5623238950Smm		if (ret != 0)
5624238950Smm			return (ret);
5625238926Smm#ifdef __FreeBSD__
5626238950Smm		root_pool_upgrade_check(zhp, cbp->cb_poolname,
5627238950Smm		    sizeof(cbp->cb_poolname));
5628271934Ssmh#endif	/* __FreeBSD__ */
5629238926Smm	}
5630168404Spjd
5631238926Smm	if (cbp->cb_version >= SPA_VERSION_FEATURES) {
5632238926Smm		int count = 0;
5633238926Smm		ret = upgrade_enable_all(zhp, &count);
5634238926Smm		if (ret != 0)
5635238926Smm			return (ret);
5636238926Smm
5637238926Smm		if (count != 0) {
5638238926Smm			printnl = B_TRUE;
5639238950Smm#ifdef __FreeBSD__
5640238951Smm			root_pool_upgrade_check(zhp, cbp->cb_poolname,
5641238951Smm			    sizeof(cbp->cb_poolname));
5642238950Smm#endif	/* __FreeBSD __*/
5643238926Smm		} else if (cur_version == SPA_VERSION) {
5644238926Smm			(void) printf(gettext("Pool '%s' already has all "
5645276226Ssmh			    "supported features enabled.\n\n"),
5646238926Smm			    zpool_get_name(zhp));
5647238926Smm		}
5648168404Spjd	}
5649168404Spjd
5650238926Smm	if (printnl) {
5651238926Smm		(void) printf(gettext("\n"));
5652238926Smm	}
5653238926Smm
5654238926Smm	return (0);
5655168404Spjd}
5656168404Spjd
5657168404Spjd/*
5658168404Spjd * zpool upgrade
5659168404Spjd * zpool upgrade -v
5660185029Spjd * zpool upgrade [-V version] <-a | pool ...>
5661168404Spjd *
5662168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade.
5663168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will
5664168404Spjd * upgrade all pools.
5665168404Spjd */
5666168404Spjdint
5667168404Spjdzpool_do_upgrade(int argc, char **argv)
5668168404Spjd{
5669168404Spjd	int c;
5670168404Spjd	upgrade_cbdata_t cb = { 0 };
5671168404Spjd	int ret = 0;
5672168404Spjd	boolean_t showversions = B_FALSE;
5673238926Smm	boolean_t upgradeall = B_FALSE;
5674185029Spjd	char *end;
5675168404Spjd
5676185029Spjd
5677168404Spjd	/* check options */
5678219089Spjd	while ((c = getopt(argc, argv, ":avV:")) != -1) {
5679168404Spjd		switch (c) {
5680168404Spjd		case 'a':
5681238926Smm			upgradeall = B_TRUE;
5682168404Spjd			break;
5683168404Spjd		case 'v':
5684168404Spjd			showversions = B_TRUE;
5685168404Spjd			break;
5686185029Spjd		case 'V':
5687185029Spjd			cb.cb_version = strtoll(optarg, &end, 10);
5688236884Smm			if (*end != '\0' ||
5689236884Smm			    !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) {
5690185029Spjd				(void) fprintf(stderr,
5691185029Spjd				    gettext("invalid version '%s'\n"), optarg);
5692185029Spjd				usage(B_FALSE);
5693185029Spjd			}
5694185029Spjd			break;
5695219089Spjd		case ':':
5696219089Spjd			(void) fprintf(stderr, gettext("missing argument for "
5697219089Spjd			    "'%c' option\n"), optopt);
5698219089Spjd			usage(B_FALSE);
5699219089Spjd			break;
5700168404Spjd		case '?':
5701168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5702168404Spjd			    optopt);
5703168404Spjd			usage(B_FALSE);
5704168404Spjd		}
5705168404Spjd	}
5706168404Spjd
5707168404Spjd	cb.cb_argc = argc;
5708168404Spjd	cb.cb_argv = argv;
5709168404Spjd	argc -= optind;
5710168404Spjd	argv += optind;
5711168404Spjd
5712185029Spjd	if (cb.cb_version == 0) {
5713185029Spjd		cb.cb_version = SPA_VERSION;
5714238926Smm	} else if (!upgradeall && argc == 0) {
5715185029Spjd		(void) fprintf(stderr, gettext("-V option is "
5716185029Spjd		    "incompatible with other arguments\n"));
5717185029Spjd		usage(B_FALSE);
5718185029Spjd	}
5719185029Spjd
5720168404Spjd	if (showversions) {
5721238926Smm		if (upgradeall || argc != 0) {
5722168404Spjd			(void) fprintf(stderr, gettext("-v option is "
5723168404Spjd			    "incompatible with other arguments\n"));
5724168404Spjd			usage(B_FALSE);
5725168404Spjd		}
5726238926Smm	} else if (upgradeall) {
5727168404Spjd		if (argc != 0) {
5728185029Spjd			(void) fprintf(stderr, gettext("-a option should not "
5729185029Spjd			    "be used along with a pool name\n"));
5730168404Spjd			usage(B_FALSE);
5731168404Spjd		}
5732168404Spjd	}
5733168404Spjd
5734236884Smm	(void) printf(gettext("This system supports ZFS pool feature "
5735236884Smm	    "flags.\n\n"));
5736168404Spjd	if (showversions) {
5737238926Smm		int i;
5738238926Smm
5739238926Smm		(void) printf(gettext("The following features are "
5740168404Spjd		    "supported:\n\n"));
5741238926Smm		(void) printf(gettext("FEAT DESCRIPTION\n"));
5742238926Smm		(void) printf("----------------------------------------------"
5743238926Smm		    "---------------\n");
5744238926Smm		for (i = 0; i < SPA_FEATURES; i++) {
5745238926Smm			zfeature_info_t *fi = &spa_feature_table[i];
5746286708Smav			const char *ro =
5747286708Smav			    (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
5748238926Smm			    " (read-only compatible)" : "";
5749238926Smm
5750238926Smm			(void) printf("%-37s%s\n", fi->fi_uname, ro);
5751238926Smm			(void) printf("     %s\n", fi->fi_desc);
5752238926Smm		}
5753238926Smm		(void) printf("\n");
5754238926Smm
5755238926Smm		(void) printf(gettext("The following legacy versions are also "
5756238926Smm		    "supported:\n\n"));
5757168404Spjd		(void) printf(gettext("VER  DESCRIPTION\n"));
5758168404Spjd		(void) printf("---  -----------------------------------------"
5759168404Spjd		    "---------------\n");
5760168404Spjd		(void) printf(gettext(" 1   Initial ZFS version\n"));
5761168404Spjd		(void) printf(gettext(" 2   Ditto blocks "
5762168404Spjd		    "(replicated metadata)\n"));
5763168404Spjd		(void) printf(gettext(" 3   Hot spares and double parity "
5764168404Spjd		    "RAID-Z\n"));
5765168404Spjd		(void) printf(gettext(" 4   zpool history\n"));
5766168404Spjd		(void) printf(gettext(" 5   Compression using the gzip "
5767168404Spjd		    "algorithm\n"));
5768185029Spjd		(void) printf(gettext(" 6   bootfs pool property\n"));
5769185029Spjd		(void) printf(gettext(" 7   Separate intent log devices\n"));
5770185029Spjd		(void) printf(gettext(" 8   Delegated administration\n"));
5771185029Spjd		(void) printf(gettext(" 9   refquota and refreservation "
5772185029Spjd		    "properties\n"));
5773185029Spjd		(void) printf(gettext(" 10  Cache devices\n"));
5774185029Spjd		(void) printf(gettext(" 11  Improved scrub performance\n"));
5775185029Spjd		(void) printf(gettext(" 12  Snapshot properties\n"));
5776185029Spjd		(void) printf(gettext(" 13  snapused property\n"));
5777209962Smm		(void) printf(gettext(" 14  passthrough-x aclinherit\n"));
5778209962Smm		(void) printf(gettext(" 15  user/group space accounting\n"));
5779219089Spjd		(void) printf(gettext(" 16  stmf property support\n"));
5780219089Spjd		(void) printf(gettext(" 17  Triple-parity RAID-Z\n"));
5781219089Spjd		(void) printf(gettext(" 18  Snapshot user holds\n"));
5782219089Spjd		(void) printf(gettext(" 19  Log device removal\n"));
5783219089Spjd		(void) printf(gettext(" 20  Compression using zle "
5784219089Spjd		    "(zero-length encoding)\n"));
5785219089Spjd		(void) printf(gettext(" 21  Deduplication\n"));
5786219089Spjd		(void) printf(gettext(" 22  Received properties\n"));
5787219089Spjd		(void) printf(gettext(" 23  Slim ZIL\n"));
5788219089Spjd		(void) printf(gettext(" 24  System attributes\n"));
5789219089Spjd		(void) printf(gettext(" 25  Improved scrub stats\n"));
5790219089Spjd		(void) printf(gettext(" 26  Improved snapshot deletion "
5791219089Spjd		    "performance\n"));
5792219089Spjd		(void) printf(gettext(" 27  Improved snapshot creation "
5793219089Spjd		    "performance\n"));
5794219089Spjd		(void) printf(gettext(" 28  Multiple vdev replacements\n"));
5795219089Spjd		(void) printf(gettext("\nFor more information on a particular "
5796219089Spjd		    "version, including supported releases,\n"));
5797219089Spjd		(void) printf(gettext("see the ZFS Administration Guide.\n\n"));
5798238926Smm	} else if (argc == 0 && upgradeall) {
5799238926Smm		cb.cb_first = B_TRUE;
5800168404Spjd		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
5801238926Smm		if (ret == 0 && cb.cb_first) {
5802238926Smm			if (cb.cb_version == SPA_VERSION) {
5803276226Ssmh				(void) printf(gettext("All %spools are already "
5804276226Ssmh				    "formatted using feature flags.\n\n"),
5805276226Ssmh				    cb.cb_unavail ? gettext("available ") : "");
5806276226Ssmh				(void) printf(gettext("Every %sfeature flags "
5807238926Smm				    "pool already has all supported features "
5808276226Ssmh				    "enabled.\n"),
5809276226Ssmh				    cb.cb_unavail ? gettext("available ") : "");
5810238926Smm			} else {
5811238926Smm				(void) printf(gettext("All pools are already "
5812238926Smm				    "formatted with version %llu or higher.\n"),
5813238926Smm				    cb.cb_version);
5814168404Spjd			}
5815168404Spjd		}
5816238926Smm	} else if (argc == 0) {
5817238926Smm		cb.cb_first = B_TRUE;
5818276226Ssmh		ret = zpool_iter(g_zfs, upgrade_list_unavail, &cb);
5819276226Ssmh		assert(ret == 0);
5820276226Ssmh
5821276226Ssmh		if (!cb.cb_first) {
5822276226Ssmh			(void) fprintf(stderr, "\n");
5823276226Ssmh		}
5824276226Ssmh
5825276226Ssmh		cb.cb_first = B_TRUE;
5826238926Smm		ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb);
5827238926Smm		assert(ret == 0);
5828168404Spjd
5829238926Smm		if (cb.cb_first) {
5830276226Ssmh			(void) printf(gettext("All %spools are formatted using "
5831276226Ssmh			    "feature flags.\n\n"), cb.cb_unavail ?
5832276226Ssmh			    gettext("available ") : "");
5833238926Smm		} else {
5834238926Smm			(void) printf(gettext("\nUse 'zpool upgrade -v' "
5835238926Smm			    "for a list of available legacy versions.\n"));
5836168404Spjd		}
5837238926Smm
5838238926Smm		cb.cb_first = B_TRUE;
5839238926Smm		ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb);
5840238926Smm		assert(ret == 0);
5841238926Smm
5842238926Smm		if (cb.cb_first) {
5843276226Ssmh			(void) printf(gettext("Every %sfeature flags pool has "
5844276226Ssmh			    "all supported features enabled.\n"),
5845276226Ssmh			    cb.cb_unavail ? gettext("available ") : "");
5846238926Smm		} else {
5847238926Smm			(void) printf(gettext("\n"));
5848238926Smm		}
5849168404Spjd	} else {
5850276226Ssmh		ret = for_each_pool(argc, argv, B_TRUE, NULL,
5851168404Spjd		    upgrade_one, &cb);
5852168404Spjd	}
5853168404Spjd
5854212050Spjd	if (cb.cb_poolname[0] != '\0') {
5855212050Spjd		(void) printf(
5856212050Spjd		    "If you boot from pool '%s', don't forget to update boot code.\n"
5857212050Spjd		    "Assuming you use GPT partitioning and da0 is your boot disk\n"
5858212050Spjd		    "the following command will do it:\n"
5859212050Spjd		    "\n"
5860212050Spjd		    "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n",
5861212050Spjd		    cb.cb_poolname);
5862212050Spjd	}
5863212050Spjd
5864168404Spjd	return (ret);
5865168404Spjd}
5866168404Spjd
5867185029Spjdtypedef struct hist_cbdata {
5868185029Spjd	boolean_t first;
5869248571Smm	boolean_t longfmt;
5870248571Smm	boolean_t internal;
5871185029Spjd} hist_cbdata_t;
5872185029Spjd
5873363954Smarkjstatic void
5874363954Smarkjprint_history_records(nvlist_t *nvhis, hist_cbdata_t *cb)
5875168404Spjd{
5876168404Spjd	nvlist_t **records;
5877168404Spjd	uint_t numrecords;
5878363954Smarkj	int i;
5879168404Spjd
5880168404Spjd	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
5881168404Spjd	    &records, &numrecords) == 0);
5882168404Spjd	for (i = 0; i < numrecords; i++) {
5883248571Smm		nvlist_t *rec = records[i];
5884248571Smm		char tbuf[30] = "";
5885185029Spjd
5886248571Smm		if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
5887248571Smm			time_t tsec;
5888248571Smm			struct tm t;
5889185029Spjd
5890248571Smm			tsec = fnvlist_lookup_uint64(records[i],
5891248571Smm			    ZPOOL_HIST_TIME);
5892248571Smm			(void) localtime_r(&tsec, &t);
5893248571Smm			(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
5894248571Smm		}
5895248571Smm
5896248571Smm		if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
5897248571Smm			(void) printf("%s %s", tbuf,
5898248571Smm			    fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
5899248571Smm		} else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
5900248571Smm			int ievent =
5901248571Smm			    fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
5902248571Smm			if (!cb->internal)
5903185029Spjd				continue;
5904248571Smm			if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
5905248571Smm				(void) printf("%s unrecognized record:\n",
5906248571Smm				    tbuf);
5907248571Smm				dump_nvlist(rec, 4);
5908185029Spjd				continue;
5909248571Smm			}
5910248571Smm			(void) printf("%s [internal %s txg:%lld] %s", tbuf,
5911248571Smm			    zfs_history_event_names[ievent],
5912248571Smm			    fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
5913248571Smm			    fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
5914248571Smm		} else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
5915248571Smm			if (!cb->internal)
5916248571Smm				continue;
5917248571Smm			(void) printf("%s [txg:%lld] %s", tbuf,
5918248571Smm			    fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
5919248571Smm			    fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
5920248571Smm			if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
5921248571Smm				(void) printf(" %s (%llu)",
5922248571Smm				    fnvlist_lookup_string(rec,
5923248571Smm				    ZPOOL_HIST_DSNAME),
5924248571Smm				    fnvlist_lookup_uint64(rec,
5925248571Smm				    ZPOOL_HIST_DSID));
5926248571Smm			}
5927248571Smm			(void) printf(" %s", fnvlist_lookup_string(rec,
5928248571Smm			    ZPOOL_HIST_INT_STR));
5929248571Smm		} else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
5930248571Smm			if (!cb->internal)
5931248571Smm				continue;
5932248571Smm			(void) printf("%s ioctl %s\n", tbuf,
5933248571Smm			    fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
5934248571Smm			if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
5935248571Smm				(void) printf("    input:\n");
5936248571Smm				dump_nvlist(fnvlist_lookup_nvlist(rec,
5937248571Smm				    ZPOOL_HIST_INPUT_NVL), 8);
5938248571Smm			}
5939248571Smm			if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
5940248571Smm				(void) printf("    output:\n");
5941248571Smm				dump_nvlist(fnvlist_lookup_nvlist(rec,
5942248571Smm				    ZPOOL_HIST_OUTPUT_NVL), 8);
5943248571Smm			}
5944325534Savg			if (nvlist_exists(rec, ZPOOL_HIST_ERRNO)) {
5945325534Savg				(void) printf("    errno: %lld\n",
5946325534Savg				    fnvlist_lookup_int64(rec,
5947325534Savg				    ZPOOL_HIST_ERRNO));
5948325534Savg			}
5949248571Smm		} else {
5950248571Smm			if (!cb->internal)
5951248571Smm				continue;
5952248571Smm			(void) printf("%s unrecognized record:\n", tbuf);
5953248571Smm			dump_nvlist(rec, 4);
5954168404Spjd		}
5955185029Spjd
5956185029Spjd		if (!cb->longfmt) {
5957185029Spjd			(void) printf("\n");
5958185029Spjd			continue;
5959185029Spjd		}
5960185029Spjd		(void) printf(" [");
5961248571Smm		if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
5962248571Smm			uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
5963248571Smm			struct passwd *pwd = getpwuid(who);
5964248571Smm			(void) printf("user %d ", (int)who);
5965248571Smm			if (pwd != NULL)
5966248571Smm				(void) printf("(%s) ", pwd->pw_name);
5967185029Spjd		}
5968248571Smm		if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
5969248571Smm			(void) printf("on %s",
5970248571Smm			    fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
5971185029Spjd		}
5972248571Smm		if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
5973248571Smm			(void) printf(":%s",
5974248571Smm			    fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
5975185029Spjd		}
5976185029Spjd		(void) printf("]");
5977185029Spjd		(void) printf("\n");
5978168404Spjd	}
5979363954Smarkj}
5980363954Smarkj
5981363954Smarkj/*
5982363954Smarkj * Print out the command history for a specific pool.
5983363954Smarkj */
5984363954Smarkjstatic int
5985363954Smarkjget_history_one(zpool_handle_t *zhp, void *data)
5986363954Smarkj{
5987363954Smarkj	nvlist_t *nvhis;
5988363954Smarkj	int ret;
5989363954Smarkj	hist_cbdata_t *cb = (hist_cbdata_t *)data;
5990363954Smarkj	uint64_t off = 0;
5991363954Smarkj	boolean_t eof = B_FALSE;
5992363954Smarkj
5993363954Smarkj	cb->first = B_FALSE;
5994363954Smarkj
5995363954Smarkj	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
5996363954Smarkj
5997363954Smarkj	while (!eof) {
5998363954Smarkj		if ((ret = zpool_get_history(zhp, &nvhis, &off, &eof)) != 0)
5999363954Smarkj			return (ret);
6000363954Smarkj
6001363954Smarkj		print_history_records(nvhis, cb);
6002363954Smarkj		nvlist_free(nvhis);
6003363954Smarkj	}
6004168404Spjd	(void) printf("\n");
6005168404Spjd
6006168404Spjd	return (ret);
6007168404Spjd}
6008168404Spjd
6009168404Spjd/*
6010168404Spjd * zpool history <pool>
6011168404Spjd *
6012168404Spjd * Displays the history of commands that modified pools.
6013168404Spjd */
6014168404Spjdint
6015168404Spjdzpool_do_history(int argc, char **argv)
6016168404Spjd{
6017185029Spjd	hist_cbdata_t cbdata = { 0 };
6018168404Spjd	int ret;
6019185029Spjd	int c;
6020168404Spjd
6021185029Spjd	cbdata.first = B_TRUE;
6022185029Spjd	/* check options */
6023185029Spjd	while ((c = getopt(argc, argv, "li")) != -1) {
6024185029Spjd		switch (c) {
6025185029Spjd		case 'l':
6026248571Smm			cbdata.longfmt = B_TRUE;
6027185029Spjd			break;
6028185029Spjd		case 'i':
6029248571Smm			cbdata.internal = B_TRUE;
6030185029Spjd			break;
6031185029Spjd		case '?':
6032185029Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6033185029Spjd			    optopt);
6034185029Spjd			usage(B_FALSE);
6035185029Spjd		}
6036185029Spjd	}
6037168404Spjd	argc -= optind;
6038168404Spjd	argv += optind;
6039168404Spjd
6040168404Spjd	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
6041185029Spjd	    &cbdata);
6042168404Spjd
6043185029Spjd	if (argc == 0 && cbdata.first == B_TRUE) {
6044168404Spjd		(void) printf(gettext("no pools available\n"));
6045168404Spjd		return (0);
6046168404Spjd	}
6047168404Spjd
6048168404Spjd	return (ret);
6049168404Spjd}
6050168404Spjd
6051168404Spjdstatic int
6052168404Spjdget_callback(zpool_handle_t *zhp, void *data)
6053168404Spjd{
6054185029Spjd	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
6055168404Spjd	char value[MAXNAMELEN];
6056185029Spjd	zprop_source_t srctype;
6057185029Spjd	zprop_list_t *pl;
6058168404Spjd
6059168404Spjd	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
6060168404Spjd
6061168404Spjd		/*
6062185029Spjd		 * Skip the special fake placeholder. This will also skip
6063185029Spjd		 * over the name property when 'all' is specified.
6064168404Spjd		 */
6065185029Spjd		if (pl->pl_prop == ZPOOL_PROP_NAME &&
6066168404Spjd		    pl == cbp->cb_proplist)
6067168404Spjd			continue;
6068168404Spjd
6069236884Smm		if (pl->pl_prop == ZPROP_INVAL &&
6070236884Smm		    (zpool_prop_feature(pl->pl_user_prop) ||
6071236884Smm		    zpool_prop_unsupported(pl->pl_user_prop))) {
6072236884Smm			srctype = ZPROP_SRC_LOCAL;
6073168404Spjd
6074236884Smm			if (zpool_prop_get_feature(zhp, pl->pl_user_prop,
6075236884Smm			    value, sizeof (value)) == 0) {
6076236884Smm				zprop_print_one_property(zpool_get_name(zhp),
6077236884Smm				    cbp, pl->pl_user_prop, value, srctype,
6078236884Smm				    NULL, NULL);
6079236884Smm			}
6080236884Smm		} else {
6081236884Smm			if (zpool_get_prop(zhp, pl->pl_prop, value,
6082263889Sdelphij			    sizeof (value), &srctype, cbp->cb_literal) != 0)
6083236884Smm				continue;
6084236884Smm
6085236884Smm			zprop_print_one_property(zpool_get_name(zhp), cbp,
6086236884Smm			    zpool_prop_to_name(pl->pl_prop), value, srctype,
6087236884Smm			    NULL, NULL);
6088236884Smm		}
6089168404Spjd	}
6090168404Spjd	return (0);
6091168404Spjd}
6092168404Spjd
6093263889Sdelphij/*
6094263889Sdelphij * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ...
6095263889Sdelphij *
6096263889Sdelphij *	-H	Scripted mode.  Don't display headers, and separate properties
6097263889Sdelphij *		by a single tab.
6098263889Sdelphij *	-o	List of columns to display.  Defaults to
6099263889Sdelphij *		"name,property,value,source".
6100342941Savg *	-p	Diplay values in parsable (exact) format.
6101263889Sdelphij *
6102263889Sdelphij * Get properties of pools in the system. Output space statistics
6103263889Sdelphij * for each one as well as other attributes.
6104263889Sdelphij */
6105168404Spjdint
6106168404Spjdzpool_do_get(int argc, char **argv)
6107168404Spjd{
6108185029Spjd	zprop_get_cbdata_t cb = { 0 };
6109185029Spjd	zprop_list_t fake_name = { 0 };
6110168404Spjd	int ret;
6111263889Sdelphij	int c, i;
6112263889Sdelphij	char *value;
6113168404Spjd
6114263889Sdelphij	cb.cb_first = B_TRUE;
6115168404Spjd
6116263889Sdelphij	/*
6117263889Sdelphij	 * Set up default columns and sources.
6118263889Sdelphij	 */
6119185029Spjd	cb.cb_sources = ZPROP_SRC_ALL;
6120168404Spjd	cb.cb_columns[0] = GET_COL_NAME;
6121168404Spjd	cb.cb_columns[1] = GET_COL_PROPERTY;
6122168404Spjd	cb.cb_columns[2] = GET_COL_VALUE;
6123168404Spjd	cb.cb_columns[3] = GET_COL_SOURCE;
6124185029Spjd	cb.cb_type = ZFS_TYPE_POOL;
6125168404Spjd
6126263889Sdelphij	/* check options */
6127263889Sdelphij	while ((c = getopt(argc, argv, ":Hpo:")) != -1) {
6128263889Sdelphij		switch (c) {
6129263889Sdelphij		case 'p':
6130263889Sdelphij			cb.cb_literal = B_TRUE;
6131263889Sdelphij			break;
6132263889Sdelphij		case 'H':
6133263889Sdelphij			cb.cb_scripted = B_TRUE;
6134263889Sdelphij			break;
6135263889Sdelphij		case 'o':
6136263889Sdelphij			bzero(&cb.cb_columns, sizeof (cb.cb_columns));
6137263889Sdelphij			i = 0;
6138263889Sdelphij			while (*optarg != '\0') {
6139263889Sdelphij				static char *col_subopts[] =
6140263889Sdelphij				{ "name", "property", "value", "source",
6141263889Sdelphij				"all", NULL };
6142263889Sdelphij
6143263889Sdelphij				if (i == ZFS_GET_NCOLS) {
6144263889Sdelphij					(void) fprintf(stderr, gettext("too "
6145263889Sdelphij					"many fields given to -o "
6146263889Sdelphij					"option\n"));
6147263889Sdelphij					usage(B_FALSE);
6148263889Sdelphij				}
6149263889Sdelphij
6150263889Sdelphij				switch (getsubopt(&optarg, col_subopts,
6151263889Sdelphij				    &value)) {
6152263889Sdelphij				case 0:
6153263889Sdelphij					cb.cb_columns[i++] = GET_COL_NAME;
6154263889Sdelphij					break;
6155263889Sdelphij				case 1:
6156263889Sdelphij					cb.cb_columns[i++] = GET_COL_PROPERTY;
6157263889Sdelphij					break;
6158263889Sdelphij				case 2:
6159263889Sdelphij					cb.cb_columns[i++] = GET_COL_VALUE;
6160263889Sdelphij					break;
6161263889Sdelphij				case 3:
6162263889Sdelphij					cb.cb_columns[i++] = GET_COL_SOURCE;
6163263889Sdelphij					break;
6164263889Sdelphij				case 4:
6165263889Sdelphij					if (i > 0) {
6166263889Sdelphij						(void) fprintf(stderr,
6167263889Sdelphij						    gettext("\"all\" conflicts "
6168263889Sdelphij						    "with specific fields "
6169263889Sdelphij						    "given to -o option\n"));
6170263889Sdelphij						usage(B_FALSE);
6171263889Sdelphij					}
6172263889Sdelphij					cb.cb_columns[0] = GET_COL_NAME;
6173263889Sdelphij					cb.cb_columns[1] = GET_COL_PROPERTY;
6174263889Sdelphij					cb.cb_columns[2] = GET_COL_VALUE;
6175263889Sdelphij					cb.cb_columns[3] = GET_COL_SOURCE;
6176263889Sdelphij					i = ZFS_GET_NCOLS;
6177263889Sdelphij					break;
6178263889Sdelphij				default:
6179263889Sdelphij					(void) fprintf(stderr,
6180263889Sdelphij					    gettext("invalid column name "
6181295844Sdim					    "'%s'\n"), suboptarg);
6182263889Sdelphij					usage(B_FALSE);
6183263889Sdelphij				}
6184263889Sdelphij			}
6185263889Sdelphij			break;
6186263889Sdelphij		case '?':
6187263889Sdelphij			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6188263889Sdelphij			    optopt);
6189263889Sdelphij			usage(B_FALSE);
6190263889Sdelphij		}
6191263889Sdelphij	}
6192263889Sdelphij
6193263889Sdelphij	argc -= optind;
6194263889Sdelphij	argv += optind;
6195263889Sdelphij
6196263889Sdelphij	if (argc < 1) {
6197263889Sdelphij		(void) fprintf(stderr, gettext("missing property "
6198263889Sdelphij		    "argument\n"));
6199263889Sdelphij		usage(B_FALSE);
6200263889Sdelphij	}
6201263889Sdelphij
6202263889Sdelphij	if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist,
6203185029Spjd	    ZFS_TYPE_POOL) != 0)
6204168404Spjd		usage(B_FALSE);
6205168404Spjd
6206263889Sdelphij	argc--;
6207263889Sdelphij	argv++;
6208263889Sdelphij
6209168404Spjd	if (cb.cb_proplist != NULL) {
6210185029Spjd		fake_name.pl_prop = ZPOOL_PROP_NAME;
6211168404Spjd		fake_name.pl_width = strlen(gettext("NAME"));
6212168404Spjd		fake_name.pl_next = cb.cb_proplist;
6213168404Spjd		cb.cb_proplist = &fake_name;
6214168404Spjd	}
6215168404Spjd
6216263889Sdelphij	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
6217168404Spjd	    get_callback, &cb);
6218168404Spjd
6219168404Spjd	if (cb.cb_proplist == &fake_name)
6220185029Spjd		zprop_free_list(fake_name.pl_next);
6221168404Spjd	else
6222185029Spjd		zprop_free_list(cb.cb_proplist);
6223168404Spjd
6224168404Spjd	return (ret);
6225168404Spjd}
6226168404Spjd
6227168404Spjdtypedef struct set_cbdata {
6228168404Spjd	char *cb_propname;
6229168404Spjd	char *cb_value;
6230168404Spjd	boolean_t cb_any_successful;
6231168404Spjd} set_cbdata_t;
6232168404Spjd
6233168404Spjdint
6234168404Spjdset_callback(zpool_handle_t *zhp, void *data)
6235168404Spjd{
6236168404Spjd	int error;
6237168404Spjd	set_cbdata_t *cb = (set_cbdata_t *)data;
6238168404Spjd
6239168404Spjd	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
6240168404Spjd
6241168404Spjd	if (!error)
6242168404Spjd		cb->cb_any_successful = B_TRUE;
6243168404Spjd
6244168404Spjd	return (error);
6245168404Spjd}
6246168404Spjd
6247168404Spjdint
6248168404Spjdzpool_do_set(int argc, char **argv)
6249168404Spjd{
6250168404Spjd	set_cbdata_t cb = { 0 };
6251168404Spjd	int error;
6252168404Spjd
6253168404Spjd	if (argc > 1 && argv[1][0] == '-') {
6254168404Spjd		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
6255168404Spjd		    argv[1][1]);
6256168404Spjd		usage(B_FALSE);
6257168404Spjd	}
6258168404Spjd
6259168404Spjd	if (argc < 2) {
6260168404Spjd		(void) fprintf(stderr, gettext("missing property=value "
6261168404Spjd		    "argument\n"));
6262168404Spjd		usage(B_FALSE);
6263168404Spjd	}
6264168404Spjd
6265168404Spjd	if (argc < 3) {
6266168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
6267168404Spjd		usage(B_FALSE);
6268168404Spjd	}
6269168404Spjd
6270168404Spjd	if (argc > 3) {
6271168404Spjd		(void) fprintf(stderr, gettext("too many pool names\n"));
6272168404Spjd		usage(B_FALSE);
6273168404Spjd	}
6274168404Spjd
6275168404Spjd	cb.cb_propname = argv[1];
6276168404Spjd	cb.cb_value = strchr(cb.cb_propname, '=');
6277168404Spjd	if (cb.cb_value == NULL) {
6278168404Spjd		(void) fprintf(stderr, gettext("missing value in "
6279168404Spjd		    "property=value argument\n"));
6280168404Spjd		usage(B_FALSE);
6281168404Spjd	}
6282168404Spjd
6283168404Spjd	*(cb.cb_value) = '\0';
6284168404Spjd	cb.cb_value++;
6285168404Spjd
6286168404Spjd	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
6287168404Spjd	    set_callback, &cb);
6288168404Spjd
6289168404Spjd	return (error);
6290168404Spjd}
6291168404Spjd
6292168404Spjdstatic int
6293168404Spjdfind_command_idx(char *command, int *idx)
6294168404Spjd{
6295168404Spjd	int i;
6296168404Spjd
6297168404Spjd	for (i = 0; i < NCOMMAND; i++) {
6298168404Spjd		if (command_table[i].name == NULL)
6299168404Spjd			continue;
6300168404Spjd
6301168404Spjd		if (strcmp(command, command_table[i].name) == 0) {
6302168404Spjd			*idx = i;
6303168404Spjd			return (0);
6304168404Spjd		}
6305168404Spjd	}
6306168404Spjd	return (1);
6307168404Spjd}
6308168404Spjd
6309168404Spjdint
6310168404Spjdmain(int argc, char **argv)
6311168404Spjd{
6312296537Smav	int ret = 0;
6313168404Spjd	int i;
6314168404Spjd	char *cmdname;
6315168404Spjd
6316168404Spjd	(void) setlocale(LC_ALL, "");
6317168404Spjd	(void) textdomain(TEXT_DOMAIN);
6318168404Spjd
6319168404Spjd	if ((g_zfs = libzfs_init()) == NULL) {
6320168404Spjd		(void) fprintf(stderr, gettext("internal error: failed to "
6321168404Spjd		    "initialize ZFS library\n"));
6322168404Spjd		return (1);
6323168404Spjd	}
6324168404Spjd
6325168404Spjd	libzfs_print_on_error(g_zfs, B_TRUE);
6326168404Spjd
6327168404Spjd	opterr = 0;
6328168404Spjd
6329168404Spjd	/*
6330168404Spjd	 * Make sure the user has specified some command.
6331168404Spjd	 */
6332168404Spjd	if (argc < 2) {
6333168404Spjd		(void) fprintf(stderr, gettext("missing command\n"));
6334168404Spjd		usage(B_FALSE);
6335168404Spjd	}
6336168404Spjd
6337168404Spjd	cmdname = argv[1];
6338168404Spjd
6339168404Spjd	/*
6340168404Spjd	 * Special case '-?'
6341168404Spjd	 */
6342168404Spjd	if (strcmp(cmdname, "-?") == 0)
6343168404Spjd		usage(B_TRUE);
6344168404Spjd
6345248571Smm	zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
6346185029Spjd
6347168404Spjd	/*
6348168404Spjd	 * Run the appropriate command.
6349168404Spjd	 */
6350168404Spjd	if (find_command_idx(cmdname, &i) == 0) {
6351168404Spjd		current_command = &command_table[i];
6352168404Spjd		ret = command_table[i].func(argc - 1, argv + 1);
6353185029Spjd	} else if (strchr(cmdname, '=')) {
6354185029Spjd		verify(find_command_idx("set", &i) == 0);
6355185029Spjd		current_command = &command_table[i];
6356185029Spjd		ret = command_table[i].func(argc, argv);
6357185029Spjd	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
6358185029Spjd		/*
6359185029Spjd		 * 'freeze' is a vile debugging abomination, so we treat
6360185029Spjd		 * it as such.
6361185029Spjd		 */
6362252059Ssmh		zfs_cmd_t zc = { 0 };
6363252059Ssmh		(void) strlcpy(zc.zc_name, argv[2], sizeof (zc.zc_name));
6364252059Ssmh		return (!!zfs_ioctl(g_zfs, ZFS_IOC_POOL_FREEZE, &zc));
6365185029Spjd	} else {
6366168404Spjd		(void) fprintf(stderr, gettext("unrecognized "
6367168404Spjd		    "command '%s'\n"), cmdname);
6368168404Spjd		usage(B_FALSE);
6369168404Spjd	}
6370168404Spjd
6371248571Smm	if (ret == 0 && log_history)
6372248571Smm		(void) zpool_log_history(g_zfs, history_str);
6373248571Smm
6374168404Spjd	libzfs_fini(g_zfs);
6375168404Spjd
6376168404Spjd	/*
6377168404Spjd	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
6378168404Spjd	 * for the purposes of running ::findleaks.
6379168404Spjd	 */
6380168404Spjd	if (getenv("ZFS_ABORT") != NULL) {
6381168404Spjd		(void) printf("dumping core by request\n");
6382168404Spjd		abort();
6383168404Spjd	}
6384168404Spjd
6385168404Spjd	return (ret);
6386168404Spjd}
6387