zpool_main.c revision 332525
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>
39168404Spjd#include <libgen.h>
40168404Spjd#include <libintl.h>
41168404Spjd#include <libuutil.h>
42168404Spjd#include <locale.h>
43168404Spjd#include <stdio.h>
44168404Spjd#include <stdlib.h>
45168404Spjd#include <string.h>
46168404Spjd#include <strings.h>
47168404Spjd#include <unistd.h>
48168404Spjd#include <priv.h>
49185029Spjd#include <pwd.h>
50185029Spjd#include <zone.h>
51168404Spjd#include <sys/time.h>
52236155Smm#include <zfs_prop.h>
53168404Spjd#include <sys/fs/zfs.h>
54168404Spjd#include <sys/stat.h>
55168404Spjd
56168404Spjd#include <libzfs.h>
57168404Spjd
58168404Spjd#include "zpool_util.h"
59185029Spjd#include "zfs_comutil.h"
60236884Smm#include "zfeature_common.h"
61168404Spjd
62219089Spjd#include "statcommon.h"
63219089Spjd
64168404Spjdstatic int zpool_do_create(int, char **);
65168404Spjdstatic int zpool_do_destroy(int, char **);
66168404Spjd
67168404Spjdstatic int zpool_do_add(int, char **);
68168404Spjdstatic int zpool_do_remove(int, char **);
69224171Sgibbsstatic int zpool_do_labelclear(int, char **);
70168404Spjd
71168404Spjdstatic int zpool_do_list(int, char **);
72168404Spjdstatic int zpool_do_iostat(int, char **);
73168404Spjdstatic int zpool_do_status(int, char **);
74168404Spjd
75168404Spjdstatic int zpool_do_online(int, char **);
76168404Spjdstatic int zpool_do_offline(int, char **);
77168404Spjdstatic int zpool_do_clear(int, char **);
78236155Smmstatic int zpool_do_reopen(int, char **);
79168404Spjd
80228103Smmstatic int zpool_do_reguid(int, char **);
81228103Smm
82168404Spjdstatic int zpool_do_attach(int, char **);
83168404Spjdstatic int zpool_do_detach(int, char **);
84168404Spjdstatic int zpool_do_replace(int, char **);
85219089Spjdstatic int zpool_do_split(int, char **);
86168404Spjd
87168404Spjdstatic int zpool_do_scrub(int, char **);
88168404Spjd
89168404Spjdstatic int zpool_do_import(int, char **);
90168404Spjdstatic int zpool_do_export(int, char **);
91168404Spjd
92168404Spjdstatic int zpool_do_upgrade(int, char **);
93168404Spjd
94168404Spjdstatic int zpool_do_history(int, char **);
95168404Spjd
96168404Spjdstatic int zpool_do_get(int, char **);
97168404Spjdstatic int zpool_do_set(int, char **);
98168404Spjd
99168404Spjd/*
100168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's
101168404Spjd * debugging facilities.
102168404Spjd */
103185029Spjd
104185029Spjd#ifdef DEBUG
105168404Spjdconst char *
106168404Spjd_umem_debug_init(void)
107168404Spjd{
108168404Spjd	return ("default,verbose"); /* $UMEM_DEBUG setting */
109168404Spjd}
110168404Spjd
111168404Spjdconst char *
112168404Spjd_umem_logging_init(void)
113168404Spjd{
114168404Spjd	return ("fail,contents"); /* $UMEM_LOGGING setting */
115168404Spjd}
116185029Spjd#endif
117168404Spjd
118168404Spjdtypedef enum {
119168404Spjd	HELP_ADD,
120168404Spjd	HELP_ATTACH,
121168404Spjd	HELP_CLEAR,
122168404Spjd	HELP_CREATE,
123168404Spjd	HELP_DESTROY,
124168404Spjd	HELP_DETACH,
125168404Spjd	HELP_EXPORT,
126168404Spjd	HELP_HISTORY,
127168404Spjd	HELP_IMPORT,
128168404Spjd	HELP_IOSTAT,
129224171Sgibbs	HELP_LABELCLEAR,
130168404Spjd	HELP_LIST,
131168404Spjd	HELP_OFFLINE,
132168404Spjd	HELP_ONLINE,
133168404Spjd	HELP_REPLACE,
134168404Spjd	HELP_REMOVE,
135168404Spjd	HELP_SCRUB,
136168404Spjd	HELP_STATUS,
137168404Spjd	HELP_UPGRADE,
138168404Spjd	HELP_GET,
139219089Spjd	HELP_SET,
140228103Smm	HELP_SPLIT,
141236155Smm	HELP_REGUID,
142236155Smm	HELP_REOPEN
143168404Spjd} zpool_help_t;
144168404Spjd
145168404Spjd
146168404Spjdtypedef struct zpool_command {
147168404Spjd	const char	*name;
148168404Spjd	int		(*func)(int, char **);
149168404Spjd	zpool_help_t	usage;
150168404Spjd} zpool_command_t;
151168404Spjd
152168404Spjd/*
153168404Spjd * Master command table.  Each ZFS command has a name, associated function, and
154168404Spjd * usage message.  The usage messages need to be internationalized, so we have
155168404Spjd * to have a function to return the usage message based on a command index.
156168404Spjd *
157168404Spjd * These commands are organized according to how they are displayed in the usage
158168404Spjd * message.  An empty command (one with a NULL name) indicates an empty line in
159168404Spjd * the generic usage message.
160168404Spjd */
161168404Spjdstatic zpool_command_t command_table[] = {
162168404Spjd	{ "create",	zpool_do_create,	HELP_CREATE		},
163168404Spjd	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
164168404Spjd	{ NULL },
165168404Spjd	{ "add",	zpool_do_add,		HELP_ADD		},
166168404Spjd	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
167168404Spjd	{ NULL },
168224171Sgibbs	{ "labelclear",	zpool_do_labelclear,	HELP_LABELCLEAR		},
169224171Sgibbs	{ NULL },
170168404Spjd	{ "list",	zpool_do_list,		HELP_LIST		},
171168404Spjd	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
172168404Spjd	{ "status",	zpool_do_status,	HELP_STATUS		},
173168404Spjd	{ NULL },
174168404Spjd	{ "online",	zpool_do_online,	HELP_ONLINE		},
175168404Spjd	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
176168404Spjd	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
177236155Smm	{ "reopen",	zpool_do_reopen,	HELP_REOPEN		},
178168404Spjd	{ NULL },
179168404Spjd	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
180168404Spjd	{ "detach",	zpool_do_detach,	HELP_DETACH		},
181168404Spjd	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
182219089Spjd	{ "split",	zpool_do_split,		HELP_SPLIT		},
183168404Spjd	{ NULL },
184168404Spjd	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
185168404Spjd	{ NULL },
186168404Spjd	{ "import",	zpool_do_import,	HELP_IMPORT		},
187168404Spjd	{ "export",	zpool_do_export,	HELP_EXPORT		},
188168404Spjd	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
189228103Smm	{ "reguid",	zpool_do_reguid,	HELP_REGUID		},
190168404Spjd	{ NULL },
191168404Spjd	{ "history",	zpool_do_history,	HELP_HISTORY		},
192168404Spjd	{ "get",	zpool_do_get,		HELP_GET		},
193168404Spjd	{ "set",	zpool_do_set,		HELP_SET		},
194168404Spjd};
195168404Spjd
196168404Spjd#define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
197168404Spjd
198248571Smmstatic zpool_command_t *current_command;
199185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN];
200248571Smmstatic boolean_t log_history = B_TRUE;
201219089Spjdstatic uint_t timestamp_fmt = NODATE;
202219089Spjd
203168404Spjdstatic const char *
204289562Smavget_usage(zpool_help_t idx)
205289562Smav{
206168404Spjd	switch (idx) {
207168404Spjd	case HELP_ADD:
208168404Spjd		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
209168404Spjd	case HELP_ATTACH:
210168404Spjd		return (gettext("\tattach [-f] <pool> <device> "
211185029Spjd		    "<new-device>\n"));
212168404Spjd	case HELP_CLEAR:
213219089Spjd		return (gettext("\tclear [-nF] <pool> [device]\n"));
214168404Spjd	case HELP_CREATE:
215331395Smav		return (gettext("\tcreate [-fnd] [-B] "
216331395Smav		    "[-o property=value] ... \n"
217185029Spjd		    "\t    [-O file-system-property=value] ... \n"
218185029Spjd		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
219168404Spjd	case HELP_DESTROY:
220168404Spjd		return (gettext("\tdestroy [-f] <pool>\n"));
221168404Spjd	case HELP_DETACH:
222168404Spjd		return (gettext("\tdetach <pool> <device>\n"));
223168404Spjd	case HELP_EXPORT:
224168404Spjd		return (gettext("\texport [-f] <pool> ...\n"));
225168404Spjd	case HELP_HISTORY:
226185029Spjd		return (gettext("\thistory [-il] [<pool>] ...\n"));
227168404Spjd	case HELP_IMPORT:
228168404Spjd		return (gettext("\timport [-d dir] [-D]\n"
229219089Spjd		    "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n"
230185029Spjd		    "\timport [-o mntopts] [-o property=value] ... \n"
231219089Spjd		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
232219089Spjd		    "[-R root] [-F [-n]] -a\n"
233185029Spjd		    "\timport [-o mntopts] [-o property=value] ... \n"
234219089Spjd		    "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
235219089Spjd		    "[-R root] [-F [-n]]\n"
236219089Spjd		    "\t    <pool | id> [newpool]\n"));
237168404Spjd	case HELP_IOSTAT:
238219089Spjd		return (gettext("\tiostat [-v] [-T d|u] [pool] ... [interval "
239168404Spjd		    "[count]]\n"));
240224171Sgibbs	case HELP_LABELCLEAR:
241224171Sgibbs		return (gettext("\tlabelclear [-f] <vdev>\n"));
242168404Spjd	case HELP_LIST:
243263889Sdelphij		return (gettext("\tlist [-Hpv] [-o property[,...]] "
244219089Spjd		    "[-T d|u] [pool] ... [interval [count]]\n"));
245168404Spjd	case HELP_OFFLINE:
246168404Spjd		return (gettext("\toffline [-t] <pool> <device> ...\n"));
247168404Spjd	case HELP_ONLINE:
248228020Smm		return (gettext("\tonline [-e] <pool> <device> ...\n"));
249168404Spjd	case HELP_REPLACE:
250168404Spjd		return (gettext("\treplace [-f] <pool> <device> "
251185029Spjd		    "[new-device]\n"));
252168404Spjd	case HELP_REMOVE:
253332525Smav		return (gettext("\tremove [-nps] <pool> <device> ...\n"));
254236155Smm	case HELP_REOPEN:
255260138Sdelphij		return (gettext("\treopen <pool>\n"));
256168404Spjd	case HELP_SCRUB:
257324010Savg		return (gettext("\tscrub [-s | -p] <pool> ...\n"));
258168404Spjd	case HELP_STATUS:
259219089Spjd		return (gettext("\tstatus [-vx] [-T d|u] [pool] ... [interval "
260219089Spjd		    "[count]]\n"));
261168404Spjd	case HELP_UPGRADE:
262228020Smm		return (gettext("\tupgrade [-v]\n"
263185029Spjd		    "\tupgrade [-V version] <-a | pool ...>\n"));
264168404Spjd	case HELP_GET:
265263889Sdelphij		return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] "
266263889Sdelphij		    "<\"all\" | property[,...]> <pool> ...\n"));
267168404Spjd	case HELP_SET:
268168404Spjd		return (gettext("\tset <property=value> <pool> \n"));
269219089Spjd	case HELP_SPLIT:
270219089Spjd		return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
271219089Spjd		    "\t    [-o property=value] <pool> <newpool> "
272219089Spjd		    "[<device> ...]\n"));
273228103Smm	case HELP_REGUID:
274228103Smm		return (gettext("\treguid <pool>\n"));
275168404Spjd	}
276168404Spjd
277168404Spjd	abort();
278168404Spjd	/* NOTREACHED */
279168404Spjd}
280168404Spjd
281168404Spjd
282168404Spjd/*
283168404Spjd * Callback routine that will print out a pool property value.
284168404Spjd */
285185029Spjdstatic int
286185029Spjdprint_prop_cb(int prop, void *cb)
287168404Spjd{
288168404Spjd	FILE *fp = cb;
289168404Spjd
290219089Spjd	(void) fprintf(fp, "\t%-15s  ", zpool_prop_to_name(prop));
291168404Spjd
292185029Spjd	if (zpool_prop_readonly(prop))
293185029Spjd		(void) fprintf(fp, "  NO   ");
294185029Spjd	else
295219089Spjd		(void) fprintf(fp, " YES   ");
296185029Spjd
297168404Spjd	if (zpool_prop_values(prop) == NULL)
298168404Spjd		(void) fprintf(fp, "-\n");
299168404Spjd	else
300168404Spjd		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
301168404Spjd
302185029Spjd	return (ZPROP_CONT);
303168404Spjd}
304168404Spjd
305168404Spjd/*
306168404Spjd * Display usage message.  If we're inside a command, display only the usage for
307168404Spjd * that command.  Otherwise, iterate over the entire command table and display
308168404Spjd * a complete usage message.
309168404Spjd */
310168404Spjdvoid
311168404Spjdusage(boolean_t requested)
312168404Spjd{
313168404Spjd	FILE *fp = requested ? stdout : stderr;
314168404Spjd
315168404Spjd	if (current_command == NULL) {
316168404Spjd		int i;
317168404Spjd
318168404Spjd		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
319168404Spjd		(void) fprintf(fp,
320168404Spjd		    gettext("where 'command' is one of the following:\n\n"));
321168404Spjd
322168404Spjd		for (i = 0; i < NCOMMAND; i++) {
323168404Spjd			if (command_table[i].name == NULL)
324168404Spjd				(void) fprintf(fp, "\n");
325168404Spjd			else
326168404Spjd				(void) fprintf(fp, "%s",
327168404Spjd				    get_usage(command_table[i].usage));
328168404Spjd		}
329168404Spjd	} else {
330168404Spjd		(void) fprintf(fp, gettext("usage:\n"));
331168404Spjd		(void) fprintf(fp, "%s", get_usage(current_command->usage));
332168404Spjd	}
333168404Spjd
334168404Spjd	if (current_command != NULL &&
335168404Spjd	    ((strcmp(current_command->name, "set") == 0) ||
336185029Spjd	    (strcmp(current_command->name, "get") == 0) ||
337185029Spjd	    (strcmp(current_command->name, "list") == 0))) {
338168404Spjd
339168404Spjd		(void) fprintf(fp,
340168404Spjd		    gettext("\nthe following properties are supported:\n"));
341168404Spjd
342219089Spjd		(void) fprintf(fp, "\n\t%-15s  %s   %s\n\n",
343185029Spjd		    "PROPERTY", "EDIT", "VALUES");
344168404Spjd
345168404Spjd		/* Iterate over all properties */
346185029Spjd		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
347185029Spjd		    ZFS_TYPE_POOL);
348236884Smm
349236884Smm		(void) fprintf(fp, "\t%-15s   ", "feature@...");
350236884Smm		(void) fprintf(fp, "YES   disabled | enabled | active\n");
351236884Smm
352236884Smm		(void) fprintf(fp, gettext("\nThe feature@ properties must be "
353243014Smm		    "appended with a feature name.\nSee zpool-features(7).\n"));
354168404Spjd	}
355168404Spjd
356168404Spjd	/*
357168404Spjd	 * See comments at end of main().
358168404Spjd	 */
359168404Spjd	if (getenv("ZFS_ABORT") != NULL) {
360168404Spjd		(void) printf("dumping core by request\n");
361168404Spjd		abort();
362168404Spjd	}
363168404Spjd
364168404Spjd	exit(requested ? 0 : 2);
365168404Spjd}
366168404Spjd
367168404Spjdvoid
368185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
369185029Spjd    boolean_t print_logs)
370168404Spjd{
371168404Spjd	nvlist_t **child;
372168404Spjd	uint_t c, children;
373168404Spjd	char *vname;
374168404Spjd
375168404Spjd	if (name != NULL)
376168404Spjd		(void) printf("\t%*s%s\n", indent, "", name);
377168404Spjd
378168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
379168404Spjd	    &child, &children) != 0)
380168404Spjd		return;
381168404Spjd
382168404Spjd	for (c = 0; c < children; c++) {
383185029Spjd		uint64_t is_log = B_FALSE;
384185029Spjd
385185029Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
386185029Spjd		    &is_log);
387185029Spjd		if ((is_log && !print_logs) || (!is_log && print_logs))
388185029Spjd			continue;
389185029Spjd
390219089Spjd		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
391185029Spjd		print_vdev_tree(zhp, vname, child[c], indent + 2,
392185029Spjd		    B_FALSE);
393168404Spjd		free(vname);
394168404Spjd	}
395168404Spjd}
396168404Spjd
397238926Smmstatic boolean_t
398238926Smmprop_list_contains_feature(nvlist_t *proplist)
399238926Smm{
400238926Smm	nvpair_t *nvp;
401238926Smm	for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp;
402238926Smm	    nvp = nvlist_next_nvpair(proplist, nvp)) {
403238926Smm		if (zpool_prop_feature(nvpair_name(nvp)))
404238926Smm			return (B_TRUE);
405238926Smm	}
406238926Smm	return (B_FALSE);
407238926Smm}
408238926Smm
409168404Spjd/*
410185029Spjd * Add a property pair (name, string-value) into a property nvlist.
411185029Spjd */
412185029Spjdstatic int
413185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props,
414185029Spjd    boolean_t poolprop)
415185029Spjd{
416185029Spjd	zpool_prop_t prop = ZPROP_INVAL;
417185029Spjd	zfs_prop_t fprop;
418185029Spjd	nvlist_t *proplist;
419185029Spjd	const char *normnm;
420185029Spjd	char *strval;
421185029Spjd
422185029Spjd	if (*props == NULL &&
423185029Spjd	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
424185029Spjd		(void) fprintf(stderr,
425185029Spjd		    gettext("internal error: out of memory\n"));
426185029Spjd		return (1);
427185029Spjd	}
428185029Spjd
429185029Spjd	proplist = *props;
430185029Spjd
431185029Spjd	if (poolprop) {
432238926Smm		const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
433238926Smm
434236884Smm		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
435236884Smm		    !zpool_prop_feature(propname)) {
436185029Spjd			(void) fprintf(stderr, gettext("property '%s' is "
437185029Spjd			    "not a valid pool property\n"), propname);
438185029Spjd			return (2);
439185029Spjd		}
440238926Smm
441238926Smm		/*
442238926Smm		 * feature@ properties and version should not be specified
443238926Smm		 * at the same time.
444238926Smm		 */
445329493Smav		if ((prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname) &&
446238926Smm		    nvlist_exists(proplist, vname)) ||
447238926Smm		    (prop == ZPOOL_PROP_VERSION &&
448238926Smm		    prop_list_contains_feature(proplist))) {
449238926Smm			(void) fprintf(stderr, gettext("'feature@' and "
450238926Smm			    "'version' properties cannot be specified "
451238926Smm			    "together\n"));
452238926Smm			return (2);
453238926Smm		}
454238926Smm
455238926Smm
456236884Smm		if (zpool_prop_feature(propname))
457236884Smm			normnm = propname;
458236884Smm		else
459236884Smm			normnm = zpool_prop_to_name(prop);
460185029Spjd	} else {
461209962Smm		if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
462209962Smm			normnm = zfs_prop_to_name(fprop);
463209962Smm		} else {
464209962Smm			normnm = propname;
465185029Spjd		}
466185029Spjd	}
467185029Spjd
468185029Spjd	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
469185029Spjd	    prop != ZPOOL_PROP_CACHEFILE) {
470185029Spjd		(void) fprintf(stderr, gettext("property '%s' "
471185029Spjd		    "specified multiple times\n"), propname);
472185029Spjd		return (2);
473185029Spjd	}
474185029Spjd
475185029Spjd	if (nvlist_add_string(proplist, normnm, propval) != 0) {
476185029Spjd		(void) fprintf(stderr, gettext("internal "
477185029Spjd		    "error: out of memory\n"));
478185029Spjd		return (1);
479185029Spjd	}
480185029Spjd
481185029Spjd	return (0);
482185029Spjd}
483185029Spjd
484185029Spjd/*
485168404Spjd * zpool add [-fn] <pool> <vdev> ...
486168404Spjd *
487168404Spjd *	-f	Force addition of devices, even if they appear in use
488168404Spjd *	-n	Do not add the devices, but display the resulting layout if
489168404Spjd *		they were to be added.
490168404Spjd *
491168404Spjd * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
492168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
493168404Spjd * libzfs.
494168404Spjd */
495168404Spjdint
496168404Spjdzpool_do_add(int argc, char **argv)
497168404Spjd{
498168404Spjd	boolean_t force = B_FALSE;
499168404Spjd	boolean_t dryrun = B_FALSE;
500168404Spjd	int c;
501168404Spjd	nvlist_t *nvroot;
502168404Spjd	char *poolname;
503331395Smav	zpool_boot_label_t boot_type;
504331395Smav	uint64_t boot_size;
505168404Spjd	int ret;
506168404Spjd	zpool_handle_t *zhp;
507168404Spjd	nvlist_t *config;
508168404Spjd
509168404Spjd	/* check options */
510168404Spjd	while ((c = getopt(argc, argv, "fn")) != -1) {
511168404Spjd		switch (c) {
512168404Spjd		case 'f':
513168404Spjd			force = B_TRUE;
514168404Spjd			break;
515168404Spjd		case 'n':
516168404Spjd			dryrun = B_TRUE;
517168404Spjd			break;
518168404Spjd		case '?':
519168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
520168404Spjd			    optopt);
521168404Spjd			usage(B_FALSE);
522168404Spjd		}
523168404Spjd	}
524168404Spjd
525168404Spjd	argc -= optind;
526168404Spjd	argv += optind;
527168404Spjd
528168404Spjd	/* get pool name and check number of arguments */
529168404Spjd	if (argc < 1) {
530168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
531168404Spjd		usage(B_FALSE);
532168404Spjd	}
533168404Spjd	if (argc < 2) {
534168404Spjd		(void) fprintf(stderr, gettext("missing vdev specification\n"));
535168404Spjd		usage(B_FALSE);
536168404Spjd	}
537168404Spjd
538168404Spjd	poolname = argv[0];
539168404Spjd
540168404Spjd	argc--;
541168404Spjd	argv++;
542168404Spjd
543168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
544168404Spjd		return (1);
545168404Spjd
546168404Spjd	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
547168404Spjd		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
548168404Spjd		    poolname);
549168404Spjd		zpool_close(zhp);
550168404Spjd		return (1);
551168404Spjd	}
552168404Spjd
553331395Smav	if (zpool_is_bootable(zhp))
554331395Smav		boot_type = ZPOOL_COPY_BOOT_LABEL;
555331395Smav	else
556331395Smav		boot_type = ZPOOL_NO_BOOT_LABEL;
557331395Smav
558168404Spjd	/* pass off to get_vdev_spec for processing */
559331395Smav	boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
560185029Spjd	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
561331395Smav	    boot_type, boot_size, argc, argv);
562168404Spjd	if (nvroot == NULL) {
563168404Spjd		zpool_close(zhp);
564168404Spjd		return (1);
565168404Spjd	}
566168404Spjd
567168404Spjd	if (dryrun) {
568168404Spjd		nvlist_t *poolnvroot;
569168404Spjd
570168404Spjd		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
571168404Spjd		    &poolnvroot) == 0);
572168404Spjd
573168404Spjd		(void) printf(gettext("would update '%s' to the following "
574168404Spjd		    "configuration:\n"), zpool_get_name(zhp));
575168404Spjd
576185029Spjd		/* print original main pool and new tree */
577185029Spjd		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
578185029Spjd		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
579168404Spjd
580185029Spjd		/* Do the same for the logs */
581185029Spjd		if (num_logs(poolnvroot) > 0) {
582185029Spjd			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
583185029Spjd			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
584185029Spjd		} else if (num_logs(nvroot) > 0) {
585185029Spjd			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
586185029Spjd		}
587185029Spjd
588168404Spjd		ret = 0;
589168404Spjd	} else {
590168404Spjd		ret = (zpool_add(zhp, nvroot) != 0);
591168404Spjd	}
592168404Spjd
593168404Spjd	nvlist_free(nvroot);
594168404Spjd	zpool_close(zhp);
595168404Spjd
596168404Spjd	return (ret);
597168404Spjd}
598168404Spjd
599168404Spjd/*
600219089Spjd * zpool remove  <pool> <vdev> ...
601168404Spjd *
602332525Smav * Removes the given vdev from the pool.
603168404Spjd */
604168404Spjdint
605168404Spjdzpool_do_remove(int argc, char **argv)
606168404Spjd{
607168404Spjd	char *poolname;
608185029Spjd	int i, ret = 0;
609168404Spjd	zpool_handle_t *zhp;
610332525Smav	boolean_t stop = B_FALSE;
611332525Smav	boolean_t noop = B_FALSE;
612332525Smav	boolean_t parsable = B_FALSE;
613332525Smav	char c;
614168404Spjd
615332525Smav	/* check options */
616332525Smav	while ((c = getopt(argc, argv, "nps")) != -1) {
617332525Smav		switch (c) {
618332525Smav		case 'n':
619332525Smav			noop = B_TRUE;
620332525Smav			break;
621332525Smav		case 'p':
622332525Smav			parsable = B_TRUE;
623332525Smav			break;
624332525Smav		case 's':
625332525Smav			stop = B_TRUE;
626332525Smav			break;
627332525Smav		case '?':
628332525Smav			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
629332525Smav			    optopt);
630332525Smav			usage(B_FALSE);
631332525Smav		}
632332525Smav	}
633168404Spjd
634332525Smav	argc -= optind;
635332525Smav	argv += optind;
636332525Smav
637168404Spjd	/* get pool name and check number of arguments */
638168404Spjd	if (argc < 1) {
639168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
640168404Spjd		usage(B_FALSE);
641168404Spjd	}
642168404Spjd
643168404Spjd	poolname = argv[0];
644168404Spjd
645168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
646168404Spjd		return (1);
647168404Spjd
648332525Smav	if (stop && noop) {
649332525Smav		(void) fprintf(stderr, gettext("stop request ignored\n"));
650332525Smav		return (0);
651332525Smav	}
652332525Smav
653332525Smav	if (stop) {
654332525Smav		if (argc > 1) {
655332525Smav			(void) fprintf(stderr, gettext("too many arguments\n"));
656332525Smav			usage(B_FALSE);
657332525Smav		}
658332525Smav		if (zpool_vdev_remove_cancel(zhp) != 0)
659185029Spjd			ret = 1;
660332525Smav	} else {
661332525Smav		if (argc < 2) {
662332525Smav			(void) fprintf(stderr, gettext("missing device\n"));
663332525Smav			usage(B_FALSE);
664332525Smav		}
665332525Smav
666332525Smav		for (i = 1; i < argc; i++) {
667332525Smav			if (noop) {
668332525Smav				uint64_t size;
669332525Smav
670332525Smav				if (zpool_vdev_indirect_size(zhp, argv[i],
671332525Smav				    &size) != 0) {
672332525Smav					ret = 1;
673332525Smav					break;
674332525Smav				}
675332525Smav				if (parsable) {
676332525Smav					(void) printf("%s %llu\n",
677332525Smav					    argv[i], size);
678332525Smav				} else {
679332525Smav					char valstr[32];
680332525Smav					zfs_nicenum(size, valstr,
681332525Smav					    sizeof (valstr));
682332525Smav					(void) printf("Memory that will be "
683332525Smav					    "used after removing %s: %s\n",
684332525Smav					    argv[i], valstr);
685332525Smav				}
686332525Smav			} else {
687332525Smav				if (zpool_vdev_remove(zhp, argv[i]) != 0)
688332525Smav					ret = 1;
689332525Smav			}
690332525Smav		}
691168404Spjd	}
692168404Spjd
693168404Spjd	return (ret);
694168404Spjd}
695168404Spjd
696168404Spjd/*
697297763Smav * zpool labelclear [-f] <vdev>
698224171Sgibbs *
699297763Smav *	-f	Force clearing the label for the vdevs which are members of
700297763Smav *		the exported or foreign pools.
701297763Smav *
702224171Sgibbs * Verifies that the vdev is not active and zeros out the label information
703224171Sgibbs * on the device.
704224171Sgibbs */
705224171Sgibbsint
706224171Sgibbszpool_do_labelclear(int argc, char **argv)
707224171Sgibbs{
708297763Smav	char vdev[MAXPATHLEN];
709297763Smav	char *name = NULL;
710297763Smav	struct stat st;
711297763Smav	int c, fd, ret = 0;
712297763Smav	nvlist_t *config;
713224171Sgibbs	pool_state_t state;
714224171Sgibbs	boolean_t inuse = B_FALSE;
715224171Sgibbs	boolean_t force = B_FALSE;
716224171Sgibbs
717224171Sgibbs	/* check options */
718224171Sgibbs	while ((c = getopt(argc, argv, "f")) != -1) {
719224171Sgibbs		switch (c) {
720224171Sgibbs		case 'f':
721224171Sgibbs			force = B_TRUE;
722224171Sgibbs			break;
723224171Sgibbs		default:
724224171Sgibbs			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
725224171Sgibbs			    optopt);
726224171Sgibbs			usage(B_FALSE);
727224171Sgibbs		}
728224171Sgibbs	}
729224171Sgibbs
730224171Sgibbs	argc -= optind;
731224171Sgibbs	argv += optind;
732224171Sgibbs
733224171Sgibbs	/* get vdev name */
734224171Sgibbs	if (argc < 1) {
735297763Smav		(void) fprintf(stderr, gettext("missing vdev name\n"));
736224171Sgibbs		usage(B_FALSE);
737224171Sgibbs	}
738297763Smav	if (argc > 1) {
739297763Smav		(void) fprintf(stderr, gettext("too many arguments\n"));
740297763Smav		usage(B_FALSE);
741297763Smav	}
742224171Sgibbs
743297763Smav	/*
744297763Smav	 * Check if we were given absolute path and use it as is.
745297763Smav	 * Otherwise if the provided vdev name doesn't point to a file,
746297763Smav	 * try prepending dsk path and appending s0.
747297763Smav	 */
748297763Smav	(void) strlcpy(vdev, argv[0], sizeof (vdev));
749297763Smav	if (vdev[0] != '/' && stat(vdev, &st) != 0) {
750297763Smav		char *s;
751297763Smav
752297763Smav		(void) snprintf(vdev, sizeof (vdev), "%s/%s",
753297763Smav#ifdef illumos
754297763Smav		    ZFS_DISK_ROOT, argv[0]);
755297763Smav		if ((s = strrchr(argv[0], 's')) == NULL ||
756297763Smav		    !isdigit(*(s + 1)))
757297763Smav			(void) strlcat(vdev, "s0", sizeof (vdev));
758297763Smav#else
759297763Smav		    "/dev", argv[0]);
760297763Smav#endif
761297763Smav		if (stat(vdev, &st) != 0) {
762297763Smav			(void) fprintf(stderr, gettext(
763297763Smav			    "failed to find device %s, try specifying absolute "
764297763Smav			    "path instead\n"), argv[0]);
765297763Smav			return (1);
766297763Smav		}
767297763Smav	}
768297763Smav
769224171Sgibbs	if ((fd = open(vdev, O_RDWR)) < 0) {
770297763Smav		(void) fprintf(stderr, gettext("failed to open %s: %s\n"),
771297763Smav		    vdev, strerror(errno));
772297763Smav		return (1);
773224171Sgibbs	}
774224171Sgibbs
775324255Savg	if (zpool_read_label(fd, &config) != 0) {
776224171Sgibbs		(void) fprintf(stderr,
777297763Smav		    gettext("failed to read label from %s\n"), vdev);
778297763Smav		return (1);
779297763Smav	}
780297763Smav	nvlist_free(config);
781224171Sgibbs
782297763Smav	ret = zpool_in_use(g_zfs, fd, &state, &name, &inuse);
783297763Smav	if (ret != 0) {
784297763Smav		(void) fprintf(stderr,
785297763Smav		    gettext("failed to check state for %s\n"), vdev);
786224171Sgibbs		return (1);
787224171Sgibbs	}
788224171Sgibbs
789297763Smav	if (!inuse)
790297763Smav		goto wipe_label;
791224171Sgibbs
792297763Smav	switch (state) {
793297763Smav	default:
794297763Smav	case POOL_STATE_ACTIVE:
795297763Smav	case POOL_STATE_SPARE:
796297763Smav	case POOL_STATE_L2CACHE:
797297763Smav		(void) fprintf(stderr, gettext(
798297763Smav		    "%s is a member (%s) of pool \"%s\"\n"),
799297763Smav		    vdev, zpool_pool_state_to_name(state), name);
800297763Smav		ret = 1;
801297763Smav		goto errout;
802224171Sgibbs
803297763Smav	case POOL_STATE_EXPORTED:
804297763Smav		if (force)
805297763Smav			break;
806297763Smav		(void) fprintf(stderr, gettext(
807297763Smav		    "use '-f' to override the following error:\n"
808297763Smav		    "%s is a member of exported pool \"%s\"\n"),
809297763Smav		    vdev, name);
810297763Smav		ret = 1;
811297763Smav		goto errout;
812224171Sgibbs
813297763Smav	case POOL_STATE_POTENTIALLY_ACTIVE:
814297763Smav		if (force)
815297763Smav			break;
816297763Smav		(void) fprintf(stderr, gettext(
817297763Smav		    "use '-f' to override the following error:\n"
818297763Smav		    "%s is a member of potentially active pool \"%s\"\n"),
819297763Smav		    vdev, name);
820297763Smav		ret = 1;
821297763Smav		goto errout;
822224171Sgibbs
823297763Smav	case POOL_STATE_DESTROYED:
824297763Smav		/* inuse should never be set for a destroyed pool */
825297763Smav		assert(0);
826297763Smav		break;
827224171Sgibbs	}
828224171Sgibbs
829224171Sgibbswipe_label:
830297763Smav	ret = zpool_clear_label(fd);
831297763Smav	if (ret != 0) {
832224171Sgibbs		(void) fprintf(stderr,
833297763Smav		    gettext("failed to clear label for %s\n"), vdev);
834224171Sgibbs	}
835224171Sgibbs
836224171Sgibbserrout:
837297763Smav	free(name);
838297763Smav	(void) close(fd);
839224171Sgibbs
840224171Sgibbs	return (ret);
841224171Sgibbs}
842224171Sgibbs
843224171Sgibbs/*
844331395Smav * zpool create [-fnd] [-B] [-o property=value] ...
845185029Spjd *		[-O file-system-property=value] ...
846185029Spjd *		[-R root] [-m mountpoint] <pool> <dev> ...
847168404Spjd *
848331395Smav *	-B	Create boot partition.
849168404Spjd *	-f	Force creation, even if devices appear in use
850168404Spjd *	-n	Do not create the pool, but display the resulting layout if it
851168404Spjd *		were to be created.
852168404Spjd *      -R	Create a pool under an alternate root
853168404Spjd *      -m	Set default mountpoint for the root dataset.  By default it's
854236884Smm *		'/<pool>'
855185029Spjd *	-o	Set property=value.
856236884Smm *	-d	Don't automatically enable all supported pool features
857236884Smm *		(individual features can be enabled with -o).
858185029Spjd *	-O	Set fsproperty=value in the pool's root file system
859168404Spjd *
860168404Spjd * Creates the named pool according to the given vdev specification.  The
861168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
862168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents
863168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation.
864168404Spjd */
865331395Smav
866331395Smav#define	SYSTEM256	(256 * 1024 * 1024)
867168404Spjdint
868168404Spjdzpool_do_create(int argc, char **argv)
869168404Spjd{
870168404Spjd	boolean_t force = B_FALSE;
871168404Spjd	boolean_t dryrun = B_FALSE;
872236884Smm	boolean_t enable_all_pool_feat = B_TRUE;
873331395Smav	zpool_boot_label_t boot_type = ZPOOL_NO_BOOT_LABEL;
874331395Smav	uint64_t boot_size = 0;
875168404Spjd	int c;
876185029Spjd	nvlist_t *nvroot = NULL;
877168404Spjd	char *poolname;
878185029Spjd	int ret = 1;
879168404Spjd	char *altroot = NULL;
880168404Spjd	char *mountpoint = NULL;
881185029Spjd	nvlist_t *fsprops = NULL;
882185029Spjd	nvlist_t *props = NULL;
883185029Spjd	char *propval;
884168404Spjd
885168404Spjd	/* check options */
886331395Smav	while ((c = getopt(argc, argv, ":fndBR:m:o:O:")) != -1) {
887168404Spjd		switch (c) {
888168404Spjd		case 'f':
889168404Spjd			force = B_TRUE;
890168404Spjd			break;
891168404Spjd		case 'n':
892168404Spjd			dryrun = B_TRUE;
893168404Spjd			break;
894236884Smm		case 'd':
895236884Smm			enable_all_pool_feat = B_FALSE;
896236884Smm			break;
897331395Smav		case 'B':
898331395Smav#ifdef illumos
899331395Smav			/*
900331395Smav			 * We should create the system partition.
901331395Smav			 * Also make sure the size is set.
902331395Smav			 */
903331395Smav			boot_type = ZPOOL_CREATE_BOOT_LABEL;
904331395Smav			if (boot_size == 0)
905331395Smav				boot_size = SYSTEM256;
906331395Smav			break;
907331395Smav#else
908331395Smav			(void) fprintf(stderr,
909331395Smav			    gettext("option '%c' is not supported\n"),
910331395Smav			    optopt);
911331395Smav			goto badusage;
912331395Smav#endif
913168404Spjd		case 'R':
914168404Spjd			altroot = optarg;
915185029Spjd			if (add_prop_list(zpool_prop_to_name(
916185029Spjd			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
917185029Spjd				goto errout;
918185029Spjd			if (nvlist_lookup_string(props,
919185029Spjd			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
920185029Spjd			    &propval) == 0)
921185029Spjd				break;
922185029Spjd			if (add_prop_list(zpool_prop_to_name(
923185029Spjd			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
924185029Spjd				goto errout;
925168404Spjd			break;
926168404Spjd		case 'm':
927251634Sdelphij			/* Equivalent to -O mountpoint=optarg */
928168404Spjd			mountpoint = optarg;
929168404Spjd			break;
930185029Spjd		case 'o':
931185029Spjd			if ((propval = strchr(optarg, '=')) == NULL) {
932185029Spjd				(void) fprintf(stderr, gettext("missing "
933185029Spjd				    "'=' for -o option\n"));
934185029Spjd				goto errout;
935185029Spjd			}
936185029Spjd			*propval = '\0';
937185029Spjd			propval++;
938185029Spjd
939185029Spjd			if (add_prop_list(optarg, propval, &props, B_TRUE))
940185029Spjd				goto errout;
941236884Smm
942236884Smm			/*
943331395Smav			 * Get bootsize value for make_root_vdev().
944331395Smav			 */
945331395Smav			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_BOOTSIZE) {
946331395Smav				if (zfs_nicestrtonum(g_zfs, propval,
947331395Smav				    &boot_size) < 0 || boot_size == 0) {
948331395Smav					(void) fprintf(stderr,
949331395Smav					    gettext("bad boot partition size "
950331395Smav					    "'%s': %s\n"),  propval,
951331395Smav					    libzfs_error_description(g_zfs));
952331395Smav					goto errout;
953331395Smav				}
954331395Smav			}
955331395Smav
956331395Smav			/*
957236884Smm			 * If the user is creating a pool that doesn't support
958236884Smm			 * feature flags, don't enable any features.
959236884Smm			 */
960236884Smm			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) {
961236884Smm				char *end;
962236884Smm				u_longlong_t ver;
963236884Smm
964236884Smm				ver = strtoull(propval, &end, 10);
965236884Smm				if (*end == '\0' &&
966236884Smm				    ver < SPA_VERSION_FEATURES) {
967236884Smm					enable_all_pool_feat = B_FALSE;
968236884Smm				}
969236884Smm			}
970279366Sdelphij			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT)
971279366Sdelphij				altroot = propval;
972185029Spjd			break;
973185029Spjd		case 'O':
974185029Spjd			if ((propval = strchr(optarg, '=')) == NULL) {
975185029Spjd				(void) fprintf(stderr, gettext("missing "
976185029Spjd				    "'=' for -O option\n"));
977185029Spjd				goto errout;
978185029Spjd			}
979185029Spjd			*propval = '\0';
980185029Spjd			propval++;
981185029Spjd
982251634Sdelphij			/*
983251634Sdelphij			 * Mountpoints are checked and then added later.
984251634Sdelphij			 * Uniquely among properties, they can be specified
985251634Sdelphij			 * more than once, to avoid conflict with -m.
986251634Sdelphij			 */
987251634Sdelphij			if (0 == strcmp(optarg,
988251634Sdelphij			    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) {
989251634Sdelphij				mountpoint = propval;
990251634Sdelphij			} else if (add_prop_list(optarg, propval, &fsprops,
991251634Sdelphij			    B_FALSE)) {
992185029Spjd				goto errout;
993251634Sdelphij			}
994185029Spjd			break;
995168404Spjd		case ':':
996168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
997168404Spjd			    "'%c' option\n"), optopt);
998185029Spjd			goto badusage;
999168404Spjd		case '?':
1000168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1001168404Spjd			    optopt);
1002185029Spjd			goto badusage;
1003168404Spjd		}
1004168404Spjd	}
1005168404Spjd
1006168404Spjd	argc -= optind;
1007168404Spjd	argv += optind;
1008168404Spjd
1009168404Spjd	/* get pool name and check number of arguments */
1010168404Spjd	if (argc < 1) {
1011168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
1012185029Spjd		goto badusage;
1013168404Spjd	}
1014168404Spjd	if (argc < 2) {
1015168404Spjd		(void) fprintf(stderr, gettext("missing vdev specification\n"));
1016185029Spjd		goto badusage;
1017168404Spjd	}
1018168404Spjd
1019168404Spjd	poolname = argv[0];
1020168404Spjd
1021168404Spjd	/*
1022168404Spjd	 * As a special case, check for use of '/' in the name, and direct the
1023168404Spjd	 * user to use 'zfs create' instead.
1024168404Spjd	 */
1025168404Spjd	if (strchr(poolname, '/') != NULL) {
1026168404Spjd		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
1027168404Spjd		    "character '/' in pool name\n"), poolname);
1028168404Spjd		(void) fprintf(stderr, gettext("use 'zfs create' to "
1029168404Spjd		    "create a dataset\n"));
1030185029Spjd		goto errout;
1031168404Spjd	}
1032168404Spjd
1033331395Smav	/*
1034331395Smav	 * Make sure the bootsize is set when ZPOOL_CREATE_BOOT_LABEL is used,
1035331395Smav	 * and not set otherwise.
1036331395Smav	 */
1037331395Smav	if (boot_type == ZPOOL_CREATE_BOOT_LABEL) {
1038331395Smav		const char *propname;
1039331395Smav		char *strptr, *buf = NULL;
1040331395Smav		int rv;
1041331395Smav
1042331395Smav		propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE);
1043331395Smav		if (nvlist_lookup_string(props, propname, &strptr) != 0) {
1044331395Smav			(void) asprintf(&buf, "%" PRIu64, boot_size);
1045331395Smav			if (buf == NULL) {
1046331395Smav				(void) fprintf(stderr,
1047331395Smav				    gettext("internal error: out of memory\n"));
1048331395Smav				goto errout;
1049331395Smav			}
1050331395Smav			rv = add_prop_list(propname, buf, &props, B_TRUE);
1051331395Smav			free(buf);
1052331395Smav			if (rv != 0)
1053331395Smav				goto errout;
1054331395Smav		}
1055331395Smav	} else {
1056331395Smav		const char *propname;
1057331395Smav		char *strptr;
1058331395Smav
1059331395Smav		propname = zpool_prop_to_name(ZPOOL_PROP_BOOTSIZE);
1060331395Smav		if (nvlist_lookup_string(props, propname, &strptr) == 0) {
1061331395Smav			(void) fprintf(stderr, gettext("error: setting boot "
1062331395Smav			    "partition size requires option '-B'\n"));
1063331395Smav			goto errout;
1064331395Smav		}
1065331395Smav	}
1066331395Smav
1067168404Spjd	/* pass off to get_vdev_spec for bulk processing */
1068185029Spjd	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
1069331395Smav	    boot_type, boot_size, argc - 1, argv + 1);
1070168404Spjd	if (nvroot == NULL)
1071185029Spjd		goto errout;
1072168404Spjd
1073168404Spjd	/* make_root_vdev() allows 0 toplevel children if there are spares */
1074185029Spjd	if (!zfs_allocatable_devs(nvroot)) {
1075168404Spjd		(void) fprintf(stderr, gettext("invalid vdev "
1076168404Spjd		    "specification: at least one toplevel vdev must be "
1077168404Spjd		    "specified\n"));
1078185029Spjd		goto errout;
1079168404Spjd	}
1080168404Spjd
1081168404Spjd	if (altroot != NULL && altroot[0] != '/') {
1082168404Spjd		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
1083168404Spjd		    "must be an absolute path\n"), altroot);
1084185029Spjd		goto errout;
1085168404Spjd	}
1086168404Spjd
1087168404Spjd	/*
1088168404Spjd	 * Check the validity of the mountpoint and direct the user to use the
1089168404Spjd	 * '-m' mountpoint option if it looks like its in use.
1090244857Spjd	 * Ignore the checks if the '-f' option is given.
1091168404Spjd	 */
1092244857Spjd	if (!force && (mountpoint == NULL ||
1093168404Spjd	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
1094244857Spjd	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0))) {
1095168404Spjd		char buf[MAXPATHLEN];
1096185029Spjd		DIR *dirp;
1097168404Spjd
1098168404Spjd		if (mountpoint && mountpoint[0] != '/') {
1099168404Spjd			(void) fprintf(stderr, gettext("invalid mountpoint "
1100168404Spjd			    "'%s': must be an absolute path, 'legacy', or "
1101168404Spjd			    "'none'\n"), mountpoint);
1102185029Spjd			goto errout;
1103168404Spjd		}
1104168404Spjd
1105168404Spjd		if (mountpoint == NULL) {
1106168404Spjd			if (altroot != NULL)
1107168404Spjd				(void) snprintf(buf, sizeof (buf), "%s/%s",
1108168404Spjd				    altroot, poolname);
1109168404Spjd			else
1110168404Spjd				(void) snprintf(buf, sizeof (buf), "/%s",
1111168404Spjd				    poolname);
1112168404Spjd		} else {
1113168404Spjd			if (altroot != NULL)
1114168404Spjd				(void) snprintf(buf, sizeof (buf), "%s%s",
1115168404Spjd				    altroot, mountpoint);
1116168404Spjd			else
1117168404Spjd				(void) snprintf(buf, sizeof (buf), "%s",
1118168404Spjd				    mountpoint);
1119168404Spjd		}
1120168404Spjd
1121185029Spjd		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
1122185029Spjd			(void) fprintf(stderr, gettext("mountpoint '%s' : "
1123185029Spjd			    "%s\n"), buf, strerror(errno));
1124185029Spjd			(void) fprintf(stderr, gettext("use '-m' "
1125185029Spjd			    "option to provide a different default\n"));
1126185029Spjd			goto errout;
1127185029Spjd		} else if (dirp) {
1128185029Spjd			int count = 0;
1129185029Spjd
1130185029Spjd			while (count < 3 && readdir(dirp) != NULL)
1131185029Spjd				count++;
1132185029Spjd			(void) closedir(dirp);
1133185029Spjd
1134185029Spjd			if (count > 2) {
1135168404Spjd				(void) fprintf(stderr, gettext("mountpoint "
1136168404Spjd				    "'%s' exists and is not empty\n"), buf);
1137185029Spjd				(void) fprintf(stderr, gettext("use '-m' "
1138185029Spjd				    "option to provide a "
1139185029Spjd				    "different default\n"));
1140185029Spjd				goto errout;
1141185029Spjd			}
1142168404Spjd		}
1143168404Spjd	}
1144168404Spjd
1145251634Sdelphij	/*
1146251634Sdelphij	 * Now that the mountpoint's validity has been checked, ensure that
1147251634Sdelphij	 * the property is set appropriately prior to creating the pool.
1148251634Sdelphij	 */
1149251634Sdelphij	if (mountpoint != NULL) {
1150251634Sdelphij		ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1151251634Sdelphij		    mountpoint, &fsprops, B_FALSE);
1152251634Sdelphij		if (ret != 0)
1153251634Sdelphij			goto errout;
1154251634Sdelphij	}
1155251634Sdelphij
1156251634Sdelphij	ret = 1;
1157168404Spjd	if (dryrun) {
1158168404Spjd		/*
1159168404Spjd		 * For a dry run invocation, print out a basic message and run
1160168404Spjd		 * through all the vdevs in the list and print out in an
1161168404Spjd		 * appropriate hierarchy.
1162168404Spjd		 */
1163168404Spjd		(void) printf(gettext("would create '%s' with the "
1164168404Spjd		    "following layout:\n\n"), poolname);
1165168404Spjd
1166185029Spjd		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
1167185029Spjd		if (num_logs(nvroot) > 0)
1168185029Spjd			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
1169168404Spjd
1170168404Spjd		ret = 0;
1171168404Spjd	} else {
1172168404Spjd		/*
1173168404Spjd		 * Hand off to libzfs.
1174168404Spjd		 */
1175236884Smm		if (enable_all_pool_feat) {
1176259813Sdelphij			spa_feature_t i;
1177236884Smm			for (i = 0; i < SPA_FEATURES; i++) {
1178236884Smm				char propname[MAXPATHLEN];
1179236884Smm				zfeature_info_t *feat = &spa_feature_table[i];
1180236884Smm
1181236884Smm				(void) snprintf(propname, sizeof (propname),
1182236884Smm				    "feature@%s", feat->fi_uname);
1183236884Smm
1184236884Smm				/*
1185236884Smm				 * Skip feature if user specified it manually
1186236884Smm				 * on the command line.
1187236884Smm				 */
1188236884Smm				if (nvlist_exists(props, propname))
1189236884Smm					continue;
1190236884Smm
1191251634Sdelphij				ret = add_prop_list(propname,
1192251634Sdelphij				    ZFS_FEATURE_ENABLED, &props, B_TRUE);
1193251634Sdelphij				if (ret != 0)
1194236884Smm					goto errout;
1195236884Smm			}
1196236884Smm		}
1197251634Sdelphij
1198251634Sdelphij		ret = 1;
1199185029Spjd		if (zpool_create(g_zfs, poolname,
1200185029Spjd		    nvroot, props, fsprops) == 0) {
1201168404Spjd			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
1202168404Spjd			    ZFS_TYPE_FILESYSTEM);
1203168404Spjd			if (pool != NULL) {
1204168404Spjd				if (zfs_mount(pool, NULL, 0) == 0)
1205185029Spjd					ret = zfs_shareall(pool);
1206168404Spjd				zfs_close(pool);
1207168404Spjd			}
1208168404Spjd		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
1209168404Spjd			(void) fprintf(stderr, gettext("pool name may have "
1210168404Spjd			    "been omitted\n"));
1211168404Spjd		}
1212168404Spjd	}
1213168404Spjd
1214185029Spjderrout:
1215168404Spjd	nvlist_free(nvroot);
1216185029Spjd	nvlist_free(fsprops);
1217185029Spjd	nvlist_free(props);
1218168404Spjd	return (ret);
1219185029Spjdbadusage:
1220185029Spjd	nvlist_free(fsprops);
1221185029Spjd	nvlist_free(props);
1222185029Spjd	usage(B_FALSE);
1223185029Spjd	return (2);
1224168404Spjd}
1225168404Spjd
1226168404Spjd/*
1227168404Spjd * zpool destroy <pool>
1228168404Spjd *
1229168404Spjd * 	-f	Forcefully unmount any datasets
1230168404Spjd *
1231168404Spjd * Destroy the given pool.  Automatically unmounts any datasets in the pool.
1232168404Spjd */
1233168404Spjdint
1234168404Spjdzpool_do_destroy(int argc, char **argv)
1235168404Spjd{
1236168404Spjd	boolean_t force = B_FALSE;
1237168404Spjd	int c;
1238168404Spjd	char *pool;
1239168404Spjd	zpool_handle_t *zhp;
1240168404Spjd	int ret;
1241168404Spjd
1242168404Spjd	/* check options */
1243168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
1244168404Spjd		switch (c) {
1245168404Spjd		case 'f':
1246168404Spjd			force = B_TRUE;
1247168404Spjd			break;
1248168404Spjd		case '?':
1249168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1250168404Spjd			    optopt);
1251168404Spjd			usage(B_FALSE);
1252168404Spjd		}
1253168404Spjd	}
1254168404Spjd
1255168404Spjd	argc -= optind;
1256168404Spjd	argv += optind;
1257168404Spjd
1258168404Spjd	/* check arguments */
1259168404Spjd	if (argc < 1) {
1260168404Spjd		(void) fprintf(stderr, gettext("missing pool argument\n"));
1261168404Spjd		usage(B_FALSE);
1262168404Spjd	}
1263168404Spjd	if (argc > 1) {
1264168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
1265168404Spjd		usage(B_FALSE);
1266168404Spjd	}
1267168404Spjd
1268168404Spjd	pool = argv[0];
1269168404Spjd
1270168404Spjd	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
1271168404Spjd		/*
1272168404Spjd		 * As a special case, check for use of '/' in the name, and
1273168404Spjd		 * direct the user to use 'zfs destroy' instead.
1274168404Spjd		 */
1275168404Spjd		if (strchr(pool, '/') != NULL)
1276168404Spjd			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
1277168404Spjd			    "destroy a dataset\n"));
1278168404Spjd		return (1);
1279168404Spjd	}
1280168404Spjd
1281168404Spjd	if (zpool_disable_datasets(zhp, force) != 0) {
1282168404Spjd		(void) fprintf(stderr, gettext("could not destroy '%s': "
1283168404Spjd		    "could not unmount datasets\n"), zpool_get_name(zhp));
1284168404Spjd		return (1);
1285168404Spjd	}
1286168404Spjd
1287248571Smm	/* The history must be logged as part of the export */
1288248571Smm	log_history = B_FALSE;
1289168404Spjd
1290248571Smm	ret = (zpool_destroy(zhp, history_str) != 0);
1291248571Smm
1292168404Spjd	zpool_close(zhp);
1293168404Spjd
1294168404Spjd	return (ret);
1295168404Spjd}
1296168404Spjd
1297168404Spjd/*
1298168404Spjd * zpool export [-f] <pool> ...
1299168404Spjd *
1300168404Spjd *	-f	Forcefully unmount datasets
1301168404Spjd *
1302168404Spjd * Export the given pools.  By default, the command will attempt to cleanly
1303168404Spjd * unmount any active datasets within the pool.  If the '-f' flag is specified,
1304168404Spjd * then the datasets will be forcefully unmounted.
1305168404Spjd */
1306168404Spjdint
1307168404Spjdzpool_do_export(int argc, char **argv)
1308168404Spjd{
1309168404Spjd	boolean_t force = B_FALSE;
1310207670Smm	boolean_t hardforce = B_FALSE;
1311168404Spjd	int c;
1312168404Spjd	zpool_handle_t *zhp;
1313168404Spjd	int ret;
1314168404Spjd	int i;
1315168404Spjd
1316168404Spjd	/* check options */
1317207670Smm	while ((c = getopt(argc, argv, "fF")) != -1) {
1318168404Spjd		switch (c) {
1319168404Spjd		case 'f':
1320168404Spjd			force = B_TRUE;
1321168404Spjd			break;
1322207670Smm		case 'F':
1323207670Smm			hardforce = B_TRUE;
1324207670Smm			break;
1325168404Spjd		case '?':
1326168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1327168404Spjd			    optopt);
1328168404Spjd			usage(B_FALSE);
1329168404Spjd		}
1330168404Spjd	}
1331168404Spjd
1332168404Spjd	argc -= optind;
1333168404Spjd	argv += optind;
1334168404Spjd
1335168404Spjd	/* check arguments */
1336168404Spjd	if (argc < 1) {
1337168404Spjd		(void) fprintf(stderr, gettext("missing pool argument\n"));
1338168404Spjd		usage(B_FALSE);
1339168404Spjd	}
1340168404Spjd
1341168404Spjd	ret = 0;
1342168404Spjd	for (i = 0; i < argc; i++) {
1343168404Spjd		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
1344168404Spjd			ret = 1;
1345168404Spjd			continue;
1346168404Spjd		}
1347168404Spjd
1348168404Spjd		if (zpool_disable_datasets(zhp, force) != 0) {
1349168404Spjd			ret = 1;
1350168404Spjd			zpool_close(zhp);
1351168404Spjd			continue;
1352168404Spjd		}
1353168404Spjd
1354248571Smm		/* The history must be logged as part of the export */
1355248571Smm		log_history = B_FALSE;
1356248571Smm
1357207670Smm		if (hardforce) {
1358248571Smm			if (zpool_export_force(zhp, history_str) != 0)
1359207670Smm				ret = 1;
1360248571Smm		} else if (zpool_export(zhp, force, history_str) != 0) {
1361168404Spjd			ret = 1;
1362207670Smm		}
1363168404Spjd
1364168404Spjd		zpool_close(zhp);
1365168404Spjd	}
1366168404Spjd
1367168404Spjd	return (ret);
1368168404Spjd}
1369168404Spjd
1370168404Spjd/*
1371168404Spjd * Given a vdev configuration, determine the maximum width needed for the device
1372168404Spjd * name column.
1373168404Spjd */
1374168404Spjdstatic int
1375168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
1376168404Spjd{
1377219089Spjd	char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
1378168404Spjd	nvlist_t **child;
1379168404Spjd	uint_t c, children;
1380168404Spjd	int ret;
1381168404Spjd
1382168404Spjd	if (strlen(name) + depth > max)
1383168404Spjd		max = strlen(name) + depth;
1384168404Spjd
1385168404Spjd	free(name);
1386168404Spjd
1387168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1388168404Spjd	    &child, &children) == 0) {
1389168404Spjd		for (c = 0; c < children; c++)
1390168404Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
1391168404Spjd			    max)) > max)
1392168404Spjd				max = ret;
1393168404Spjd	}
1394168404Spjd
1395185029Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1396185029Spjd	    &child, &children) == 0) {
1397185029Spjd		for (c = 0; c < children; c++)
1398185029Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
1399185029Spjd			    max)) > max)
1400185029Spjd				max = ret;
1401185029Spjd	}
1402185029Spjd
1403168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1404168404Spjd	    &child, &children) == 0) {
1405168404Spjd		for (c = 0; c < children; c++)
1406168404Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
1407168404Spjd			    max)) > max)
1408168404Spjd				max = ret;
1409168404Spjd	}
1410168404Spjd
1411168404Spjd
1412168404Spjd	return (max);
1413168404Spjd}
1414168404Spjd
1415213197Smmtypedef struct spare_cbdata {
1416213197Smm	uint64_t	cb_guid;
1417213197Smm	zpool_handle_t	*cb_zhp;
1418213197Smm} spare_cbdata_t;
1419168404Spjd
1420213197Smmstatic boolean_t
1421213197Smmfind_vdev(nvlist_t *nv, uint64_t search)
1422213197Smm{
1423213197Smm	uint64_t guid;
1424213197Smm	nvlist_t **child;
1425213197Smm	uint_t c, children;
1426213197Smm
1427213197Smm	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
1428213197Smm	    search == guid)
1429213197Smm		return (B_TRUE);
1430213197Smm
1431213197Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1432213197Smm	    &child, &children) == 0) {
1433213197Smm		for (c = 0; c < children; c++)
1434213197Smm			if (find_vdev(child[c], search))
1435213197Smm				return (B_TRUE);
1436213197Smm	}
1437213197Smm
1438213197Smm	return (B_FALSE);
1439213197Smm}
1440213197Smm
1441213197Smmstatic int
1442213197Smmfind_spare(zpool_handle_t *zhp, void *data)
1443213197Smm{
1444213197Smm	spare_cbdata_t *cbp = data;
1445213197Smm	nvlist_t *config, *nvroot;
1446213197Smm
1447213197Smm	config = zpool_get_config(zhp, NULL);
1448213197Smm	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1449213197Smm	    &nvroot) == 0);
1450213197Smm
1451213197Smm	if (find_vdev(nvroot, cbp->cb_guid)) {
1452213197Smm		cbp->cb_zhp = zhp;
1453213197Smm		return (1);
1454213197Smm	}
1455213197Smm
1456213197Smm	zpool_close(zhp);
1457213197Smm	return (0);
1458213197Smm}
1459213197Smm
1460168404Spjd/*
1461213197Smm * Print out configuration state as requested by status_callback.
1462213197Smm */
1463213197Smmvoid
1464213197Smmprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
1465213197Smm    int namewidth, int depth, boolean_t isspare)
1466213197Smm{
1467213197Smm	nvlist_t **child;
1468254591Sgibbs	uint_t c, vsc, children;
1469219089Spjd	pool_scan_stat_t *ps = NULL;
1470213197Smm	vdev_stat_t *vs;
1471219089Spjd	char rbuf[6], wbuf[6], cbuf[6];
1472213197Smm	char *vname;
1473213197Smm	uint64_t notpresent;
1474254591Sgibbs	uint64_t ashift;
1475213197Smm	spare_cbdata_t cb;
1476224169Sgibbs	const char *state;
1477332525Smav	char *type;
1478213197Smm
1479213197Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1480213197Smm	    &child, &children) != 0)
1481213197Smm		children = 0;
1482213197Smm
1483219089Spjd	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1484254591Sgibbs	    (uint64_t **)&vs, &vsc) == 0);
1485219089Spjd
1486332525Smav	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
1487332525Smav
1488332525Smav	if (strcmp(type, VDEV_TYPE_INDIRECT) == 0)
1489332525Smav		return;
1490332525Smav
1491213197Smm	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1492213197Smm	if (isspare) {
1493213197Smm		/*
1494213197Smm		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
1495213197Smm		 * online drives.
1496213197Smm		 */
1497213197Smm		if (vs->vs_aux == VDEV_AUX_SPARED)
1498213197Smm			state = "INUSE";
1499213197Smm		else if (vs->vs_state == VDEV_STATE_HEALTHY)
1500213197Smm			state = "AVAIL";
1501213197Smm	}
1502213197Smm
1503213197Smm	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
1504213197Smm	    name, state);
1505213197Smm
1506213197Smm	if (!isspare) {
1507213197Smm		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
1508213197Smm		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
1509213197Smm		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
1510213197Smm		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
1511213197Smm	}
1512213197Smm
1513213197Smm	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1514224170Sgibbs	    &notpresent) == 0 ||
1515224170Sgibbs	    vs->vs_state <= VDEV_STATE_CANT_OPEN) {
1516213197Smm		char *path;
1517224170Sgibbs		if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0)
1518224170Sgibbs			(void) printf("  was %s", path);
1519213197Smm	} else if (vs->vs_aux != 0) {
1520213197Smm		(void) printf("  ");
1521213197Smm
1522213197Smm		switch (vs->vs_aux) {
1523213197Smm		case VDEV_AUX_OPEN_FAILED:
1524213197Smm			(void) printf(gettext("cannot open"));
1525213197Smm			break;
1526213197Smm
1527213197Smm		case VDEV_AUX_BAD_GUID_SUM:
1528213197Smm			(void) printf(gettext("missing device"));
1529213197Smm			break;
1530213197Smm
1531213197Smm		case VDEV_AUX_NO_REPLICAS:
1532213197Smm			(void) printf(gettext("insufficient replicas"));
1533213197Smm			break;
1534213197Smm
1535213197Smm		case VDEV_AUX_VERSION_NEWER:
1536213197Smm			(void) printf(gettext("newer version"));
1537213197Smm			break;
1538213197Smm
1539236884Smm		case VDEV_AUX_UNSUP_FEAT:
1540236884Smm			(void) printf(gettext("unsupported feature(s)"));
1541236884Smm			break;
1542236884Smm
1543254591Sgibbs		case VDEV_AUX_ASHIFT_TOO_BIG:
1544254591Sgibbs			(void) printf(gettext("unsupported minimum blocksize"));
1545254591Sgibbs			break;
1546254591Sgibbs
1547213197Smm		case VDEV_AUX_SPARED:
1548213197Smm			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1549213197Smm			    &cb.cb_guid) == 0);
1550213197Smm			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
1551213197Smm				if (strcmp(zpool_get_name(cb.cb_zhp),
1552213197Smm				    zpool_get_name(zhp)) == 0)
1553213197Smm					(void) printf(gettext("currently in "
1554213197Smm					    "use"));
1555213197Smm				else
1556213197Smm					(void) printf(gettext("in use by "
1557213197Smm					    "pool '%s'"),
1558213197Smm					    zpool_get_name(cb.cb_zhp));
1559213197Smm				zpool_close(cb.cb_zhp);
1560213197Smm			} else {
1561213197Smm				(void) printf(gettext("currently in use"));
1562213197Smm			}
1563213197Smm			break;
1564213197Smm
1565213197Smm		case VDEV_AUX_ERR_EXCEEDED:
1566213197Smm			(void) printf(gettext("too many errors"));
1567213197Smm			break;
1568213197Smm
1569213197Smm		case VDEV_AUX_IO_FAILURE:
1570213197Smm			(void) printf(gettext("experienced I/O failures"));
1571213197Smm			break;
1572213197Smm
1573213197Smm		case VDEV_AUX_BAD_LOG:
1574213197Smm			(void) printf(gettext("bad intent log"));
1575213197Smm			break;
1576213197Smm
1577219089Spjd		case VDEV_AUX_EXTERNAL:
1578219089Spjd			(void) printf(gettext("external device fault"));
1579219089Spjd			break;
1580219089Spjd
1581219089Spjd		case VDEV_AUX_SPLIT_POOL:
1582219089Spjd			(void) printf(gettext("split into new pool"));
1583219089Spjd			break;
1584219089Spjd
1585213197Smm		default:
1586213197Smm			(void) printf(gettext("corrupted data"));
1587213197Smm			break;
1588213197Smm		}
1589254591Sgibbs	} else if (children == 0 && !isspare &&
1590254591Sgibbs	    VDEV_STAT_VALID(vs_physical_ashift, vsc) &&
1591254591Sgibbs	    vs->vs_configured_ashift < vs->vs_physical_ashift) {
1592254591Sgibbs		(void) printf(
1593254591Sgibbs		    gettext("  block size: %dB configured, %dB native"),
1594254591Sgibbs		    1 << vs->vs_configured_ashift, 1 << vs->vs_physical_ashift);
1595213197Smm	}
1596213197Smm
1597219089Spjd	(void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS,
1598219089Spjd	    (uint64_t **)&ps, &c);
1599219089Spjd
1600219089Spjd	if (ps && ps->pss_state == DSS_SCANNING &&
1601219089Spjd	    vs->vs_scan_processed != 0 && children == 0) {
1602219089Spjd		(void) printf(gettext("  (%s)"),
1603219089Spjd		    (ps->pss_func == POOL_SCAN_RESILVER) ?
1604219089Spjd		    "resilvering" : "repairing");
1605219089Spjd	}
1606219089Spjd
1607213197Smm	(void) printf("\n");
1608213197Smm
1609213197Smm	for (c = 0; c < children; c++) {
1610219089Spjd		uint64_t islog = B_FALSE, ishole = B_FALSE;
1611213197Smm
1612219089Spjd		/* Don't print logs or holes here */
1613213197Smm		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1614219089Spjd		    &islog);
1615219089Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
1616219089Spjd		    &ishole);
1617219089Spjd		if (islog || ishole)
1618213197Smm			continue;
1619219089Spjd		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1620213197Smm		print_status_config(zhp, vname, child[c],
1621213197Smm		    namewidth, depth + 2, isspare);
1622213197Smm		free(vname);
1623213197Smm	}
1624213197Smm}
1625213197Smm
1626213197Smm
1627213197Smm/*
1628168404Spjd * Print the configuration of an exported pool.  Iterate over all vdevs in the
1629168404Spjd * pool, printing out the name and status for each one.
1630168404Spjd */
1631168404Spjdvoid
1632213197Smmprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
1633168404Spjd{
1634168404Spjd	nvlist_t **child;
1635168404Spjd	uint_t c, children;
1636168404Spjd	vdev_stat_t *vs;
1637168404Spjd	char *type, *vname;
1638168404Spjd
1639168404Spjd	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
1640219089Spjd	if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
1641219089Spjd	    strcmp(type, VDEV_TYPE_HOLE) == 0)
1642168404Spjd		return;
1643168404Spjd
1644219089Spjd	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
1645168404Spjd	    (uint64_t **)&vs, &c) == 0);
1646168404Spjd
1647168404Spjd	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
1648185029Spjd	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
1649168404Spjd
1650168404Spjd	if (vs->vs_aux != 0) {
1651185029Spjd		(void) printf("  ");
1652168404Spjd
1653168404Spjd		switch (vs->vs_aux) {
1654168404Spjd		case VDEV_AUX_OPEN_FAILED:
1655168404Spjd			(void) printf(gettext("cannot open"));
1656168404Spjd			break;
1657168404Spjd
1658168404Spjd		case VDEV_AUX_BAD_GUID_SUM:
1659168404Spjd			(void) printf(gettext("missing device"));
1660168404Spjd			break;
1661168404Spjd
1662168404Spjd		case VDEV_AUX_NO_REPLICAS:
1663168404Spjd			(void) printf(gettext("insufficient replicas"));
1664168404Spjd			break;
1665168404Spjd
1666168404Spjd		case VDEV_AUX_VERSION_NEWER:
1667168404Spjd			(void) printf(gettext("newer version"));
1668168404Spjd			break;
1669168404Spjd
1670236884Smm		case VDEV_AUX_UNSUP_FEAT:
1671236884Smm			(void) printf(gettext("unsupported feature(s)"));
1672236884Smm			break;
1673236884Smm
1674185029Spjd		case VDEV_AUX_ERR_EXCEEDED:
1675185029Spjd			(void) printf(gettext("too many errors"));
1676185029Spjd			break;
1677185029Spjd
1678168404Spjd		default:
1679168404Spjd			(void) printf(gettext("corrupted data"));
1680168404Spjd			break;
1681168404Spjd		}
1682168404Spjd	}
1683168404Spjd	(void) printf("\n");
1684168404Spjd
1685168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1686168404Spjd	    &child, &children) != 0)
1687168404Spjd		return;
1688168404Spjd
1689168404Spjd	for (c = 0; c < children; c++) {
1690185029Spjd		uint64_t is_log = B_FALSE;
1691185029Spjd
1692185029Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1693185029Spjd		    &is_log);
1694213197Smm		if (is_log)
1695185029Spjd			continue;
1696185029Spjd
1697219089Spjd		vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
1698213197Smm		print_import_config(vname, child[c], namewidth, depth + 2);
1699168404Spjd		free(vname);
1700168404Spjd	}
1701168404Spjd
1702185029Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1703185029Spjd	    &child, &children) == 0) {
1704185029Spjd		(void) printf(gettext("\tcache\n"));
1705185029Spjd		for (c = 0; c < children; c++) {
1706219089Spjd			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1707185029Spjd			(void) printf("\t  %s\n", vname);
1708185029Spjd			free(vname);
1709185029Spjd		}
1710185029Spjd	}
1711185029Spjd
1712168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1713185029Spjd	    &child, &children) == 0) {
1714185029Spjd		(void) printf(gettext("\tspares\n"));
1715185029Spjd		for (c = 0; c < children; c++) {
1716219089Spjd			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
1717185029Spjd			(void) printf("\t  %s\n", vname);
1718185029Spjd			free(vname);
1719185029Spjd		}
1720168404Spjd	}
1721168404Spjd}
1722168404Spjd
1723168404Spjd/*
1724213197Smm * Print log vdevs.
1725213197Smm * Logs are recorded as top level vdevs in the main pool child array
1726213197Smm * but with "is_log" set to 1. We use either print_status_config() or
1727213197Smm * print_import_config() to print the top level logs then any log
1728213197Smm * children (eg mirrored slogs) are printed recursively - which
1729213197Smm * works because only the top level vdev is marked "is_log"
1730213197Smm */
1731213197Smmstatic void
1732213197Smmprint_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
1733213197Smm{
1734213197Smm	uint_t c, children;
1735213197Smm	nvlist_t **child;
1736213197Smm
1737213197Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1738213197Smm	    &children) != 0)
1739213197Smm		return;
1740213197Smm
1741213197Smm	(void) printf(gettext("\tlogs\n"));
1742213197Smm
1743213197Smm	for (c = 0; c < children; c++) {
1744213197Smm		uint64_t is_log = B_FALSE;
1745213197Smm		char *name;
1746213197Smm
1747213197Smm		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1748213197Smm		    &is_log);
1749213197Smm		if (!is_log)
1750213197Smm			continue;
1751219089Spjd		name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
1752213197Smm		if (verbose)
1753213197Smm			print_status_config(zhp, name, child[c], namewidth,
1754213197Smm			    2, B_FALSE);
1755213197Smm		else
1756213197Smm			print_import_config(name, child[c], namewidth, 2);
1757213197Smm		free(name);
1758213197Smm	}
1759213197Smm}
1760219089Spjd
1761213197Smm/*
1762168404Spjd * Display the status for the given pool.
1763168404Spjd */
1764168404Spjdstatic void
1765168404Spjdshow_import(nvlist_t *config)
1766168404Spjd{
1767168404Spjd	uint64_t pool_state;
1768168404Spjd	vdev_stat_t *vs;
1769168404Spjd	char *name;
1770168404Spjd	uint64_t guid;
1771168404Spjd	char *msgid;
1772168404Spjd	nvlist_t *nvroot;
1773168404Spjd	int reason;
1774168404Spjd	const char *health;
1775168404Spjd	uint_t vsc;
1776168404Spjd	int namewidth;
1777228103Smm	char *comment;
1778168404Spjd
1779168404Spjd	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1780168404Spjd	    &name) == 0);
1781168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1782168404Spjd	    &guid) == 0);
1783168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1784168404Spjd	    &pool_state) == 0);
1785168404Spjd	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1786168404Spjd	    &nvroot) == 0);
1787168404Spjd
1788219089Spjd	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
1789168404Spjd	    (uint64_t **)&vs, &vsc) == 0);
1790185029Spjd	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1791168404Spjd
1792168404Spjd	reason = zpool_import_status(config, &msgid);
1793168404Spjd
1794228103Smm	(void) printf(gettext("   pool: %s\n"), name);
1795228103Smm	(void) printf(gettext("     id: %llu\n"), (u_longlong_t)guid);
1796228103Smm	(void) printf(gettext("  state: %s"), health);
1797168404Spjd	if (pool_state == POOL_STATE_DESTROYED)
1798168404Spjd		(void) printf(gettext(" (DESTROYED)"));
1799168404Spjd	(void) printf("\n");
1800168404Spjd
1801168404Spjd	switch (reason) {
1802168404Spjd	case ZPOOL_STATUS_MISSING_DEV_R:
1803168404Spjd	case ZPOOL_STATUS_MISSING_DEV_NR:
1804168404Spjd	case ZPOOL_STATUS_BAD_GUID_SUM:
1805228103Smm		(void) printf(gettext(" status: One or more devices are "
1806228103Smm		    "missing from the system.\n"));
1807168404Spjd		break;
1808168404Spjd
1809168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1810168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1811228103Smm		(void) printf(gettext(" status: One or more devices contains "
1812168404Spjd		    "corrupted data.\n"));
1813168404Spjd		break;
1814168404Spjd
1815168404Spjd	case ZPOOL_STATUS_CORRUPT_DATA:
1816228103Smm		(void) printf(
1817228103Smm		    gettext(" status: The pool data is corrupted.\n"));
1818168404Spjd		break;
1819168404Spjd
1820168404Spjd	case ZPOOL_STATUS_OFFLINE_DEV:
1821228103Smm		(void) printf(gettext(" status: One or more devices "
1822168404Spjd		    "are offlined.\n"));
1823168404Spjd		break;
1824168404Spjd
1825168404Spjd	case ZPOOL_STATUS_CORRUPT_POOL:
1826228103Smm		(void) printf(gettext(" status: The pool metadata is "
1827168404Spjd		    "corrupted.\n"));
1828168404Spjd		break;
1829168404Spjd
1830168404Spjd	case ZPOOL_STATUS_VERSION_OLDER:
1831238926Smm		(void) printf(gettext(" status: The pool is formatted using a "
1832238926Smm		    "legacy on-disk version.\n"));
1833168404Spjd		break;
1834168404Spjd
1835168404Spjd	case ZPOOL_STATUS_VERSION_NEWER:
1836228103Smm		(void) printf(gettext(" status: The pool is formatted using an "
1837168404Spjd		    "incompatible version.\n"));
1838168404Spjd		break;
1839168404Spjd
1840238926Smm	case ZPOOL_STATUS_FEAT_DISABLED:
1841238926Smm		(void) printf(gettext(" status: Some supported features are "
1842238926Smm		    "not enabled on the pool.\n"));
1843238926Smm		break;
1844238926Smm
1845236884Smm	case ZPOOL_STATUS_UNSUP_FEAT_READ:
1846236884Smm		(void) printf(gettext("status: The pool uses the following "
1847236884Smm		    "feature(s) not supported on this sytem:\n"));
1848236884Smm		zpool_print_unsup_feat(config);
1849236884Smm		break;
1850236884Smm
1851236884Smm	case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
1852236884Smm		(void) printf(gettext("status: The pool can only be accessed "
1853236884Smm		    "in read-only mode on this system. It\n\tcannot be "
1854236884Smm		    "accessed in read-write mode because it uses the "
1855236884Smm		    "following\n\tfeature(s) not supported on this system:\n"));
1856236884Smm		zpool_print_unsup_feat(config);
1857236884Smm		break;
1858236884Smm
1859168498Spjd	case ZPOOL_STATUS_HOSTID_MISMATCH:
1860228103Smm		(void) printf(gettext(" status: The pool was last accessed by "
1861168498Spjd		    "another system.\n"));
1862168498Spjd		break;
1863185029Spjd
1864185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_R:
1865185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_NR:
1866228103Smm		(void) printf(gettext(" status: One or more devices are "
1867185029Spjd		    "faulted.\n"));
1868185029Spjd		break;
1869185029Spjd
1870185029Spjd	case ZPOOL_STATUS_BAD_LOG:
1871228103Smm		(void) printf(gettext(" status: An intent log record cannot be "
1872185029Spjd		    "read.\n"));
1873185029Spjd		break;
1874185029Spjd
1875219089Spjd	case ZPOOL_STATUS_RESILVERING:
1876228103Smm		(void) printf(gettext(" status: One or more devices were being "
1877219089Spjd		    "resilvered.\n"));
1878219089Spjd		break;
1879219089Spjd
1880259131Sdelphij	case ZPOOL_STATUS_NON_NATIVE_ASHIFT:
1881259131Sdelphij		(void) printf(gettext("status: One or more devices were "
1882259131Sdelphij		    "configured to use a non-native block size.\n"
1883259131Sdelphij		    "\tExpect reduced performance.\n"));
1884259131Sdelphij		break;
1885259131Sdelphij
1886168404Spjd	default:
1887168404Spjd		/*
1888168404Spjd		 * No other status can be seen when importing pools.
1889168404Spjd		 */
1890168404Spjd		assert(reason == ZPOOL_STATUS_OK);
1891168404Spjd	}
1892168404Spjd
1893168404Spjd	/*
1894168404Spjd	 * Print out an action according to the overall state of the pool.
1895168404Spjd	 */
1896168404Spjd	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1897238926Smm		if (reason == ZPOOL_STATUS_VERSION_OLDER ||
1898238926Smm		    reason == ZPOOL_STATUS_FEAT_DISABLED) {
1899228103Smm			(void) printf(gettext(" action: The pool can be "
1900168404Spjd			    "imported using its name or numeric identifier, "
1901168404Spjd			    "though\n\tsome features will not be available "
1902168404Spjd			    "without an explicit 'zpool upgrade'.\n"));
1903238926Smm		} else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) {
1904228103Smm			(void) printf(gettext(" action: The pool can be "
1905168498Spjd			    "imported using its name or numeric "
1906168498Spjd			    "identifier and\n\tthe '-f' flag.\n"));
1907238926Smm		} else {
1908228103Smm			(void) printf(gettext(" action: The pool can be "
1909168404Spjd			    "imported using its name or numeric "
1910168404Spjd			    "identifier.\n"));
1911238926Smm		}
1912168404Spjd	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1913228103Smm		(void) printf(gettext(" action: The pool can be imported "
1914168404Spjd		    "despite missing or damaged devices.  The\n\tfault "
1915168404Spjd		    "tolerance of the pool may be compromised if imported.\n"));
1916168404Spjd	} else {
1917168404Spjd		switch (reason) {
1918168404Spjd		case ZPOOL_STATUS_VERSION_NEWER:
1919228103Smm			(void) printf(gettext(" action: The pool cannot be "
1920168404Spjd			    "imported.  Access the pool on a system running "
1921168404Spjd			    "newer\n\tsoftware, or recreate the pool from "
1922168404Spjd			    "backup.\n"));
1923168404Spjd			break;
1924236884Smm		case ZPOOL_STATUS_UNSUP_FEAT_READ:
1925236884Smm			(void) printf(gettext("action: The pool cannot be "
1926236884Smm			    "imported. Access the pool on a system that "
1927236884Smm			    "supports\n\tthe required feature(s), or recreate "
1928236884Smm			    "the pool from backup.\n"));
1929236884Smm			break;
1930236884Smm		case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
1931236884Smm			(void) printf(gettext("action: The pool cannot be "
1932236884Smm			    "imported in read-write mode. Import the pool "
1933236884Smm			    "with\n"
1934236884Smm			    "\t\"-o readonly=on\", access the pool on a system "
1935236884Smm			    "that supports the\n\trequired feature(s), or "
1936236884Smm			    "recreate the pool from backup.\n"));
1937236884Smm			break;
1938168404Spjd		case ZPOOL_STATUS_MISSING_DEV_R:
1939168404Spjd		case ZPOOL_STATUS_MISSING_DEV_NR:
1940168404Spjd		case ZPOOL_STATUS_BAD_GUID_SUM:
1941228103Smm			(void) printf(gettext(" action: The pool cannot be "
1942168404Spjd			    "imported. Attach the missing\n\tdevices and try "
1943168404Spjd			    "again.\n"));
1944168404Spjd			break;
1945168404Spjd		default:
1946228103Smm			(void) printf(gettext(" action: The pool cannot be "
1947168404Spjd			    "imported due to damaged devices or data.\n"));
1948168404Spjd		}
1949168404Spjd	}
1950168404Spjd
1951228103Smm	/* Print the comment attached to the pool. */
1952228103Smm	if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
1953228103Smm		(void) printf(gettext("comment: %s\n"), comment);
1954228103Smm
1955168404Spjd	/*
1956168404Spjd	 * If the state is "closed" or "can't open", and the aux state
1957168404Spjd	 * is "corrupt data":
1958168404Spjd	 */
1959168404Spjd	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
1960168404Spjd	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
1961168404Spjd	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1962168404Spjd		if (pool_state == POOL_STATE_DESTROYED)
1963168404Spjd			(void) printf(gettext("\tThe pool was destroyed, "
1964168404Spjd			    "but can be imported using the '-Df' flags.\n"));
1965168404Spjd		else if (pool_state != POOL_STATE_EXPORTED)
1966168404Spjd			(void) printf(gettext("\tThe pool may be active on "
1967185029Spjd			    "another system, but can be imported using\n\t"
1968168404Spjd			    "the '-f' flag.\n"));
1969168404Spjd	}
1970168404Spjd
1971168404Spjd	if (msgid != NULL)
1972236146Smm		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
1973168404Spjd		    msgid);
1974168404Spjd
1975228103Smm	(void) printf(gettext(" config:\n\n"));
1976168404Spjd
1977168404Spjd	namewidth = max_width(NULL, nvroot, 0, 0);
1978168404Spjd	if (namewidth < 10)
1979168404Spjd		namewidth = 10;
1980168404Spjd
1981213197Smm	print_import_config(name, nvroot, namewidth, 0);
1982213197Smm	if (num_logs(nvroot) > 0)
1983213197Smm		print_logs(NULL, nvroot, namewidth, B_FALSE);
1984185029Spjd
1985168404Spjd	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
1986168404Spjd		(void) printf(gettext("\n\tAdditional devices are known to "
1987168404Spjd		    "be part of this pool, though their\n\texact "
1988168404Spjd		    "configuration cannot be determined.\n"));
1989168404Spjd	}
1990168404Spjd}
1991168404Spjd
1992168404Spjd/*
1993168404Spjd * Perform the import for the given configuration.  This passes the heavy
1994185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained
1995185029Spjd * within the pool.
1996168404Spjd */
1997168404Spjdstatic int
1998168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts,
1999219089Spjd    nvlist_t *props, int flags)
2000168404Spjd{
2001168404Spjd	zpool_handle_t *zhp;
2002168404Spjd	char *name;
2003168404Spjd	uint64_t state;
2004168404Spjd	uint64_t version;
2005168404Spjd
2006168404Spjd	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
2007168404Spjd	    &name) == 0);
2008168404Spjd
2009168404Spjd	verify(nvlist_lookup_uint64(config,
2010168404Spjd	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
2011168404Spjd	verify(nvlist_lookup_uint64(config,
2012168404Spjd	    ZPOOL_CONFIG_VERSION, &version) == 0);
2013236884Smm	if (!SPA_VERSION_IS_SUPPORTED(version)) {
2014168404Spjd		(void) fprintf(stderr, gettext("cannot import '%s': pool "
2015236884Smm		    "is formatted using an unsupported ZFS version\n"), name);
2016168404Spjd		return (1);
2017219089Spjd	} else if (state != POOL_STATE_EXPORTED &&
2018219089Spjd	    !(flags & ZFS_IMPORT_ANY_HOST)) {
2019168498Spjd		uint64_t hostid;
2020168498Spjd
2021168498Spjd		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
2022168498Spjd		    &hostid) == 0) {
2023168498Spjd			if ((unsigned long)hostid != gethostid()) {
2024168498Spjd				char *hostname;
2025168498Spjd				uint64_t timestamp;
2026168498Spjd				time_t t;
2027168498Spjd
2028168498Spjd				verify(nvlist_lookup_string(config,
2029168498Spjd				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
2030168498Spjd				verify(nvlist_lookup_uint64(config,
2031168498Spjd				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
2032168498Spjd				t = timestamp;
2033168498Spjd				(void) fprintf(stderr, gettext("cannot import "
2034168498Spjd				    "'%s': pool may be in use from other "
2035168498Spjd				    "system, it was last accessed by %s "
2036168498Spjd				    "(hostid: 0x%lx) on %s"), name, hostname,
2037168498Spjd				    (unsigned long)hostid,
2038168498Spjd				    asctime(localtime(&t)));
2039168498Spjd				(void) fprintf(stderr, gettext("use '-f' to "
2040168498Spjd				    "import anyway\n"));
2041168498Spjd				return (1);
2042168498Spjd			}
2043168498Spjd		} else {
2044168498Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
2045168498Spjd			    "pool may be in use from other system\n"), name);
2046168498Spjd			(void) fprintf(stderr, gettext("use '-f' to import "
2047168498Spjd			    "anyway\n"));
2048168498Spjd			return (1);
2049168498Spjd		}
2050168404Spjd	}
2051168404Spjd
2052219089Spjd	if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
2053168404Spjd		return (1);
2054168404Spjd
2055168404Spjd	if (newname != NULL)
2056168404Spjd		name = (char *)newname;
2057168404Spjd
2058209962Smm	if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
2059209962Smm		return (1);
2060168404Spjd
2061209962Smm	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
2062219089Spjd	    !(flags & ZFS_IMPORT_ONLY) &&
2063209962Smm	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
2064168404Spjd		zpool_close(zhp);
2065168404Spjd		return (1);
2066168404Spjd	}
2067168404Spjd
2068168404Spjd	zpool_close(zhp);
2069219089Spjd	return (0);
2070168404Spjd}
2071168404Spjd
2072168404Spjd/*
2073168404Spjd * zpool import [-d dir] [-D]
2074185029Spjd *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
2075185029Spjd *              [-d dir | -c cachefile] [-f] -a
2076185029Spjd *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
2077219089Spjd *              [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool]
2078168404Spjd *
2079185029Spjd *	 -c	Read pool information from a cachefile instead of searching
2080185029Spjd *		devices.
2081185029Spjd *
2082168404Spjd *       -d	Scan in a specific directory, other than /dev/dsk.  More than
2083168404Spjd *		one directory can be specified using multiple '-d' options.
2084168404Spjd *
2085168404Spjd *       -D     Scan for previously destroyed pools or import all or only
2086168404Spjd *              specified destroyed pools.
2087168404Spjd *
2088168404Spjd *       -R	Temporarily import the pool, with all mountpoints relative to
2089168404Spjd *		the given root.  The pool will remain exported when the machine
2090168404Spjd *		is rebooted.
2091168404Spjd *
2092219089Spjd *       -V	Import even in the presence of faulted vdevs.  This is an
2093185029Spjd *       	intentionally undocumented option for testing purposes, and
2094185029Spjd *       	treats the pool configuration as complete, leaving any bad
2095209962Smm *		vdevs in the FAULTED state. In other words, it does verbatim
2096209962Smm *		import.
2097185029Spjd *
2098219089Spjd *       -f	Force import, even if it appears that the pool is active.
2099219089Spjd *
2100219089Spjd *       -F     Attempt rewind if necessary.
2101219089Spjd *
2102219089Spjd *       -n     See if rewind would work, but don't actually rewind.
2103219089Spjd *
2104219089Spjd *       -N     Import the pool but don't mount datasets.
2105219089Spjd *
2106219089Spjd *       -T     Specify a starting txg to use for import. This option is
2107219089Spjd *       	intentionally undocumented option for testing purposes.
2108219089Spjd *
2109168404Spjd *       -a	Import all pools found.
2110168404Spjd *
2111185029Spjd *       -o	Set property=value and/or temporary mount options (without '=').
2112185029Spjd *
2113168404Spjd * The import command scans for pools to import, and import pools based on pool
2114168404Spjd * name and GUID.  The pool can also be renamed as part of the import process.
2115168404Spjd */
2116168404Spjdint
2117168404Spjdzpool_do_import(int argc, char **argv)
2118168404Spjd{
2119168404Spjd	char **searchdirs = NULL;
2120168404Spjd	int nsearch = 0;
2121168404Spjd	int c;
2122219089Spjd	int err = 0;
2123185029Spjd	nvlist_t *pools = NULL;
2124168404Spjd	boolean_t do_all = B_FALSE;
2125168404Spjd	boolean_t do_destroyed = B_FALSE;
2126168404Spjd	char *mntopts = NULL;
2127168404Spjd	nvpair_t *elem;
2128168404Spjd	nvlist_t *config;
2129185029Spjd	uint64_t searchguid = 0;
2130185029Spjd	char *searchname = NULL;
2131185029Spjd	char *propval;
2132168404Spjd	nvlist_t *found_config;
2133219089Spjd	nvlist_t *policy = NULL;
2134185029Spjd	nvlist_t *props = NULL;
2135168404Spjd	boolean_t first;
2136219089Spjd	int flags = ZFS_IMPORT_NORMAL;
2137219089Spjd	uint32_t rewind_policy = ZPOOL_NO_REWIND;
2138219089Spjd	boolean_t dryrun = B_FALSE;
2139219089Spjd	boolean_t do_rewind = B_FALSE;
2140219089Spjd	boolean_t xtreme_rewind = B_FALSE;
2141219089Spjd	uint64_t pool_state, txg = -1ULL;
2142185029Spjd	char *cachefile = NULL;
2143219089Spjd	importargs_t idata = { 0 };
2144219089Spjd	char *endptr;
2145168404Spjd
2146168404Spjd	/* check options */
2147263385Sdelphij	while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:R:T:VX")) != -1) {
2148168404Spjd		switch (c) {
2149168404Spjd		case 'a':
2150168404Spjd			do_all = B_TRUE;
2151168404Spjd			break;
2152185029Spjd		case 'c':
2153185029Spjd			cachefile = optarg;
2154185029Spjd			break;
2155168404Spjd		case 'd':
2156168404Spjd			if (searchdirs == NULL) {
2157168404Spjd				searchdirs = safe_malloc(sizeof (char *));
2158168404Spjd			} else {
2159168404Spjd				char **tmp = safe_malloc((nsearch + 1) *
2160168404Spjd				    sizeof (char *));
2161168404Spjd				bcopy(searchdirs, tmp, nsearch *
2162168404Spjd				    sizeof (char *));
2163168404Spjd				free(searchdirs);
2164168404Spjd				searchdirs = tmp;
2165168404Spjd			}
2166168404Spjd			searchdirs[nsearch++] = optarg;
2167168404Spjd			break;
2168168404Spjd		case 'D':
2169168404Spjd			do_destroyed = B_TRUE;
2170168404Spjd			break;
2171168404Spjd		case 'f':
2172219089Spjd			flags |= ZFS_IMPORT_ANY_HOST;
2173168404Spjd			break;
2174185029Spjd		case 'F':
2175219089Spjd			do_rewind = B_TRUE;
2176185029Spjd			break;
2177219089Spjd		case 'm':
2178219089Spjd			flags |= ZFS_IMPORT_MISSING_LOG;
2179219089Spjd			break;
2180219089Spjd		case 'n':
2181219089Spjd			dryrun = B_TRUE;
2182219089Spjd			break;
2183219089Spjd		case 'N':
2184219089Spjd			flags |= ZFS_IMPORT_ONLY;
2185219089Spjd			break;
2186168404Spjd		case 'o':
2187185029Spjd			if ((propval = strchr(optarg, '=')) != NULL) {
2188185029Spjd				*propval = '\0';
2189185029Spjd				propval++;
2190185029Spjd				if (add_prop_list(optarg, propval,
2191185029Spjd				    &props, B_TRUE))
2192185029Spjd					goto error;
2193185029Spjd			} else {
2194185029Spjd				mntopts = optarg;
2195185029Spjd			}
2196168404Spjd			break;
2197168404Spjd		case 'R':
2198185029Spjd			if (add_prop_list(zpool_prop_to_name(
2199185029Spjd			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
2200185029Spjd				goto error;
2201185029Spjd			if (nvlist_lookup_string(props,
2202185029Spjd			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
2203185029Spjd			    &propval) == 0)
2204185029Spjd				break;
2205185029Spjd			if (add_prop_list(zpool_prop_to_name(
2206185029Spjd			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
2207185029Spjd				goto error;
2208168404Spjd			break;
2209219089Spjd		case 'T':
2210219089Spjd			errno = 0;
2211268720Sdelphij			txg = strtoull(optarg, &endptr, 0);
2212219089Spjd			if (errno != 0 || *endptr != '\0') {
2213219089Spjd				(void) fprintf(stderr,
2214219089Spjd				    gettext("invalid txg value\n"));
2215219089Spjd				usage(B_FALSE);
2216219089Spjd			}
2217219089Spjd			rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
2218219089Spjd			break;
2219219089Spjd		case 'V':
2220219089Spjd			flags |= ZFS_IMPORT_VERBATIM;
2221219089Spjd			break;
2222219089Spjd		case 'X':
2223219089Spjd			xtreme_rewind = B_TRUE;
2224219089Spjd			break;
2225168404Spjd		case ':':
2226168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
2227168404Spjd			    "'%c' option\n"), optopt);
2228168404Spjd			usage(B_FALSE);
2229168404Spjd			break;
2230168404Spjd		case '?':
2231168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2232168404Spjd			    optopt);
2233168404Spjd			usage(B_FALSE);
2234168404Spjd		}
2235168404Spjd	}
2236168404Spjd
2237168404Spjd	argc -= optind;
2238168404Spjd	argv += optind;
2239168404Spjd
2240185029Spjd	if (cachefile && nsearch != 0) {
2241185029Spjd		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
2242185029Spjd		usage(B_FALSE);
2243185029Spjd	}
2244185029Spjd
2245219089Spjd	if ((dryrun || xtreme_rewind) && !do_rewind) {
2246219089Spjd		(void) fprintf(stderr,
2247219089Spjd		    gettext("-n or -X only meaningful with -F\n"));
2248219089Spjd		usage(B_FALSE);
2249219089Spjd	}
2250219089Spjd	if (dryrun)
2251219089Spjd		rewind_policy = ZPOOL_TRY_REWIND;
2252219089Spjd	else if (do_rewind)
2253219089Spjd		rewind_policy = ZPOOL_DO_REWIND;
2254219089Spjd	if (xtreme_rewind)
2255219089Spjd		rewind_policy |= ZPOOL_EXTREME_REWIND;
2256219089Spjd
2257219089Spjd	/* In the future, we can capture further policy and include it here */
2258219089Spjd	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
2259219089Spjd	    nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 ||
2260219089Spjd	    nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
2261219089Spjd		goto error;
2262219089Spjd
2263168404Spjd	if (searchdirs == NULL) {
2264168404Spjd		searchdirs = safe_malloc(sizeof (char *));
2265235478Savg		searchdirs[0] = "/dev";
2266168404Spjd		nsearch = 1;
2267168404Spjd	}
2268168404Spjd
2269168404Spjd	/* check argument count */
2270168404Spjd	if (do_all) {
2271168404Spjd		if (argc != 0) {
2272168404Spjd			(void) fprintf(stderr, gettext("too many arguments\n"));
2273168404Spjd			usage(B_FALSE);
2274168404Spjd		}
2275168404Spjd	} else {
2276168404Spjd		if (argc > 2) {
2277168404Spjd			(void) fprintf(stderr, gettext("too many arguments\n"));
2278168404Spjd			usage(B_FALSE);
2279168404Spjd		}
2280168404Spjd
2281168404Spjd		/*
2282168404Spjd		 * Check for the SYS_CONFIG privilege.  We do this explicitly
2283168404Spjd		 * here because otherwise any attempt to discover pools will
2284168404Spjd		 * silently fail.
2285168404Spjd		 */
2286168404Spjd		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
2287168404Spjd			(void) fprintf(stderr, gettext("cannot "
2288168404Spjd			    "discover pools: permission denied\n"));
2289168404Spjd			free(searchdirs);
2290219089Spjd			nvlist_free(policy);
2291168404Spjd			return (1);
2292168404Spjd		}
2293168404Spjd	}
2294168404Spjd
2295168404Spjd	/*
2296168404Spjd	 * Depending on the arguments given, we do one of the following:
2297168404Spjd	 *
2298168404Spjd	 *	<none>	Iterate through all pools and display information about
2299168404Spjd	 *		each one.
2300168404Spjd	 *
2301168404Spjd	 *	-a	Iterate through all pools and try to import each one.
2302168404Spjd	 *
2303168404Spjd	 *	<id>	Find the pool that corresponds to the given GUID/pool
2304168404Spjd	 *		name and import that one.
2305168404Spjd	 *
2306168404Spjd	 *	-D	Above options applies only to destroyed pools.
2307168404Spjd	 */
2308168404Spjd	if (argc != 0) {
2309168404Spjd		char *endptr;
2310168404Spjd
2311168404Spjd		errno = 0;
2312168404Spjd		searchguid = strtoull(argv[0], &endptr, 10);
2313254758Sdelphij		if (errno != 0 || *endptr != '\0') {
2314168404Spjd			searchname = argv[0];
2315254758Sdelphij			searchguid = 0;
2316254758Sdelphij		}
2317168404Spjd		found_config = NULL;
2318168404Spjd
2319185029Spjd		/*
2320219089Spjd		 * User specified a name or guid.  Ensure it's unique.
2321185029Spjd		 */
2322219089Spjd		idata.unique = B_TRUE;
2323185029Spjd	}
2324185029Spjd
2325219089Spjd
2326219089Spjd	idata.path = searchdirs;
2327219089Spjd	idata.paths = nsearch;
2328219089Spjd	idata.poolname = searchname;
2329219089Spjd	idata.guid = searchguid;
2330219089Spjd	idata.cachefile = cachefile;
2331219089Spjd
2332219089Spjd	pools = zpool_search_import(g_zfs, &idata);
2333219089Spjd
2334219089Spjd	if (pools != NULL && idata.exists &&
2335219089Spjd	    (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
2336219089Spjd		(void) fprintf(stderr, gettext("cannot import '%s': "
2337219089Spjd		    "a pool with that name already exists\n"),
2338219089Spjd		    argv[0]);
2339219089Spjd		(void) fprintf(stderr, gettext("use the form '%s "
2340219089Spjd		    "<pool | id> <newpool>' to give it a new name\n"),
2341219089Spjd		    "zpool import");
2342219089Spjd		err = 1;
2343219089Spjd	} else if (pools == NULL && idata.exists) {
2344219089Spjd		(void) fprintf(stderr, gettext("cannot import '%s': "
2345219089Spjd		    "a pool with that name is already created/imported,\n"),
2346219089Spjd		    argv[0]);
2347219089Spjd		(void) fprintf(stderr, gettext("and no additional pools "
2348219089Spjd		    "with that name were found\n"));
2349219089Spjd		err = 1;
2350219089Spjd	} else if (pools == NULL) {
2351185029Spjd		if (argc != 0) {
2352185029Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
2353185029Spjd			    "no such pool available\n"), argv[0]);
2354185029Spjd		}
2355219089Spjd		err = 1;
2356219089Spjd	}
2357219089Spjd
2358219089Spjd	if (err == 1) {
2359185029Spjd		free(searchdirs);
2360219089Spjd		nvlist_free(policy);
2361185029Spjd		return (1);
2362185029Spjd	}
2363185029Spjd
2364185029Spjd	/*
2365185029Spjd	 * At this point we have a list of import candidate configs. Even if
2366185029Spjd	 * we were searching by pool name or guid, we still need to
2367185029Spjd	 * post-process the list to deal with pool state and possible
2368185029Spjd	 * duplicate names.
2369185029Spjd	 */
2370168404Spjd	err = 0;
2371168404Spjd	elem = NULL;
2372168404Spjd	first = B_TRUE;
2373168404Spjd	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
2374168404Spjd
2375168404Spjd		verify(nvpair_value_nvlist(elem, &config) == 0);
2376168404Spjd
2377168404Spjd		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
2378168404Spjd		    &pool_state) == 0);
2379168404Spjd		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
2380168404Spjd			continue;
2381168404Spjd		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
2382168404Spjd			continue;
2383168404Spjd
2384219089Spjd		verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY,
2385219089Spjd		    policy) == 0);
2386219089Spjd
2387168404Spjd		if (argc == 0) {
2388168404Spjd			if (first)
2389168404Spjd				first = B_FALSE;
2390168404Spjd			else if (!do_all)
2391168404Spjd				(void) printf("\n");
2392168404Spjd
2393219089Spjd			if (do_all) {
2394168404Spjd				err |= do_import(config, NULL, mntopts,
2395219089Spjd				    props, flags);
2396219089Spjd			} else {
2397168404Spjd				show_import(config);
2398219089Spjd			}
2399168404Spjd		} else if (searchname != NULL) {
2400168404Spjd			char *name;
2401168404Spjd
2402168404Spjd			/*
2403168404Spjd			 * We are searching for a pool based on name.
2404168404Spjd			 */
2405168404Spjd			verify(nvlist_lookup_string(config,
2406168404Spjd			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
2407168404Spjd
2408168404Spjd			if (strcmp(name, searchname) == 0) {
2409168404Spjd				if (found_config != NULL) {
2410168404Spjd					(void) fprintf(stderr, gettext(
2411168404Spjd					    "cannot import '%s': more than "
2412168404Spjd					    "one matching pool\n"), searchname);
2413168404Spjd					(void) fprintf(stderr, gettext(
2414168404Spjd					    "import by numeric ID instead\n"));
2415168404Spjd					err = B_TRUE;
2416168404Spjd				}
2417168404Spjd				found_config = config;
2418168404Spjd			}
2419168404Spjd		} else {
2420168404Spjd			uint64_t guid;
2421168404Spjd
2422168404Spjd			/*
2423168404Spjd			 * Search for a pool by guid.
2424168404Spjd			 */
2425168404Spjd			verify(nvlist_lookup_uint64(config,
2426168404Spjd			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
2427168404Spjd
2428168404Spjd			if (guid == searchguid)
2429168404Spjd				found_config = config;
2430168404Spjd		}
2431168404Spjd	}
2432168404Spjd
2433168404Spjd	/*
2434168404Spjd	 * If we were searching for a specific pool, verify that we found a
2435168404Spjd	 * pool, and then do the import.
2436168404Spjd	 */
2437168404Spjd	if (argc != 0 && err == 0) {
2438168404Spjd		if (found_config == NULL) {
2439168404Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
2440168404Spjd			    "no such pool available\n"), argv[0]);
2441168404Spjd			err = B_TRUE;
2442168404Spjd		} else {
2443168404Spjd			err |= do_import(found_config, argc == 1 ? NULL :
2444219089Spjd			    argv[1], mntopts, props, flags);
2445168404Spjd		}
2446168404Spjd	}
2447168404Spjd
2448168404Spjd	/*
2449168404Spjd	 * If we were just looking for pools, report an error if none were
2450168404Spjd	 * found.
2451168404Spjd	 */
2452168404Spjd	if (argc == 0 && first)
2453168404Spjd		(void) fprintf(stderr,
2454168404Spjd		    gettext("no pools available to import\n"));
2455168404Spjd
2456185029Spjderror:
2457185029Spjd	nvlist_free(props);
2458168404Spjd	nvlist_free(pools);
2459219089Spjd	nvlist_free(policy);
2460168404Spjd	free(searchdirs);
2461168404Spjd
2462168404Spjd	return (err ? 1 : 0);
2463168404Spjd}
2464168404Spjd
2465168404Spjdtypedef struct iostat_cbdata {
2466236155Smm	boolean_t cb_verbose;
2467236155Smm	int cb_namewidth;
2468236155Smm	int cb_iteration;
2469168404Spjd	zpool_list_t *cb_list;
2470168404Spjd} iostat_cbdata_t;
2471168404Spjd
2472168404Spjdstatic void
2473168404Spjdprint_iostat_separator(iostat_cbdata_t *cb)
2474168404Spjd{
2475168404Spjd	int i = 0;
2476168404Spjd
2477168404Spjd	for (i = 0; i < cb->cb_namewidth; i++)
2478168404Spjd		(void) printf("-");
2479168404Spjd	(void) printf("  -----  -----  -----  -----  -----  -----\n");
2480168404Spjd}
2481168404Spjd
2482168404Spjdstatic void
2483168404Spjdprint_iostat_header(iostat_cbdata_t *cb)
2484168404Spjd{
2485168404Spjd	(void) printf("%*s     capacity     operations    bandwidth\n",
2486168404Spjd	    cb->cb_namewidth, "");
2487219089Spjd	(void) printf("%-*s  alloc   free   read  write   read  write\n",
2488168404Spjd	    cb->cb_namewidth, "pool");
2489168404Spjd	print_iostat_separator(cb);
2490168404Spjd}
2491168404Spjd
2492168404Spjd/*
2493168404Spjd * Display a single statistic.
2494168404Spjd */
2495185029Spjdstatic void
2496168404Spjdprint_one_stat(uint64_t value)
2497168404Spjd{
2498168404Spjd	char buf[64];
2499168404Spjd
2500168404Spjd	zfs_nicenum(value, buf, sizeof (buf));
2501168404Spjd	(void) printf("  %5s", buf);
2502168404Spjd}
2503168404Spjd
2504168404Spjd/*
2505168404Spjd * Print out all the statistics for the given vdev.  This can either be the
2506168404Spjd * toplevel configuration, or called recursively.  If 'name' is NULL, then this
2507168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats.
2508168404Spjd */
2509168404Spjdvoid
2510168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
2511168404Spjd    nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
2512168404Spjd{
2513168404Spjd	nvlist_t **oldchild, **newchild;
2514168404Spjd	uint_t c, children;
2515168404Spjd	vdev_stat_t *oldvs, *newvs;
2516168404Spjd	vdev_stat_t zerovs = { 0 };
2517168404Spjd	uint64_t tdelta;
2518168404Spjd	double scale;
2519168404Spjd	char *vname;
2520168404Spjd
2521332525Smav	if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
2522332525Smav		return;
2523332525Smav
2524168404Spjd	if (oldnv != NULL) {
2525219089Spjd		verify(nvlist_lookup_uint64_array(oldnv,
2526219089Spjd		    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
2527168404Spjd	} else {
2528168404Spjd		oldvs = &zerovs;
2529168404Spjd	}
2530168404Spjd
2531219089Spjd	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
2532168404Spjd	    (uint64_t **)&newvs, &c) == 0);
2533168404Spjd
2534168404Spjd	if (strlen(name) + depth > cb->cb_namewidth)
2535168404Spjd		(void) printf("%*s%s", depth, "", name);
2536168404Spjd	else
2537168404Spjd		(void) printf("%*s%s%*s", depth, "", name,
2538168404Spjd		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
2539168404Spjd
2540168404Spjd	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
2541168404Spjd
2542168404Spjd	if (tdelta == 0)
2543168404Spjd		scale = 1.0;
2544168404Spjd	else
2545168404Spjd		scale = (double)NANOSEC / tdelta;
2546168404Spjd
2547168404Spjd	/* only toplevel vdevs have capacity stats */
2548168404Spjd	if (newvs->vs_space == 0) {
2549168404Spjd		(void) printf("      -      -");
2550168404Spjd	} else {
2551168404Spjd		print_one_stat(newvs->vs_alloc);
2552168404Spjd		print_one_stat(newvs->vs_space - newvs->vs_alloc);
2553168404Spjd	}
2554168404Spjd
2555168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
2556168404Spjd	    oldvs->vs_ops[ZIO_TYPE_READ])));
2557168404Spjd
2558168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
2559168404Spjd	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
2560168404Spjd
2561168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
2562168404Spjd	    oldvs->vs_bytes[ZIO_TYPE_READ])));
2563168404Spjd
2564168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
2565168404Spjd	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
2566168404Spjd
2567168404Spjd	(void) printf("\n");
2568168404Spjd
2569168404Spjd	if (!cb->cb_verbose)
2570168404Spjd		return;
2571168404Spjd
2572168404Spjd	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
2573168404Spjd	    &newchild, &children) != 0)
2574168404Spjd		return;
2575168404Spjd
2576168404Spjd	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
2577168404Spjd	    &oldchild, &c) != 0)
2578168404Spjd		return;
2579168404Spjd
2580168404Spjd	for (c = 0; c < children; c++) {
2581227497Smm		uint64_t ishole = B_FALSE, islog = B_FALSE;
2582219089Spjd
2583227497Smm		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
2584227497Smm		    &ishole);
2585227497Smm
2586227497Smm		(void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
2587227497Smm		    &islog);
2588227497Smm
2589227497Smm		if (ishole || islog)
2590219089Spjd			continue;
2591219089Spjd
2592219089Spjd		vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
2593168404Spjd		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2594168404Spjd		    newchild[c], cb, depth + 2);
2595168404Spjd		free(vname);
2596168404Spjd	}
2597185029Spjd
2598185029Spjd	/*
2599227497Smm	 * Log device section
2600227497Smm	 */
2601227497Smm
2602227497Smm	if (num_logs(newnv) > 0) {
2603227497Smm		(void) printf("%-*s      -      -      -      -      -      "
2604227497Smm		    "-\n", cb->cb_namewidth, "logs");
2605227497Smm
2606227497Smm		for (c = 0; c < children; c++) {
2607227497Smm			uint64_t islog = B_FALSE;
2608227497Smm			(void) nvlist_lookup_uint64(newchild[c],
2609227497Smm			    ZPOOL_CONFIG_IS_LOG, &islog);
2610227497Smm
2611227497Smm			if (islog) {
2612227497Smm				vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
2613227497Smm				    B_FALSE);
2614227497Smm				print_vdev_stats(zhp, vname, oldnv ?
2615227497Smm				    oldchild[c] : NULL, newchild[c],
2616227497Smm				    cb, depth + 2);
2617227497Smm				free(vname);
2618227497Smm			}
2619227497Smm		}
2620227497Smm
2621227497Smm	}
2622227497Smm
2623227497Smm	/*
2624185029Spjd	 * Include level 2 ARC devices in iostat output
2625185029Spjd	 */
2626185029Spjd	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
2627185029Spjd	    &newchild, &children) != 0)
2628185029Spjd		return;
2629185029Spjd
2630185029Spjd	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
2631185029Spjd	    &oldchild, &c) != 0)
2632185029Spjd		return;
2633185029Spjd
2634185029Spjd	if (children > 0) {
2635185029Spjd		(void) printf("%-*s      -      -      -      -      -      "
2636185029Spjd		    "-\n", cb->cb_namewidth, "cache");
2637185029Spjd		for (c = 0; c < children; c++) {
2638219089Spjd			vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
2639219089Spjd			    B_FALSE);
2640185029Spjd			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
2641185029Spjd			    newchild[c], cb, depth + 2);
2642185029Spjd			free(vname);
2643185029Spjd		}
2644185029Spjd	}
2645168404Spjd}
2646168404Spjd
2647168404Spjdstatic int
2648168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data)
2649168404Spjd{
2650168404Spjd	iostat_cbdata_t *cb = data;
2651168404Spjd	boolean_t missing;
2652168404Spjd
2653168404Spjd	/*
2654168404Spjd	 * If the pool has disappeared, remove it from the list and continue.
2655168404Spjd	 */
2656168404Spjd	if (zpool_refresh_stats(zhp, &missing) != 0)
2657168404Spjd		return (-1);
2658168404Spjd
2659168404Spjd	if (missing)
2660168404Spjd		pool_list_remove(cb->cb_list, zhp);
2661168404Spjd
2662168404Spjd	return (0);
2663168404Spjd}
2664168404Spjd
2665168404Spjd/*
2666168404Spjd * Callback to print out the iostats for the given pool.
2667168404Spjd */
2668168404Spjdint
2669168404Spjdprint_iostat(zpool_handle_t *zhp, void *data)
2670168404Spjd{
2671168404Spjd	iostat_cbdata_t *cb = data;
2672168404Spjd	nvlist_t *oldconfig, *newconfig;
2673168404Spjd	nvlist_t *oldnvroot, *newnvroot;
2674168404Spjd
2675168404Spjd	newconfig = zpool_get_config(zhp, &oldconfig);
2676168404Spjd
2677168404Spjd	if (cb->cb_iteration == 1)
2678168404Spjd		oldconfig = NULL;
2679168404Spjd
2680168404Spjd	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
2681168404Spjd	    &newnvroot) == 0);
2682168404Spjd
2683168404Spjd	if (oldconfig == NULL)
2684168404Spjd		oldnvroot = NULL;
2685168404Spjd	else
2686168404Spjd		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
2687168404Spjd		    &oldnvroot) == 0);
2688168404Spjd
2689168404Spjd	/*
2690168404Spjd	 * Print out the statistics for the pool.
2691168404Spjd	 */
2692168404Spjd	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
2693168404Spjd
2694168404Spjd	if (cb->cb_verbose)
2695168404Spjd		print_iostat_separator(cb);
2696168404Spjd
2697168404Spjd	return (0);
2698168404Spjd}
2699168404Spjd
2700168404Spjdint
2701168404Spjdget_namewidth(zpool_handle_t *zhp, void *data)
2702168404Spjd{
2703168404Spjd	iostat_cbdata_t *cb = data;
2704168404Spjd	nvlist_t *config, *nvroot;
2705168404Spjd
2706168404Spjd	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
2707168404Spjd		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2708168404Spjd		    &nvroot) == 0);
2709168404Spjd		if (!cb->cb_verbose)
2710168404Spjd			cb->cb_namewidth = strlen(zpool_get_name(zhp));
2711168404Spjd		else
2712236145Smm			cb->cb_namewidth = max_width(zhp, nvroot, 0,
2713236145Smm			    cb->cb_namewidth);
2714168404Spjd	}
2715168404Spjd
2716168404Spjd	/*
2717168404Spjd	 * The width must fall into the range [10,38].  The upper limit is the
2718168404Spjd	 * maximum we can have and still fit in 80 columns.
2719168404Spjd	 */
2720168404Spjd	if (cb->cb_namewidth < 10)
2721168404Spjd		cb->cb_namewidth = 10;
2722168404Spjd	if (cb->cb_namewidth > 38)
2723168404Spjd		cb->cb_namewidth = 38;
2724168404Spjd
2725168404Spjd	return (0);
2726168404Spjd}
2727168404Spjd
2728168404Spjd/*
2729219089Spjd * Parse the input string, get the 'interval' and 'count' value if there is one.
2730168404Spjd */
2731219089Spjdstatic void
2732219089Spjdget_interval_count(int *argcp, char **argv, unsigned long *iv,
2733219089Spjd    unsigned long *cnt)
2734168404Spjd{
2735168404Spjd	unsigned long interval = 0, count = 0;
2736219089Spjd	int argc = *argcp, errno;
2737168404Spjd
2738168404Spjd	/*
2739168404Spjd	 * Determine if the last argument is an integer or a pool name
2740168404Spjd	 */
2741168404Spjd	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2742168404Spjd		char *end;
2743168404Spjd
2744168404Spjd		errno = 0;
2745168404Spjd		interval = strtoul(argv[argc - 1], &end, 10);
2746168404Spjd
2747168404Spjd		if (*end == '\0' && errno == 0) {
2748168404Spjd			if (interval == 0) {
2749168404Spjd				(void) fprintf(stderr, gettext("interval "
2750168404Spjd				    "cannot be zero\n"));
2751168404Spjd				usage(B_FALSE);
2752168404Spjd			}
2753168404Spjd			/*
2754168404Spjd			 * Ignore the last parameter
2755168404Spjd			 */
2756168404Spjd			argc--;
2757168404Spjd		} else {
2758168404Spjd			/*
2759168404Spjd			 * If this is not a valid number, just plow on.  The
2760168404Spjd			 * user will get a more informative error message later
2761168404Spjd			 * on.
2762168404Spjd			 */
2763168404Spjd			interval = 0;
2764168404Spjd		}
2765168404Spjd	}
2766168404Spjd
2767168404Spjd	/*
2768168404Spjd	 * If the last argument is also an integer, then we have both a count
2769219089Spjd	 * and an interval.
2770168404Spjd	 */
2771168404Spjd	if (argc > 0 && isdigit(argv[argc - 1][0])) {
2772168404Spjd		char *end;
2773168404Spjd
2774168404Spjd		errno = 0;
2775168404Spjd		count = interval;
2776168404Spjd		interval = strtoul(argv[argc - 1], &end, 10);
2777168404Spjd
2778168404Spjd		if (*end == '\0' && errno == 0) {
2779168404Spjd			if (interval == 0) {
2780168404Spjd				(void) fprintf(stderr, gettext("interval "
2781168404Spjd				    "cannot be zero\n"));
2782168404Spjd				usage(B_FALSE);
2783168404Spjd			}
2784168404Spjd
2785168404Spjd			/*
2786168404Spjd			 * Ignore the last parameter
2787168404Spjd			 */
2788168404Spjd			argc--;
2789168404Spjd		} else {
2790168404Spjd			interval = 0;
2791168404Spjd		}
2792168404Spjd	}
2793168404Spjd
2794219089Spjd	*iv = interval;
2795219089Spjd	*cnt = count;
2796219089Spjd	*argcp = argc;
2797219089Spjd}
2798219089Spjd
2799219089Spjdstatic void
2800219089Spjdget_timestamp_arg(char c)
2801219089Spjd{
2802219089Spjd	if (c == 'u')
2803219089Spjd		timestamp_fmt = UDATE;
2804219089Spjd	else if (c == 'd')
2805219089Spjd		timestamp_fmt = DDATE;
2806219089Spjd	else
2807219089Spjd		usage(B_FALSE);
2808219089Spjd}
2809219089Spjd
2810219089Spjd/*
2811219089Spjd * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]]
2812219089Spjd *
2813219089Spjd *	-v	Display statistics for individual vdevs
2814219089Spjd *	-T	Display a timestamp in date(1) or Unix format
2815219089Spjd *
2816219089Spjd * This command can be tricky because we want to be able to deal with pool
2817219089Spjd * creation/destruction as well as vdev configuration changes.  The bulk of this
2818219089Spjd * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
2819219089Spjd * on pool_list_update() to detect the addition of new pools.  Configuration
2820219089Spjd * changes are all handled within libzfs.
2821219089Spjd */
2822219089Spjdint
2823219089Spjdzpool_do_iostat(int argc, char **argv)
2824219089Spjd{
2825219089Spjd	int c;
2826219089Spjd	int ret;
2827219089Spjd	int npools;
2828219089Spjd	unsigned long interval = 0, count = 0;
2829219089Spjd	zpool_list_t *list;
2830219089Spjd	boolean_t verbose = B_FALSE;
2831219089Spjd	iostat_cbdata_t cb;
2832219089Spjd
2833219089Spjd	/* check options */
2834219089Spjd	while ((c = getopt(argc, argv, "T:v")) != -1) {
2835219089Spjd		switch (c) {
2836219089Spjd		case 'T':
2837219089Spjd			get_timestamp_arg(*optarg);
2838219089Spjd			break;
2839219089Spjd		case 'v':
2840219089Spjd			verbose = B_TRUE;
2841219089Spjd			break;
2842219089Spjd		case '?':
2843219089Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2844219089Spjd			    optopt);
2845219089Spjd			usage(B_FALSE);
2846219089Spjd		}
2847219089Spjd	}
2848219089Spjd
2849219089Spjd	argc -= optind;
2850219089Spjd	argv += optind;
2851219089Spjd
2852219089Spjd	get_interval_count(&argc, argv, &interval, &count);
2853219089Spjd
2854168404Spjd	/*
2855168404Spjd	 * Construct the list of all interesting pools.
2856168404Spjd	 */
2857168404Spjd	ret = 0;
2858168404Spjd	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
2859168404Spjd		return (1);
2860168404Spjd
2861168404Spjd	if (pool_list_count(list) == 0 && argc != 0) {
2862168404Spjd		pool_list_free(list);
2863168404Spjd		return (1);
2864168404Spjd	}
2865168404Spjd
2866168404Spjd	if (pool_list_count(list) == 0 && interval == 0) {
2867168404Spjd		pool_list_free(list);
2868168404Spjd		(void) fprintf(stderr, gettext("no pools available\n"));
2869168404Spjd		return (1);
2870168404Spjd	}
2871168404Spjd
2872168404Spjd	/*
2873168404Spjd	 * Enter the main iostat loop.
2874168404Spjd	 */
2875168404Spjd	cb.cb_list = list;
2876168404Spjd	cb.cb_verbose = verbose;
2877168404Spjd	cb.cb_iteration = 0;
2878168404Spjd	cb.cb_namewidth = 0;
2879168404Spjd
2880168404Spjd	for (;;) {
2881168404Spjd		pool_list_update(list);
2882168404Spjd
2883168404Spjd		if ((npools = pool_list_count(list)) == 0)
2884168404Spjd			break;
2885168404Spjd
2886168404Spjd		/*
2887168404Spjd		 * Refresh all statistics.  This is done as an explicit step
2888168404Spjd		 * before calculating the maximum name width, so that any
2889168404Spjd		 * configuration changes are properly accounted for.
2890168404Spjd		 */
2891168404Spjd		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
2892168404Spjd
2893168404Spjd		/*
2894168404Spjd		 * Iterate over all pools to determine the maximum width
2895168404Spjd		 * for the pool / device name column across all pools.
2896168404Spjd		 */
2897168404Spjd		cb.cb_namewidth = 0;
2898168404Spjd		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
2899168404Spjd
2900219089Spjd		if (timestamp_fmt != NODATE)
2901219089Spjd			print_timestamp(timestamp_fmt);
2902219089Spjd
2903168404Spjd		/*
2904168404Spjd		 * If it's the first time, or verbose mode, print the header.
2905168404Spjd		 */
2906168404Spjd		if (++cb.cb_iteration == 1 || verbose)
2907168404Spjd			print_iostat_header(&cb);
2908168404Spjd
2909168404Spjd		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2910168404Spjd
2911168404Spjd		/*
2912168404Spjd		 * If there's more than one pool, and we're not in verbose mode
2913168404Spjd		 * (which prints a separator for us), then print a separator.
2914168404Spjd		 */
2915168404Spjd		if (npools > 1 && !verbose)
2916168404Spjd			print_iostat_separator(&cb);
2917168404Spjd
2918168404Spjd		if (verbose)
2919168404Spjd			(void) printf("\n");
2920168404Spjd
2921168404Spjd		/*
2922168404Spjd		 * Flush the output so that redirection to a file isn't buffered
2923168404Spjd		 * indefinitely.
2924168404Spjd		 */
2925168404Spjd		(void) fflush(stdout);
2926168404Spjd
2927168404Spjd		if (interval == 0)
2928168404Spjd			break;
2929168404Spjd
2930168404Spjd		if (count != 0 && --count == 0)
2931168404Spjd			break;
2932168404Spjd
2933168404Spjd		(void) sleep(interval);
2934168404Spjd	}
2935168404Spjd
2936168404Spjd	pool_list_free(list);
2937168404Spjd
2938168404Spjd	return (ret);
2939168404Spjd}
2940168404Spjd
2941168404Spjdtypedef struct list_cbdata {
2942236155Smm	boolean_t	cb_verbose;
2943236155Smm	int		cb_namewidth;
2944168404Spjd	boolean_t	cb_scripted;
2945185029Spjd	zprop_list_t	*cb_proplist;
2946263889Sdelphij	boolean_t	cb_literal;
2947168404Spjd} list_cbdata_t;
2948168404Spjd
2949168404Spjd/*
2950168404Spjd * Given a list of columns to display, output appropriate headers for each one.
2951168404Spjd */
2952185029Spjdstatic void
2953236155Smmprint_header(list_cbdata_t *cb)
2954168404Spjd{
2955236155Smm	zprop_list_t *pl = cb->cb_proplist;
2956236884Smm	char headerbuf[ZPOOL_MAXPROPLEN];
2957185029Spjd	const char *header;
2958185029Spjd	boolean_t first = B_TRUE;
2959185029Spjd	boolean_t right_justify;
2960236155Smm	size_t width = 0;
2961168404Spjd
2962185029Spjd	for (; pl != NULL; pl = pl->pl_next) {
2963236155Smm		width = pl->pl_width;
2964236155Smm		if (first && cb->cb_verbose) {
2965236155Smm			/*
2966236155Smm			 * Reset the width to accommodate the verbose listing
2967236155Smm			 * of devices.
2968236155Smm			 */
2969236155Smm			width = cb->cb_namewidth;
2970236155Smm		}
2971236155Smm
2972185029Spjd		if (!first)
2973168404Spjd			(void) printf("  ");
2974168404Spjd		else
2975185029Spjd			first = B_FALSE;
2976168404Spjd
2977236884Smm		right_justify = B_FALSE;
2978236884Smm		if (pl->pl_prop != ZPROP_INVAL) {
2979236884Smm			header = zpool_prop_column_name(pl->pl_prop);
2980236884Smm			right_justify = zpool_prop_align_right(pl->pl_prop);
2981236884Smm		} else {
2982236884Smm			int i;
2983185029Spjd
2984236884Smm			for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
2985236884Smm				headerbuf[i] = toupper(pl->pl_user_prop[i]);
2986236884Smm			headerbuf[i] = '\0';
2987236884Smm			header = headerbuf;
2988236884Smm		}
2989236884Smm
2990185029Spjd		if (pl->pl_next == NULL && !right_justify)
2991185029Spjd			(void) printf("%s", header);
2992185029Spjd		else if (right_justify)
2993236155Smm			(void) printf("%*s", width, header);
2994185029Spjd		else
2995236155Smm			(void) printf("%-*s", width, header);
2996236155Smm
2997168404Spjd	}
2998168404Spjd
2999168404Spjd	(void) printf("\n");
3000168404Spjd}
3001168404Spjd
3002185029Spjd/*
3003185029Spjd * Given a pool and a list of properties, print out all the properties according
3004185029Spjd * to the described layout.
3005185029Spjd */
3006185029Spjdstatic void
3007236155Smmprint_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
3008168404Spjd{
3009236155Smm	zprop_list_t *pl = cb->cb_proplist;
3010185029Spjd	boolean_t first = B_TRUE;
3011185029Spjd	char property[ZPOOL_MAXPROPLEN];
3012185029Spjd	char *propstr;
3013185029Spjd	boolean_t right_justify;
3014236155Smm	size_t width;
3015168404Spjd
3016185029Spjd	for (; pl != NULL; pl = pl->pl_next) {
3017236155Smm
3018236155Smm		width = pl->pl_width;
3019236155Smm		if (first && cb->cb_verbose) {
3020236155Smm			/*
3021236155Smm			 * Reset the width to accommodate the verbose listing
3022236155Smm			 * of devices.
3023236155Smm			 */
3024236155Smm			width = cb->cb_namewidth;
3025236155Smm		}
3026236155Smm
3027185029Spjd		if (!first) {
3028236155Smm			if (cb->cb_scripted)
3029168404Spjd				(void) printf("\t");
3030168404Spjd			else
3031168404Spjd				(void) printf("  ");
3032185029Spjd		} else {
3033185029Spjd			first = B_FALSE;
3034168404Spjd		}
3035168404Spjd
3036185029Spjd		right_justify = B_FALSE;
3037185029Spjd		if (pl->pl_prop != ZPROP_INVAL) {
3038272502Sdelphij			if (zpool_get_prop(zhp, pl->pl_prop, property,
3039263889Sdelphij			    sizeof (property), NULL, cb->cb_literal) != 0)
3040185029Spjd				propstr = "-";
3041168404Spjd			else
3042185029Spjd				propstr = property;
3043168404Spjd
3044185029Spjd			right_justify = zpool_prop_align_right(pl->pl_prop);
3045236884Smm		} else if ((zpool_prop_feature(pl->pl_user_prop) ||
3046236884Smm		    zpool_prop_unsupported(pl->pl_user_prop)) &&
3047236884Smm		    zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
3048236884Smm		    sizeof (property)) == 0) {
3049236884Smm			propstr = property;
3050185029Spjd		} else {
3051185029Spjd			propstr = "-";
3052185029Spjd		}
3053168404Spjd
3054168404Spjd
3055185029Spjd		/*
3056185029Spjd		 * If this is being called in scripted mode, or if this is the
3057185029Spjd		 * last column and it is left-justified, don't include a width
3058185029Spjd		 * format specifier.
3059185029Spjd		 */
3060236155Smm		if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
3061185029Spjd			(void) printf("%s", propstr);
3062185029Spjd		else if (right_justify)
3063185029Spjd			(void) printf("%*s", width, propstr);
3064185029Spjd		else
3065185029Spjd			(void) printf("%-*s", width, propstr);
3066185029Spjd	}
3067168404Spjd
3068185029Spjd	(void) printf("\n");
3069185029Spjd}
3070168404Spjd
3071236155Smmstatic void
3072272502Sdelphijprint_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted,
3073272502Sdelphij    boolean_t valid)
3074236155Smm{
3075236155Smm	char propval[64];
3076236155Smm	boolean_t fixed;
3077236155Smm	size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
3078236155Smm
3079272502Sdelphij	switch (prop) {
3080272502Sdelphij	case ZPOOL_PROP_EXPANDSZ:
3081272502Sdelphij		if (value == 0)
3082272502Sdelphij			(void) strlcpy(propval, "-", sizeof (propval));
3083272502Sdelphij		else
3084272502Sdelphij			zfs_nicenum(value, propval, sizeof (propval));
3085272502Sdelphij		break;
3086272502Sdelphij	case ZPOOL_PROP_FRAGMENTATION:
3087272502Sdelphij		if (value == ZFS_FRAG_INVALID) {
3088272502Sdelphij			(void) strlcpy(propval, "-", sizeof (propval));
3089272502Sdelphij		} else {
3090272502Sdelphij			(void) snprintf(propval, sizeof (propval), "%llu%%",
3091272502Sdelphij			    value);
3092272502Sdelphij		}
3093272502Sdelphij		break;
3094272502Sdelphij	case ZPOOL_PROP_CAPACITY:
3095269118Sdelphij		(void) snprintf(propval, sizeof (propval), "%llu%%", value);
3096272502Sdelphij		break;
3097272502Sdelphij	default:
3098269118Sdelphij		zfs_nicenum(value, propval, sizeof (propval));
3099272502Sdelphij	}
3100236155Smm
3101272502Sdelphij	if (!valid)
3102272502Sdelphij		(void) strlcpy(propval, "-", sizeof (propval));
3103272502Sdelphij
3104236155Smm	if (scripted)
3105236155Smm		(void) printf("\t%s", propval);
3106236155Smm	else
3107236155Smm		(void) printf("  %*s", width, propval);
3108236155Smm}
3109236155Smm
3110236155Smmvoid
3111236155Smmprint_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
3112236155Smm    list_cbdata_t *cb, int depth)
3113236155Smm{
3114236155Smm	nvlist_t **child;
3115236155Smm	vdev_stat_t *vs;
3116236155Smm	uint_t c, children;
3117236155Smm	char *vname;
3118236155Smm	boolean_t scripted = cb->cb_scripted;
3119289536Smav	uint64_t islog = B_FALSE;
3120289536Smav	boolean_t haslog = B_FALSE;
3121289536Smav	char *dashes = "%-*s      -      -      -         -      -      -\n";
3122236155Smm
3123236155Smm	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
3124236155Smm	    (uint64_t **)&vs, &c) == 0);
3125236155Smm
3126236155Smm	if (name != NULL) {
3127272502Sdelphij		boolean_t toplevel = (vs->vs_space != 0);
3128272502Sdelphij		uint64_t cap;
3129272502Sdelphij
3130332525Smav		if (strcmp(name, VDEV_TYPE_INDIRECT) == 0)
3131332525Smav			return;
3132332525Smav
3133236155Smm		if (scripted)
3134236155Smm			(void) printf("\t%s", name);
3135236155Smm		else if (strlen(name) + depth > cb->cb_namewidth)
3136236155Smm			(void) printf("%*s%s", depth, "", name);
3137236155Smm		else
3138236155Smm			(void) printf("%*s%s%*s", depth, "", name,
3139236155Smm			    (int)(cb->cb_namewidth - strlen(name) - depth), "");
3140236155Smm
3141272502Sdelphij		/*
3142272502Sdelphij		 * Print the properties for the individual vdevs. Some
3143272502Sdelphij		 * properties are only applicable to toplevel vdevs. The
3144272502Sdelphij		 * 'toplevel' boolean value is passed to the print_one_column()
3145272502Sdelphij		 * to indicate that the value is valid.
3146272502Sdelphij		 */
3147272502Sdelphij		print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted,
3148272502Sdelphij		    toplevel);
3149272502Sdelphij		print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted,
3150272502Sdelphij		    toplevel);
3151272502Sdelphij		print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc,
3152272502Sdelphij		    scripted, toplevel);
3153272502Sdelphij		print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted,
3154272502Sdelphij		    B_TRUE);
3155272502Sdelphij		print_one_column(ZPOOL_PROP_FRAGMENTATION,
3156272502Sdelphij		    vs->vs_fragmentation, scripted,
3157272502Sdelphij		    (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel));
3158272502Sdelphij		cap = (vs->vs_space == 0) ? 0 :
3159272502Sdelphij		    (vs->vs_alloc * 100 / vs->vs_space);
3160272502Sdelphij		print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel);
3161236155Smm		(void) printf("\n");
3162236155Smm	}
3163236155Smm
3164236155Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
3165236155Smm	    &child, &children) != 0)
3166236155Smm		return;
3167236155Smm
3168236155Smm	for (c = 0; c < children; c++) {
3169236155Smm		uint64_t ishole = B_FALSE;
3170236155Smm
3171236155Smm		if (nvlist_lookup_uint64(child[c],
3172236155Smm		    ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
3173236155Smm			continue;
3174236155Smm
3175289536Smav		if (nvlist_lookup_uint64(child[c],
3176289536Smav		    ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) {
3177289536Smav			haslog = B_TRUE;
3178289536Smav			continue;
3179289536Smav		}
3180289536Smav
3181236155Smm		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
3182236155Smm		print_list_stats(zhp, vname, child[c], cb, depth + 2);
3183236155Smm		free(vname);
3184236155Smm	}
3185236155Smm
3186289536Smav	if (haslog == B_TRUE) {
3187289536Smav		/* LINTED E_SEC_PRINTF_VAR_FMT */
3188289536Smav		(void) printf(dashes, cb->cb_namewidth, "log");
3189289536Smav		for (c = 0; c < children; c++) {
3190289536Smav			if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
3191289536Smav			    &islog) != 0 || !islog)
3192289536Smav				continue;
3193289536Smav			vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
3194289536Smav			print_list_stats(zhp, vname, child[c], cb, depth + 2);
3195289536Smav			free(vname);
3196289536Smav		}
3197289536Smav	}
3198289536Smav
3199236155Smm	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
3200289536Smav	    &child, &children) == 0 && children > 0) {
3201289536Smav		/* LINTED E_SEC_PRINTF_VAR_FMT */
3202289536Smav		(void) printf(dashes, cb->cb_namewidth, "cache");
3203289536Smav		for (c = 0; c < children; c++) {
3204289536Smav			vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
3205289536Smav			print_list_stats(zhp, vname, child[c], cb, depth + 2);
3206289536Smav			free(vname);
3207289536Smav		}
3208289536Smav	}
3209236155Smm
3210289536Smav	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child,
3211289536Smav	    &children) == 0 && children > 0) {
3212289536Smav		/* LINTED E_SEC_PRINTF_VAR_FMT */
3213289536Smav		(void) printf(dashes, cb->cb_namewidth, "spare");
3214236155Smm		for (c = 0; c < children; c++) {
3215289536Smav			vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
3216236155Smm			print_list_stats(zhp, vname, child[c], cb, depth + 2);
3217236155Smm			free(vname);
3218236155Smm		}
3219236155Smm	}
3220236155Smm}
3221236155Smm
3222236155Smm
3223185029Spjd/*
3224185029Spjd * Generic callback function to list a pool.
3225185029Spjd */
3226185029Spjdint
3227185029Spjdlist_callback(zpool_handle_t *zhp, void *data)
3228185029Spjd{
3229185029Spjd	list_cbdata_t *cbp = data;
3230236155Smm	nvlist_t *config;
3231236155Smm	nvlist_t *nvroot;
3232168404Spjd
3233236155Smm	config = zpool_get_config(zhp, NULL);
3234168404Spjd
3235236155Smm	print_pool(zhp, cbp);
3236236155Smm	if (!cbp->cb_verbose)
3237236155Smm		return (0);
3238168404Spjd
3239236155Smm	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
3240236155Smm	    &nvroot) == 0);
3241236155Smm	print_list_stats(zhp, NULL, nvroot, cbp, 0);
3242236155Smm
3243168404Spjd	return (0);
3244168404Spjd}
3245168404Spjd
3246168404Spjd/*
3247263889Sdelphij * zpool list [-Hp] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
3248168404Spjd *
3249185029Spjd *	-H	Scripted mode.  Don't display headers, and separate properties
3250185029Spjd *		by a single tab.
3251185029Spjd *	-o	List of properties to display.  Defaults to
3252272502Sdelphij *		"name,size,allocated,free,expandsize,fragmentation,capacity,"
3253272502Sdelphij *		"dedupratio,health,altroot"
3254263889Sdelphij * 	-p	Diplay values in parsable (exact) format.
3255219089Spjd *	-T	Display a timestamp in date(1) or Unix format
3256168404Spjd *
3257168404Spjd * List all pools in the system, whether or not they're healthy.  Output space
3258168404Spjd * statistics for each one, as well as health status summary.
3259168404Spjd */
3260168404Spjdint
3261168404Spjdzpool_do_list(int argc, char **argv)
3262168404Spjd{
3263168404Spjd	int c;
3264168404Spjd	int ret;
3265168404Spjd	list_cbdata_t cb = { 0 };
3266185029Spjd	static char default_props[] =
3267272502Sdelphij	    "name,size,allocated,free,expandsize,fragmentation,capacity,"
3268269118Sdelphij	    "dedupratio,health,altroot";
3269185029Spjd	char *props = default_props;
3270219089Spjd	unsigned long interval = 0, count = 0;
3271236155Smm	zpool_list_t *list;
3272236155Smm	boolean_t first = B_TRUE;
3273168404Spjd
3274168404Spjd	/* check options */
3275263889Sdelphij	while ((c = getopt(argc, argv, ":Ho:pT:v")) != -1) {
3276168404Spjd		switch (c) {
3277168404Spjd		case 'H':
3278168404Spjd			cb.cb_scripted = B_TRUE;
3279168404Spjd			break;
3280168404Spjd		case 'o':
3281185029Spjd			props = optarg;
3282168404Spjd			break;
3283263889Sdelphij		case 'p':
3284263889Sdelphij			cb.cb_literal = B_TRUE;
3285263889Sdelphij			break;
3286219089Spjd		case 'T':
3287219089Spjd			get_timestamp_arg(*optarg);
3288219089Spjd			break;
3289236155Smm		case 'v':
3290236155Smm			cb.cb_verbose = B_TRUE;
3291236155Smm			break;
3292168404Spjd		case ':':
3293168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
3294168404Spjd			    "'%c' option\n"), optopt);
3295168404Spjd			usage(B_FALSE);
3296168404Spjd			break;
3297168404Spjd		case '?':
3298168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3299168404Spjd			    optopt);
3300168404Spjd			usage(B_FALSE);
3301168404Spjd		}
3302168404Spjd	}
3303168404Spjd
3304168404Spjd	argc -= optind;
3305168404Spjd	argv += optind;
3306168404Spjd
3307219089Spjd	get_interval_count(&argc, argv, &interval, &count);
3308219089Spjd
3309185029Spjd	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
3310185029Spjd		usage(B_FALSE);
3311168404Spjd
3312219089Spjd	for (;;) {
3313268470Sdelphij		if ((list = pool_list_get(argc, argv, &cb.cb_proplist,
3314268470Sdelphij		    &ret)) == NULL)
3315268470Sdelphij			return (1);
3316168404Spjd
3317236155Smm		if (pool_list_count(list) == 0)
3318236155Smm			break;
3319236155Smm
3320236155Smm		cb.cb_namewidth = 0;
3321236155Smm		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
3322236155Smm
3323219089Spjd		if (timestamp_fmt != NODATE)
3324219089Spjd			print_timestamp(timestamp_fmt);
3325168404Spjd
3326236155Smm		if (!cb.cb_scripted && (first || cb.cb_verbose)) {
3327236155Smm			print_header(&cb);
3328236155Smm			first = B_FALSE;
3329219089Spjd		}
3330236155Smm		ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
3331219089Spjd
3332219089Spjd		if (interval == 0)
3333219089Spjd			break;
3334219089Spjd
3335219089Spjd		if (count != 0 && --count == 0)
3336219089Spjd			break;
3337219089Spjd
3338268470Sdelphij		pool_list_free(list);
3339219089Spjd		(void) sleep(interval);
3340168404Spjd	}
3341168404Spjd
3342268470Sdelphij	if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
3343268470Sdelphij		(void) printf(gettext("no pools available\n"));
3344268470Sdelphij		ret = 0;
3345268470Sdelphij	}
3346268470Sdelphij
3347268470Sdelphij	pool_list_free(list);
3348219089Spjd	zprop_free_list(cb.cb_proplist);
3349168404Spjd	return (ret);
3350168404Spjd}
3351168404Spjd
3352168404Spjdstatic int
3353168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing)
3354168404Spjd{
3355168404Spjd	boolean_t force = B_FALSE;
3356168404Spjd	int c;
3357168404Spjd	nvlist_t *nvroot;
3358168404Spjd	char *poolname, *old_disk, *new_disk;
3359168404Spjd	zpool_handle_t *zhp;
3360331395Smav	zpool_boot_label_t boot_type;
3361331395Smav	uint64_t boot_size;
3362168404Spjd	int ret;
3363168404Spjd
3364168404Spjd	/* check options */
3365168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
3366168404Spjd		switch (c) {
3367168404Spjd		case 'f':
3368168404Spjd			force = B_TRUE;
3369168404Spjd			break;
3370168404Spjd		case '?':
3371168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3372168404Spjd			    optopt);
3373168404Spjd			usage(B_FALSE);
3374168404Spjd		}
3375168404Spjd	}
3376168404Spjd
3377168404Spjd	argc -= optind;
3378168404Spjd	argv += optind;
3379168404Spjd
3380168404Spjd	/* get pool name and check number of arguments */
3381168404Spjd	if (argc < 1) {
3382168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
3383168404Spjd		usage(B_FALSE);
3384168404Spjd	}
3385168404Spjd
3386168404Spjd	poolname = argv[0];
3387168404Spjd
3388168404Spjd	if (argc < 2) {
3389168404Spjd		(void) fprintf(stderr,
3390168404Spjd		    gettext("missing <device> specification\n"));
3391168404Spjd		usage(B_FALSE);
3392168404Spjd	}
3393168404Spjd
3394168404Spjd	old_disk = argv[1];
3395168404Spjd
3396168404Spjd	if (argc < 3) {
3397168404Spjd		if (!replacing) {
3398168404Spjd			(void) fprintf(stderr,
3399168404Spjd			    gettext("missing <new_device> specification\n"));
3400168404Spjd			usage(B_FALSE);
3401168404Spjd		}
3402168404Spjd		new_disk = old_disk;
3403168404Spjd		argc -= 1;
3404168404Spjd		argv += 1;
3405168404Spjd	} else {
3406168404Spjd		new_disk = argv[2];
3407168404Spjd		argc -= 2;
3408168404Spjd		argv += 2;
3409168404Spjd	}
3410168404Spjd
3411168404Spjd	if (argc > 1) {
3412168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
3413168404Spjd		usage(B_FALSE);
3414168404Spjd	}
3415168404Spjd
3416168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3417168404Spjd		return (1);
3418168404Spjd
3419185029Spjd	if (zpool_get_config(zhp, NULL) == NULL) {
3420168404Spjd		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
3421168404Spjd		    poolname);
3422168404Spjd		zpool_close(zhp);
3423168404Spjd		return (1);
3424168404Spjd	}
3425168404Spjd
3426331395Smav	if (zpool_is_bootable(zhp))
3427331395Smav		boot_type = ZPOOL_COPY_BOOT_LABEL;
3428331395Smav	else
3429331395Smav		boot_type = ZPOOL_NO_BOOT_LABEL;
3430331395Smav
3431331395Smav	boot_size = zpool_get_prop_int(zhp, ZPOOL_PROP_BOOTSIZE, NULL);
3432185029Spjd	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
3433331395Smav	    boot_type, boot_size, argc, argv);
3434168404Spjd	if (nvroot == NULL) {
3435168404Spjd		zpool_close(zhp);
3436168404Spjd		return (1);
3437168404Spjd	}
3438168404Spjd
3439168404Spjd	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
3440168404Spjd
3441168404Spjd	nvlist_free(nvroot);
3442168404Spjd	zpool_close(zhp);
3443168404Spjd
3444168404Spjd	return (ret);
3445168404Spjd}
3446168404Spjd
3447168404Spjd/*
3448168404Spjd * zpool replace [-f] <pool> <device> <new_device>
3449168404Spjd *
3450168404Spjd *	-f	Force attach, even if <new_device> appears to be in use.
3451168404Spjd *
3452168404Spjd * Replace <device> with <new_device>.
3453168404Spjd */
3454168404Spjd/* ARGSUSED */
3455168404Spjdint
3456168404Spjdzpool_do_replace(int argc, char **argv)
3457168404Spjd{
3458168404Spjd	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
3459168404Spjd}
3460168404Spjd
3461168404Spjd/*
3462168404Spjd * zpool attach [-f] <pool> <device> <new_device>
3463168404Spjd *
3464168404Spjd *	-f	Force attach, even if <new_device> appears to be in use.
3465168404Spjd *
3466168404Spjd * Attach <new_device> to the mirror containing <device>.  If <device> is not
3467168404Spjd * part of a mirror, then <device> will be transformed into a mirror of
3468168404Spjd * <device> and <new_device>.  In either case, <new_device> will begin life
3469168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself.
3470168404Spjd */
3471168404Spjdint
3472168404Spjdzpool_do_attach(int argc, char **argv)
3473168404Spjd{
3474168404Spjd	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
3475168404Spjd}
3476168404Spjd
3477168404Spjd/*
3478168404Spjd * zpool detach [-f] <pool> <device>
3479168404Spjd *
3480168404Spjd *	-f	Force detach of <device>, even if DTLs argue against it
3481168404Spjd *		(not supported yet)
3482168404Spjd *
3483168404Spjd * Detach a device from a mirror.  The operation will be refused if <device>
3484168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device
3485168404Spjd * has the only valid copy of some data.
3486168404Spjd */
3487168404Spjd/* ARGSUSED */
3488168404Spjdint
3489168404Spjdzpool_do_detach(int argc, char **argv)
3490168404Spjd{
3491168404Spjd	int c;
3492168404Spjd	char *poolname, *path;
3493168404Spjd	zpool_handle_t *zhp;
3494168404Spjd	int ret;
3495168404Spjd
3496168404Spjd	/* check options */
3497168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
3498168404Spjd		switch (c) {
3499168404Spjd		case 'f':
3500168404Spjd		case '?':
3501168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3502168404Spjd			    optopt);
3503168404Spjd			usage(B_FALSE);
3504168404Spjd		}
3505168404Spjd	}
3506168404Spjd
3507168404Spjd	argc -= optind;
3508168404Spjd	argv += optind;
3509168404Spjd
3510168404Spjd	/* get pool name and check number of arguments */
3511168404Spjd	if (argc < 1) {
3512168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
3513168404Spjd		usage(B_FALSE);
3514168404Spjd	}
3515168404Spjd
3516168404Spjd	if (argc < 2) {
3517168404Spjd		(void) fprintf(stderr,
3518168404Spjd		    gettext("missing <device> specification\n"));
3519168404Spjd		usage(B_FALSE);
3520168404Spjd	}
3521168404Spjd
3522168404Spjd	poolname = argv[0];
3523168404Spjd	path = argv[1];
3524168404Spjd
3525168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3526168404Spjd		return (1);
3527168404Spjd
3528168404Spjd	ret = zpool_vdev_detach(zhp, path);
3529168404Spjd
3530168404Spjd	zpool_close(zhp);
3531168404Spjd
3532168404Spjd	return (ret);
3533168404Spjd}
3534168404Spjd
3535168404Spjd/*
3536219089Spjd * zpool split [-n] [-o prop=val] ...
3537219089Spjd *		[-o mntopt] ...
3538219089Spjd *		[-R altroot] <pool> <newpool> [<device> ...]
3539219089Spjd *
3540219089Spjd *	-n	Do not split the pool, but display the resulting layout if
3541219089Spjd *		it were to be split.
3542219089Spjd *	-o	Set property=value, or set mount options.
3543219089Spjd *	-R	Mount the split-off pool under an alternate root.
3544219089Spjd *
3545219089Spjd * Splits the named pool and gives it the new pool name.  Devices to be split
3546219089Spjd * off may be listed, provided that no more than one device is specified
3547219089Spjd * per top-level vdev mirror.  The newly split pool is left in an exported
3548219089Spjd * state unless -R is specified.
3549219089Spjd *
3550219089Spjd * Restrictions: the top-level of the pool pool must only be made up of
3551219089Spjd * mirrors; all devices in the pool must be healthy; no device may be
3552219089Spjd * undergoing a resilvering operation.
3553219089Spjd */
3554219089Spjdint
3555219089Spjdzpool_do_split(int argc, char **argv)
3556219089Spjd{
3557219089Spjd	char *srcpool, *newpool, *propval;
3558219089Spjd	char *mntopts = NULL;
3559219089Spjd	splitflags_t flags;
3560219089Spjd	int c, ret = 0;
3561219089Spjd	zpool_handle_t *zhp;
3562219089Spjd	nvlist_t *config, *props = NULL;
3563219089Spjd
3564219089Spjd	flags.dryrun = B_FALSE;
3565219089Spjd	flags.import = B_FALSE;
3566219089Spjd
3567219089Spjd	/* check options */
3568219089Spjd	while ((c = getopt(argc, argv, ":R:no:")) != -1) {
3569219089Spjd		switch (c) {
3570219089Spjd		case 'R':
3571219089Spjd			flags.import = B_TRUE;
3572219089Spjd			if (add_prop_list(
3573219089Spjd			    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
3574219089Spjd			    &props, B_TRUE) != 0) {
3575296528Smav				nvlist_free(props);
3576219089Spjd				usage(B_FALSE);
3577219089Spjd			}
3578219089Spjd			break;
3579219089Spjd		case 'n':
3580219089Spjd			flags.dryrun = B_TRUE;
3581219089Spjd			break;
3582219089Spjd		case 'o':
3583219089Spjd			if ((propval = strchr(optarg, '=')) != NULL) {
3584219089Spjd				*propval = '\0';
3585219089Spjd				propval++;
3586219089Spjd				if (add_prop_list(optarg, propval,
3587219089Spjd				    &props, B_TRUE) != 0) {
3588296528Smav					nvlist_free(props);
3589219089Spjd					usage(B_FALSE);
3590219089Spjd				}
3591219089Spjd			} else {
3592219089Spjd				mntopts = optarg;
3593219089Spjd			}
3594219089Spjd			break;
3595219089Spjd		case ':':
3596219089Spjd			(void) fprintf(stderr, gettext("missing argument for "
3597219089Spjd			    "'%c' option\n"), optopt);
3598219089Spjd			usage(B_FALSE);
3599219089Spjd			break;
3600219089Spjd		case '?':
3601219089Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3602219089Spjd			    optopt);
3603219089Spjd			usage(B_FALSE);
3604219089Spjd			break;
3605219089Spjd		}
3606219089Spjd	}
3607219089Spjd
3608219089Spjd	if (!flags.import && mntopts != NULL) {
3609219089Spjd		(void) fprintf(stderr, gettext("setting mntopts is only "
3610219089Spjd		    "valid when importing the pool\n"));
3611219089Spjd		usage(B_FALSE);
3612219089Spjd	}
3613219089Spjd
3614219089Spjd	argc -= optind;
3615219089Spjd	argv += optind;
3616219089Spjd
3617219089Spjd	if (argc < 1) {
3618219089Spjd		(void) fprintf(stderr, gettext("Missing pool name\n"));
3619219089Spjd		usage(B_FALSE);
3620219089Spjd	}
3621219089Spjd	if (argc < 2) {
3622219089Spjd		(void) fprintf(stderr, gettext("Missing new pool name\n"));
3623219089Spjd		usage(B_FALSE);
3624219089Spjd	}
3625219089Spjd
3626219089Spjd	srcpool = argv[0];
3627219089Spjd	newpool = argv[1];
3628219089Spjd
3629219089Spjd	argc -= 2;
3630219089Spjd	argv += 2;
3631219089Spjd
3632219089Spjd	if ((zhp = zpool_open(g_zfs, srcpool)) == NULL)
3633219089Spjd		return (1);
3634219089Spjd
3635219089Spjd	config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
3636219089Spjd	if (config == NULL) {
3637219089Spjd		ret = 1;
3638219089Spjd	} else {
3639219089Spjd		if (flags.dryrun) {
3640219089Spjd			(void) printf(gettext("would create '%s' with the "
3641219089Spjd			    "following layout:\n\n"), newpool);
3642219089Spjd			print_vdev_tree(NULL, newpool, config, 0, B_FALSE);
3643219089Spjd		}
3644219089Spjd		nvlist_free(config);
3645219089Spjd	}
3646219089Spjd
3647219089Spjd	zpool_close(zhp);
3648219089Spjd
3649219089Spjd	if (ret != 0 || flags.dryrun || !flags.import)
3650219089Spjd		return (ret);
3651219089Spjd
3652219089Spjd	/*
3653219089Spjd	 * The split was successful. Now we need to open the new
3654219089Spjd	 * pool and import it.
3655219089Spjd	 */
3656219089Spjd	if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
3657219089Spjd		return (1);
3658219089Spjd	if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
3659219089Spjd	    zpool_enable_datasets(zhp, mntopts, 0) != 0) {
3660219089Spjd		ret = 1;
3661240415Smm		(void) fprintf(stderr, gettext("Split was successful, but "
3662219089Spjd		    "the datasets could not all be mounted\n"));
3663219089Spjd		(void) fprintf(stderr, gettext("Try doing '%s' with a "
3664219089Spjd		    "different altroot\n"), "zpool import");
3665219089Spjd	}
3666219089Spjd	zpool_close(zhp);
3667219089Spjd
3668219089Spjd	return (ret);
3669219089Spjd}
3670219089Spjd
3671219089Spjd
3672219089Spjd
3673219089Spjd/*
3674168404Spjd * zpool online <pool> <device> ...
3675168404Spjd */
3676168404Spjdint
3677168404Spjdzpool_do_online(int argc, char **argv)
3678168404Spjd{
3679168404Spjd	int c, i;
3680168404Spjd	char *poolname;
3681168404Spjd	zpool_handle_t *zhp;
3682168404Spjd	int ret = 0;
3683185029Spjd	vdev_state_t newstate;
3684219089Spjd	int flags = 0;
3685168404Spjd
3686168404Spjd	/* check options */
3687219089Spjd	while ((c = getopt(argc, argv, "et")) != -1) {
3688168404Spjd		switch (c) {
3689219089Spjd		case 'e':
3690219089Spjd			flags |= ZFS_ONLINE_EXPAND;
3691219089Spjd			break;
3692168404Spjd		case 't':
3693168404Spjd		case '?':
3694168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3695168404Spjd			    optopt);
3696168404Spjd			usage(B_FALSE);
3697168404Spjd		}
3698168404Spjd	}
3699168404Spjd
3700168404Spjd	argc -= optind;
3701168404Spjd	argv += optind;
3702168404Spjd
3703168404Spjd	/* get pool name and check number of arguments */
3704168404Spjd	if (argc < 1) {
3705168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
3706168404Spjd		usage(B_FALSE);
3707168404Spjd	}
3708168404Spjd	if (argc < 2) {
3709168404Spjd		(void) fprintf(stderr, gettext("missing device name\n"));
3710168404Spjd		usage(B_FALSE);
3711168404Spjd	}
3712168404Spjd
3713168404Spjd	poolname = argv[0];
3714168404Spjd
3715168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3716168404Spjd		return (1);
3717168404Spjd
3718185029Spjd	for (i = 1; i < argc; i++) {
3719219089Spjd		if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
3720185029Spjd			if (newstate != VDEV_STATE_HEALTHY) {
3721185029Spjd				(void) printf(gettext("warning: device '%s' "
3722185029Spjd				    "onlined, but remains in faulted state\n"),
3723185029Spjd				    argv[i]);
3724185029Spjd				if (newstate == VDEV_STATE_FAULTED)
3725185029Spjd					(void) printf(gettext("use 'zpool "
3726185029Spjd					    "clear' to restore a faulted "
3727185029Spjd					    "device\n"));
3728185029Spjd				else
3729185029Spjd					(void) printf(gettext("use 'zpool "
3730185029Spjd					    "replace' to replace devices "
3731185029Spjd					    "that are no longer present\n"));
3732185029Spjd			}
3733185029Spjd		} else {
3734168404Spjd			ret = 1;
3735185029Spjd		}
3736185029Spjd	}
3737168404Spjd
3738168404Spjd	zpool_close(zhp);
3739168404Spjd
3740168404Spjd	return (ret);
3741168404Spjd}
3742168404Spjd
3743168404Spjd/*
3744168404Spjd * zpool offline [-ft] <pool> <device> ...
3745168404Spjd *
3746168404Spjd *	-f	Force the device into the offline state, even if doing
3747168404Spjd *		so would appear to compromise pool availability.
3748168404Spjd *		(not supported yet)
3749168404Spjd *
3750168404Spjd *	-t	Only take the device off-line temporarily.  The offline
3751168404Spjd *		state will not be persistent across reboots.
3752168404Spjd */
3753168404Spjd/* ARGSUSED */
3754168404Spjdint
3755168404Spjdzpool_do_offline(int argc, char **argv)
3756168404Spjd{
3757168404Spjd	int c, i;
3758168404Spjd	char *poolname;
3759168404Spjd	zpool_handle_t *zhp;
3760168404Spjd	int ret = 0;
3761168404Spjd	boolean_t istmp = B_FALSE;
3762168404Spjd
3763168404Spjd	/* check options */
3764168404Spjd	while ((c = getopt(argc, argv, "ft")) != -1) {
3765168404Spjd		switch (c) {
3766168404Spjd		case 't':
3767168404Spjd			istmp = B_TRUE;
3768168404Spjd			break;
3769168404Spjd		case 'f':
3770168404Spjd		case '?':
3771168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3772168404Spjd			    optopt);
3773168404Spjd			usage(B_FALSE);
3774168404Spjd		}
3775168404Spjd	}
3776168404Spjd
3777168404Spjd	argc -= optind;
3778168404Spjd	argv += optind;
3779168404Spjd
3780168404Spjd	/* get pool name and check number of arguments */
3781168404Spjd	if (argc < 1) {
3782168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
3783168404Spjd		usage(B_FALSE);
3784168404Spjd	}
3785168404Spjd	if (argc < 2) {
3786168404Spjd		(void) fprintf(stderr, gettext("missing device name\n"));
3787168404Spjd		usage(B_FALSE);
3788168404Spjd	}
3789168404Spjd
3790168404Spjd	poolname = argv[0];
3791168404Spjd
3792168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3793168404Spjd		return (1);
3794168404Spjd
3795185029Spjd	for (i = 1; i < argc; i++) {
3796185029Spjd		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
3797168404Spjd			ret = 1;
3798185029Spjd	}
3799168404Spjd
3800168404Spjd	zpool_close(zhp);
3801168404Spjd
3802168404Spjd	return (ret);
3803168404Spjd}
3804168404Spjd
3805168404Spjd/*
3806168404Spjd * zpool clear <pool> [device]
3807168404Spjd *
3808168404Spjd * Clear all errors associated with a pool or a particular device.
3809168404Spjd */
3810168404Spjdint
3811168404Spjdzpool_do_clear(int argc, char **argv)
3812168404Spjd{
3813219089Spjd	int c;
3814168404Spjd	int ret = 0;
3815219089Spjd	boolean_t dryrun = B_FALSE;
3816219089Spjd	boolean_t do_rewind = B_FALSE;
3817219089Spjd	boolean_t xtreme_rewind = B_FALSE;
3818219089Spjd	uint32_t rewind_policy = ZPOOL_NO_REWIND;
3819219089Spjd	nvlist_t *policy = NULL;
3820168404Spjd	zpool_handle_t *zhp;
3821168404Spjd	char *pool, *device;
3822168404Spjd
3823219089Spjd	/* check options */
3824219089Spjd	while ((c = getopt(argc, argv, "FnX")) != -1) {
3825219089Spjd		switch (c) {
3826219089Spjd		case 'F':
3827219089Spjd			do_rewind = B_TRUE;
3828219089Spjd			break;
3829219089Spjd		case 'n':
3830219089Spjd			dryrun = B_TRUE;
3831219089Spjd			break;
3832219089Spjd		case 'X':
3833219089Spjd			xtreme_rewind = B_TRUE;
3834219089Spjd			break;
3835219089Spjd		case '?':
3836219089Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3837219089Spjd			    optopt);
3838219089Spjd			usage(B_FALSE);
3839219089Spjd		}
3840219089Spjd	}
3841219089Spjd
3842219089Spjd	argc -= optind;
3843219089Spjd	argv += optind;
3844219089Spjd
3845219089Spjd	if (argc < 1) {
3846168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
3847168404Spjd		usage(B_FALSE);
3848168404Spjd	}
3849168404Spjd
3850219089Spjd	if (argc > 2) {
3851168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
3852168404Spjd		usage(B_FALSE);
3853168404Spjd	}
3854168404Spjd
3855219089Spjd	if ((dryrun || xtreme_rewind) && !do_rewind) {
3856219089Spjd		(void) fprintf(stderr,
3857219089Spjd		    gettext("-n or -X only meaningful with -F\n"));
3858219089Spjd		usage(B_FALSE);
3859219089Spjd	}
3860219089Spjd	if (dryrun)
3861219089Spjd		rewind_policy = ZPOOL_TRY_REWIND;
3862219089Spjd	else if (do_rewind)
3863219089Spjd		rewind_policy = ZPOOL_DO_REWIND;
3864219089Spjd	if (xtreme_rewind)
3865219089Spjd		rewind_policy |= ZPOOL_EXTREME_REWIND;
3866168404Spjd
3867219089Spjd	/* In future, further rewind policy choices can be passed along here */
3868219089Spjd	if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
3869219089Spjd	    nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
3870168404Spjd		return (1);
3871168404Spjd
3872219089Spjd	pool = argv[0];
3873219089Spjd	device = argc == 2 ? argv[1] : NULL;
3874219089Spjd
3875219089Spjd	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
3876219089Spjd		nvlist_free(policy);
3877219089Spjd		return (1);
3878219089Spjd	}
3879219089Spjd
3880219089Spjd	if (zpool_clear(zhp, device, policy) != 0)
3881168404Spjd		ret = 1;
3882168404Spjd
3883168404Spjd	zpool_close(zhp);
3884168404Spjd
3885219089Spjd	nvlist_free(policy);
3886219089Spjd
3887168404Spjd	return (ret);
3888168404Spjd}
3889168404Spjd
3890228103Smm/*
3891228103Smm * zpool reguid <pool>
3892228103Smm */
3893228103Smmint
3894228103Smmzpool_do_reguid(int argc, char **argv)
3895228103Smm{
3896228103Smm	int c;
3897228103Smm	char *poolname;
3898228103Smm	zpool_handle_t *zhp;
3899228103Smm	int ret = 0;
3900228103Smm
3901228103Smm	/* check options */
3902228103Smm	while ((c = getopt(argc, argv, "")) != -1) {
3903228103Smm		switch (c) {
3904228103Smm		case '?':
3905228103Smm			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3906228103Smm			    optopt);
3907228103Smm			usage(B_FALSE);
3908228103Smm		}
3909228103Smm	}
3910228103Smm
3911228103Smm	argc -= optind;
3912228103Smm	argv += optind;
3913228103Smm
3914228103Smm	/* get pool name and check number of arguments */
3915228103Smm	if (argc < 1) {
3916228103Smm		(void) fprintf(stderr, gettext("missing pool name\n"));
3917228103Smm		usage(B_FALSE);
3918228103Smm	}
3919228103Smm
3920228103Smm	if (argc > 1) {
3921228103Smm		(void) fprintf(stderr, gettext("too many arguments\n"));
3922228103Smm		usage(B_FALSE);
3923228103Smm	}
3924228103Smm
3925228103Smm	poolname = argv[0];
3926228103Smm	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
3927228103Smm		return (1);
3928228103Smm
3929228103Smm	ret = zpool_reguid(zhp);
3930228103Smm
3931228103Smm	zpool_close(zhp);
3932228103Smm	return (ret);
3933228103Smm}
3934228103Smm
3935228103Smm
3936236155Smm/*
3937236155Smm * zpool reopen <pool>
3938236155Smm *
3939236155Smm * Reopen the pool so that the kernel can update the sizes of all vdevs.
3940236155Smm */
3941236155Smmint
3942236155Smmzpool_do_reopen(int argc, char **argv)
3943236155Smm{
3944260138Sdelphij	int c;
3945236155Smm	int ret = 0;
3946236155Smm	zpool_handle_t *zhp;
3947236155Smm	char *pool;
3948236155Smm
3949260138Sdelphij	/* check options */
3950260138Sdelphij	while ((c = getopt(argc, argv, "")) != -1) {
3951260138Sdelphij		switch (c) {
3952260138Sdelphij		case '?':
3953260138Sdelphij			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3954260138Sdelphij			    optopt);
3955260138Sdelphij			usage(B_FALSE);
3956260138Sdelphij		}
3957260138Sdelphij	}
3958260138Sdelphij
3959236155Smm	argc--;
3960236155Smm	argv++;
3961236155Smm
3962260138Sdelphij	if (argc < 1) {
3963260138Sdelphij		(void) fprintf(stderr, gettext("missing pool name\n"));
3964260138Sdelphij		usage(B_FALSE);
3965260138Sdelphij	}
3966236155Smm
3967260138Sdelphij	if (argc > 1) {
3968260138Sdelphij		(void) fprintf(stderr, gettext("too many arguments\n"));
3969260138Sdelphij		usage(B_FALSE);
3970260138Sdelphij	}
3971260138Sdelphij
3972236155Smm	pool = argv[0];
3973236155Smm	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
3974236155Smm		return (1);
3975236155Smm
3976236155Smm	ret = zpool_reopen(zhp);
3977236155Smm	zpool_close(zhp);
3978236155Smm	return (ret);
3979236155Smm}
3980236155Smm
3981168404Spjdtypedef struct scrub_cbdata {
3982168404Spjd	int	cb_type;
3983168404Spjd	int	cb_argc;
3984168404Spjd	char	**cb_argv;
3985324010Savg	pool_scrub_cmd_t cb_scrub_cmd;
3986168404Spjd} scrub_cbdata_t;
3987168404Spjd
3988168404Spjdint
3989168404Spjdscrub_callback(zpool_handle_t *zhp, void *data)
3990168404Spjd{
3991168404Spjd	scrub_cbdata_t *cb = data;
3992168404Spjd	int err;
3993168404Spjd
3994168404Spjd	/*
3995168404Spjd	 * Ignore faulted pools.
3996168404Spjd	 */
3997168404Spjd	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
3998168404Spjd		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
3999168404Spjd		    "currently unavailable\n"), zpool_get_name(zhp));
4000168404Spjd		return (1);
4001168404Spjd	}
4002168404Spjd
4003324010Savg	err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd);
4004168404Spjd
4005168404Spjd	return (err != 0);
4006168404Spjd}
4007168404Spjd
4008168404Spjd/*
4009324010Savg * zpool scrub [-s | -p] <pool> ...
4010168404Spjd *
4011168404Spjd *	-s	Stop.  Stops any in-progress scrub.
4012324010Savg *	-p	Pause. Pause in-progress scrub.
4013168404Spjd */
4014168404Spjdint
4015168404Spjdzpool_do_scrub(int argc, char **argv)
4016168404Spjd{
4017168404Spjd	int c;
4018168404Spjd	scrub_cbdata_t cb;
4019168404Spjd
4020219089Spjd	cb.cb_type = POOL_SCAN_SCRUB;
4021324010Savg	cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
4022168404Spjd
4023168404Spjd	/* check options */
4024324010Savg	while ((c = getopt(argc, argv, "sp")) != -1) {
4025168404Spjd		switch (c) {
4026168404Spjd		case 's':
4027219089Spjd			cb.cb_type = POOL_SCAN_NONE;
4028168404Spjd			break;
4029324010Savg		case 'p':
4030324010Savg			cb.cb_scrub_cmd = POOL_SCRUB_PAUSE;
4031324010Savg			break;
4032168404Spjd		case '?':
4033168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4034168404Spjd			    optopt);
4035168404Spjd			usage(B_FALSE);
4036168404Spjd		}
4037168404Spjd	}
4038168404Spjd
4039324010Savg	if (cb.cb_type == POOL_SCAN_NONE &&
4040324010Savg	    cb.cb_scrub_cmd == POOL_SCRUB_PAUSE) {
4041324010Savg		(void) fprintf(stderr, gettext("invalid option combination: "
4042324010Savg		    "-s and -p are mutually exclusive\n"));
4043324010Savg		usage(B_FALSE);
4044324010Savg	}
4045324010Savg
4046168404Spjd	cb.cb_argc = argc;
4047168404Spjd	cb.cb_argv = argv;
4048168404Spjd	argc -= optind;
4049168404Spjd	argv += optind;
4050168404Spjd
4051168404Spjd	if (argc < 1) {
4052168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
4053168404Spjd		usage(B_FALSE);
4054168404Spjd	}
4055168404Spjd
4056168404Spjd	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
4057168404Spjd}
4058168404Spjd
4059168404Spjdtypedef struct status_cbdata {
4060168404Spjd	int		cb_count;
4061168404Spjd	boolean_t	cb_allpools;
4062168404Spjd	boolean_t	cb_verbose;
4063168404Spjd	boolean_t	cb_explain;
4064168404Spjd	boolean_t	cb_first;
4065219089Spjd	boolean_t	cb_dedup_stats;
4066168404Spjd} status_cbdata_t;
4067168404Spjd
4068168404Spjd/*
4069168404Spjd * Print out detailed scrub status.
4070168404Spjd */
4071332525Smavstatic void
4072219089Spjdprint_scan_status(pool_scan_stat_t *ps)
4073168404Spjd{
4074324010Savg	time_t start, end, pause;
4075219089Spjd	uint64_t elapsed, mins_left, hours_left;
4076219089Spjd	uint64_t pass_exam, examined, total;
4077219089Spjd	uint_t rate;
4078168404Spjd	double fraction_done;
4079219089Spjd	char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
4080168404Spjd
4081226583Spjd	(void) printf(gettext("  scan: "));
4082168404Spjd
4083219089Spjd	/* If there's never been a scan, there's not much to say. */
4084219089Spjd	if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
4085219089Spjd	    ps->pss_func >= POOL_SCAN_FUNCS) {
4086168404Spjd		(void) printf(gettext("none requested\n"));
4087168404Spjd		return;
4088168404Spjd	}
4089168404Spjd
4090219089Spjd	start = ps->pss_start_time;
4091219089Spjd	end = ps->pss_end_time;
4092324010Savg	pause = ps->pss_pass_scrub_pause;
4093219089Spjd	zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
4094168404Spjd
4095219089Spjd	assert(ps->pss_func == POOL_SCAN_SCRUB ||
4096219089Spjd	    ps->pss_func == POOL_SCAN_RESILVER);
4097219089Spjd	/*
4098219089Spjd	 * Scan is finished or canceled.
4099219089Spjd	 */
4100219089Spjd	if (ps->pss_state == DSS_FINISHED) {
4101219089Spjd		uint64_t minutes_taken = (end - start) / 60;
4102296537Smav		char *fmt = NULL;
4103168404Spjd
4104219089Spjd		if (ps->pss_func == POOL_SCAN_SCRUB) {
4105219089Spjd			fmt = gettext("scrub repaired %s in %lluh%um with "
4106219089Spjd			    "%llu errors on %s");
4107219089Spjd		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
4108219089Spjd			fmt = gettext("resilvered %s in %lluh%um with "
4109219089Spjd			    "%llu errors on %s");
4110219089Spjd		}
4111219089Spjd		/* LINTED */
4112219089Spjd		(void) printf(fmt, processed_buf,
4113185029Spjd		    (u_longlong_t)(minutes_taken / 60),
4114185029Spjd		    (uint_t)(minutes_taken % 60),
4115219089Spjd		    (u_longlong_t)ps->pss_errors,
4116219089Spjd		    ctime((time_t *)&end));
4117168404Spjd		return;
4118219089Spjd	} else if (ps->pss_state == DSS_CANCELED) {
4119219089Spjd		if (ps->pss_func == POOL_SCAN_SCRUB) {
4120219089Spjd			(void) printf(gettext("scrub canceled on %s"),
4121219089Spjd			    ctime(&end));
4122219089Spjd		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
4123219089Spjd			(void) printf(gettext("resilver canceled on %s"),
4124219089Spjd			    ctime(&end));
4125219089Spjd		}
4126219089Spjd		return;
4127168404Spjd	}
4128168404Spjd
4129219089Spjd	assert(ps->pss_state == DSS_SCANNING);
4130168404Spjd
4131219089Spjd	/*
4132219089Spjd	 * Scan is in progress.
4133219089Spjd	 */
4134219089Spjd	if (ps->pss_func == POOL_SCAN_SCRUB) {
4135324010Savg		if (pause == 0) {
4136324010Savg			(void) printf(gettext("scrub in progress since %s"),
4137324010Savg			    ctime(&start));
4138324010Savg		} else {
4139324010Savg			char buf[32];
4140324010Savg			struct tm *p = localtime(&pause);
4141324010Savg			(void) strftime(buf, sizeof (buf), "%a %b %e %T %Y", p);
4142324010Savg			(void) printf(gettext("scrub paused since %s\n"), buf);
4143324010Savg			(void) printf(gettext("\tscrub started on   %s"),
4144324010Savg			    ctime(&start));
4145324010Savg		}
4146219089Spjd	} else if (ps->pss_func == POOL_SCAN_RESILVER) {
4147219089Spjd		(void) printf(gettext("resilver in progress since %s"),
4148219089Spjd		    ctime(&start));
4149219089Spjd	}
4150219089Spjd
4151219089Spjd	examined = ps->pss_examined ? ps->pss_examined : 1;
4152219089Spjd	total = ps->pss_to_examine;
4153168404Spjd	fraction_done = (double)examined / total;
4154168404Spjd
4155219089Spjd	/* elapsed time for this pass */
4156219089Spjd	elapsed = time(NULL) - ps->pss_pass_start;
4157324010Savg	elapsed -= ps->pss_pass_scrub_spent_paused;
4158219089Spjd	elapsed = elapsed ? elapsed : 1;
4159219089Spjd	pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1;
4160219089Spjd	rate = pass_exam / elapsed;
4161219089Spjd	rate = rate ? rate : 1;
4162219089Spjd	mins_left = ((total - examined) / rate) / 60;
4163219089Spjd	hours_left = mins_left / 60;
4164219089Spjd
4165219089Spjd	zfs_nicenum(examined, examined_buf, sizeof (examined_buf));
4166219089Spjd	zfs_nicenum(total, total_buf, sizeof (total_buf));
4167219089Spjd
4168219089Spjd	/*
4169219089Spjd	 * do not print estimated time if hours_left is more than 30 days
4170324010Savg	 * or we have a paused scrub
4171219089Spjd	 */
4172324010Savg	if (pause == 0) {
4173324010Savg		zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
4174324010Savg		(void) printf(gettext("\t%s scanned out of %s at %s/s"),
4175324010Savg		    examined_buf, total_buf, rate_buf);
4176324010Savg		if (hours_left < (30 * 24)) {
4177324010Savg			(void) printf(gettext(", %lluh%um to go\n"),
4178324010Savg			    (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
4179324010Savg		} else {
4180324010Savg			(void) printf(gettext(
4181324010Savg			    ", (scan is slow, no estimated time)\n"));
4182324010Savg		}
4183219089Spjd	} else {
4184324010Savg		(void) printf(gettext("\t%s scanned out of %s\n"),
4185324010Savg		    examined_buf, total_buf);
4186219089Spjd	}
4187219089Spjd
4188219089Spjd	if (ps->pss_func == POOL_SCAN_RESILVER) {
4189226583Spjd		(void) printf(gettext("        %s resilvered, %.2f%% done\n"),
4190219089Spjd		    processed_buf, 100 * fraction_done);
4191219089Spjd	} else if (ps->pss_func == POOL_SCAN_SCRUB) {
4192226583Spjd		(void) printf(gettext("        %s repaired, %.2f%% done\n"),
4193219089Spjd		    processed_buf, 100 * fraction_done);
4194219089Spjd	}
4195168404Spjd}
4196168404Spjd
4197332525Smav/*
4198332525Smav * Print out detailed removal status.
4199332525Smav */
4200168404Spjdstatic void
4201332525Smavprint_removal_status(zpool_handle_t *zhp, pool_removal_stat_t *prs)
4202332525Smav{
4203332525Smav	char copied_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
4204332525Smav	time_t start, end;
4205332525Smav	nvlist_t *config, *nvroot;
4206332525Smav	nvlist_t **child;
4207332525Smav	uint_t children;
4208332525Smav	char *vdev_name;
4209332525Smav
4210332525Smav	if (prs == NULL || prs->prs_state == DSS_NONE)
4211332525Smav		return;
4212332525Smav
4213332525Smav	/*
4214332525Smav	 * Determine name of vdev.
4215332525Smav	 */
4216332525Smav	config = zpool_get_config(zhp, NULL);
4217332525Smav	nvroot = fnvlist_lookup_nvlist(config,
4218332525Smav	    ZPOOL_CONFIG_VDEV_TREE);
4219332525Smav	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
4220332525Smav	    &child, &children) == 0);
4221332525Smav	assert(prs->prs_removing_vdev < children);
4222332525Smav	vdev_name = zpool_vdev_name(g_zfs, zhp,
4223332525Smav	    child[prs->prs_removing_vdev], B_TRUE);
4224332525Smav
4225332525Smav	(void) printf(gettext("remove: "));
4226332525Smav
4227332525Smav	start = prs->prs_start_time;
4228332525Smav	end = prs->prs_end_time;
4229332525Smav	zfs_nicenum(prs->prs_copied, copied_buf, sizeof (copied_buf));
4230332525Smav
4231332525Smav	/*
4232332525Smav	 * Removal is finished or canceled.
4233332525Smav	 */
4234332525Smav	if (prs->prs_state == DSS_FINISHED) {
4235332525Smav		uint64_t minutes_taken = (end - start) / 60;
4236332525Smav
4237332525Smav		(void) printf(gettext("Removal of vdev %llu copied %s "
4238332525Smav		    "in %lluh%um, completed on %s"),
4239332525Smav		    (longlong_t)prs->prs_removing_vdev,
4240332525Smav		    copied_buf,
4241332525Smav		    (u_longlong_t)(minutes_taken / 60),
4242332525Smav		    (uint_t)(minutes_taken % 60),
4243332525Smav		    ctime((time_t *)&end));
4244332525Smav	} else if (prs->prs_state == DSS_CANCELED) {
4245332525Smav		(void) printf(gettext("Removal of %s canceled on %s"),
4246332525Smav		    vdev_name, ctime(&end));
4247332525Smav	} else {
4248332525Smav		uint64_t copied, total, elapsed, mins_left, hours_left;
4249332525Smav		double fraction_done;
4250332525Smav		uint_t rate;
4251332525Smav
4252332525Smav		assert(prs->prs_state == DSS_SCANNING);
4253332525Smav
4254332525Smav		/*
4255332525Smav		 * Removal is in progress.
4256332525Smav		 */
4257332525Smav		(void) printf(gettext(
4258332525Smav		    "Evacuation of %s in progress since %s"),
4259332525Smav		    vdev_name, ctime(&start));
4260332525Smav
4261332525Smav		copied = prs->prs_copied > 0 ? prs->prs_copied : 1;
4262332525Smav		total = prs->prs_to_copy;
4263332525Smav		fraction_done = (double)copied / total;
4264332525Smav
4265332525Smav		/* elapsed time for this pass */
4266332525Smav		elapsed = time(NULL) - prs->prs_start_time;
4267332525Smav		elapsed = elapsed > 0 ? elapsed : 1;
4268332525Smav		rate = copied / elapsed;
4269332525Smav		rate = rate > 0 ? rate : 1;
4270332525Smav		mins_left = ((total - copied) / rate) / 60;
4271332525Smav		hours_left = mins_left / 60;
4272332525Smav
4273332525Smav		zfs_nicenum(copied, examined_buf, sizeof (examined_buf));
4274332525Smav		zfs_nicenum(total, total_buf, sizeof (total_buf));
4275332525Smav		zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
4276332525Smav
4277332525Smav		/*
4278332525Smav		 * do not print estimated time if hours_left is more than
4279332525Smav		 * 30 days
4280332525Smav		 */
4281332525Smav		(void) printf(gettext("    %s copied out of %s at %s/s, "
4282332525Smav		    "%.2f%% done"),
4283332525Smav		    examined_buf, total_buf, rate_buf, 100 * fraction_done);
4284332525Smav		if (hours_left < (30 * 24)) {
4285332525Smav			(void) printf(gettext(", %lluh%um to go\n"),
4286332525Smav			    (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
4287332525Smav		} else {
4288332525Smav			(void) printf(gettext(
4289332525Smav			    ", (copy is slow, no estimated time)\n"));
4290332525Smav		}
4291332525Smav	}
4292332525Smav
4293332525Smav	if (prs->prs_mapping_memory > 0) {
4294332525Smav		char mem_buf[7];
4295332525Smav		zfs_nicenum(prs->prs_mapping_memory, mem_buf, sizeof (mem_buf));
4296332525Smav		(void) printf(gettext("    %s memory used for "
4297332525Smav		    "removed device mappings\n"),
4298332525Smav		    mem_buf);
4299332525Smav	}
4300332525Smav}
4301332525Smav
4302332525Smavstatic void
4303168404Spjdprint_error_log(zpool_handle_t *zhp)
4304168404Spjd{
4305185029Spjd	nvlist_t *nverrlist = NULL;
4306168404Spjd	nvpair_t *elem;
4307168404Spjd	char *pathname;
4308168404Spjd	size_t len = MAXPATHLEN * 2;
4309168404Spjd
4310168404Spjd	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
4311168404Spjd		(void) printf("errors: List of errors unavailable "
4312168404Spjd		    "(insufficient privileges)\n");
4313168404Spjd		return;
4314168404Spjd	}
4315168404Spjd
4316168404Spjd	(void) printf("errors: Permanent errors have been "
4317168404Spjd	    "detected in the following files:\n\n");
4318168404Spjd
4319168404Spjd	pathname = safe_malloc(len);
4320168404Spjd	elem = NULL;
4321168404Spjd	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
4322168404Spjd		nvlist_t *nv;
4323168404Spjd		uint64_t dsobj, obj;
4324168404Spjd
4325168404Spjd		verify(nvpair_value_nvlist(elem, &nv) == 0);
4326168404Spjd		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
4327168404Spjd		    &dsobj) == 0);
4328168404Spjd		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
4329168404Spjd		    &obj) == 0);
4330168404Spjd		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
4331168404Spjd		(void) printf("%7s %s\n", "", pathname);
4332168404Spjd	}
4333168404Spjd	free(pathname);
4334168404Spjd	nvlist_free(nverrlist);
4335168404Spjd}
4336168404Spjd
4337168404Spjdstatic void
4338168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
4339168404Spjd    int namewidth)
4340168404Spjd{
4341168404Spjd	uint_t i;
4342168404Spjd	char *name;
4343168404Spjd
4344168404Spjd	if (nspares == 0)
4345168404Spjd		return;
4346168404Spjd
4347168404Spjd	(void) printf(gettext("\tspares\n"));
4348168404Spjd
4349168404Spjd	for (i = 0; i < nspares; i++) {
4350219089Spjd		name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE);
4351168404Spjd		print_status_config(zhp, name, spares[i],
4352209962Smm		    namewidth, 2, B_TRUE);
4353168404Spjd		free(name);
4354168404Spjd	}
4355168404Spjd}
4356168404Spjd
4357185029Spjdstatic void
4358185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
4359185029Spjd    int namewidth)
4360185029Spjd{
4361185029Spjd	uint_t i;
4362185029Spjd	char *name;
4363185029Spjd
4364185029Spjd	if (nl2cache == 0)
4365185029Spjd		return;
4366185029Spjd
4367185029Spjd	(void) printf(gettext("\tcache\n"));
4368185029Spjd
4369185029Spjd	for (i = 0; i < nl2cache; i++) {
4370219089Spjd		name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE);
4371185029Spjd		print_status_config(zhp, name, l2cache[i],
4372209962Smm		    namewidth, 2, B_FALSE);
4373185029Spjd		free(name);
4374185029Spjd	}
4375185029Spjd}
4376185029Spjd
4377219089Spjdstatic void
4378219089Spjdprint_dedup_stats(nvlist_t *config)
4379219089Spjd{
4380219089Spjd	ddt_histogram_t *ddh;
4381219089Spjd	ddt_stat_t *dds;
4382219089Spjd	ddt_object_t *ddo;
4383219089Spjd	uint_t c;
4384219089Spjd
4385219089Spjd	/*
4386219089Spjd	 * If the pool was faulted then we may not have been able to
4387253441Sdelphij	 * obtain the config. Otherwise, if we have anything in the dedup
4388219089Spjd	 * table continue processing the stats.
4389219089Spjd	 */
4390219089Spjd	if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
4391227497Smm	    (uint64_t **)&ddo, &c) != 0)
4392219089Spjd		return;
4393219089Spjd
4394219089Spjd	(void) printf("\n");
4395227497Smm	(void) printf(gettext(" dedup: "));
4396227497Smm	if (ddo->ddo_count == 0) {
4397227497Smm		(void) printf(gettext("no DDT entries\n"));
4398227497Smm		return;
4399227497Smm	}
4400227497Smm
4401219089Spjd	(void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
4402219089Spjd	    (u_longlong_t)ddo->ddo_count,
4403219089Spjd	    (u_longlong_t)ddo->ddo_dspace,
4404219089Spjd	    (u_longlong_t)ddo->ddo_mspace);
4405219089Spjd
4406219089Spjd	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
4407219089Spjd	    (uint64_t **)&dds, &c) == 0);
4408219089Spjd	verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
4409219089Spjd	    (uint64_t **)&ddh, &c) == 0);
4410219089Spjd	zpool_dump_ddt(dds, ddh);
4411219089Spjd}
4412219089Spjd
4413168404Spjd/*
4414168404Spjd * Display a summary of pool status.  Displays a summary such as:
4415168404Spjd *
4416168404Spjd *        pool: tank
4417168404Spjd *	status: DEGRADED
4418168404Spjd *	reason: One or more devices ...
4419236146Smm *         see: http://illumos.org/msg/ZFS-xxxx-01
4420168404Spjd *	config:
4421168404Spjd *		mirror		DEGRADED
4422168404Spjd *                c1t0d0	OK
4423168404Spjd *                c2t0d0	UNAVAIL
4424168404Spjd *
4425168404Spjd * When given the '-v' option, we print out the complete config.  If the '-e'
4426168404Spjd * option is specified, then we print out error rate information as well.
4427168404Spjd */
4428168404Spjdint
4429168404Spjdstatus_callback(zpool_handle_t *zhp, void *data)
4430168404Spjd{
4431168404Spjd	status_cbdata_t *cbp = data;
4432168404Spjd	nvlist_t *config, *nvroot;
4433168404Spjd	char *msgid;
4434168404Spjd	int reason;
4435168404Spjd	const char *health;
4436168404Spjd	uint_t c;
4437168404Spjd	vdev_stat_t *vs;
4438168404Spjd
4439168404Spjd	config = zpool_get_config(zhp, NULL);
4440168404Spjd	reason = zpool_get_status(zhp, &msgid);
4441168404Spjd
4442168404Spjd	cbp->cb_count++;
4443168404Spjd
4444168404Spjd	/*
4445168404Spjd	 * If we were given 'zpool status -x', only report those pools with
4446168404Spjd	 * problems.
4447168404Spjd	 */
4448248267Smm	if (cbp->cb_explain &&
4449248267Smm	    (reason == ZPOOL_STATUS_OK ||
4450248267Smm	    reason == ZPOOL_STATUS_VERSION_OLDER ||
4451268621Ssmh	    reason == ZPOOL_STATUS_NON_NATIVE_ASHIFT ||
4452248267Smm	    reason == ZPOOL_STATUS_FEAT_DISABLED)) {
4453168404Spjd		if (!cbp->cb_allpools) {
4454168404Spjd			(void) printf(gettext("pool '%s' is healthy\n"),
4455168404Spjd			    zpool_get_name(zhp));
4456168404Spjd			if (cbp->cb_first)
4457168404Spjd				cbp->cb_first = B_FALSE;
4458168404Spjd		}
4459168404Spjd		return (0);
4460168404Spjd	}
4461168404Spjd
4462168404Spjd	if (cbp->cb_first)
4463168404Spjd		cbp->cb_first = B_FALSE;
4464168404Spjd	else
4465168404Spjd		(void) printf("\n");
4466168404Spjd
4467332525Smav	nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
4468219089Spjd	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
4469168404Spjd	    (uint64_t **)&vs, &c) == 0);
4470185029Spjd	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
4471168404Spjd
4472168404Spjd	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
4473168404Spjd	(void) printf(gettext(" state: %s\n"), health);
4474168404Spjd
4475168404Spjd	switch (reason) {
4476168404Spjd	case ZPOOL_STATUS_MISSING_DEV_R:
4477168404Spjd		(void) printf(gettext("status: One or more devices could not "
4478168404Spjd		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
4479168404Spjd		    "continue functioning in a degraded state.\n"));
4480168404Spjd		(void) printf(gettext("action: Attach the missing device and "
4481168404Spjd		    "online it using 'zpool online'.\n"));
4482168404Spjd		break;
4483168404Spjd
4484168404Spjd	case ZPOOL_STATUS_MISSING_DEV_NR:
4485168404Spjd		(void) printf(gettext("status: One or more devices could not "
4486168404Spjd		    "be opened.  There are insufficient\n\treplicas for the "
4487168404Spjd		    "pool to continue functioning.\n"));
4488168404Spjd		(void) printf(gettext("action: Attach the missing device and "
4489168404Spjd		    "online it using 'zpool online'.\n"));
4490168404Spjd		break;
4491168404Spjd
4492168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_R:
4493168404Spjd		(void) printf(gettext("status: One or more devices could not "
4494168404Spjd		    "be used because the label is missing or\n\tinvalid.  "
4495168404Spjd		    "Sufficient replicas exist for the pool to continue\n\t"
4496168404Spjd		    "functioning in a degraded state.\n"));
4497168404Spjd		(void) printf(gettext("action: Replace the device using "
4498168404Spjd		    "'zpool replace'.\n"));
4499168404Spjd		break;
4500168404Spjd
4501168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
4502168404Spjd		(void) printf(gettext("status: One or more devices could not "
4503168404Spjd		    "be used because the label is missing \n\tor invalid.  "
4504168404Spjd		    "There are insufficient replicas for the pool to "
4505168404Spjd		    "continue\n\tfunctioning.\n"));
4506219089Spjd		zpool_explain_recover(zpool_get_handle(zhp),
4507219089Spjd		    zpool_get_name(zhp), reason, config);
4508168404Spjd		break;
4509168404Spjd
4510168404Spjd	case ZPOOL_STATUS_FAILING_DEV:
4511168404Spjd		(void) printf(gettext("status: One or more devices has "
4512168404Spjd		    "experienced an unrecoverable error.  An\n\tattempt was "
4513168404Spjd		    "made to correct the error.  Applications are "
4514168404Spjd		    "unaffected.\n"));
4515168404Spjd		(void) printf(gettext("action: Determine if the device needs "
4516168404Spjd		    "to be replaced, and clear the errors\n\tusing "
4517168404Spjd		    "'zpool clear' or replace the device with 'zpool "
4518168404Spjd		    "replace'.\n"));
4519168404Spjd		break;
4520168404Spjd
4521168404Spjd	case ZPOOL_STATUS_OFFLINE_DEV:
4522168404Spjd		(void) printf(gettext("status: One or more devices has "
4523168404Spjd		    "been taken offline by the administrator.\n\tSufficient "
4524168404Spjd		    "replicas exist for the pool to continue functioning in "
4525168404Spjd		    "a\n\tdegraded state.\n"));
4526168404Spjd		(void) printf(gettext("action: Online the device using "
4527168404Spjd		    "'zpool online' or replace the device with\n\t'zpool "
4528168404Spjd		    "replace'.\n"));
4529168404Spjd		break;
4530168404Spjd
4531219089Spjd	case ZPOOL_STATUS_REMOVED_DEV:
4532219089Spjd		(void) printf(gettext("status: One or more devices has "
4533219089Spjd		    "been removed by the administrator.\n\tSufficient "
4534219089Spjd		    "replicas exist for the pool to continue functioning in "
4535219089Spjd		    "a\n\tdegraded state.\n"));
4536219089Spjd		(void) printf(gettext("action: Online the device using "
4537219089Spjd		    "'zpool online' or replace the device with\n\t'zpool "
4538219089Spjd		    "replace'.\n"));
4539219089Spjd		break;
4540219089Spjd
4541168404Spjd	case ZPOOL_STATUS_RESILVERING:
4542168404Spjd		(void) printf(gettext("status: One or more devices is "
4543168404Spjd		    "currently being resilvered.  The pool will\n\tcontinue "
4544168404Spjd		    "to function, possibly in a degraded state.\n"));
4545168404Spjd		(void) printf(gettext("action: Wait for the resilver to "
4546168404Spjd		    "complete.\n"));
4547168404Spjd		break;
4548168404Spjd
4549168404Spjd	case ZPOOL_STATUS_CORRUPT_DATA:
4550168404Spjd		(void) printf(gettext("status: One or more devices has "
4551168404Spjd		    "experienced an error resulting in data\n\tcorruption.  "
4552168404Spjd		    "Applications may be affected.\n"));
4553168404Spjd		(void) printf(gettext("action: Restore the file in question "
4554168404Spjd		    "if possible.  Otherwise restore the\n\tentire pool from "
4555168404Spjd		    "backup.\n"));
4556168404Spjd		break;
4557168404Spjd
4558168404Spjd	case ZPOOL_STATUS_CORRUPT_POOL:
4559168404Spjd		(void) printf(gettext("status: The pool metadata is corrupted "
4560168404Spjd		    "and the pool cannot be opened.\n"));
4561219089Spjd		zpool_explain_recover(zpool_get_handle(zhp),
4562219089Spjd		    zpool_get_name(zhp), reason, config);
4563168404Spjd		break;
4564168404Spjd
4565168404Spjd	case ZPOOL_STATUS_VERSION_OLDER:
4566238926Smm		(void) printf(gettext("status: The pool is formatted using a "
4567238926Smm		    "legacy on-disk format.  The pool can\n\tstill be used, "
4568238926Smm		    "but some features are unavailable.\n"));
4569168404Spjd		(void) printf(gettext("action: Upgrade the pool using 'zpool "
4570168404Spjd		    "upgrade'.  Once this is done, the\n\tpool will no longer "
4571238926Smm		    "be accessible on software that does not support feature\n"
4572238926Smm		    "\tflags.\n"));
4573168404Spjd		break;
4574168404Spjd
4575168404Spjd	case ZPOOL_STATUS_VERSION_NEWER:
4576168404Spjd		(void) printf(gettext("status: The pool has been upgraded to a "
4577168404Spjd		    "newer, incompatible on-disk version.\n\tThe pool cannot "
4578168404Spjd		    "be accessed on this system.\n"));
4579168404Spjd		(void) printf(gettext("action: Access the pool from a system "
4580168404Spjd		    "running more recent software, or\n\trestore the pool from "
4581168404Spjd		    "backup.\n"));
4582168404Spjd		break;
4583168404Spjd
4584238926Smm	case ZPOOL_STATUS_FEAT_DISABLED:
4585238926Smm		(void) printf(gettext("status: Some supported features are not "
4586238926Smm		    "enabled on the pool. The pool can\n\tstill be used, but "
4587238926Smm		    "some features are unavailable.\n"));
4588238926Smm		(void) printf(gettext("action: Enable all features using "
4589238926Smm		    "'zpool upgrade'. Once this is done,\n\tthe pool may no "
4590238926Smm		    "longer be accessible by software that does not support\n\t"
4591243014Smm		    "the features. See zpool-features(7) for details.\n"));
4592238926Smm		break;
4593238926Smm
4594236884Smm	case ZPOOL_STATUS_UNSUP_FEAT_READ:
4595236884Smm		(void) printf(gettext("status: The pool cannot be accessed on "
4596236884Smm		    "this system because it uses the\n\tfollowing feature(s) "
4597236884Smm		    "not supported on this system:\n"));
4598236884Smm		zpool_print_unsup_feat(config);
4599236884Smm		(void) printf("\n");
4600236884Smm		(void) printf(gettext("action: Access the pool from a system "
4601236884Smm		    "that supports the required feature(s),\n\tor restore the "
4602236884Smm		    "pool from backup.\n"));
4603236884Smm		break;
4604236884Smm
4605236884Smm	case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
4606236884Smm		(void) printf(gettext("status: The pool can only be accessed "
4607236884Smm		    "in read-only mode on this system. It\n\tcannot be "
4608236884Smm		    "accessed in read-write mode because it uses the "
4609236884Smm		    "following\n\tfeature(s) not supported on this system:\n"));
4610236884Smm		zpool_print_unsup_feat(config);
4611236884Smm		(void) printf("\n");
4612236884Smm		(void) printf(gettext("action: The pool cannot be accessed in "
4613236884Smm		    "read-write mode. Import the pool with\n"
4614236884Smm		    "\t\"-o readonly=on\", access the pool from a system that "
4615236884Smm		    "supports the\n\trequired feature(s), or restore the "
4616236884Smm		    "pool from backup.\n"));
4617236884Smm		break;
4618236884Smm
4619185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_R:
4620185029Spjd		(void) printf(gettext("status: One or more devices are "
4621185029Spjd		    "faulted in response to persistent errors.\n\tSufficient "
4622185029Spjd		    "replicas exist for the pool to continue functioning "
4623185029Spjd		    "in a\n\tdegraded state.\n"));
4624185029Spjd		(void) printf(gettext("action: Replace the faulted device, "
4625185029Spjd		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
4626185029Spjd		break;
4627185029Spjd
4628185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_NR:
4629185029Spjd		(void) printf(gettext("status: One or more devices are "
4630185029Spjd		    "faulted in response to persistent errors.  There are "
4631185029Spjd		    "insufficient replicas for the pool to\n\tcontinue "
4632185029Spjd		    "functioning.\n"));
4633185029Spjd		(void) printf(gettext("action: Destroy and re-create the pool "
4634185029Spjd		    "from a backup source.  Manually marking the device\n"
4635185029Spjd		    "\trepaired using 'zpool clear' may allow some data "
4636185029Spjd		    "to be recovered.\n"));
4637185029Spjd		break;
4638185029Spjd
4639185029Spjd	case ZPOOL_STATUS_IO_FAILURE_WAIT:
4640185029Spjd	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
4641185029Spjd		(void) printf(gettext("status: One or more devices are "
4642185029Spjd		    "faulted in response to IO failures.\n"));
4643185029Spjd		(void) printf(gettext("action: Make sure the affected devices "
4644185029Spjd		    "are connected, then run 'zpool clear'.\n"));
4645185029Spjd		break;
4646185029Spjd
4647185029Spjd	case ZPOOL_STATUS_BAD_LOG:
4648185029Spjd		(void) printf(gettext("status: An intent log record "
4649185029Spjd		    "could not be read.\n"
4650185029Spjd		    "\tWaiting for adminstrator intervention to fix the "
4651185029Spjd		    "faulted pool.\n"));
4652185029Spjd		(void) printf(gettext("action: Either restore the affected "
4653185029Spjd		    "device(s) and run 'zpool online',\n"
4654185029Spjd		    "\tor ignore the intent log records by running "
4655185029Spjd		    "'zpool clear'.\n"));
4656185029Spjd		break;
4657185029Spjd
4658254591Sgibbs	case ZPOOL_STATUS_NON_NATIVE_ASHIFT:
4659254591Sgibbs		(void) printf(gettext("status: One or more devices are "
4660254591Sgibbs		    "configured to use a non-native block size.\n"
4661254591Sgibbs		    "\tExpect reduced performance.\n"));
4662254591Sgibbs		(void) printf(gettext("action: Replace affected devices with "
4663254591Sgibbs		    "devices that support the\n\tconfigured block size, or "
4664254591Sgibbs		    "migrate data to a properly configured\n\tpool.\n"));
4665254591Sgibbs		break;
4666254591Sgibbs
4667168404Spjd	default:
4668168404Spjd		/*
4669168404Spjd		 * The remaining errors can't actually be generated, yet.
4670168404Spjd		 */
4671168404Spjd		assert(reason == ZPOOL_STATUS_OK);
4672168404Spjd	}
4673168404Spjd
4674168404Spjd	if (msgid != NULL)
4675236146Smm		(void) printf(gettext("   see: http://illumos.org/msg/%s\n"),
4676168404Spjd		    msgid);
4677168404Spjd
4678168404Spjd	if (config != NULL) {
4679168404Spjd		int namewidth;
4680168404Spjd		uint64_t nerr;
4681185029Spjd		nvlist_t **spares, **l2cache;
4682185029Spjd		uint_t nspares, nl2cache;
4683219089Spjd		pool_scan_stat_t *ps = NULL;
4684332525Smav		pool_removal_stat_t *prs = NULL;
4685168404Spjd
4686219089Spjd		(void) nvlist_lookup_uint64_array(nvroot,
4687219089Spjd		    ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
4688219089Spjd		print_scan_status(ps);
4689168404Spjd
4690332525Smav		(void) nvlist_lookup_uint64_array(nvroot,
4691332525Smav		    ZPOOL_CONFIG_REMOVAL_STATS, (uint64_t **)&prs, &c);
4692332525Smav		print_removal_status(zhp, prs);
4693332525Smav
4694168404Spjd		namewidth = max_width(zhp, nvroot, 0, 0);
4695168404Spjd		if (namewidth < 10)
4696168404Spjd			namewidth = 10;
4697168404Spjd
4698168404Spjd		(void) printf(gettext("config:\n\n"));
4699168404Spjd		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
4700168404Spjd		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
4701168404Spjd		print_status_config(zhp, zpool_get_name(zhp), nvroot,
4702209962Smm		    namewidth, 0, B_FALSE);
4703209962Smm
4704185029Spjd		if (num_logs(nvroot) > 0)
4705213197Smm			print_logs(zhp, nvroot, namewidth, B_TRUE);
4706185029Spjd		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
4707185029Spjd		    &l2cache, &nl2cache) == 0)
4708185029Spjd			print_l2cache(zhp, l2cache, nl2cache, namewidth);
4709185029Spjd
4710168404Spjd		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
4711168404Spjd		    &spares, &nspares) == 0)
4712168404Spjd			print_spares(zhp, spares, nspares, namewidth);
4713168404Spjd
4714168404Spjd		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
4715168404Spjd		    &nerr) == 0) {
4716168404Spjd			nvlist_t *nverrlist = NULL;
4717168404Spjd
4718168404Spjd			/*
4719168404Spjd			 * If the approximate error count is small, get a
4720168404Spjd			 * precise count by fetching the entire log and
4721168404Spjd			 * uniquifying the results.
4722168404Spjd			 */
4723185029Spjd			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
4724168404Spjd			    zpool_get_errlog(zhp, &nverrlist) == 0) {
4725168404Spjd				nvpair_t *elem;
4726168404Spjd
4727168404Spjd				elem = NULL;
4728168404Spjd				nerr = 0;
4729168404Spjd				while ((elem = nvlist_next_nvpair(nverrlist,
4730168404Spjd				    elem)) != NULL) {
4731168404Spjd					nerr++;
4732168404Spjd				}
4733168404Spjd			}
4734168404Spjd			nvlist_free(nverrlist);
4735168404Spjd
4736168404Spjd			(void) printf("\n");
4737168404Spjd
4738168404Spjd			if (nerr == 0)
4739168404Spjd				(void) printf(gettext("errors: No known data "
4740168404Spjd				    "errors\n"));
4741168404Spjd			else if (!cbp->cb_verbose)
4742168404Spjd				(void) printf(gettext("errors: %llu data "
4743168404Spjd				    "errors, use '-v' for a list\n"),
4744168404Spjd				    (u_longlong_t)nerr);
4745168404Spjd			else
4746168404Spjd				print_error_log(zhp);
4747168404Spjd		}
4748219089Spjd
4749219089Spjd		if (cbp->cb_dedup_stats)
4750219089Spjd			print_dedup_stats(config);
4751168404Spjd	} else {
4752168404Spjd		(void) printf(gettext("config: The configuration cannot be "
4753168404Spjd		    "determined.\n"));
4754168404Spjd	}
4755168404Spjd
4756168404Spjd	return (0);
4757168404Spjd}
4758168404Spjd
4759168404Spjd/*
4760219089Spjd * zpool status [-vx] [-T d|u] [pool] ... [interval [count]]
4761168404Spjd *
4762168404Spjd *	-v	Display complete error logs
4763168404Spjd *	-x	Display only pools with potential problems
4764219089Spjd *	-D	Display dedup status (undocumented)
4765219089Spjd *	-T	Display a timestamp in date(1) or Unix format
4766168404Spjd *
4767168404Spjd * Describes the health status of all pools or some subset.
4768168404Spjd */
4769168404Spjdint
4770168404Spjdzpool_do_status(int argc, char **argv)
4771168404Spjd{
4772168404Spjd	int c;
4773168404Spjd	int ret;
4774219089Spjd	unsigned long interval = 0, count = 0;
4775168404Spjd	status_cbdata_t cb = { 0 };
4776168404Spjd
4777168404Spjd	/* check options */
4778219089Spjd	while ((c = getopt(argc, argv, "vxDT:")) != -1) {
4779168404Spjd		switch (c) {
4780168404Spjd		case 'v':
4781168404Spjd			cb.cb_verbose = B_TRUE;
4782168404Spjd			break;
4783168404Spjd		case 'x':
4784168404Spjd			cb.cb_explain = B_TRUE;
4785168404Spjd			break;
4786219089Spjd		case 'D':
4787219089Spjd			cb.cb_dedup_stats = B_TRUE;
4788219089Spjd			break;
4789219089Spjd		case 'T':
4790219089Spjd			get_timestamp_arg(*optarg);
4791219089Spjd			break;
4792168404Spjd		case '?':
4793168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
4794168404Spjd			    optopt);
4795168404Spjd			usage(B_FALSE);
4796168404Spjd		}
4797168404Spjd	}
4798168404Spjd
4799168404Spjd	argc -= optind;
4800168404Spjd	argv += optind;
4801168404Spjd
4802219089Spjd	get_interval_count(&argc, argv, &interval, &count);
4803168404Spjd
4804168404Spjd	if (argc == 0)
4805168404Spjd		cb.cb_allpools = B_TRUE;
4806168404Spjd
4807219089Spjd	cb.cb_first = B_TRUE;
4808168404Spjd
4809219089Spjd	for (;;) {
4810219089Spjd		if (timestamp_fmt != NODATE)
4811219089Spjd			print_timestamp(timestamp_fmt);
4812168404Spjd
4813219089Spjd		ret = for_each_pool(argc, argv, B_TRUE, NULL,
4814219089Spjd		    status_callback, &cb);
4815219089Spjd
4816219089Spjd		if (argc == 0 && cb.cb_count == 0)
4817219089Spjd			(void) printf(gettext("no pools available\n"));
4818219089Spjd		else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
4819219089Spjd			(void) printf(gettext("all pools are healthy\n"));
4820219089Spjd
4821219089Spjd		if (ret != 0)
4822219089Spjd			return (ret);
4823219089Spjd
4824219089Spjd		if (interval == 0)
4825219089Spjd			break;
4826219089Spjd
4827219089Spjd		if (count != 0 && --count == 0)
4828219089Spjd			break;
4829219089Spjd
4830219089Spjd		(void) sleep(interval);
4831219089Spjd	}
4832219089Spjd
4833219089Spjd	return (0);
4834168404Spjd}
4835168404Spjd
4836168404Spjdtypedef struct upgrade_cbdata {
4837276226Ssmh	boolean_t	cb_first;
4838276226Ssmh	boolean_t	cb_unavail;
4839307108Smav	char		cb_poolname[ZFS_MAX_DATASET_NAME_LEN];
4840276226Ssmh	int		cb_argc;
4841276226Ssmh	uint64_t	cb_version;
4842276226Ssmh	char		**cb_argv;
4843168404Spjd} upgrade_cbdata_t;
4844168404Spjd
4845238950Smm#ifdef __FreeBSD__
4846168404Spjdstatic int
4847212050Spjdis_root_pool(zpool_handle_t *zhp)
4848212050Spjd{
4849212050Spjd	static struct statfs sfs;
4850212050Spjd	static char *poolname = NULL;
4851212050Spjd	static boolean_t stated = B_FALSE;
4852212050Spjd	char *slash;
4853212050Spjd
4854212067Spjd	if (!stated) {
4855212050Spjd		stated = B_TRUE;
4856212050Spjd		if (statfs("/", &sfs) == -1) {
4857212050Spjd			(void) fprintf(stderr,
4858212050Spjd			    "Unable to stat root file system: %s.\n",
4859212050Spjd			    strerror(errno));
4860212067Spjd			return (0);
4861212050Spjd		}
4862212050Spjd		if (strcmp(sfs.f_fstypename, "zfs") != 0)
4863212067Spjd			return (0);
4864212050Spjd		poolname = sfs.f_mntfromname;
4865212050Spjd		if ((slash = strchr(poolname, '/')) != NULL)
4866212050Spjd			*slash = '\0';
4867212050Spjd	}
4868212050Spjd	return (poolname != NULL && strcmp(poolname, zpool_get_name(zhp)) == 0);
4869212050Spjd}
4870212050Spjd
4871238950Smmstatic void
4872271934Ssmhroot_pool_upgrade_check(zpool_handle_t *zhp, char *poolname, int size)
4873271934Ssmh{
4874238950Smm
4875238950Smm	if (poolname[0] == '\0' && is_root_pool(zhp))
4876238950Smm		(void) strlcpy(poolname, zpool_get_name(zhp), size);
4877238950Smm}
4878238950Smm#endif	/* FreeBSD */
4879238950Smm
4880212050Spjdstatic int
4881238926Smmupgrade_version(zpool_handle_t *zhp, uint64_t version)
4882238926Smm{
4883238926Smm	int ret;
4884238926Smm	nvlist_t *config;
4885238926Smm	uint64_t oldversion;
4886238926Smm
4887238926Smm	config = zpool_get_config(zhp, NULL);
4888238926Smm	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
4889238926Smm	    &oldversion) == 0);
4890238926Smm
4891238926Smm	assert(SPA_VERSION_IS_SUPPORTED(oldversion));
4892238926Smm	assert(oldversion < version);
4893238926Smm
4894238926Smm	ret = zpool_upgrade(zhp, version);
4895238926Smm	if (ret != 0)
4896238926Smm		return (ret);
4897238926Smm
4898238926Smm	if (version >= SPA_VERSION_FEATURES) {
4899238926Smm		(void) printf(gettext("Successfully upgraded "
4900238926Smm		    "'%s' from version %llu to feature flags.\n"),
4901238926Smm		    zpool_get_name(zhp), oldversion);
4902238926Smm	} else {
4903238926Smm		(void) printf(gettext("Successfully upgraded "
4904238926Smm		    "'%s' from version %llu to version %llu.\n"),
4905238926Smm		    zpool_get_name(zhp), oldversion, version);
4906238926Smm	}
4907238926Smm
4908238926Smm	return (0);
4909238926Smm}
4910238926Smm
4911238926Smmstatic int
4912238926Smmupgrade_enable_all(zpool_handle_t *zhp, int *countp)
4913238926Smm{
4914238926Smm	int i, ret, count;
4915238926Smm	boolean_t firstff = B_TRUE;
4916238926Smm	nvlist_t *enabled = zpool_get_features(zhp);
4917238926Smm
4918238926Smm	count = 0;
4919238926Smm	for (i = 0; i < SPA_FEATURES; i++) {
4920238926Smm		const char *fname = spa_feature_table[i].fi_uname;
4921238926Smm		const char *fguid = spa_feature_table[i].fi_guid;
4922238926Smm		if (!nvlist_exists(enabled, fguid)) {
4923238926Smm			char *propname;
4924238926Smm			verify(-1 != asprintf(&propname, "feature@%s", fname));
4925238926Smm			ret = zpool_set_prop(zhp, propname,
4926238926Smm			    ZFS_FEATURE_ENABLED);
4927238926Smm			if (ret != 0) {
4928238926Smm				free(propname);
4929238926Smm				return (ret);
4930238926Smm			}
4931238926Smm			count++;
4932238926Smm
4933238926Smm			if (firstff) {
4934238926Smm				(void) printf(gettext("Enabled the "
4935238926Smm				    "following features on '%s':\n"),
4936238926Smm				    zpool_get_name(zhp));
4937238926Smm				firstff = B_FALSE;
4938238926Smm			}
4939238926Smm			(void) printf(gettext("  %s\n"), fname);
4940238926Smm			free(propname);
4941238926Smm		}
4942238926Smm	}
4943238926Smm
4944238926Smm	if (countp != NULL)
4945238926Smm		*countp = count;
4946238926Smm	return (0);
4947238926Smm}
4948238926Smm
4949238926Smmstatic int
4950168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg)
4951168404Spjd{
4952168404Spjd	upgrade_cbdata_t *cbp = arg;
4953168404Spjd	nvlist_t *config;
4954168404Spjd	uint64_t version;
4955238926Smm	boolean_t printnl = B_FALSE;
4956238926Smm	int ret;
4957168404Spjd
4958276194Ssmh	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
4959276194Ssmh		(void) fprintf(stderr, gettext("cannot upgrade '%s': pool is "
4960276226Ssmh		    "currently unavailable.\n\n"), zpool_get_name(zhp));
4961276226Ssmh		cbp->cb_unavail = B_TRUE;
4962276194Ssmh		/* Allow iteration to continue. */
4963276194Ssmh		return (0);
4964276194Ssmh	}
4965276194Ssmh
4966168404Spjd	config = zpool_get_config(zhp, NULL);
4967168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
4968168404Spjd	    &version) == 0);
4969168404Spjd
4970238926Smm	assert(SPA_VERSION_IS_SUPPORTED(version));
4971168404Spjd
4972238926Smm	if (version < cbp->cb_version) {
4973238926Smm		cbp->cb_first = B_FALSE;
4974238926Smm		ret = upgrade_version(zhp, cbp->cb_version);
4975238926Smm		if (ret != 0)
4976238926Smm			return (ret);
4977238926Smm#ifdef __FreeBSD__
4978238950Smm		root_pool_upgrade_check(zhp, cbp->cb_poolname,
4979238950Smm		    sizeof(cbp->cb_poolname));
4980271934Ssmh#endif	/* __FreeBSD__ */
4981238926Smm		printnl = B_TRUE;
4982238926Smm
4983238926Smm#ifdef illumos
4984238926Smm		/*
4985238926Smm		 * If they did "zpool upgrade -a", then we could
4986238926Smm		 * be doing ioctls to different pools.  We need
4987238926Smm		 * to log this history once to each pool, and bypass
4988238926Smm		 * the normal history logging that happens in main().
4989238926Smm		 */
4990238926Smm		(void) zpool_log_history(g_zfs, history_str);
4991238926Smm		log_history = B_FALSE;
4992238926Smm#endif
4993238926Smm	}
4994238926Smm
4995238926Smm	if (cbp->cb_version >= SPA_VERSION_FEATURES) {
4996238926Smm		int count;
4997238926Smm		ret = upgrade_enable_all(zhp, &count);
4998238926Smm		if (ret != 0)
4999238926Smm			return (ret);
5000238926Smm
5001238926Smm		if (count > 0) {
5002168404Spjd			cbp->cb_first = B_FALSE;
5003238926Smm			printnl = B_TRUE;
5004271934Ssmh#ifdef __FreeBSD__
5005271934Ssmh			root_pool_upgrade_check(zhp, cbp->cb_poolname,
5006271934Ssmh			    sizeof(cbp->cb_poolname));
5007271934Ssmh#endif	/* __FreeBSD__ */
5008248571Smm			/*
5009248571Smm			 * If they did "zpool upgrade -a", then we could
5010248571Smm			 * be doing ioctls to different pools.  We need
5011248571Smm			 * to log this history once to each pool, and bypass
5012248571Smm			 * the normal history logging that happens in main().
5013248571Smm			 */
5014248571Smm			(void) zpool_log_history(g_zfs, history_str);
5015248571Smm			log_history = B_FALSE;
5016168404Spjd		}
5017238926Smm	}
5018168404Spjd
5019238926Smm	if (printnl) {
5020238926Smm		(void) printf(gettext("\n"));
5021238926Smm	}
5022238926Smm
5023238926Smm	return (0);
5024238926Smm}
5025238926Smm
5026238926Smmstatic int
5027276226Ssmhupgrade_list_unavail(zpool_handle_t *zhp, void *arg)
5028276226Ssmh{
5029276226Ssmh	upgrade_cbdata_t *cbp = arg;
5030276226Ssmh
5031276226Ssmh	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
5032276226Ssmh		if (cbp->cb_first) {
5033276226Ssmh			(void) fprintf(stderr, gettext("The following pools "
5034276226Ssmh			    "are unavailable and cannot be upgraded as this "
5035276226Ssmh			    "time.\n\n"));
5036276226Ssmh			(void) fprintf(stderr, gettext("POOL\n"));
5037276226Ssmh			(void) fprintf(stderr, gettext("------------\n"));
5038276226Ssmh			cbp->cb_first = B_FALSE;
5039276226Ssmh		}
5040276226Ssmh		(void) printf(gettext("%s\n"), zpool_get_name(zhp));
5041276226Ssmh		cbp->cb_unavail = B_TRUE;
5042276226Ssmh	}
5043276226Ssmh	return (0);
5044276226Ssmh}
5045276226Ssmh
5046276226Ssmhstatic int
5047238926Smmupgrade_list_older_cb(zpool_handle_t *zhp, void *arg)
5048238926Smm{
5049238926Smm	upgrade_cbdata_t *cbp = arg;
5050238926Smm	nvlist_t *config;
5051238926Smm	uint64_t version;
5052238926Smm
5053276226Ssmh	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
5054276226Ssmh		/*
5055276226Ssmh		 * This will have been reported by upgrade_list_unavail so
5056276226Ssmh		 * just allow iteration to continue.
5057276226Ssmh		 */
5058276226Ssmh		cbp->cb_unavail = B_TRUE;
5059276226Ssmh		return (0);
5060276226Ssmh	}
5061276226Ssmh
5062238926Smm	config = zpool_get_config(zhp, NULL);
5063238926Smm	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
5064238926Smm	    &version) == 0);
5065238926Smm
5066238926Smm	assert(SPA_VERSION_IS_SUPPORTED(version));
5067238926Smm
5068238926Smm	if (version < SPA_VERSION_FEATURES) {
5069168404Spjd		if (cbp->cb_first) {
5070168404Spjd			(void) printf(gettext("The following pools are "
5071238926Smm			    "formatted with legacy version numbers and can\n"
5072238926Smm			    "be upgraded to use feature flags.  After "
5073238926Smm			    "being upgraded, these pools\nwill no "
5074238926Smm			    "longer be accessible by software that does not "
5075238926Smm			    "support feature\nflags.\n\n"));
5076168404Spjd			(void) printf(gettext("VER  POOL\n"));
5077168404Spjd			(void) printf(gettext("---  ------------\n"));
5078168404Spjd			cbp->cb_first = B_FALSE;
5079168404Spjd		}
5080168404Spjd
5081168404Spjd		(void) printf("%2llu   %s\n", (u_longlong_t)version,
5082168404Spjd		    zpool_get_name(zhp));
5083168404Spjd	}
5084168404Spjd
5085238926Smm	return (0);
5086168404Spjd}
5087168404Spjd
5088238926Smmstatic int
5089238926Smmupgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg)
5090238926Smm{
5091238926Smm	upgrade_cbdata_t *cbp = arg;
5092238926Smm	nvlist_t *config;
5093238926Smm	uint64_t version;
5094238926Smm
5095276194Ssmh	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
5096276226Ssmh		/*
5097276226Ssmh		 * This will have been reported by upgrade_list_unavail so
5098276226Ssmh		 * just allow iteration to continue.
5099276226Ssmh		 */
5100276226Ssmh		cbp->cb_unavail = B_TRUE;
5101276194Ssmh		return (0);
5102276194Ssmh	}
5103276194Ssmh
5104238926Smm	config = zpool_get_config(zhp, NULL);
5105238926Smm	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
5106238926Smm	    &version) == 0);
5107238926Smm
5108238926Smm	if (version >= SPA_VERSION_FEATURES) {
5109238926Smm		int i;
5110238926Smm		boolean_t poolfirst = B_TRUE;
5111238926Smm		nvlist_t *enabled = zpool_get_features(zhp);
5112238926Smm
5113238926Smm		for (i = 0; i < SPA_FEATURES; i++) {
5114238926Smm			const char *fguid = spa_feature_table[i].fi_guid;
5115238926Smm			const char *fname = spa_feature_table[i].fi_uname;
5116238926Smm			if (!nvlist_exists(enabled, fguid)) {
5117238926Smm				if (cbp->cb_first) {
5118238926Smm					(void) printf(gettext("\nSome "
5119238926Smm					    "supported features are not "
5120238926Smm					    "enabled on the following pools. "
5121238926Smm					    "Once a\nfeature is enabled the "
5122238926Smm					    "pool may become incompatible with "
5123238926Smm					    "software\nthat does not support "
5124238926Smm					    "the feature. See "
5125243014Smm					    "zpool-features(7) for "
5126238926Smm					    "details.\n\n"));
5127238926Smm					(void) printf(gettext("POOL  "
5128238926Smm					    "FEATURE\n"));
5129238926Smm					(void) printf(gettext("------"
5130238926Smm					    "---------\n"));
5131238926Smm					cbp->cb_first = B_FALSE;
5132238926Smm				}
5133238926Smm
5134238926Smm				if (poolfirst) {
5135238926Smm					(void) printf(gettext("%s\n"),
5136238926Smm					    zpool_get_name(zhp));
5137238926Smm					poolfirst = B_FALSE;
5138238926Smm				}
5139238926Smm
5140238926Smm				(void) printf(gettext("      %s\n"), fname);
5141238926Smm			}
5142238926Smm		}
5143238926Smm	}
5144238926Smm
5145238926Smm	return (0);
5146238926Smm}
5147238926Smm
5148168404Spjd/* ARGSUSED */
5149168404Spjdstatic int
5150168404Spjdupgrade_one(zpool_handle_t *zhp, void *data)
5151168404Spjd{
5152238926Smm	boolean_t printnl = B_FALSE;
5153185029Spjd	upgrade_cbdata_t *cbp = data;
5154185029Spjd	uint64_t cur_version;
5155168404Spjd	int ret;
5156168404Spjd
5157276226Ssmh	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
5158276226Ssmh		(void) fprintf(stderr, gettext("cannot upgrade '%s': pool is "
5159276226Ssmh		    "is currently unavailable.\n\n"), zpool_get_name(zhp));
5160276226Ssmh		cbp->cb_unavail = B_TRUE;
5161276226Ssmh		return (1);
5162276226Ssmh	}
5163276226Ssmh
5164185029Spjd	if (strcmp("log", zpool_get_name(zhp)) == 0) {
5165185029Spjd		(void) printf(gettext("'log' is now a reserved word\n"
5166185029Spjd		    "Pool 'log' must be renamed using export and import"
5167276226Ssmh		    " to upgrade.\n\n"));
5168185029Spjd		return (1);
5169185029Spjd	}
5170168404Spjd
5171185029Spjd	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
5172185029Spjd	if (cur_version > cbp->cb_version) {
5173168404Spjd		(void) printf(gettext("Pool '%s' is already formatted "
5174238926Smm		    "using more current version '%llu'.\n\n"),
5175185029Spjd		    zpool_get_name(zhp), cur_version);
5176185029Spjd		return (0);
5177185029Spjd	}
5178238926Smm
5179238926Smm	if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) {
5180185029Spjd		(void) printf(gettext("Pool '%s' is already formatted "
5181238926Smm		    "using version %llu.\n\n"), zpool_get_name(zhp),
5182238926Smm		    cbp->cb_version);
5183168404Spjd		return (0);
5184168404Spjd	}
5185168404Spjd
5186238926Smm	if (cur_version != cbp->cb_version) {
5187238926Smm		printnl = B_TRUE;
5188238926Smm		ret = upgrade_version(zhp, cbp->cb_version);
5189238950Smm		if (ret != 0)
5190238950Smm			return (ret);
5191238926Smm#ifdef __FreeBSD__
5192238950Smm		root_pool_upgrade_check(zhp, cbp->cb_poolname,
5193238950Smm		    sizeof(cbp->cb_poolname));
5194271934Ssmh#endif	/* __FreeBSD__ */
5195238926Smm	}
5196168404Spjd
5197238926Smm	if (cbp->cb_version >= SPA_VERSION_FEATURES) {
5198238926Smm		int count = 0;
5199238926Smm		ret = upgrade_enable_all(zhp, &count);
5200238926Smm		if (ret != 0)
5201238926Smm			return (ret);
5202238926Smm
5203238926Smm		if (count != 0) {
5204238926Smm			printnl = B_TRUE;
5205238950Smm#ifdef __FreeBSD__
5206238951Smm			root_pool_upgrade_check(zhp, cbp->cb_poolname,
5207238951Smm			    sizeof(cbp->cb_poolname));
5208238950Smm#endif	/* __FreeBSD __*/
5209238926Smm		} else if (cur_version == SPA_VERSION) {
5210238926Smm			(void) printf(gettext("Pool '%s' already has all "
5211276226Ssmh			    "supported features enabled.\n\n"),
5212238926Smm			    zpool_get_name(zhp));
5213238926Smm		}
5214168404Spjd	}
5215168404Spjd
5216238926Smm	if (printnl) {
5217238926Smm		(void) printf(gettext("\n"));
5218238926Smm	}
5219238926Smm
5220238926Smm	return (0);
5221168404Spjd}
5222168404Spjd
5223168404Spjd/*
5224168404Spjd * zpool upgrade
5225168404Spjd * zpool upgrade -v
5226185029Spjd * zpool upgrade [-V version] <-a | pool ...>
5227168404Spjd *
5228168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade.
5229168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will
5230168404Spjd * upgrade all pools.
5231168404Spjd */
5232168404Spjdint
5233168404Spjdzpool_do_upgrade(int argc, char **argv)
5234168404Spjd{
5235168404Spjd	int c;
5236168404Spjd	upgrade_cbdata_t cb = { 0 };
5237168404Spjd	int ret = 0;
5238168404Spjd	boolean_t showversions = B_FALSE;
5239238926Smm	boolean_t upgradeall = B_FALSE;
5240185029Spjd	char *end;
5241168404Spjd
5242185029Spjd
5243168404Spjd	/* check options */
5244219089Spjd	while ((c = getopt(argc, argv, ":avV:")) != -1) {
5245168404Spjd		switch (c) {
5246168404Spjd		case 'a':
5247238926Smm			upgradeall = B_TRUE;
5248168404Spjd			break;
5249168404Spjd		case 'v':
5250168404Spjd			showversions = B_TRUE;
5251168404Spjd			break;
5252185029Spjd		case 'V':
5253185029Spjd			cb.cb_version = strtoll(optarg, &end, 10);
5254236884Smm			if (*end != '\0' ||
5255236884Smm			    !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) {
5256185029Spjd				(void) fprintf(stderr,
5257185029Spjd				    gettext("invalid version '%s'\n"), optarg);
5258185029Spjd				usage(B_FALSE);
5259185029Spjd			}
5260185029Spjd			break;
5261219089Spjd		case ':':
5262219089Spjd			(void) fprintf(stderr, gettext("missing argument for "
5263219089Spjd			    "'%c' option\n"), optopt);
5264219089Spjd			usage(B_FALSE);
5265219089Spjd			break;
5266168404Spjd		case '?':
5267168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5268168404Spjd			    optopt);
5269168404Spjd			usage(B_FALSE);
5270168404Spjd		}
5271168404Spjd	}
5272168404Spjd
5273168404Spjd	cb.cb_argc = argc;
5274168404Spjd	cb.cb_argv = argv;
5275168404Spjd	argc -= optind;
5276168404Spjd	argv += optind;
5277168404Spjd
5278185029Spjd	if (cb.cb_version == 0) {
5279185029Spjd		cb.cb_version = SPA_VERSION;
5280238926Smm	} else if (!upgradeall && argc == 0) {
5281185029Spjd		(void) fprintf(stderr, gettext("-V option is "
5282185029Spjd		    "incompatible with other arguments\n"));
5283185029Spjd		usage(B_FALSE);
5284185029Spjd	}
5285185029Spjd
5286168404Spjd	if (showversions) {
5287238926Smm		if (upgradeall || argc != 0) {
5288168404Spjd			(void) fprintf(stderr, gettext("-v option is "
5289168404Spjd			    "incompatible with other arguments\n"));
5290168404Spjd			usage(B_FALSE);
5291168404Spjd		}
5292238926Smm	} else if (upgradeall) {
5293168404Spjd		if (argc != 0) {
5294185029Spjd			(void) fprintf(stderr, gettext("-a option should not "
5295185029Spjd			    "be used along with a pool name\n"));
5296168404Spjd			usage(B_FALSE);
5297168404Spjd		}
5298168404Spjd	}
5299168404Spjd
5300236884Smm	(void) printf(gettext("This system supports ZFS pool feature "
5301236884Smm	    "flags.\n\n"));
5302168404Spjd	if (showversions) {
5303238926Smm		int i;
5304238926Smm
5305238926Smm		(void) printf(gettext("The following features are "
5306168404Spjd		    "supported:\n\n"));
5307238926Smm		(void) printf(gettext("FEAT DESCRIPTION\n"));
5308238926Smm		(void) printf("----------------------------------------------"
5309238926Smm		    "---------------\n");
5310238926Smm		for (i = 0; i < SPA_FEATURES; i++) {
5311238926Smm			zfeature_info_t *fi = &spa_feature_table[i];
5312286708Smav			const char *ro =
5313286708Smav			    (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
5314238926Smm			    " (read-only compatible)" : "";
5315238926Smm
5316238926Smm			(void) printf("%-37s%s\n", fi->fi_uname, ro);
5317238926Smm			(void) printf("     %s\n", fi->fi_desc);
5318238926Smm		}
5319238926Smm		(void) printf("\n");
5320238926Smm
5321238926Smm		(void) printf(gettext("The following legacy versions are also "
5322238926Smm		    "supported:\n\n"));
5323168404Spjd		(void) printf(gettext("VER  DESCRIPTION\n"));
5324168404Spjd		(void) printf("---  -----------------------------------------"
5325168404Spjd		    "---------------\n");
5326168404Spjd		(void) printf(gettext(" 1   Initial ZFS version\n"));
5327168404Spjd		(void) printf(gettext(" 2   Ditto blocks "
5328168404Spjd		    "(replicated metadata)\n"));
5329168404Spjd		(void) printf(gettext(" 3   Hot spares and double parity "
5330168404Spjd		    "RAID-Z\n"));
5331168404Spjd		(void) printf(gettext(" 4   zpool history\n"));
5332168404Spjd		(void) printf(gettext(" 5   Compression using the gzip "
5333168404Spjd		    "algorithm\n"));
5334185029Spjd		(void) printf(gettext(" 6   bootfs pool property\n"));
5335185029Spjd		(void) printf(gettext(" 7   Separate intent log devices\n"));
5336185029Spjd		(void) printf(gettext(" 8   Delegated administration\n"));
5337185029Spjd		(void) printf(gettext(" 9   refquota and refreservation "
5338185029Spjd		    "properties\n"));
5339185029Spjd		(void) printf(gettext(" 10  Cache devices\n"));
5340185029Spjd		(void) printf(gettext(" 11  Improved scrub performance\n"));
5341185029Spjd		(void) printf(gettext(" 12  Snapshot properties\n"));
5342185029Spjd		(void) printf(gettext(" 13  snapused property\n"));
5343209962Smm		(void) printf(gettext(" 14  passthrough-x aclinherit\n"));
5344209962Smm		(void) printf(gettext(" 15  user/group space accounting\n"));
5345219089Spjd		(void) printf(gettext(" 16  stmf property support\n"));
5346219089Spjd		(void) printf(gettext(" 17  Triple-parity RAID-Z\n"));
5347219089Spjd		(void) printf(gettext(" 18  Snapshot user holds\n"));
5348219089Spjd		(void) printf(gettext(" 19  Log device removal\n"));
5349219089Spjd		(void) printf(gettext(" 20  Compression using zle "
5350219089Spjd		    "(zero-length encoding)\n"));
5351219089Spjd		(void) printf(gettext(" 21  Deduplication\n"));
5352219089Spjd		(void) printf(gettext(" 22  Received properties\n"));
5353219089Spjd		(void) printf(gettext(" 23  Slim ZIL\n"));
5354219089Spjd		(void) printf(gettext(" 24  System attributes\n"));
5355219089Spjd		(void) printf(gettext(" 25  Improved scrub stats\n"));
5356219089Spjd		(void) printf(gettext(" 26  Improved snapshot deletion "
5357219089Spjd		    "performance\n"));
5358219089Spjd		(void) printf(gettext(" 27  Improved snapshot creation "
5359219089Spjd		    "performance\n"));
5360219089Spjd		(void) printf(gettext(" 28  Multiple vdev replacements\n"));
5361219089Spjd		(void) printf(gettext("\nFor more information on a particular "
5362219089Spjd		    "version, including supported releases,\n"));
5363219089Spjd		(void) printf(gettext("see the ZFS Administration Guide.\n\n"));
5364238926Smm	} else if (argc == 0 && upgradeall) {
5365238926Smm		cb.cb_first = B_TRUE;
5366168404Spjd		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
5367238926Smm		if (ret == 0 && cb.cb_first) {
5368238926Smm			if (cb.cb_version == SPA_VERSION) {
5369276226Ssmh				(void) printf(gettext("All %spools are already "
5370276226Ssmh				    "formatted using feature flags.\n\n"),
5371276226Ssmh				    cb.cb_unavail ? gettext("available ") : "");
5372276226Ssmh				(void) printf(gettext("Every %sfeature flags "
5373238926Smm				    "pool already has all supported features "
5374276226Ssmh				    "enabled.\n"),
5375276226Ssmh				    cb.cb_unavail ? gettext("available ") : "");
5376238926Smm			} else {
5377238926Smm				(void) printf(gettext("All pools are already "
5378238926Smm				    "formatted with version %llu or higher.\n"),
5379238926Smm				    cb.cb_version);
5380168404Spjd			}
5381168404Spjd		}
5382238926Smm	} else if (argc == 0) {
5383238926Smm		cb.cb_first = B_TRUE;
5384276226Ssmh		ret = zpool_iter(g_zfs, upgrade_list_unavail, &cb);
5385276226Ssmh		assert(ret == 0);
5386276226Ssmh
5387276226Ssmh		if (!cb.cb_first) {
5388276226Ssmh			(void) fprintf(stderr, "\n");
5389276226Ssmh		}
5390276226Ssmh
5391276226Ssmh		cb.cb_first = B_TRUE;
5392238926Smm		ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb);
5393238926Smm		assert(ret == 0);
5394168404Spjd
5395238926Smm		if (cb.cb_first) {
5396276226Ssmh			(void) printf(gettext("All %spools are formatted using "
5397276226Ssmh			    "feature flags.\n\n"), cb.cb_unavail ?
5398276226Ssmh			    gettext("available ") : "");
5399238926Smm		} else {
5400238926Smm			(void) printf(gettext("\nUse 'zpool upgrade -v' "
5401238926Smm			    "for a list of available legacy versions.\n"));
5402168404Spjd		}
5403238926Smm
5404238926Smm		cb.cb_first = B_TRUE;
5405238926Smm		ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb);
5406238926Smm		assert(ret == 0);
5407238926Smm
5408238926Smm		if (cb.cb_first) {
5409276226Ssmh			(void) printf(gettext("Every %sfeature flags pool has "
5410276226Ssmh			    "all supported features enabled.\n"),
5411276226Ssmh			    cb.cb_unavail ? gettext("available ") : "");
5412238926Smm		} else {
5413238926Smm			(void) printf(gettext("\n"));
5414238926Smm		}
5415168404Spjd	} else {
5416276226Ssmh		ret = for_each_pool(argc, argv, B_TRUE, NULL,
5417168404Spjd		    upgrade_one, &cb);
5418168404Spjd	}
5419168404Spjd
5420212050Spjd	if (cb.cb_poolname[0] != '\0') {
5421212050Spjd		(void) printf(
5422212050Spjd		    "If you boot from pool '%s', don't forget to update boot code.\n"
5423212050Spjd		    "Assuming you use GPT partitioning and da0 is your boot disk\n"
5424212050Spjd		    "the following command will do it:\n"
5425212050Spjd		    "\n"
5426212050Spjd		    "\tgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0\n\n",
5427212050Spjd		    cb.cb_poolname);
5428212050Spjd	}
5429212050Spjd
5430168404Spjd	return (ret);
5431168404Spjd}
5432168404Spjd
5433185029Spjdtypedef struct hist_cbdata {
5434185029Spjd	boolean_t first;
5435248571Smm	boolean_t longfmt;
5436248571Smm	boolean_t internal;
5437185029Spjd} hist_cbdata_t;
5438185029Spjd
5439168404Spjd/*
5440168404Spjd * Print out the command history for a specific pool.
5441168404Spjd */
5442168404Spjdstatic int
5443168404Spjdget_history_one(zpool_handle_t *zhp, void *data)
5444168404Spjd{
5445168404Spjd	nvlist_t *nvhis;
5446168404Spjd	nvlist_t **records;
5447168404Spjd	uint_t numrecords;
5448168404Spjd	int ret, i;
5449185029Spjd	hist_cbdata_t *cb = (hist_cbdata_t *)data;
5450168404Spjd
5451185029Spjd	cb->first = B_FALSE;
5452168404Spjd
5453168404Spjd	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
5454168404Spjd
5455168404Spjd	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
5456168404Spjd		return (ret);
5457168404Spjd
5458168404Spjd	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
5459168404Spjd	    &records, &numrecords) == 0);
5460168404Spjd	for (i = 0; i < numrecords; i++) {
5461248571Smm		nvlist_t *rec = records[i];
5462248571Smm		char tbuf[30] = "";
5463185029Spjd
5464248571Smm		if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
5465248571Smm			time_t tsec;
5466248571Smm			struct tm t;
5467185029Spjd
5468248571Smm			tsec = fnvlist_lookup_uint64(records[i],
5469248571Smm			    ZPOOL_HIST_TIME);
5470248571Smm			(void) localtime_r(&tsec, &t);
5471248571Smm			(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
5472248571Smm		}
5473248571Smm
5474248571Smm		if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
5475248571Smm			(void) printf("%s %s", tbuf,
5476248571Smm			    fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
5477248571Smm		} else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
5478248571Smm			int ievent =
5479248571Smm			    fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
5480248571Smm			if (!cb->internal)
5481185029Spjd				continue;
5482248571Smm			if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
5483248571Smm				(void) printf("%s unrecognized record:\n",
5484248571Smm				    tbuf);
5485248571Smm				dump_nvlist(rec, 4);
5486185029Spjd				continue;
5487248571Smm			}
5488248571Smm			(void) printf("%s [internal %s txg:%lld] %s", tbuf,
5489248571Smm			    zfs_history_event_names[ievent],
5490248571Smm			    fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
5491248571Smm			    fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
5492248571Smm		} else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
5493248571Smm			if (!cb->internal)
5494248571Smm				continue;
5495248571Smm			(void) printf("%s [txg:%lld] %s", tbuf,
5496248571Smm			    fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
5497248571Smm			    fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
5498248571Smm			if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
5499248571Smm				(void) printf(" %s (%llu)",
5500248571Smm				    fnvlist_lookup_string(rec,
5501248571Smm				    ZPOOL_HIST_DSNAME),
5502248571Smm				    fnvlist_lookup_uint64(rec,
5503248571Smm				    ZPOOL_HIST_DSID));
5504248571Smm			}
5505248571Smm			(void) printf(" %s", fnvlist_lookup_string(rec,
5506248571Smm			    ZPOOL_HIST_INT_STR));
5507248571Smm		} else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
5508248571Smm			if (!cb->internal)
5509248571Smm				continue;
5510248571Smm			(void) printf("%s ioctl %s\n", tbuf,
5511248571Smm			    fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
5512248571Smm			if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
5513248571Smm				(void) printf("    input:\n");
5514248571Smm				dump_nvlist(fnvlist_lookup_nvlist(rec,
5515248571Smm				    ZPOOL_HIST_INPUT_NVL), 8);
5516248571Smm			}
5517248571Smm			if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
5518248571Smm				(void) printf("    output:\n");
5519248571Smm				dump_nvlist(fnvlist_lookup_nvlist(rec,
5520248571Smm				    ZPOOL_HIST_OUTPUT_NVL), 8);
5521248571Smm			}
5522325534Savg			if (nvlist_exists(rec, ZPOOL_HIST_ERRNO)) {
5523325534Savg				(void) printf("    errno: %lld\n",
5524325534Savg				    fnvlist_lookup_int64(rec,
5525325534Savg				    ZPOOL_HIST_ERRNO));
5526325534Savg			}
5527248571Smm		} else {
5528248571Smm			if (!cb->internal)
5529248571Smm				continue;
5530248571Smm			(void) printf("%s unrecognized record:\n", tbuf);
5531248571Smm			dump_nvlist(rec, 4);
5532168404Spjd		}
5533185029Spjd
5534185029Spjd		if (!cb->longfmt) {
5535185029Spjd			(void) printf("\n");
5536185029Spjd			continue;
5537185029Spjd		}
5538185029Spjd		(void) printf(" [");
5539248571Smm		if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
5540248571Smm			uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
5541248571Smm			struct passwd *pwd = getpwuid(who);
5542248571Smm			(void) printf("user %d ", (int)who);
5543248571Smm			if (pwd != NULL)
5544248571Smm				(void) printf("(%s) ", pwd->pw_name);
5545185029Spjd		}
5546248571Smm		if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
5547248571Smm			(void) printf("on %s",
5548248571Smm			    fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
5549185029Spjd		}
5550248571Smm		if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
5551248571Smm			(void) printf(":%s",
5552248571Smm			    fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
5553185029Spjd		}
5554185029Spjd		(void) printf("]");
5555185029Spjd		(void) printf("\n");
5556168404Spjd	}
5557168404Spjd	(void) printf("\n");
5558168404Spjd	nvlist_free(nvhis);
5559168404Spjd
5560168404Spjd	return (ret);
5561168404Spjd}
5562168404Spjd
5563168404Spjd/*
5564168404Spjd * zpool history <pool>
5565168404Spjd *
5566168404Spjd * Displays the history of commands that modified pools.
5567168404Spjd */
5568168404Spjdint
5569168404Spjdzpool_do_history(int argc, char **argv)
5570168404Spjd{
5571185029Spjd	hist_cbdata_t cbdata = { 0 };
5572168404Spjd	int ret;
5573185029Spjd	int c;
5574168404Spjd
5575185029Spjd	cbdata.first = B_TRUE;
5576185029Spjd	/* check options */
5577185029Spjd	while ((c = getopt(argc, argv, "li")) != -1) {
5578185029Spjd		switch (c) {
5579185029Spjd		case 'l':
5580248571Smm			cbdata.longfmt = B_TRUE;
5581185029Spjd			break;
5582185029Spjd		case 'i':
5583248571Smm			cbdata.internal = B_TRUE;
5584185029Spjd			break;
5585185029Spjd		case '?':
5586185029Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5587185029Spjd			    optopt);
5588185029Spjd			usage(B_FALSE);
5589185029Spjd		}
5590185029Spjd	}
5591168404Spjd	argc -= optind;
5592168404Spjd	argv += optind;
5593168404Spjd
5594168404Spjd	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
5595185029Spjd	    &cbdata);
5596168404Spjd
5597185029Spjd	if (argc == 0 && cbdata.first == B_TRUE) {
5598168404Spjd		(void) printf(gettext("no pools available\n"));
5599168404Spjd		return (0);
5600168404Spjd	}
5601168404Spjd
5602168404Spjd	return (ret);
5603168404Spjd}
5604168404Spjd
5605168404Spjdstatic int
5606168404Spjdget_callback(zpool_handle_t *zhp, void *data)
5607168404Spjd{
5608185029Spjd	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
5609168404Spjd	char value[MAXNAMELEN];
5610185029Spjd	zprop_source_t srctype;
5611185029Spjd	zprop_list_t *pl;
5612168404Spjd
5613168404Spjd	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
5614168404Spjd
5615168404Spjd		/*
5616185029Spjd		 * Skip the special fake placeholder. This will also skip
5617185029Spjd		 * over the name property when 'all' is specified.
5618168404Spjd		 */
5619185029Spjd		if (pl->pl_prop == ZPOOL_PROP_NAME &&
5620168404Spjd		    pl == cbp->cb_proplist)
5621168404Spjd			continue;
5622168404Spjd
5623236884Smm		if (pl->pl_prop == ZPROP_INVAL &&
5624236884Smm		    (zpool_prop_feature(pl->pl_user_prop) ||
5625236884Smm		    zpool_prop_unsupported(pl->pl_user_prop))) {
5626236884Smm			srctype = ZPROP_SRC_LOCAL;
5627168404Spjd
5628236884Smm			if (zpool_prop_get_feature(zhp, pl->pl_user_prop,
5629236884Smm			    value, sizeof (value)) == 0) {
5630236884Smm				zprop_print_one_property(zpool_get_name(zhp),
5631236884Smm				    cbp, pl->pl_user_prop, value, srctype,
5632236884Smm				    NULL, NULL);
5633236884Smm			}
5634236884Smm		} else {
5635236884Smm			if (zpool_get_prop(zhp, pl->pl_prop, value,
5636263889Sdelphij			    sizeof (value), &srctype, cbp->cb_literal) != 0)
5637236884Smm				continue;
5638236884Smm
5639236884Smm			zprop_print_one_property(zpool_get_name(zhp), cbp,
5640236884Smm			    zpool_prop_to_name(pl->pl_prop), value, srctype,
5641236884Smm			    NULL, NULL);
5642236884Smm		}
5643168404Spjd	}
5644168404Spjd	return (0);
5645168404Spjd}
5646168404Spjd
5647263889Sdelphij/*
5648263889Sdelphij * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ...
5649263889Sdelphij *
5650263889Sdelphij *	-H	Scripted mode.  Don't display headers, and separate properties
5651263889Sdelphij *		by a single tab.
5652263889Sdelphij *	-o	List of columns to display.  Defaults to
5653263889Sdelphij *		"name,property,value,source".
5654263889Sdelphij * 	-p	Diplay values in parsable (exact) format.
5655263889Sdelphij *
5656263889Sdelphij * Get properties of pools in the system. Output space statistics
5657263889Sdelphij * for each one as well as other attributes.
5658263889Sdelphij */
5659168404Spjdint
5660168404Spjdzpool_do_get(int argc, char **argv)
5661168404Spjd{
5662185029Spjd	zprop_get_cbdata_t cb = { 0 };
5663185029Spjd	zprop_list_t fake_name = { 0 };
5664168404Spjd	int ret;
5665263889Sdelphij	int c, i;
5666263889Sdelphij	char *value;
5667168404Spjd
5668263889Sdelphij	cb.cb_first = B_TRUE;
5669168404Spjd
5670263889Sdelphij	/*
5671263889Sdelphij	 * Set up default columns and sources.
5672263889Sdelphij	 */
5673185029Spjd	cb.cb_sources = ZPROP_SRC_ALL;
5674168404Spjd	cb.cb_columns[0] = GET_COL_NAME;
5675168404Spjd	cb.cb_columns[1] = GET_COL_PROPERTY;
5676168404Spjd	cb.cb_columns[2] = GET_COL_VALUE;
5677168404Spjd	cb.cb_columns[3] = GET_COL_SOURCE;
5678185029Spjd	cb.cb_type = ZFS_TYPE_POOL;
5679168404Spjd
5680263889Sdelphij	/* check options */
5681263889Sdelphij	while ((c = getopt(argc, argv, ":Hpo:")) != -1) {
5682263889Sdelphij		switch (c) {
5683263889Sdelphij		case 'p':
5684263889Sdelphij			cb.cb_literal = B_TRUE;
5685263889Sdelphij			break;
5686263889Sdelphij		case 'H':
5687263889Sdelphij			cb.cb_scripted = B_TRUE;
5688263889Sdelphij			break;
5689263889Sdelphij		case 'o':
5690263889Sdelphij			bzero(&cb.cb_columns, sizeof (cb.cb_columns));
5691263889Sdelphij			i = 0;
5692263889Sdelphij			while (*optarg != '\0') {
5693263889Sdelphij				static char *col_subopts[] =
5694263889Sdelphij				{ "name", "property", "value", "source",
5695263889Sdelphij				"all", NULL };
5696263889Sdelphij
5697263889Sdelphij				if (i == ZFS_GET_NCOLS) {
5698263889Sdelphij					(void) fprintf(stderr, gettext("too "
5699263889Sdelphij					"many fields given to -o "
5700263889Sdelphij					"option\n"));
5701263889Sdelphij					usage(B_FALSE);
5702263889Sdelphij				}
5703263889Sdelphij
5704263889Sdelphij				switch (getsubopt(&optarg, col_subopts,
5705263889Sdelphij				    &value)) {
5706263889Sdelphij				case 0:
5707263889Sdelphij					cb.cb_columns[i++] = GET_COL_NAME;
5708263889Sdelphij					break;
5709263889Sdelphij				case 1:
5710263889Sdelphij					cb.cb_columns[i++] = GET_COL_PROPERTY;
5711263889Sdelphij					break;
5712263889Sdelphij				case 2:
5713263889Sdelphij					cb.cb_columns[i++] = GET_COL_VALUE;
5714263889Sdelphij					break;
5715263889Sdelphij				case 3:
5716263889Sdelphij					cb.cb_columns[i++] = GET_COL_SOURCE;
5717263889Sdelphij					break;
5718263889Sdelphij				case 4:
5719263889Sdelphij					if (i > 0) {
5720263889Sdelphij						(void) fprintf(stderr,
5721263889Sdelphij						    gettext("\"all\" conflicts "
5722263889Sdelphij						    "with specific fields "
5723263889Sdelphij						    "given to -o option\n"));
5724263889Sdelphij						usage(B_FALSE);
5725263889Sdelphij					}
5726263889Sdelphij					cb.cb_columns[0] = GET_COL_NAME;
5727263889Sdelphij					cb.cb_columns[1] = GET_COL_PROPERTY;
5728263889Sdelphij					cb.cb_columns[2] = GET_COL_VALUE;
5729263889Sdelphij					cb.cb_columns[3] = GET_COL_SOURCE;
5730263889Sdelphij					i = ZFS_GET_NCOLS;
5731263889Sdelphij					break;
5732263889Sdelphij				default:
5733263889Sdelphij					(void) fprintf(stderr,
5734263889Sdelphij					    gettext("invalid column name "
5735295844Sdim					    "'%s'\n"), suboptarg);
5736263889Sdelphij					usage(B_FALSE);
5737263889Sdelphij				}
5738263889Sdelphij			}
5739263889Sdelphij			break;
5740263889Sdelphij		case '?':
5741263889Sdelphij			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5742263889Sdelphij			    optopt);
5743263889Sdelphij			usage(B_FALSE);
5744263889Sdelphij		}
5745263889Sdelphij	}
5746263889Sdelphij
5747263889Sdelphij	argc -= optind;
5748263889Sdelphij	argv += optind;
5749263889Sdelphij
5750263889Sdelphij	if (argc < 1) {
5751263889Sdelphij		(void) fprintf(stderr, gettext("missing property "
5752263889Sdelphij		    "argument\n"));
5753263889Sdelphij		usage(B_FALSE);
5754263889Sdelphij	}
5755263889Sdelphij
5756263889Sdelphij	if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist,
5757185029Spjd	    ZFS_TYPE_POOL) != 0)
5758168404Spjd		usage(B_FALSE);
5759168404Spjd
5760263889Sdelphij	argc--;
5761263889Sdelphij	argv++;
5762263889Sdelphij
5763168404Spjd	if (cb.cb_proplist != NULL) {
5764185029Spjd		fake_name.pl_prop = ZPOOL_PROP_NAME;
5765168404Spjd		fake_name.pl_width = strlen(gettext("NAME"));
5766168404Spjd		fake_name.pl_next = cb.cb_proplist;
5767168404Spjd		cb.cb_proplist = &fake_name;
5768168404Spjd	}
5769168404Spjd
5770263889Sdelphij	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
5771168404Spjd	    get_callback, &cb);
5772168404Spjd
5773168404Spjd	if (cb.cb_proplist == &fake_name)
5774185029Spjd		zprop_free_list(fake_name.pl_next);
5775168404Spjd	else
5776185029Spjd		zprop_free_list(cb.cb_proplist);
5777168404Spjd
5778168404Spjd	return (ret);
5779168404Spjd}
5780168404Spjd
5781168404Spjdtypedef struct set_cbdata {
5782168404Spjd	char *cb_propname;
5783168404Spjd	char *cb_value;
5784168404Spjd	boolean_t cb_any_successful;
5785168404Spjd} set_cbdata_t;
5786168404Spjd
5787168404Spjdint
5788168404Spjdset_callback(zpool_handle_t *zhp, void *data)
5789168404Spjd{
5790168404Spjd	int error;
5791168404Spjd	set_cbdata_t *cb = (set_cbdata_t *)data;
5792168404Spjd
5793168404Spjd	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
5794168404Spjd
5795168404Spjd	if (!error)
5796168404Spjd		cb->cb_any_successful = B_TRUE;
5797168404Spjd
5798168404Spjd	return (error);
5799168404Spjd}
5800168404Spjd
5801168404Spjdint
5802168404Spjdzpool_do_set(int argc, char **argv)
5803168404Spjd{
5804168404Spjd	set_cbdata_t cb = { 0 };
5805168404Spjd	int error;
5806168404Spjd
5807168404Spjd	if (argc > 1 && argv[1][0] == '-') {
5808168404Spjd		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
5809168404Spjd		    argv[1][1]);
5810168404Spjd		usage(B_FALSE);
5811168404Spjd	}
5812168404Spjd
5813168404Spjd	if (argc < 2) {
5814168404Spjd		(void) fprintf(stderr, gettext("missing property=value "
5815168404Spjd		    "argument\n"));
5816168404Spjd		usage(B_FALSE);
5817168404Spjd	}
5818168404Spjd
5819168404Spjd	if (argc < 3) {
5820168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
5821168404Spjd		usage(B_FALSE);
5822168404Spjd	}
5823168404Spjd
5824168404Spjd	if (argc > 3) {
5825168404Spjd		(void) fprintf(stderr, gettext("too many pool names\n"));
5826168404Spjd		usage(B_FALSE);
5827168404Spjd	}
5828168404Spjd
5829168404Spjd	cb.cb_propname = argv[1];
5830168404Spjd	cb.cb_value = strchr(cb.cb_propname, '=');
5831168404Spjd	if (cb.cb_value == NULL) {
5832168404Spjd		(void) fprintf(stderr, gettext("missing value in "
5833168404Spjd		    "property=value argument\n"));
5834168404Spjd		usage(B_FALSE);
5835168404Spjd	}
5836168404Spjd
5837168404Spjd	*(cb.cb_value) = '\0';
5838168404Spjd	cb.cb_value++;
5839168404Spjd
5840168404Spjd	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
5841168404Spjd	    set_callback, &cb);
5842168404Spjd
5843168404Spjd	return (error);
5844168404Spjd}
5845168404Spjd
5846168404Spjdstatic int
5847168404Spjdfind_command_idx(char *command, int *idx)
5848168404Spjd{
5849168404Spjd	int i;
5850168404Spjd
5851168404Spjd	for (i = 0; i < NCOMMAND; i++) {
5852168404Spjd		if (command_table[i].name == NULL)
5853168404Spjd			continue;
5854168404Spjd
5855168404Spjd		if (strcmp(command, command_table[i].name) == 0) {
5856168404Spjd			*idx = i;
5857168404Spjd			return (0);
5858168404Spjd		}
5859168404Spjd	}
5860168404Spjd	return (1);
5861168404Spjd}
5862168404Spjd
5863168404Spjdint
5864168404Spjdmain(int argc, char **argv)
5865168404Spjd{
5866296537Smav	int ret = 0;
5867168404Spjd	int i;
5868168404Spjd	char *cmdname;
5869168404Spjd
5870168404Spjd	(void) setlocale(LC_ALL, "");
5871168404Spjd	(void) textdomain(TEXT_DOMAIN);
5872168404Spjd
5873168404Spjd	if ((g_zfs = libzfs_init()) == NULL) {
5874168404Spjd		(void) fprintf(stderr, gettext("internal error: failed to "
5875168404Spjd		    "initialize ZFS library\n"));
5876168404Spjd		return (1);
5877168404Spjd	}
5878168404Spjd
5879168404Spjd	libzfs_print_on_error(g_zfs, B_TRUE);
5880168404Spjd
5881168404Spjd	opterr = 0;
5882168404Spjd
5883168404Spjd	/*
5884168404Spjd	 * Make sure the user has specified some command.
5885168404Spjd	 */
5886168404Spjd	if (argc < 2) {
5887168404Spjd		(void) fprintf(stderr, gettext("missing command\n"));
5888168404Spjd		usage(B_FALSE);
5889168404Spjd	}
5890168404Spjd
5891168404Spjd	cmdname = argv[1];
5892168404Spjd
5893168404Spjd	/*
5894168404Spjd	 * Special case '-?'
5895168404Spjd	 */
5896168404Spjd	if (strcmp(cmdname, "-?") == 0)
5897168404Spjd		usage(B_TRUE);
5898168404Spjd
5899248571Smm	zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
5900185029Spjd
5901168404Spjd	/*
5902168404Spjd	 * Run the appropriate command.
5903168404Spjd	 */
5904168404Spjd	if (find_command_idx(cmdname, &i) == 0) {
5905168404Spjd		current_command = &command_table[i];
5906168404Spjd		ret = command_table[i].func(argc - 1, argv + 1);
5907185029Spjd	} else if (strchr(cmdname, '=')) {
5908185029Spjd		verify(find_command_idx("set", &i) == 0);
5909185029Spjd		current_command = &command_table[i];
5910185029Spjd		ret = command_table[i].func(argc, argv);
5911185029Spjd	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
5912185029Spjd		/*
5913185029Spjd		 * 'freeze' is a vile debugging abomination, so we treat
5914185029Spjd		 * it as such.
5915185029Spjd		 */
5916252059Ssmh		zfs_cmd_t zc = { 0 };
5917252059Ssmh		(void) strlcpy(zc.zc_name, argv[2], sizeof (zc.zc_name));
5918252059Ssmh		return (!!zfs_ioctl(g_zfs, ZFS_IOC_POOL_FREEZE, &zc));
5919185029Spjd	} else {
5920168404Spjd		(void) fprintf(stderr, gettext("unrecognized "
5921168404Spjd		    "command '%s'\n"), cmdname);
5922168404Spjd		usage(B_FALSE);
5923168404Spjd	}
5924168404Spjd
5925248571Smm	if (ret == 0 && log_history)
5926248571Smm		(void) zpool_log_history(g_zfs, history_str);
5927248571Smm
5928168404Spjd	libzfs_fini(g_zfs);
5929168404Spjd
5930168404Spjd	/*
5931168404Spjd	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
5932168404Spjd	 * for the purposes of running ::findleaks.
5933168404Spjd	 */
5934168404Spjd	if (getenv("ZFS_ABORT") != NULL) {
5935168404Spjd		(void) printf("dumping core by request\n");
5936168404Spjd		abort();
5937168404Spjd	}
5938168404Spjd
5939168404Spjd	return (ret);
5940168404Spjd}
5941