zpool_main.c revision 185029
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/*
23185029Spjd * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24168404Spjd * Use is subject to license terms.
25168404Spjd */
26168404Spjd
27168404Spjd#include <solaris.h>
28168404Spjd#include <assert.h>
29168404Spjd#include <ctype.h>
30168404Spjd#include <dirent.h>
31168404Spjd#include <errno.h>
32168404Spjd#include <fcntl.h>
33168404Spjd#include <libgen.h>
34168404Spjd#include <libintl.h>
35168404Spjd#include <libuutil.h>
36168404Spjd#include <locale.h>
37168404Spjd#include <stdio.h>
38168404Spjd#include <stdlib.h>
39168404Spjd#include <string.h>
40168404Spjd#include <strings.h>
41168404Spjd#include <unistd.h>
42168404Spjd#include <priv.h>
43185029Spjd#include <pwd.h>
44185029Spjd#include <zone.h>
45168404Spjd#include <sys/time.h>
46168404Spjd#include <sys/fs/zfs.h>
47168404Spjd
48168404Spjd#include <sys/stat.h>
49168404Spjd
50168404Spjd#include <libzfs.h>
51168404Spjd
52168404Spjd#include "zpool_util.h"
53185029Spjd#include "zfs_comutil.h"
54168404Spjd
55168404Spjdstatic int zpool_do_create(int, char **);
56168404Spjdstatic int zpool_do_destroy(int, char **);
57168404Spjd
58168404Spjdstatic int zpool_do_add(int, char **);
59168404Spjdstatic int zpool_do_remove(int, char **);
60168404Spjd
61168404Spjdstatic int zpool_do_list(int, char **);
62168404Spjdstatic int zpool_do_iostat(int, char **);
63168404Spjdstatic int zpool_do_status(int, char **);
64168404Spjd
65168404Spjdstatic int zpool_do_online(int, char **);
66168404Spjdstatic int zpool_do_offline(int, char **);
67168404Spjdstatic int zpool_do_clear(int, char **);
68168404Spjd
69168404Spjdstatic int zpool_do_attach(int, char **);
70168404Spjdstatic int zpool_do_detach(int, char **);
71168404Spjdstatic int zpool_do_replace(int, char **);
72168404Spjd
73168404Spjdstatic int zpool_do_scrub(int, char **);
74168404Spjd
75168404Spjdstatic int zpool_do_import(int, char **);
76168404Spjdstatic int zpool_do_export(int, char **);
77168404Spjd
78168404Spjdstatic int zpool_do_upgrade(int, char **);
79168404Spjd
80168404Spjdstatic int zpool_do_history(int, char **);
81168404Spjd
82168404Spjdstatic int zpool_do_get(int, char **);
83168404Spjdstatic int zpool_do_set(int, char **);
84168404Spjd
85168404Spjd/*
86168404Spjd * These libumem hooks provide a reasonable set of defaults for the allocator's
87168404Spjd * debugging facilities.
88168404Spjd */
89185029Spjd
90185029Spjd#ifdef DEBUG
91168404Spjdconst char *
92168404Spjd_umem_debug_init(void)
93168404Spjd{
94168404Spjd	return ("default,verbose"); /* $UMEM_DEBUG setting */
95168404Spjd}
96168404Spjd
97168404Spjdconst char *
98168404Spjd_umem_logging_init(void)
99168404Spjd{
100168404Spjd	return ("fail,contents"); /* $UMEM_LOGGING setting */
101168404Spjd}
102185029Spjd#endif
103168404Spjd
104168404Spjdtypedef enum {
105168404Spjd	HELP_ADD,
106168404Spjd	HELP_ATTACH,
107168404Spjd	HELP_CLEAR,
108168404Spjd	HELP_CREATE,
109168404Spjd	HELP_DESTROY,
110168404Spjd	HELP_DETACH,
111168404Spjd	HELP_EXPORT,
112168404Spjd	HELP_HISTORY,
113168404Spjd	HELP_IMPORT,
114168404Spjd	HELP_IOSTAT,
115168404Spjd	HELP_LIST,
116168404Spjd	HELP_OFFLINE,
117168404Spjd	HELP_ONLINE,
118168404Spjd	HELP_REPLACE,
119168404Spjd	HELP_REMOVE,
120168404Spjd	HELP_SCRUB,
121168404Spjd	HELP_STATUS,
122168404Spjd	HELP_UPGRADE,
123168404Spjd	HELP_GET,
124168404Spjd	HELP_SET
125168404Spjd} zpool_help_t;
126168404Spjd
127168404Spjd
128168404Spjdtypedef struct zpool_command {
129168404Spjd	const char	*name;
130168404Spjd	int		(*func)(int, char **);
131168404Spjd	zpool_help_t	usage;
132168404Spjd} zpool_command_t;
133168404Spjd
134168404Spjd/*
135168404Spjd * Master command table.  Each ZFS command has a name, associated function, and
136168404Spjd * usage message.  The usage messages need to be internationalized, so we have
137168404Spjd * to have a function to return the usage message based on a command index.
138168404Spjd *
139168404Spjd * These commands are organized according to how they are displayed in the usage
140168404Spjd * message.  An empty command (one with a NULL name) indicates an empty line in
141168404Spjd * the generic usage message.
142168404Spjd */
143168404Spjdstatic zpool_command_t command_table[] = {
144168404Spjd	{ "create",	zpool_do_create,	HELP_CREATE		},
145168404Spjd	{ "destroy",	zpool_do_destroy,	HELP_DESTROY		},
146168404Spjd	{ NULL },
147168404Spjd	{ "add",	zpool_do_add,		HELP_ADD		},
148168404Spjd	{ "remove",	zpool_do_remove,	HELP_REMOVE		},
149168404Spjd	{ NULL },
150168404Spjd	{ "list",	zpool_do_list,		HELP_LIST		},
151168404Spjd	{ "iostat",	zpool_do_iostat,	HELP_IOSTAT		},
152168404Spjd	{ "status",	zpool_do_status,	HELP_STATUS		},
153168404Spjd	{ NULL },
154168404Spjd	{ "online",	zpool_do_online,	HELP_ONLINE		},
155168404Spjd	{ "offline",	zpool_do_offline,	HELP_OFFLINE		},
156168404Spjd	{ "clear",	zpool_do_clear,		HELP_CLEAR		},
157168404Spjd	{ NULL },
158168404Spjd	{ "attach",	zpool_do_attach,	HELP_ATTACH		},
159168404Spjd	{ "detach",	zpool_do_detach,	HELP_DETACH		},
160168404Spjd	{ "replace",	zpool_do_replace,	HELP_REPLACE		},
161168404Spjd	{ NULL },
162168404Spjd	{ "scrub",	zpool_do_scrub,		HELP_SCRUB		},
163168404Spjd	{ NULL },
164168404Spjd	{ "import",	zpool_do_import,	HELP_IMPORT		},
165168404Spjd	{ "export",	zpool_do_export,	HELP_EXPORT		},
166168404Spjd	{ "upgrade",	zpool_do_upgrade,	HELP_UPGRADE		},
167168404Spjd	{ NULL },
168168404Spjd	{ "history",	zpool_do_history,	HELP_HISTORY		},
169168404Spjd	{ "get",	zpool_do_get,		HELP_GET		},
170168404Spjd	{ "set",	zpool_do_set,		HELP_SET		},
171168404Spjd};
172168404Spjd
173168404Spjd#define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
174168404Spjd
175168404Spjdzpool_command_t *current_command;
176185029Spjdstatic char history_str[HIS_MAX_RECORD_LEN];
177168404Spjd
178168404Spjdstatic const char *
179168404Spjdget_usage(zpool_help_t idx) {
180168404Spjd	switch (idx) {
181168404Spjd	case HELP_ADD:
182168404Spjd		return (gettext("\tadd [-fn] <pool> <vdev> ...\n"));
183168404Spjd	case HELP_ATTACH:
184168404Spjd		return (gettext("\tattach [-f] <pool> <device> "
185185029Spjd		    "<new-device>\n"));
186168404Spjd	case HELP_CLEAR:
187168404Spjd		return (gettext("\tclear <pool> [device]\n"));
188168404Spjd	case HELP_CREATE:
189185029Spjd		return (gettext("\tcreate [-fn] [-o property=value] ... \n"
190185029Spjd		    "\t    [-O file-system-property=value] ... \n"
191185029Spjd		    "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
192168404Spjd	case HELP_DESTROY:
193168404Spjd		return (gettext("\tdestroy [-f] <pool>\n"));
194168404Spjd	case HELP_DETACH:
195168404Spjd		return (gettext("\tdetach <pool> <device>\n"));
196168404Spjd	case HELP_EXPORT:
197168404Spjd		return (gettext("\texport [-f] <pool> ...\n"));
198168404Spjd	case HELP_HISTORY:
199185029Spjd		return (gettext("\thistory [-il] [<pool>] ...\n"));
200168404Spjd	case HELP_IMPORT:
201168404Spjd		return (gettext("\timport [-d dir] [-D]\n"
202185029Spjd		    "\timport [-o mntopts] [-o property=value] ... \n"
203185029Spjd		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] -a\n"
204185029Spjd		    "\timport [-o mntopts] [-o property=value] ... \n"
205185029Spjd		    "\t    [-d dir | -c cachefile] [-D] [-f] [-R root] "
206185029Spjd		    "<pool | id> [newpool]\n"));
207168404Spjd	case HELP_IOSTAT:
208168404Spjd		return (gettext("\tiostat [-v] [pool] ... [interval "
209168404Spjd		    "[count]]\n"));
210168404Spjd	case HELP_LIST:
211185029Spjd		return (gettext("\tlist [-H] [-o property[,...]] "
212168404Spjd		    "[pool] ...\n"));
213168404Spjd	case HELP_OFFLINE:
214168404Spjd		return (gettext("\toffline [-t] <pool> <device> ...\n"));
215168404Spjd	case HELP_ONLINE:
216168404Spjd		return (gettext("\tonline <pool> <device> ...\n"));
217168404Spjd	case HELP_REPLACE:
218168404Spjd		return (gettext("\treplace [-f] <pool> <device> "
219185029Spjd		    "[new-device]\n"));
220168404Spjd	case HELP_REMOVE:
221185029Spjd		return (gettext("\tremove <pool> <device> ...\n"));
222168404Spjd	case HELP_SCRUB:
223168404Spjd		return (gettext("\tscrub [-s] <pool> ...\n"));
224168404Spjd	case HELP_STATUS:
225168404Spjd		return (gettext("\tstatus [-vx] [pool] ...\n"));
226168404Spjd	case HELP_UPGRADE:
227168404Spjd		return (gettext("\tupgrade\n"
228168404Spjd		    "\tupgrade -v\n"
229185029Spjd		    "\tupgrade [-V version] <-a | pool ...>\n"));
230168404Spjd	case HELP_GET:
231185029Spjd		return (gettext("\tget <\"all\" | property[,...]> "
232168404Spjd		    "<pool> ...\n"));
233168404Spjd	case HELP_SET:
234168404Spjd		return (gettext("\tset <property=value> <pool> \n"));
235168404Spjd	}
236168404Spjd
237168404Spjd	abort();
238168404Spjd	/* NOTREACHED */
239168404Spjd}
240168404Spjd
241168404Spjd
242168404Spjd/*
243168404Spjd * Callback routine that will print out a pool property value.
244168404Spjd */
245185029Spjdstatic int
246185029Spjdprint_prop_cb(int prop, void *cb)
247168404Spjd{
248168404Spjd	FILE *fp = cb;
249168404Spjd
250168404Spjd	(void) fprintf(fp, "\t%-13s  ", zpool_prop_to_name(prop));
251168404Spjd
252185029Spjd	if (zpool_prop_readonly(prop))
253185029Spjd		(void) fprintf(fp, "  NO   ");
254185029Spjd	else
255185029Spjd		(void) fprintf(fp, " YES    ");
256185029Spjd
257168404Spjd	if (zpool_prop_values(prop) == NULL)
258168404Spjd		(void) fprintf(fp, "-\n");
259168404Spjd	else
260168404Spjd		(void) fprintf(fp, "%s\n", zpool_prop_values(prop));
261168404Spjd
262185029Spjd	return (ZPROP_CONT);
263168404Spjd}
264168404Spjd
265168404Spjd/*
266168404Spjd * Display usage message.  If we're inside a command, display only the usage for
267168404Spjd * that command.  Otherwise, iterate over the entire command table and display
268168404Spjd * a complete usage message.
269168404Spjd */
270168404Spjdvoid
271168404Spjdusage(boolean_t requested)
272168404Spjd{
273168404Spjd	FILE *fp = requested ? stdout : stderr;
274168404Spjd
275168404Spjd	if (current_command == NULL) {
276168404Spjd		int i;
277168404Spjd
278168404Spjd		(void) fprintf(fp, gettext("usage: zpool command args ...\n"));
279168404Spjd		(void) fprintf(fp,
280168404Spjd		    gettext("where 'command' is one of the following:\n\n"));
281168404Spjd
282168404Spjd		for (i = 0; i < NCOMMAND; i++) {
283168404Spjd			if (command_table[i].name == NULL)
284168404Spjd				(void) fprintf(fp, "\n");
285168404Spjd			else
286168404Spjd				(void) fprintf(fp, "%s",
287168404Spjd				    get_usage(command_table[i].usage));
288168404Spjd		}
289168404Spjd	} else {
290168404Spjd		(void) fprintf(fp, gettext("usage:\n"));
291168404Spjd		(void) fprintf(fp, "%s", get_usage(current_command->usage));
292168404Spjd	}
293168404Spjd
294168404Spjd	if (current_command != NULL &&
295168404Spjd	    ((strcmp(current_command->name, "set") == 0) ||
296185029Spjd	    (strcmp(current_command->name, "get") == 0) ||
297185029Spjd	    (strcmp(current_command->name, "list") == 0))) {
298168404Spjd
299168404Spjd		(void) fprintf(fp,
300168404Spjd		    gettext("\nthe following properties are supported:\n"));
301168404Spjd
302185029Spjd		(void) fprintf(fp, "\n\t%-13s  %s  %s\n\n",
303185029Spjd		    "PROPERTY", "EDIT", "VALUES");
304168404Spjd
305168404Spjd		/* Iterate over all properties */
306185029Spjd		(void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
307185029Spjd		    ZFS_TYPE_POOL);
308168404Spjd	}
309168404Spjd
310168404Spjd	/*
311168404Spjd	 * See comments at end of main().
312168404Spjd	 */
313168404Spjd	if (getenv("ZFS_ABORT") != NULL) {
314168404Spjd		(void) printf("dumping core by request\n");
315168404Spjd		abort();
316168404Spjd	}
317168404Spjd
318168404Spjd	exit(requested ? 0 : 2);
319168404Spjd}
320168404Spjd
321168404Spjdvoid
322185029Spjdprint_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
323185029Spjd    boolean_t print_logs)
324168404Spjd{
325168404Spjd	nvlist_t **child;
326168404Spjd	uint_t c, children;
327168404Spjd	char *vname;
328168404Spjd
329168404Spjd	if (name != NULL)
330168404Spjd		(void) printf("\t%*s%s\n", indent, "", name);
331168404Spjd
332168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
333168404Spjd	    &child, &children) != 0)
334168404Spjd		return;
335168404Spjd
336168404Spjd	for (c = 0; c < children; c++) {
337185029Spjd		uint64_t is_log = B_FALSE;
338185029Spjd
339185029Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
340185029Spjd		    &is_log);
341185029Spjd		if ((is_log && !print_logs) || (!is_log && print_logs))
342185029Spjd			continue;
343185029Spjd
344168404Spjd		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
345185029Spjd		print_vdev_tree(zhp, vname, child[c], indent + 2,
346185029Spjd		    B_FALSE);
347168404Spjd		free(vname);
348168404Spjd	}
349168404Spjd}
350168404Spjd
351168404Spjd/*
352185029Spjd * Add a property pair (name, string-value) into a property nvlist.
353185029Spjd */
354185029Spjdstatic int
355185029Spjdadd_prop_list(const char *propname, char *propval, nvlist_t **props,
356185029Spjd    boolean_t poolprop)
357185029Spjd{
358185029Spjd	zpool_prop_t prop = ZPROP_INVAL;
359185029Spjd	zfs_prop_t fprop;
360185029Spjd	nvlist_t *proplist;
361185029Spjd	const char *normnm;
362185029Spjd	char *strval;
363185029Spjd
364185029Spjd	if (*props == NULL &&
365185029Spjd	    nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
366185029Spjd		(void) fprintf(stderr,
367185029Spjd		    gettext("internal error: out of memory\n"));
368185029Spjd		return (1);
369185029Spjd	}
370185029Spjd
371185029Spjd	proplist = *props;
372185029Spjd
373185029Spjd	if (poolprop) {
374185029Spjd		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
375185029Spjd			(void) fprintf(stderr, gettext("property '%s' is "
376185029Spjd			    "not a valid pool property\n"), propname);
377185029Spjd			return (2);
378185029Spjd		}
379185029Spjd		normnm = zpool_prop_to_name(prop);
380185029Spjd	} else {
381185029Spjd		if ((fprop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
382185029Spjd			(void) fprintf(stderr, gettext("property '%s' is "
383185029Spjd			    "not a valid file system property\n"), propname);
384185029Spjd			return (2);
385185029Spjd		}
386185029Spjd		normnm = zfs_prop_to_name(fprop);
387185029Spjd	}
388185029Spjd
389185029Spjd	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
390185029Spjd	    prop != ZPOOL_PROP_CACHEFILE) {
391185029Spjd		(void) fprintf(stderr, gettext("property '%s' "
392185029Spjd		    "specified multiple times\n"), propname);
393185029Spjd		return (2);
394185029Spjd	}
395185029Spjd
396185029Spjd	if (nvlist_add_string(proplist, normnm, propval) != 0) {
397185029Spjd		(void) fprintf(stderr, gettext("internal "
398185029Spjd		    "error: out of memory\n"));
399185029Spjd		return (1);
400185029Spjd	}
401185029Spjd
402185029Spjd	return (0);
403185029Spjd}
404185029Spjd
405185029Spjd/*
406168404Spjd * zpool add [-fn] <pool> <vdev> ...
407168404Spjd *
408168404Spjd *	-f	Force addition of devices, even if they appear in use
409168404Spjd *	-n	Do not add the devices, but display the resulting layout if
410168404Spjd *		they were to be added.
411168404Spjd *
412168404Spjd * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
413168404Spjd * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
414168404Spjd * libzfs.
415168404Spjd */
416168404Spjdint
417168404Spjdzpool_do_add(int argc, char **argv)
418168404Spjd{
419168404Spjd	boolean_t force = B_FALSE;
420168404Spjd	boolean_t dryrun = B_FALSE;
421168404Spjd	int c;
422168404Spjd	nvlist_t *nvroot;
423168404Spjd	char *poolname;
424168404Spjd	int ret;
425168404Spjd	zpool_handle_t *zhp;
426168404Spjd	nvlist_t *config;
427168404Spjd
428168404Spjd	/* check options */
429168404Spjd	while ((c = getopt(argc, argv, "fn")) != -1) {
430168404Spjd		switch (c) {
431168404Spjd		case 'f':
432168404Spjd			force = B_TRUE;
433168404Spjd			break;
434168404Spjd		case 'n':
435168404Spjd			dryrun = B_TRUE;
436168404Spjd			break;
437168404Spjd		case '?':
438168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
439168404Spjd			    optopt);
440168404Spjd			usage(B_FALSE);
441168404Spjd		}
442168404Spjd	}
443168404Spjd
444168404Spjd	argc -= optind;
445168404Spjd	argv += optind;
446168404Spjd
447168404Spjd	/* get pool name and check number of arguments */
448168404Spjd	if (argc < 1) {
449168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
450168404Spjd		usage(B_FALSE);
451168404Spjd	}
452168404Spjd	if (argc < 2) {
453168404Spjd		(void) fprintf(stderr, gettext("missing vdev specification\n"));
454168404Spjd		usage(B_FALSE);
455168404Spjd	}
456168404Spjd
457168404Spjd	poolname = argv[0];
458168404Spjd
459168404Spjd	argc--;
460168404Spjd	argv++;
461168404Spjd
462168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
463168404Spjd		return (1);
464168404Spjd
465168404Spjd	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
466168404Spjd		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
467168404Spjd		    poolname);
468168404Spjd		zpool_close(zhp);
469168404Spjd		return (1);
470168404Spjd	}
471168404Spjd
472168404Spjd	/* pass off to get_vdev_spec for processing */
473185029Spjd	nvroot = make_root_vdev(zhp, force, !force, B_FALSE, dryrun,
474185029Spjd	    argc, argv);
475168404Spjd	if (nvroot == NULL) {
476168404Spjd		zpool_close(zhp);
477168404Spjd		return (1);
478168404Spjd	}
479168404Spjd
480168404Spjd	if (dryrun) {
481168404Spjd		nvlist_t *poolnvroot;
482168404Spjd
483168404Spjd		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
484168404Spjd		    &poolnvroot) == 0);
485168404Spjd
486168404Spjd		(void) printf(gettext("would update '%s' to the following "
487168404Spjd		    "configuration:\n"), zpool_get_name(zhp));
488168404Spjd
489185029Spjd		/* print original main pool and new tree */
490185029Spjd		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
491185029Spjd		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
492168404Spjd
493185029Spjd		/* Do the same for the logs */
494185029Spjd		if (num_logs(poolnvroot) > 0) {
495185029Spjd			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
496185029Spjd			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
497185029Spjd		} else if (num_logs(nvroot) > 0) {
498185029Spjd			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
499185029Spjd		}
500185029Spjd
501168404Spjd		ret = 0;
502168404Spjd	} else {
503168404Spjd		ret = (zpool_add(zhp, nvroot) != 0);
504168404Spjd	}
505168404Spjd
506168404Spjd	nvlist_free(nvroot);
507168404Spjd	zpool_close(zhp);
508168404Spjd
509168404Spjd	return (ret);
510168404Spjd}
511168404Spjd
512168404Spjd/*
513185029Spjd * zpool remove <pool> <vdev> ...
514168404Spjd *
515168404Spjd * Removes the given vdev from the pool.  Currently, this only supports removing
516185029Spjd * spares and cache devices from the pool.  Eventually, we'll want to support
517185029Spjd * removing leaf vdevs (as an alias for 'detach') as well as toplevel vdevs.
518168404Spjd */
519168404Spjdint
520168404Spjdzpool_do_remove(int argc, char **argv)
521168404Spjd{
522168404Spjd	char *poolname;
523185029Spjd	int i, ret = 0;
524168404Spjd	zpool_handle_t *zhp;
525168404Spjd
526168404Spjd	argc--;
527168404Spjd	argv++;
528168404Spjd
529168404Spjd	/* get pool name and check number of arguments */
530168404Spjd	if (argc < 1) {
531168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
532168404Spjd		usage(B_FALSE);
533168404Spjd	}
534168404Spjd	if (argc < 2) {
535168404Spjd		(void) fprintf(stderr, gettext("missing device\n"));
536168404Spjd		usage(B_FALSE);
537168404Spjd	}
538168404Spjd
539168404Spjd	poolname = argv[0];
540168404Spjd
541168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
542168404Spjd		return (1);
543168404Spjd
544185029Spjd	for (i = 1; i < argc; i++) {
545185029Spjd		if (zpool_vdev_remove(zhp, argv[i]) != 0)
546185029Spjd			ret = 1;
547168404Spjd	}
548168404Spjd
549168404Spjd	return (ret);
550168404Spjd}
551168404Spjd
552168404Spjd/*
553185029Spjd * zpool create [-fn] [-o property=value] ...
554185029Spjd *		[-O file-system-property=value] ...
555185029Spjd *		[-R root] [-m mountpoint] <pool> <dev> ...
556168404Spjd *
557168404Spjd *	-f	Force creation, even if devices appear in use
558168404Spjd *	-n	Do not create the pool, but display the resulting layout if it
559168404Spjd *		were to be created.
560168404Spjd *      -R	Create a pool under an alternate root
561168404Spjd *      -m	Set default mountpoint for the root dataset.  By default it's
562168404Spjd *      	'/<pool>'
563185029Spjd *	-o	Set property=value.
564185029Spjd *	-O	Set fsproperty=value in the pool's root file system
565168404Spjd *
566168404Spjd * Creates the named pool according to the given vdev specification.  The
567168404Spjd * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
568168404Spjd * we get the nvlist back from get_vdev_spec(), we either print out the contents
569168404Spjd * (if '-n' was specified), or pass it to libzfs to do the creation.
570168404Spjd */
571168404Spjdint
572168404Spjdzpool_do_create(int argc, char **argv)
573168404Spjd{
574168404Spjd	boolean_t force = B_FALSE;
575168404Spjd	boolean_t dryrun = B_FALSE;
576168404Spjd	int c;
577185029Spjd	nvlist_t *nvroot = NULL;
578168404Spjd	char *poolname;
579185029Spjd	int ret = 1;
580168404Spjd	char *altroot = NULL;
581168404Spjd	char *mountpoint = NULL;
582185029Spjd	nvlist_t *fsprops = NULL;
583185029Spjd	nvlist_t *props = NULL;
584185029Spjd	char *propval;
585168404Spjd
586168404Spjd	/* check options */
587185029Spjd	while ((c = getopt(argc, argv, ":fnR:m:o:O:")) != -1) {
588168404Spjd		switch (c) {
589168404Spjd		case 'f':
590168404Spjd			force = B_TRUE;
591168404Spjd			break;
592168404Spjd		case 'n':
593168404Spjd			dryrun = B_TRUE;
594168404Spjd			break;
595168404Spjd		case 'R':
596168404Spjd			altroot = optarg;
597185029Spjd			if (add_prop_list(zpool_prop_to_name(
598185029Spjd			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
599185029Spjd				goto errout;
600185029Spjd			if (nvlist_lookup_string(props,
601185029Spjd			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
602185029Spjd			    &propval) == 0)
603185029Spjd				break;
604185029Spjd			if (add_prop_list(zpool_prop_to_name(
605185029Spjd			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
606185029Spjd				goto errout;
607168404Spjd			break;
608168404Spjd		case 'm':
609168404Spjd			mountpoint = optarg;
610168404Spjd			break;
611185029Spjd		case 'o':
612185029Spjd			if ((propval = strchr(optarg, '=')) == NULL) {
613185029Spjd				(void) fprintf(stderr, gettext("missing "
614185029Spjd				    "'=' for -o option\n"));
615185029Spjd				goto errout;
616185029Spjd			}
617185029Spjd			*propval = '\0';
618185029Spjd			propval++;
619185029Spjd
620185029Spjd			if (add_prop_list(optarg, propval, &props, B_TRUE))
621185029Spjd				goto errout;
622185029Spjd			break;
623185029Spjd		case 'O':
624185029Spjd			if ((propval = strchr(optarg, '=')) == NULL) {
625185029Spjd				(void) fprintf(stderr, gettext("missing "
626185029Spjd				    "'=' for -O option\n"));
627185029Spjd				goto errout;
628185029Spjd			}
629185029Spjd			*propval = '\0';
630185029Spjd			propval++;
631185029Spjd
632185029Spjd			if (add_prop_list(optarg, propval, &fsprops, B_FALSE))
633185029Spjd				goto errout;
634185029Spjd			break;
635168404Spjd		case ':':
636168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
637168404Spjd			    "'%c' option\n"), optopt);
638185029Spjd			goto badusage;
639168404Spjd		case '?':
640168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
641168404Spjd			    optopt);
642185029Spjd			goto badusage;
643168404Spjd		}
644168404Spjd	}
645168404Spjd
646168404Spjd	argc -= optind;
647168404Spjd	argv += optind;
648168404Spjd
649168404Spjd	/* get pool name and check number of arguments */
650168404Spjd	if (argc < 1) {
651168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
652185029Spjd		goto badusage;
653168404Spjd	}
654168404Spjd	if (argc < 2) {
655168404Spjd		(void) fprintf(stderr, gettext("missing vdev specification\n"));
656185029Spjd		goto badusage;
657168404Spjd	}
658168404Spjd
659168404Spjd	poolname = argv[0];
660168404Spjd
661168404Spjd	/*
662168404Spjd	 * As a special case, check for use of '/' in the name, and direct the
663168404Spjd	 * user to use 'zfs create' instead.
664168404Spjd	 */
665168404Spjd	if (strchr(poolname, '/') != NULL) {
666168404Spjd		(void) fprintf(stderr, gettext("cannot create '%s': invalid "
667168404Spjd		    "character '/' in pool name\n"), poolname);
668168404Spjd		(void) fprintf(stderr, gettext("use 'zfs create' to "
669168404Spjd		    "create a dataset\n"));
670185029Spjd		goto errout;
671168404Spjd	}
672168404Spjd
673168404Spjd	/* pass off to get_vdev_spec for bulk processing */
674185029Spjd	nvroot = make_root_vdev(NULL, force, !force, B_FALSE, dryrun,
675185029Spjd	    argc - 1, argv + 1);
676168404Spjd	if (nvroot == NULL)
677185029Spjd		goto errout;
678168404Spjd
679168404Spjd	/* make_root_vdev() allows 0 toplevel children if there are spares */
680185029Spjd	if (!zfs_allocatable_devs(nvroot)) {
681168404Spjd		(void) fprintf(stderr, gettext("invalid vdev "
682168404Spjd		    "specification: at least one toplevel vdev must be "
683168404Spjd		    "specified\n"));
684185029Spjd		goto errout;
685168404Spjd	}
686168404Spjd
687168404Spjd
688168404Spjd	if (altroot != NULL && altroot[0] != '/') {
689168404Spjd		(void) fprintf(stderr, gettext("invalid alternate root '%s': "
690168404Spjd		    "must be an absolute path\n"), altroot);
691185029Spjd		goto errout;
692168404Spjd	}
693168404Spjd
694168404Spjd	/*
695168404Spjd	 * Check the validity of the mountpoint and direct the user to use the
696168404Spjd	 * '-m' mountpoint option if it looks like its in use.
697168404Spjd	 */
698168404Spjd	if (mountpoint == NULL ||
699168404Spjd	    (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
700168404Spjd	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
701168404Spjd		char buf[MAXPATHLEN];
702185029Spjd		DIR *dirp;
703168404Spjd
704168404Spjd		if (mountpoint && mountpoint[0] != '/') {
705168404Spjd			(void) fprintf(stderr, gettext("invalid mountpoint "
706168404Spjd			    "'%s': must be an absolute path, 'legacy', or "
707168404Spjd			    "'none'\n"), mountpoint);
708185029Spjd			goto errout;
709168404Spjd		}
710168404Spjd
711168404Spjd		if (mountpoint == NULL) {
712168404Spjd			if (altroot != NULL)
713168404Spjd				(void) snprintf(buf, sizeof (buf), "%s/%s",
714168404Spjd				    altroot, poolname);
715168404Spjd			else
716168404Spjd				(void) snprintf(buf, sizeof (buf), "/%s",
717168404Spjd				    poolname);
718168404Spjd		} else {
719168404Spjd			if (altroot != NULL)
720168404Spjd				(void) snprintf(buf, sizeof (buf), "%s%s",
721168404Spjd				    altroot, mountpoint);
722168404Spjd			else
723168404Spjd				(void) snprintf(buf, sizeof (buf), "%s",
724168404Spjd				    mountpoint);
725168404Spjd		}
726168404Spjd
727185029Spjd		if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
728185029Spjd			(void) fprintf(stderr, gettext("mountpoint '%s' : "
729185029Spjd			    "%s\n"), buf, strerror(errno));
730185029Spjd			(void) fprintf(stderr, gettext("use '-m' "
731185029Spjd			    "option to provide a different default\n"));
732185029Spjd			goto errout;
733185029Spjd		} else if (dirp) {
734185029Spjd			int count = 0;
735185029Spjd
736185029Spjd			while (count < 3 && readdir(dirp) != NULL)
737185029Spjd				count++;
738185029Spjd			(void) closedir(dirp);
739185029Spjd
740185029Spjd			if (count > 2) {
741168404Spjd				(void) fprintf(stderr, gettext("mountpoint "
742168404Spjd				    "'%s' exists and is not empty\n"), buf);
743185029Spjd				(void) fprintf(stderr, gettext("use '-m' "
744185029Spjd				    "option to provide a "
745185029Spjd				    "different default\n"));
746185029Spjd				goto errout;
747185029Spjd			}
748168404Spjd		}
749168404Spjd	}
750168404Spjd
751168404Spjd	if (dryrun) {
752168404Spjd		/*
753168404Spjd		 * For a dry run invocation, print out a basic message and run
754168404Spjd		 * through all the vdevs in the list and print out in an
755168404Spjd		 * appropriate hierarchy.
756168404Spjd		 */
757168404Spjd		(void) printf(gettext("would create '%s' with the "
758168404Spjd		    "following layout:\n\n"), poolname);
759168404Spjd
760185029Spjd		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
761185029Spjd		if (num_logs(nvroot) > 0)
762185029Spjd			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
763168404Spjd
764168404Spjd		ret = 0;
765168404Spjd	} else {
766168404Spjd		/*
767168404Spjd		 * Hand off to libzfs.
768168404Spjd		 */
769185029Spjd		if (zpool_create(g_zfs, poolname,
770185029Spjd		    nvroot, props, fsprops) == 0) {
771168404Spjd			zfs_handle_t *pool = zfs_open(g_zfs, poolname,
772168404Spjd			    ZFS_TYPE_FILESYSTEM);
773168404Spjd			if (pool != NULL) {
774168404Spjd				if (mountpoint != NULL)
775168404Spjd					verify(zfs_prop_set(pool,
776168404Spjd					    zfs_prop_to_name(
777168404Spjd					    ZFS_PROP_MOUNTPOINT),
778168404Spjd					    mountpoint) == 0);
779168404Spjd				if (zfs_mount(pool, NULL, 0) == 0)
780185029Spjd					ret = zfs_shareall(pool);
781168404Spjd				zfs_close(pool);
782168404Spjd			}
783168404Spjd		} else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
784168404Spjd			(void) fprintf(stderr, gettext("pool name may have "
785168404Spjd			    "been omitted\n"));
786168404Spjd		}
787168404Spjd	}
788168404Spjd
789185029Spjderrout:
790168404Spjd	nvlist_free(nvroot);
791185029Spjd	nvlist_free(fsprops);
792185029Spjd	nvlist_free(props);
793168404Spjd	return (ret);
794185029Spjdbadusage:
795185029Spjd	nvlist_free(fsprops);
796185029Spjd	nvlist_free(props);
797185029Spjd	usage(B_FALSE);
798185029Spjd	return (2);
799168404Spjd}
800168404Spjd
801168404Spjd/*
802168404Spjd * zpool destroy <pool>
803168404Spjd *
804168404Spjd * 	-f	Forcefully unmount any datasets
805168404Spjd *
806168404Spjd * Destroy the given pool.  Automatically unmounts any datasets in the pool.
807168404Spjd */
808168404Spjdint
809168404Spjdzpool_do_destroy(int argc, char **argv)
810168404Spjd{
811168404Spjd	boolean_t force = B_FALSE;
812168404Spjd	int c;
813168404Spjd	char *pool;
814168404Spjd	zpool_handle_t *zhp;
815168404Spjd	int ret;
816168404Spjd
817168404Spjd	/* check options */
818168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
819168404Spjd		switch (c) {
820168404Spjd		case 'f':
821168404Spjd			force = B_TRUE;
822168404Spjd			break;
823168404Spjd		case '?':
824168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
825168404Spjd			    optopt);
826168404Spjd			usage(B_FALSE);
827168404Spjd		}
828168404Spjd	}
829168404Spjd
830168404Spjd	argc -= optind;
831168404Spjd	argv += optind;
832168404Spjd
833168404Spjd	/* check arguments */
834168404Spjd	if (argc < 1) {
835168404Spjd		(void) fprintf(stderr, gettext("missing pool argument\n"));
836168404Spjd		usage(B_FALSE);
837168404Spjd	}
838168404Spjd	if (argc > 1) {
839168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
840168404Spjd		usage(B_FALSE);
841168404Spjd	}
842168404Spjd
843168404Spjd	pool = argv[0];
844168404Spjd
845168404Spjd	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
846168404Spjd		/*
847168404Spjd		 * As a special case, check for use of '/' in the name, and
848168404Spjd		 * direct the user to use 'zfs destroy' instead.
849168404Spjd		 */
850168404Spjd		if (strchr(pool, '/') != NULL)
851168404Spjd			(void) fprintf(stderr, gettext("use 'zfs destroy' to "
852168404Spjd			    "destroy a dataset\n"));
853168404Spjd		return (1);
854168404Spjd	}
855168404Spjd
856168404Spjd	if (zpool_disable_datasets(zhp, force) != 0) {
857168404Spjd		(void) fprintf(stderr, gettext("could not destroy '%s': "
858168404Spjd		    "could not unmount datasets\n"), zpool_get_name(zhp));
859168404Spjd		return (1);
860168404Spjd	}
861168404Spjd
862168404Spjd	ret = (zpool_destroy(zhp) != 0);
863168404Spjd
864168404Spjd	zpool_close(zhp);
865168404Spjd
866168404Spjd	return (ret);
867168404Spjd}
868168404Spjd
869168404Spjd/*
870168404Spjd * zpool export [-f] <pool> ...
871168404Spjd *
872168404Spjd *	-f	Forcefully unmount datasets
873168404Spjd *
874168404Spjd * Export the given pools.  By default, the command will attempt to cleanly
875168404Spjd * unmount any active datasets within the pool.  If the '-f' flag is specified,
876168404Spjd * then the datasets will be forcefully unmounted.
877168404Spjd */
878168404Spjdint
879168404Spjdzpool_do_export(int argc, char **argv)
880168404Spjd{
881168404Spjd	boolean_t force = B_FALSE;
882168404Spjd	int c;
883168404Spjd	zpool_handle_t *zhp;
884168404Spjd	int ret;
885168404Spjd	int i;
886168404Spjd
887168404Spjd	/* check options */
888168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
889168404Spjd		switch (c) {
890168404Spjd		case 'f':
891168404Spjd			force = B_TRUE;
892168404Spjd			break;
893168404Spjd		case '?':
894168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
895168404Spjd			    optopt);
896168404Spjd			usage(B_FALSE);
897168404Spjd		}
898168404Spjd	}
899168404Spjd
900168404Spjd	argc -= optind;
901168404Spjd	argv += optind;
902168404Spjd
903168404Spjd	/* check arguments */
904168404Spjd	if (argc < 1) {
905168404Spjd		(void) fprintf(stderr, gettext("missing pool argument\n"));
906168404Spjd		usage(B_FALSE);
907168404Spjd	}
908168404Spjd
909168404Spjd	ret = 0;
910168404Spjd	for (i = 0; i < argc; i++) {
911168404Spjd		if ((zhp = zpool_open_canfail(g_zfs, argv[i])) == NULL) {
912168404Spjd			ret = 1;
913168404Spjd			continue;
914168404Spjd		}
915168404Spjd
916168404Spjd		if (zpool_disable_datasets(zhp, force) != 0) {
917168404Spjd			ret = 1;
918168404Spjd			zpool_close(zhp);
919168404Spjd			continue;
920168404Spjd		}
921168404Spjd
922185029Spjd		if (zpool_export(zhp, force) != 0)
923168404Spjd			ret = 1;
924168404Spjd
925168404Spjd		zpool_close(zhp);
926168404Spjd	}
927168404Spjd
928168404Spjd	return (ret);
929168404Spjd}
930168404Spjd
931168404Spjd/*
932168404Spjd * Given a vdev configuration, determine the maximum width needed for the device
933168404Spjd * name column.
934168404Spjd */
935168404Spjdstatic int
936168404Spjdmax_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
937168404Spjd{
938168404Spjd	char *name = zpool_vdev_name(g_zfs, zhp, nv);
939168404Spjd	nvlist_t **child;
940168404Spjd	uint_t c, children;
941168404Spjd	int ret;
942168404Spjd
943168404Spjd	if (strlen(name) + depth > max)
944168404Spjd		max = strlen(name) + depth;
945168404Spjd
946168404Spjd	free(name);
947168404Spjd
948168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
949168404Spjd	    &child, &children) == 0) {
950168404Spjd		for (c = 0; c < children; c++)
951168404Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
952168404Spjd			    max)) > max)
953168404Spjd				max = ret;
954168404Spjd	}
955168404Spjd
956185029Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
957185029Spjd	    &child, &children) == 0) {
958185029Spjd		for (c = 0; c < children; c++)
959185029Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
960185029Spjd			    max)) > max)
961185029Spjd				max = ret;
962185029Spjd	}
963185029Spjd
964168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
965168404Spjd	    &child, &children) == 0) {
966168404Spjd		for (c = 0; c < children; c++)
967168404Spjd			if ((ret = max_width(zhp, child[c], depth + 2,
968168404Spjd			    max)) > max)
969168404Spjd				max = ret;
970168404Spjd	}
971168404Spjd
972168404Spjd
973168404Spjd	return (max);
974168404Spjd}
975168404Spjd
976168404Spjd
977168404Spjd/*
978168404Spjd * Print the configuration of an exported pool.  Iterate over all vdevs in the
979168404Spjd * pool, printing out the name and status for each one.
980168404Spjd */
981168404Spjdvoid
982185029Spjdprint_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
983185029Spjd    boolean_t print_logs)
984168404Spjd{
985168404Spjd	nvlist_t **child;
986168404Spjd	uint_t c, children;
987168404Spjd	vdev_stat_t *vs;
988168404Spjd	char *type, *vname;
989168404Spjd
990168404Spjd	verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
991168404Spjd	if (strcmp(type, VDEV_TYPE_MISSING) == 0)
992168404Spjd		return;
993168404Spjd
994168404Spjd	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
995168404Spjd	    (uint64_t **)&vs, &c) == 0);
996168404Spjd
997168404Spjd	(void) printf("\t%*s%-*s", depth, "", namewidth - depth, name);
998185029Spjd	(void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
999168404Spjd
1000168404Spjd	if (vs->vs_aux != 0) {
1001185029Spjd		(void) printf("  ");
1002168404Spjd
1003168404Spjd		switch (vs->vs_aux) {
1004168404Spjd		case VDEV_AUX_OPEN_FAILED:
1005168404Spjd			(void) printf(gettext("cannot open"));
1006168404Spjd			break;
1007168404Spjd
1008168404Spjd		case VDEV_AUX_BAD_GUID_SUM:
1009168404Spjd			(void) printf(gettext("missing device"));
1010168404Spjd			break;
1011168404Spjd
1012168404Spjd		case VDEV_AUX_NO_REPLICAS:
1013168404Spjd			(void) printf(gettext("insufficient replicas"));
1014168404Spjd			break;
1015168404Spjd
1016168404Spjd		case VDEV_AUX_VERSION_NEWER:
1017168404Spjd			(void) printf(gettext("newer version"));
1018168404Spjd			break;
1019168404Spjd
1020185029Spjd		case VDEV_AUX_ERR_EXCEEDED:
1021185029Spjd			(void) printf(gettext("too many errors"));
1022185029Spjd			break;
1023185029Spjd
1024168404Spjd		default:
1025168404Spjd			(void) printf(gettext("corrupted data"));
1026168404Spjd			break;
1027168404Spjd		}
1028168404Spjd	}
1029168404Spjd	(void) printf("\n");
1030168404Spjd
1031168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1032168404Spjd	    &child, &children) != 0)
1033168404Spjd		return;
1034168404Spjd
1035168404Spjd	for (c = 0; c < children; c++) {
1036185029Spjd		uint64_t is_log = B_FALSE;
1037185029Spjd
1038185029Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
1039185029Spjd		    &is_log);
1040185029Spjd		if ((is_log && !print_logs) || (!is_log && print_logs))
1041185029Spjd			continue;
1042185029Spjd
1043168404Spjd		vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1044168404Spjd		print_import_config(vname, child[c],
1045185029Spjd		    namewidth, depth + 2, B_FALSE);
1046168404Spjd		free(vname);
1047168404Spjd	}
1048168404Spjd
1049185029Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1050185029Spjd	    &child, &children) == 0) {
1051185029Spjd		(void) printf(gettext("\tcache\n"));
1052185029Spjd		for (c = 0; c < children; c++) {
1053185029Spjd			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1054185029Spjd			(void) printf("\t  %s\n", vname);
1055185029Spjd			free(vname);
1056185029Spjd		}
1057185029Spjd	}
1058185029Spjd
1059168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
1060185029Spjd	    &child, &children) == 0) {
1061185029Spjd		(void) printf(gettext("\tspares\n"));
1062185029Spjd		for (c = 0; c < children; c++) {
1063185029Spjd			vname = zpool_vdev_name(g_zfs, NULL, child[c]);
1064185029Spjd			(void) printf("\t  %s\n", vname);
1065185029Spjd			free(vname);
1066185029Spjd		}
1067168404Spjd	}
1068168404Spjd}
1069168404Spjd
1070168404Spjd/*
1071168404Spjd * Display the status for the given pool.
1072168404Spjd */
1073168404Spjdstatic void
1074168404Spjdshow_import(nvlist_t *config)
1075168404Spjd{
1076168404Spjd	uint64_t pool_state;
1077168404Spjd	vdev_stat_t *vs;
1078168404Spjd	char *name;
1079168404Spjd	uint64_t guid;
1080168404Spjd	char *msgid;
1081168404Spjd	nvlist_t *nvroot;
1082168404Spjd	int reason;
1083168404Spjd	const char *health;
1084168404Spjd	uint_t vsc;
1085168404Spjd	int namewidth;
1086168404Spjd
1087168404Spjd	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1088168404Spjd	    &name) == 0);
1089168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1090168404Spjd	    &guid) == 0);
1091168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1092168404Spjd	    &pool_state) == 0);
1093168404Spjd	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1094168404Spjd	    &nvroot) == 0);
1095168404Spjd
1096168404Spjd	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
1097168404Spjd	    (uint64_t **)&vs, &vsc) == 0);
1098185029Spjd	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
1099168404Spjd
1100168404Spjd	reason = zpool_import_status(config, &msgid);
1101168404Spjd
1102168404Spjd	(void) printf(gettext("  pool: %s\n"), name);
1103168404Spjd	(void) printf(gettext("    id: %llu\n"), (u_longlong_t)guid);
1104168404Spjd	(void) printf(gettext(" state: %s"), health);
1105168404Spjd	if (pool_state == POOL_STATE_DESTROYED)
1106168404Spjd		(void) printf(gettext(" (DESTROYED)"));
1107168404Spjd	(void) printf("\n");
1108168404Spjd
1109168404Spjd	switch (reason) {
1110168404Spjd	case ZPOOL_STATUS_MISSING_DEV_R:
1111168404Spjd	case ZPOOL_STATUS_MISSING_DEV_NR:
1112168404Spjd	case ZPOOL_STATUS_BAD_GUID_SUM:
1113168404Spjd		(void) printf(gettext("status: One or more devices are missing "
1114168404Spjd		    "from the system.\n"));
1115168404Spjd		break;
1116168404Spjd
1117168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_R:
1118168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
1119168404Spjd		(void) printf(gettext("status: One or more devices contains "
1120168404Spjd		    "corrupted data.\n"));
1121168404Spjd		break;
1122168404Spjd
1123168404Spjd	case ZPOOL_STATUS_CORRUPT_DATA:
1124168404Spjd		(void) printf(gettext("status: The pool data is corrupted.\n"));
1125168404Spjd		break;
1126168404Spjd
1127168404Spjd	case ZPOOL_STATUS_OFFLINE_DEV:
1128168404Spjd		(void) printf(gettext("status: One or more devices "
1129168404Spjd		    "are offlined.\n"));
1130168404Spjd		break;
1131168404Spjd
1132168404Spjd	case ZPOOL_STATUS_CORRUPT_POOL:
1133168404Spjd		(void) printf(gettext("status: The pool metadata is "
1134168404Spjd		    "corrupted.\n"));
1135168404Spjd		break;
1136168404Spjd
1137168404Spjd	case ZPOOL_STATUS_VERSION_OLDER:
1138168404Spjd		(void) printf(gettext("status: The pool is formatted using an "
1139168404Spjd		    "older on-disk version.\n"));
1140168404Spjd		break;
1141168404Spjd
1142168404Spjd	case ZPOOL_STATUS_VERSION_NEWER:
1143168404Spjd		(void) printf(gettext("status: The pool is formatted using an "
1144168404Spjd		    "incompatible version.\n"));
1145168404Spjd		break;
1146168404Spjd
1147168498Spjd	case ZPOOL_STATUS_HOSTID_MISMATCH:
1148168498Spjd		(void) printf(gettext("status: The pool was last accessed by "
1149168498Spjd		    "another system.\n"));
1150168498Spjd		break;
1151185029Spjd
1152185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_R:
1153185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_NR:
1154185029Spjd		(void) printf(gettext("status: One or more devices are "
1155185029Spjd		    "faulted.\n"));
1156185029Spjd		break;
1157185029Spjd
1158185029Spjd	case ZPOOL_STATUS_BAD_LOG:
1159185029Spjd		(void) printf(gettext("status: An intent log record cannot be "
1160185029Spjd		    "read.\n"));
1161185029Spjd		break;
1162185029Spjd
1163168404Spjd	default:
1164168404Spjd		/*
1165168404Spjd		 * No other status can be seen when importing pools.
1166168404Spjd		 */
1167168404Spjd		assert(reason == ZPOOL_STATUS_OK);
1168168404Spjd	}
1169168404Spjd
1170168404Spjd	/*
1171168404Spjd	 * Print out an action according to the overall state of the pool.
1172168404Spjd	 */
1173168404Spjd	if (vs->vs_state == VDEV_STATE_HEALTHY) {
1174168404Spjd		if (reason == ZPOOL_STATUS_VERSION_OLDER)
1175168404Spjd			(void) printf(gettext("action: The pool can be "
1176168404Spjd			    "imported using its name or numeric identifier, "
1177168404Spjd			    "though\n\tsome features will not be available "
1178168404Spjd			    "without an explicit 'zpool upgrade'.\n"));
1179168498Spjd		else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH)
1180168498Spjd			(void) printf(gettext("action: The pool can be "
1181168498Spjd			    "imported using its name or numeric "
1182168498Spjd			    "identifier and\n\tthe '-f' flag.\n"));
1183168404Spjd		else
1184168404Spjd			(void) printf(gettext("action: The pool can be "
1185168404Spjd			    "imported using its name or numeric "
1186168404Spjd			    "identifier.\n"));
1187168404Spjd	} else if (vs->vs_state == VDEV_STATE_DEGRADED) {
1188168404Spjd		(void) printf(gettext("action: The pool can be imported "
1189168404Spjd		    "despite missing or damaged devices.  The\n\tfault "
1190168404Spjd		    "tolerance of the pool may be compromised if imported.\n"));
1191168404Spjd	} else {
1192168404Spjd		switch (reason) {
1193168404Spjd		case ZPOOL_STATUS_VERSION_NEWER:
1194168404Spjd			(void) printf(gettext("action: The pool cannot be "
1195168404Spjd			    "imported.  Access the pool on a system running "
1196168404Spjd			    "newer\n\tsoftware, or recreate the pool from "
1197168404Spjd			    "backup.\n"));
1198168404Spjd			break;
1199168404Spjd		case ZPOOL_STATUS_MISSING_DEV_R:
1200168404Spjd		case ZPOOL_STATUS_MISSING_DEV_NR:
1201168404Spjd		case ZPOOL_STATUS_BAD_GUID_SUM:
1202168404Spjd			(void) printf(gettext("action: The pool cannot be "
1203168404Spjd			    "imported. Attach the missing\n\tdevices and try "
1204168404Spjd			    "again.\n"));
1205168404Spjd			break;
1206168404Spjd		default:
1207168404Spjd			(void) printf(gettext("action: The pool cannot be "
1208168404Spjd			    "imported due to damaged devices or data.\n"));
1209168404Spjd		}
1210168404Spjd	}
1211168404Spjd
1212168404Spjd	/*
1213168404Spjd	 * If the state is "closed" or "can't open", and the aux state
1214168404Spjd	 * is "corrupt data":
1215168404Spjd	 */
1216168404Spjd	if (((vs->vs_state == VDEV_STATE_CLOSED) ||
1217168404Spjd	    (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
1218168404Spjd	    (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
1219168404Spjd		if (pool_state == POOL_STATE_DESTROYED)
1220168404Spjd			(void) printf(gettext("\tThe pool was destroyed, "
1221168404Spjd			    "but can be imported using the '-Df' flags.\n"));
1222168404Spjd		else if (pool_state != POOL_STATE_EXPORTED)
1223168404Spjd			(void) printf(gettext("\tThe pool may be active on "
1224185029Spjd			    "another system, but can be imported using\n\t"
1225168404Spjd			    "the '-f' flag.\n"));
1226168404Spjd	}
1227168404Spjd
1228168404Spjd	if (msgid != NULL)
1229168404Spjd		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
1230168404Spjd		    msgid);
1231168404Spjd
1232168404Spjd	(void) printf(gettext("config:\n\n"));
1233168404Spjd
1234168404Spjd	namewidth = max_width(NULL, nvroot, 0, 0);
1235168404Spjd	if (namewidth < 10)
1236168404Spjd		namewidth = 10;
1237168404Spjd
1238185029Spjd	print_import_config(name, nvroot, namewidth, 0, B_FALSE);
1239185029Spjd	if (num_logs(nvroot) > 0) {
1240185029Spjd		(void) printf(gettext("\tlogs\n"));
1241185029Spjd		print_import_config(name, nvroot, namewidth, 0, B_TRUE);
1242185029Spjd	}
1243185029Spjd
1244168404Spjd	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
1245168404Spjd		(void) printf(gettext("\n\tAdditional devices are known to "
1246168404Spjd		    "be part of this pool, though their\n\texact "
1247168404Spjd		    "configuration cannot be determined.\n"));
1248168404Spjd	}
1249168404Spjd}
1250168404Spjd
1251168404Spjd/*
1252168404Spjd * Perform the import for the given configuration.  This passes the heavy
1253185029Spjd * lifting off to zpool_import_props(), and then mounts the datasets contained
1254185029Spjd * within the pool.
1255168404Spjd */
1256168404Spjdstatic int
1257168404Spjddo_import(nvlist_t *config, const char *newname, const char *mntopts,
1258185029Spjd    int force, nvlist_t *props, boolean_t allowfaulted)
1259168404Spjd{
1260168404Spjd	zpool_handle_t *zhp;
1261168404Spjd	char *name;
1262168404Spjd	uint64_t state;
1263168404Spjd	uint64_t version;
1264185029Spjd	int error = 0;
1265168404Spjd
1266168404Spjd	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1267168404Spjd	    &name) == 0);
1268168404Spjd
1269168404Spjd	verify(nvlist_lookup_uint64(config,
1270168404Spjd	    ZPOOL_CONFIG_POOL_STATE, &state) == 0);
1271168404Spjd	verify(nvlist_lookup_uint64(config,
1272168404Spjd	    ZPOOL_CONFIG_VERSION, &version) == 0);
1273185029Spjd	if (version > SPA_VERSION) {
1274168404Spjd		(void) fprintf(stderr, gettext("cannot import '%s': pool "
1275168404Spjd		    "is formatted using a newer ZFS version\n"), name);
1276168404Spjd		return (1);
1277168404Spjd	} else if (state != POOL_STATE_EXPORTED && !force) {
1278168498Spjd		uint64_t hostid;
1279168498Spjd
1280168498Spjd		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
1281168498Spjd		    &hostid) == 0) {
1282168498Spjd			if ((unsigned long)hostid != gethostid()) {
1283168498Spjd				char *hostname;
1284168498Spjd				uint64_t timestamp;
1285168498Spjd				time_t t;
1286168498Spjd
1287168498Spjd				verify(nvlist_lookup_string(config,
1288168498Spjd				    ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
1289168498Spjd				verify(nvlist_lookup_uint64(config,
1290168498Spjd				    ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
1291168498Spjd				t = timestamp;
1292168498Spjd				(void) fprintf(stderr, gettext("cannot import "
1293168498Spjd				    "'%s': pool may be in use from other "
1294168498Spjd				    "system, it was last accessed by %s "
1295168498Spjd				    "(hostid: 0x%lx) on %s"), name, hostname,
1296168498Spjd				    (unsigned long)hostid,
1297168498Spjd				    asctime(localtime(&t)));
1298168498Spjd				(void) fprintf(stderr, gettext("use '-f' to "
1299168498Spjd				    "import anyway\n"));
1300168498Spjd				return (1);
1301168498Spjd			}
1302168498Spjd		} else {
1303168498Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
1304168498Spjd			    "pool may be in use from other system\n"), name);
1305168498Spjd			(void) fprintf(stderr, gettext("use '-f' to import "
1306168498Spjd			    "anyway\n"));
1307168498Spjd			return (1);
1308168498Spjd		}
1309168404Spjd	}
1310168404Spjd
1311185029Spjd	if (zpool_import_props(g_zfs, config, newname, props,
1312185029Spjd	    allowfaulted) != 0)
1313168404Spjd		return (1);
1314168404Spjd
1315168404Spjd	if (newname != NULL)
1316168404Spjd		name = (char *)newname;
1317168404Spjd
1318185029Spjd	verify((zhp = zpool_open_canfail(g_zfs, name)) != NULL);
1319168404Spjd
1320168404Spjd	if (zpool_enable_datasets(zhp, mntopts, 0) != 0) {
1321168404Spjd		zpool_close(zhp);
1322168404Spjd		return (1);
1323168404Spjd	}
1324168404Spjd
1325168404Spjd	zpool_close(zhp);
1326185029Spjd	return (error);
1327168404Spjd}
1328168404Spjd
1329168404Spjd/*
1330168404Spjd * zpool import [-d dir] [-D]
1331185029Spjd *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
1332185029Spjd *              [-d dir | -c cachefile] [-f] -a
1333185029Spjd *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
1334185029Spjd *              [-d dir | -c cachefile] [-f] <pool | id> [newpool]
1335168404Spjd *
1336185029Spjd *	 -c	Read pool information from a cachefile instead of searching
1337185029Spjd *		devices.
1338185029Spjd *
1339168404Spjd *       -d	Scan in a specific directory, other than /dev/dsk.  More than
1340168404Spjd *		one directory can be specified using multiple '-d' options.
1341168404Spjd *
1342168404Spjd *       -D     Scan for previously destroyed pools or import all or only
1343168404Spjd *              specified destroyed pools.
1344168404Spjd *
1345168404Spjd *       -R	Temporarily import the pool, with all mountpoints relative to
1346168404Spjd *		the given root.  The pool will remain exported when the machine
1347168404Spjd *		is rebooted.
1348168404Spjd *
1349168404Spjd *       -f	Force import, even if it appears that the pool is active.
1350168404Spjd *
1351185029Spjd *       -F	Import even in the presence of faulted vdevs.  This is an
1352185029Spjd *       	intentionally undocumented option for testing purposes, and
1353185029Spjd *       	treats the pool configuration as complete, leaving any bad
1354185029Spjd *		vdevs in the FAULTED state.
1355185029Spjd *
1356168404Spjd *       -a	Import all pools found.
1357168404Spjd *
1358185029Spjd *       -o	Set property=value and/or temporary mount options (without '=').
1359185029Spjd *
1360168404Spjd * The import command scans for pools to import, and import pools based on pool
1361168404Spjd * name and GUID.  The pool can also be renamed as part of the import process.
1362168404Spjd */
1363168404Spjdint
1364168404Spjdzpool_do_import(int argc, char **argv)
1365168404Spjd{
1366168404Spjd	char **searchdirs = NULL;
1367168404Spjd	int nsearch = 0;
1368168404Spjd	int c;
1369168404Spjd	int err;
1370185029Spjd	nvlist_t *pools = NULL;
1371168404Spjd	boolean_t do_all = B_FALSE;
1372168404Spjd	boolean_t do_destroyed = B_FALSE;
1373168404Spjd	char *mntopts = NULL;
1374168404Spjd	boolean_t do_force = B_FALSE;
1375168404Spjd	nvpair_t *elem;
1376168404Spjd	nvlist_t *config;
1377185029Spjd	uint64_t searchguid = 0;
1378185029Spjd	char *searchname = NULL;
1379185029Spjd	char *propval;
1380168404Spjd	nvlist_t *found_config;
1381185029Spjd	nvlist_t *props = NULL;
1382168404Spjd	boolean_t first;
1383185029Spjd	boolean_t allow_faulted = B_FALSE;
1384168404Spjd	uint64_t pool_state;
1385185029Spjd	char *cachefile = NULL;
1386168404Spjd
1387168404Spjd	/* check options */
1388185029Spjd	while ((c = getopt(argc, argv, ":ac:d:DfFo:p:R:")) != -1) {
1389168404Spjd		switch (c) {
1390168404Spjd		case 'a':
1391168404Spjd			do_all = B_TRUE;
1392168404Spjd			break;
1393185029Spjd		case 'c':
1394185029Spjd			cachefile = optarg;
1395185029Spjd			break;
1396168404Spjd		case 'd':
1397168404Spjd			if (searchdirs == NULL) {
1398168404Spjd				searchdirs = safe_malloc(sizeof (char *));
1399168404Spjd			} else {
1400168404Spjd				char **tmp = safe_malloc((nsearch + 1) *
1401168404Spjd				    sizeof (char *));
1402168404Spjd				bcopy(searchdirs, tmp, nsearch *
1403168404Spjd				    sizeof (char *));
1404168404Spjd				free(searchdirs);
1405168404Spjd				searchdirs = tmp;
1406168404Spjd			}
1407168404Spjd			searchdirs[nsearch++] = optarg;
1408168404Spjd			break;
1409168404Spjd		case 'D':
1410168404Spjd			do_destroyed = B_TRUE;
1411168404Spjd			break;
1412168404Spjd		case 'f':
1413168404Spjd			do_force = B_TRUE;
1414168404Spjd			break;
1415185029Spjd		case 'F':
1416185029Spjd			allow_faulted = B_TRUE;
1417185029Spjd			break;
1418168404Spjd		case 'o':
1419185029Spjd			if ((propval = strchr(optarg, '=')) != NULL) {
1420185029Spjd				*propval = '\0';
1421185029Spjd				propval++;
1422185029Spjd				if (add_prop_list(optarg, propval,
1423185029Spjd				    &props, B_TRUE))
1424185029Spjd					goto error;
1425185029Spjd			} else {
1426185029Spjd				mntopts = optarg;
1427185029Spjd			}
1428168404Spjd			break;
1429168404Spjd		case 'R':
1430185029Spjd			if (add_prop_list(zpool_prop_to_name(
1431185029Spjd			    ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
1432185029Spjd				goto error;
1433185029Spjd			if (nvlist_lookup_string(props,
1434185029Spjd			    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE),
1435185029Spjd			    &propval) == 0)
1436185029Spjd				break;
1437185029Spjd			if (add_prop_list(zpool_prop_to_name(
1438185029Spjd			    ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
1439185029Spjd				goto error;
1440168404Spjd			break;
1441168404Spjd		case ':':
1442168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
1443168404Spjd			    "'%c' option\n"), optopt);
1444168404Spjd			usage(B_FALSE);
1445168404Spjd			break;
1446168404Spjd		case '?':
1447168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1448168404Spjd			    optopt);
1449168404Spjd			usage(B_FALSE);
1450168404Spjd		}
1451168404Spjd	}
1452168404Spjd
1453168404Spjd	argc -= optind;
1454168404Spjd	argv += optind;
1455168404Spjd
1456185029Spjd	if (cachefile && nsearch != 0) {
1457185029Spjd		(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
1458185029Spjd		usage(B_FALSE);
1459185029Spjd	}
1460185029Spjd
1461168404Spjd	if (searchdirs == NULL) {
1462168404Spjd		searchdirs = safe_malloc(sizeof (char *));
1463185029Spjd		searchdirs[0] = "/dev/dsk";
1464168404Spjd		nsearch = 1;
1465168404Spjd	}
1466168404Spjd
1467168404Spjd	/* check argument count */
1468168404Spjd	if (do_all) {
1469168404Spjd		if (argc != 0) {
1470168404Spjd			(void) fprintf(stderr, gettext("too many arguments\n"));
1471168404Spjd			usage(B_FALSE);
1472168404Spjd		}
1473168404Spjd	} else {
1474168404Spjd		if (argc > 2) {
1475168404Spjd			(void) fprintf(stderr, gettext("too many arguments\n"));
1476168404Spjd			usage(B_FALSE);
1477168404Spjd		}
1478168404Spjd
1479168404Spjd		/*
1480168404Spjd		 * Check for the SYS_CONFIG privilege.  We do this explicitly
1481168404Spjd		 * here because otherwise any attempt to discover pools will
1482168404Spjd		 * silently fail.
1483168404Spjd		 */
1484168404Spjd		if (argc == 0 && !priv_ineffect(PRIV_SYS_CONFIG)) {
1485168404Spjd			(void) fprintf(stderr, gettext("cannot "
1486168404Spjd			    "discover pools: permission denied\n"));
1487168404Spjd			free(searchdirs);
1488168404Spjd			return (1);
1489168404Spjd		}
1490168404Spjd	}
1491168404Spjd
1492168404Spjd	/*
1493168404Spjd	 * Depending on the arguments given, we do one of the following:
1494168404Spjd	 *
1495168404Spjd	 *	<none>	Iterate through all pools and display information about
1496168404Spjd	 *		each one.
1497168404Spjd	 *
1498168404Spjd	 *	-a	Iterate through all pools and try to import each one.
1499168404Spjd	 *
1500168404Spjd	 *	<id>	Find the pool that corresponds to the given GUID/pool
1501168404Spjd	 *		name and import that one.
1502168404Spjd	 *
1503168404Spjd	 *	-D	Above options applies only to destroyed pools.
1504168404Spjd	 */
1505168404Spjd	if (argc != 0) {
1506168404Spjd		char *endptr;
1507168404Spjd
1508168404Spjd		errno = 0;
1509168404Spjd		searchguid = strtoull(argv[0], &endptr, 10);
1510168404Spjd		if (errno != 0 || *endptr != '\0')
1511168404Spjd			searchname = argv[0];
1512168404Spjd		found_config = NULL;
1513168404Spjd	}
1514168404Spjd
1515185029Spjd	if (cachefile) {
1516185029Spjd		pools = zpool_find_import_cached(g_zfs, cachefile, searchname,
1517185029Spjd		    searchguid);
1518185029Spjd	} else if (searchname != NULL) {
1519185029Spjd		pools = zpool_find_import_byname(g_zfs, nsearch, searchdirs,
1520185029Spjd		    searchname);
1521185029Spjd	} else {
1522185029Spjd		/*
1523185029Spjd		 * It's OK to search by guid even if searchguid is 0.
1524185029Spjd		 */
1525185029Spjd		pools = zpool_find_import_byguid(g_zfs, nsearch, searchdirs,
1526185029Spjd		    searchguid);
1527185029Spjd	}
1528185029Spjd
1529185029Spjd	if (pools == NULL) {
1530185029Spjd		if (argc != 0) {
1531185029Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
1532185029Spjd			    "no such pool available\n"), argv[0]);
1533185029Spjd		}
1534185029Spjd		free(searchdirs);
1535185029Spjd		return (1);
1536185029Spjd	}
1537185029Spjd
1538185029Spjd	/*
1539185029Spjd	 * At this point we have a list of import candidate configs. Even if
1540185029Spjd	 * we were searching by pool name or guid, we still need to
1541185029Spjd	 * post-process the list to deal with pool state and possible
1542185029Spjd	 * duplicate names.
1543185029Spjd	 */
1544168404Spjd	err = 0;
1545168404Spjd	elem = NULL;
1546168404Spjd	first = B_TRUE;
1547168404Spjd	while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1548168404Spjd
1549168404Spjd		verify(nvpair_value_nvlist(elem, &config) == 0);
1550168404Spjd
1551168404Spjd		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
1552168404Spjd		    &pool_state) == 0);
1553168404Spjd		if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
1554168404Spjd			continue;
1555168404Spjd		if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
1556168404Spjd			continue;
1557168404Spjd
1558168404Spjd		if (argc == 0) {
1559168404Spjd			if (first)
1560168404Spjd				first = B_FALSE;
1561168404Spjd			else if (!do_all)
1562168404Spjd				(void) printf("\n");
1563168404Spjd
1564168404Spjd			if (do_all)
1565168404Spjd				err |= do_import(config, NULL, mntopts,
1566185029Spjd				    do_force, props, allow_faulted);
1567168404Spjd			else
1568168404Spjd				show_import(config);
1569168404Spjd		} else if (searchname != NULL) {
1570168404Spjd			char *name;
1571168404Spjd
1572168404Spjd			/*
1573168404Spjd			 * We are searching for a pool based on name.
1574168404Spjd			 */
1575168404Spjd			verify(nvlist_lookup_string(config,
1576168404Spjd			    ZPOOL_CONFIG_POOL_NAME, &name) == 0);
1577168404Spjd
1578168404Spjd			if (strcmp(name, searchname) == 0) {
1579168404Spjd				if (found_config != NULL) {
1580168404Spjd					(void) fprintf(stderr, gettext(
1581168404Spjd					    "cannot import '%s': more than "
1582168404Spjd					    "one matching pool\n"), searchname);
1583168404Spjd					(void) fprintf(stderr, gettext(
1584168404Spjd					    "import by numeric ID instead\n"));
1585168404Spjd					err = B_TRUE;
1586168404Spjd				}
1587168404Spjd				found_config = config;
1588168404Spjd			}
1589168404Spjd		} else {
1590168404Spjd			uint64_t guid;
1591168404Spjd
1592168404Spjd			/*
1593168404Spjd			 * Search for a pool by guid.
1594168404Spjd			 */
1595168404Spjd			verify(nvlist_lookup_uint64(config,
1596168404Spjd			    ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
1597168404Spjd
1598168404Spjd			if (guid == searchguid)
1599168404Spjd				found_config = config;
1600168404Spjd		}
1601168404Spjd	}
1602168404Spjd
1603168404Spjd	/*
1604168404Spjd	 * If we were searching for a specific pool, verify that we found a
1605168404Spjd	 * pool, and then do the import.
1606168404Spjd	 */
1607168404Spjd	if (argc != 0 && err == 0) {
1608168404Spjd		if (found_config == NULL) {
1609168404Spjd			(void) fprintf(stderr, gettext("cannot import '%s': "
1610168404Spjd			    "no such pool available\n"), argv[0]);
1611168404Spjd			err = B_TRUE;
1612168404Spjd		} else {
1613168404Spjd			err |= do_import(found_config, argc == 1 ? NULL :
1614185029Spjd			    argv[1], mntopts, do_force, props, allow_faulted);
1615168404Spjd		}
1616168404Spjd	}
1617168404Spjd
1618168404Spjd	/*
1619168404Spjd	 * If we were just looking for pools, report an error if none were
1620168404Spjd	 * found.
1621168404Spjd	 */
1622168404Spjd	if (argc == 0 && first)
1623168404Spjd		(void) fprintf(stderr,
1624168404Spjd		    gettext("no pools available to import\n"));
1625168404Spjd
1626185029Spjderror:
1627185029Spjd	nvlist_free(props);
1628168404Spjd	nvlist_free(pools);
1629168404Spjd	free(searchdirs);
1630168404Spjd
1631168404Spjd	return (err ? 1 : 0);
1632168404Spjd}
1633168404Spjd
1634168404Spjdtypedef struct iostat_cbdata {
1635168404Spjd	zpool_list_t *cb_list;
1636168404Spjd	int cb_verbose;
1637168404Spjd	int cb_iteration;
1638168404Spjd	int cb_namewidth;
1639168404Spjd} iostat_cbdata_t;
1640168404Spjd
1641168404Spjdstatic void
1642168404Spjdprint_iostat_separator(iostat_cbdata_t *cb)
1643168404Spjd{
1644168404Spjd	int i = 0;
1645168404Spjd
1646168404Spjd	for (i = 0; i < cb->cb_namewidth; i++)
1647168404Spjd		(void) printf("-");
1648168404Spjd	(void) printf("  -----  -----  -----  -----  -----  -----\n");
1649168404Spjd}
1650168404Spjd
1651168404Spjdstatic void
1652168404Spjdprint_iostat_header(iostat_cbdata_t *cb)
1653168404Spjd{
1654168404Spjd	(void) printf("%*s     capacity     operations    bandwidth\n",
1655168404Spjd	    cb->cb_namewidth, "");
1656168404Spjd	(void) printf("%-*s   used  avail   read  write   read  write\n",
1657168404Spjd	    cb->cb_namewidth, "pool");
1658168404Spjd	print_iostat_separator(cb);
1659168404Spjd}
1660168404Spjd
1661168404Spjd/*
1662168404Spjd * Display a single statistic.
1663168404Spjd */
1664185029Spjdstatic void
1665168404Spjdprint_one_stat(uint64_t value)
1666168404Spjd{
1667168404Spjd	char buf[64];
1668168404Spjd
1669168404Spjd	zfs_nicenum(value, buf, sizeof (buf));
1670168404Spjd	(void) printf("  %5s", buf);
1671168404Spjd}
1672168404Spjd
1673168404Spjd/*
1674168404Spjd * Print out all the statistics for the given vdev.  This can either be the
1675168404Spjd * toplevel configuration, or called recursively.  If 'name' is NULL, then this
1676168404Spjd * is a verbose output, and we don't want to display the toplevel pool stats.
1677168404Spjd */
1678168404Spjdvoid
1679168404Spjdprint_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
1680168404Spjd    nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
1681168404Spjd{
1682168404Spjd	nvlist_t **oldchild, **newchild;
1683168404Spjd	uint_t c, children;
1684168404Spjd	vdev_stat_t *oldvs, *newvs;
1685168404Spjd	vdev_stat_t zerovs = { 0 };
1686168404Spjd	uint64_t tdelta;
1687168404Spjd	double scale;
1688168404Spjd	char *vname;
1689168404Spjd
1690168404Spjd	if (oldnv != NULL) {
1691168404Spjd		verify(nvlist_lookup_uint64_array(oldnv, ZPOOL_CONFIG_STATS,
1692168404Spjd		    (uint64_t **)&oldvs, &c) == 0);
1693168404Spjd	} else {
1694168404Spjd		oldvs = &zerovs;
1695168404Spjd	}
1696168404Spjd
1697168404Spjd	verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_STATS,
1698168404Spjd	    (uint64_t **)&newvs, &c) == 0);
1699168404Spjd
1700168404Spjd	if (strlen(name) + depth > cb->cb_namewidth)
1701168404Spjd		(void) printf("%*s%s", depth, "", name);
1702168404Spjd	else
1703168404Spjd		(void) printf("%*s%s%*s", depth, "", name,
1704168404Spjd		    (int)(cb->cb_namewidth - strlen(name) - depth), "");
1705168404Spjd
1706168404Spjd	tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
1707168404Spjd
1708168404Spjd	if (tdelta == 0)
1709168404Spjd		scale = 1.0;
1710168404Spjd	else
1711168404Spjd		scale = (double)NANOSEC / tdelta;
1712168404Spjd
1713168404Spjd	/* only toplevel vdevs have capacity stats */
1714168404Spjd	if (newvs->vs_space == 0) {
1715168404Spjd		(void) printf("      -      -");
1716168404Spjd	} else {
1717168404Spjd		print_one_stat(newvs->vs_alloc);
1718168404Spjd		print_one_stat(newvs->vs_space - newvs->vs_alloc);
1719168404Spjd	}
1720168404Spjd
1721168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_READ] -
1722168404Spjd	    oldvs->vs_ops[ZIO_TYPE_READ])));
1723168404Spjd
1724168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_ops[ZIO_TYPE_WRITE] -
1725168404Spjd	    oldvs->vs_ops[ZIO_TYPE_WRITE])));
1726168404Spjd
1727168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_READ] -
1728168404Spjd	    oldvs->vs_bytes[ZIO_TYPE_READ])));
1729168404Spjd
1730168404Spjd	print_one_stat((uint64_t)(scale * (newvs->vs_bytes[ZIO_TYPE_WRITE] -
1731168404Spjd	    oldvs->vs_bytes[ZIO_TYPE_WRITE])));
1732168404Spjd
1733168404Spjd	(void) printf("\n");
1734168404Spjd
1735168404Spjd	if (!cb->cb_verbose)
1736168404Spjd		return;
1737168404Spjd
1738168404Spjd	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
1739168404Spjd	    &newchild, &children) != 0)
1740168404Spjd		return;
1741168404Spjd
1742168404Spjd	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
1743168404Spjd	    &oldchild, &c) != 0)
1744168404Spjd		return;
1745168404Spjd
1746168404Spjd	for (c = 0; c < children; c++) {
1747168404Spjd		vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1748168404Spjd		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1749168404Spjd		    newchild[c], cb, depth + 2);
1750168404Spjd		free(vname);
1751168404Spjd	}
1752185029Spjd
1753185029Spjd	/*
1754185029Spjd	 * Include level 2 ARC devices in iostat output
1755185029Spjd	 */
1756185029Spjd	if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
1757185029Spjd	    &newchild, &children) != 0)
1758185029Spjd		return;
1759185029Spjd
1760185029Spjd	if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
1761185029Spjd	    &oldchild, &c) != 0)
1762185029Spjd		return;
1763185029Spjd
1764185029Spjd	if (children > 0) {
1765185029Spjd		(void) printf("%-*s      -      -      -      -      -      "
1766185029Spjd		    "-\n", cb->cb_namewidth, "cache");
1767185029Spjd		for (c = 0; c < children; c++) {
1768185029Spjd			vname = zpool_vdev_name(g_zfs, zhp, newchild[c]);
1769185029Spjd			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
1770185029Spjd			    newchild[c], cb, depth + 2);
1771185029Spjd			free(vname);
1772185029Spjd		}
1773185029Spjd	}
1774168404Spjd}
1775168404Spjd
1776168404Spjdstatic int
1777168404Spjdrefresh_iostat(zpool_handle_t *zhp, void *data)
1778168404Spjd{
1779168404Spjd	iostat_cbdata_t *cb = data;
1780168404Spjd	boolean_t missing;
1781168404Spjd
1782168404Spjd	/*
1783168404Spjd	 * If the pool has disappeared, remove it from the list and continue.
1784168404Spjd	 */
1785168404Spjd	if (zpool_refresh_stats(zhp, &missing) != 0)
1786168404Spjd		return (-1);
1787168404Spjd
1788168404Spjd	if (missing)
1789168404Spjd		pool_list_remove(cb->cb_list, zhp);
1790168404Spjd
1791168404Spjd	return (0);
1792168404Spjd}
1793168404Spjd
1794168404Spjd/*
1795168404Spjd * Callback to print out the iostats for the given pool.
1796168404Spjd */
1797168404Spjdint
1798168404Spjdprint_iostat(zpool_handle_t *zhp, void *data)
1799168404Spjd{
1800168404Spjd	iostat_cbdata_t *cb = data;
1801168404Spjd	nvlist_t *oldconfig, *newconfig;
1802168404Spjd	nvlist_t *oldnvroot, *newnvroot;
1803168404Spjd
1804168404Spjd	newconfig = zpool_get_config(zhp, &oldconfig);
1805168404Spjd
1806168404Spjd	if (cb->cb_iteration == 1)
1807168404Spjd		oldconfig = NULL;
1808168404Spjd
1809168404Spjd	verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
1810168404Spjd	    &newnvroot) == 0);
1811168404Spjd
1812168404Spjd	if (oldconfig == NULL)
1813168404Spjd		oldnvroot = NULL;
1814168404Spjd	else
1815168404Spjd		verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
1816168404Spjd		    &oldnvroot) == 0);
1817168404Spjd
1818168404Spjd	/*
1819168404Spjd	 * Print out the statistics for the pool.
1820168404Spjd	 */
1821168404Spjd	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
1822168404Spjd
1823168404Spjd	if (cb->cb_verbose)
1824168404Spjd		print_iostat_separator(cb);
1825168404Spjd
1826168404Spjd	return (0);
1827168404Spjd}
1828168404Spjd
1829168404Spjdint
1830168404Spjdget_namewidth(zpool_handle_t *zhp, void *data)
1831168404Spjd{
1832168404Spjd	iostat_cbdata_t *cb = data;
1833168404Spjd	nvlist_t *config, *nvroot;
1834168404Spjd
1835168404Spjd	if ((config = zpool_get_config(zhp, NULL)) != NULL) {
1836168404Spjd		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1837168404Spjd		    &nvroot) == 0);
1838168404Spjd		if (!cb->cb_verbose)
1839168404Spjd			cb->cb_namewidth = strlen(zpool_get_name(zhp));
1840168404Spjd		else
1841168404Spjd			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
1842168404Spjd	}
1843168404Spjd
1844168404Spjd	/*
1845168404Spjd	 * The width must fall into the range [10,38].  The upper limit is the
1846168404Spjd	 * maximum we can have and still fit in 80 columns.
1847168404Spjd	 */
1848168404Spjd	if (cb->cb_namewidth < 10)
1849168404Spjd		cb->cb_namewidth = 10;
1850168404Spjd	if (cb->cb_namewidth > 38)
1851168404Spjd		cb->cb_namewidth = 38;
1852168404Spjd
1853168404Spjd	return (0);
1854168404Spjd}
1855168404Spjd
1856168404Spjd/*
1857168404Spjd * zpool iostat [-v] [pool] ... [interval [count]]
1858168404Spjd *
1859168404Spjd *	-v	Display statistics for individual vdevs
1860168404Spjd *
1861168404Spjd * This command can be tricky because we want to be able to deal with pool
1862168404Spjd * creation/destruction as well as vdev configuration changes.  The bulk of this
1863168404Spjd * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
1864168404Spjd * on pool_list_update() to detect the addition of new pools.  Configuration
1865168404Spjd * changes are all handled within libzfs.
1866168404Spjd */
1867168404Spjdint
1868168404Spjdzpool_do_iostat(int argc, char **argv)
1869168404Spjd{
1870168404Spjd	int c;
1871168404Spjd	int ret;
1872168404Spjd	int npools;
1873168404Spjd	unsigned long interval = 0, count = 0;
1874168404Spjd	zpool_list_t *list;
1875168404Spjd	boolean_t verbose = B_FALSE;
1876168404Spjd	iostat_cbdata_t cb;
1877168404Spjd
1878168404Spjd	/* check options */
1879168404Spjd	while ((c = getopt(argc, argv, "v")) != -1) {
1880168404Spjd		switch (c) {
1881168404Spjd		case 'v':
1882168404Spjd			verbose = B_TRUE;
1883168404Spjd			break;
1884168404Spjd		case '?':
1885168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
1886168404Spjd			    optopt);
1887168404Spjd			usage(B_FALSE);
1888168404Spjd		}
1889168404Spjd	}
1890168404Spjd
1891168404Spjd	argc -= optind;
1892168404Spjd	argv += optind;
1893168404Spjd
1894168404Spjd	/*
1895168404Spjd	 * Determine if the last argument is an integer or a pool name
1896168404Spjd	 */
1897168404Spjd	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1898168404Spjd		char *end;
1899168404Spjd
1900168404Spjd		errno = 0;
1901168404Spjd		interval = strtoul(argv[argc - 1], &end, 10);
1902168404Spjd
1903168404Spjd		if (*end == '\0' && errno == 0) {
1904168404Spjd			if (interval == 0) {
1905168404Spjd				(void) fprintf(stderr, gettext("interval "
1906168404Spjd				    "cannot be zero\n"));
1907168404Spjd				usage(B_FALSE);
1908168404Spjd			}
1909168404Spjd
1910168404Spjd			/*
1911168404Spjd			 * Ignore the last parameter
1912168404Spjd			 */
1913168404Spjd			argc--;
1914168404Spjd		} else {
1915168404Spjd			/*
1916168404Spjd			 * If this is not a valid number, just plow on.  The
1917168404Spjd			 * user will get a more informative error message later
1918168404Spjd			 * on.
1919168404Spjd			 */
1920168404Spjd			interval = 0;
1921168404Spjd		}
1922168404Spjd	}
1923168404Spjd
1924168404Spjd	/*
1925168404Spjd	 * If the last argument is also an integer, then we have both a count
1926168404Spjd	 * and an integer.
1927168404Spjd	 */
1928168404Spjd	if (argc > 0 && isdigit(argv[argc - 1][0])) {
1929168404Spjd		char *end;
1930168404Spjd
1931168404Spjd		errno = 0;
1932168404Spjd		count = interval;
1933168404Spjd		interval = strtoul(argv[argc - 1], &end, 10);
1934168404Spjd
1935168404Spjd		if (*end == '\0' && errno == 0) {
1936168404Spjd			if (interval == 0) {
1937168404Spjd				(void) fprintf(stderr, gettext("interval "
1938168404Spjd				    "cannot be zero\n"));
1939168404Spjd				usage(B_FALSE);
1940168404Spjd			}
1941168404Spjd
1942168404Spjd			/*
1943168404Spjd			 * Ignore the last parameter
1944168404Spjd			 */
1945168404Spjd			argc--;
1946168404Spjd		} else {
1947168404Spjd			interval = 0;
1948168404Spjd		}
1949168404Spjd	}
1950168404Spjd
1951168404Spjd	/*
1952168404Spjd	 * Construct the list of all interesting pools.
1953168404Spjd	 */
1954168404Spjd	ret = 0;
1955168404Spjd	if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
1956168404Spjd		return (1);
1957168404Spjd
1958168404Spjd	if (pool_list_count(list) == 0 && argc != 0) {
1959168404Spjd		pool_list_free(list);
1960168404Spjd		return (1);
1961168404Spjd	}
1962168404Spjd
1963168404Spjd	if (pool_list_count(list) == 0 && interval == 0) {
1964168404Spjd		pool_list_free(list);
1965168404Spjd		(void) fprintf(stderr, gettext("no pools available\n"));
1966168404Spjd		return (1);
1967168404Spjd	}
1968168404Spjd
1969168404Spjd	/*
1970168404Spjd	 * Enter the main iostat loop.
1971168404Spjd	 */
1972168404Spjd	cb.cb_list = list;
1973168404Spjd	cb.cb_verbose = verbose;
1974168404Spjd	cb.cb_iteration = 0;
1975168404Spjd	cb.cb_namewidth = 0;
1976168404Spjd
1977168404Spjd	for (;;) {
1978168404Spjd		pool_list_update(list);
1979168404Spjd
1980168404Spjd		if ((npools = pool_list_count(list)) == 0)
1981168404Spjd			break;
1982168404Spjd
1983168404Spjd		/*
1984168404Spjd		 * Refresh all statistics.  This is done as an explicit step
1985168404Spjd		 * before calculating the maximum name width, so that any
1986168404Spjd		 * configuration changes are properly accounted for.
1987168404Spjd		 */
1988168404Spjd		(void) pool_list_iter(list, B_FALSE, refresh_iostat, &cb);
1989168404Spjd
1990168404Spjd		/*
1991168404Spjd		 * Iterate over all pools to determine the maximum width
1992168404Spjd		 * for the pool / device name column across all pools.
1993168404Spjd		 */
1994168404Spjd		cb.cb_namewidth = 0;
1995168404Spjd		(void) pool_list_iter(list, B_FALSE, get_namewidth, &cb);
1996168404Spjd
1997168404Spjd		/*
1998168404Spjd		 * If it's the first time, or verbose mode, print the header.
1999168404Spjd		 */
2000168404Spjd		if (++cb.cb_iteration == 1 || verbose)
2001168404Spjd			print_iostat_header(&cb);
2002168404Spjd
2003168404Spjd		(void) pool_list_iter(list, B_FALSE, print_iostat, &cb);
2004168404Spjd
2005168404Spjd		/*
2006168404Spjd		 * If there's more than one pool, and we're not in verbose mode
2007168404Spjd		 * (which prints a separator for us), then print a separator.
2008168404Spjd		 */
2009168404Spjd		if (npools > 1 && !verbose)
2010168404Spjd			print_iostat_separator(&cb);
2011168404Spjd
2012168404Spjd		if (verbose)
2013168404Spjd			(void) printf("\n");
2014168404Spjd
2015168404Spjd		/*
2016168404Spjd		 * Flush the output so that redirection to a file isn't buffered
2017168404Spjd		 * indefinitely.
2018168404Spjd		 */
2019168404Spjd		(void) fflush(stdout);
2020168404Spjd
2021168404Spjd		if (interval == 0)
2022168404Spjd			break;
2023168404Spjd
2024168404Spjd		if (count != 0 && --count == 0)
2025168404Spjd			break;
2026168404Spjd
2027168404Spjd		(void) sleep(interval);
2028168404Spjd	}
2029168404Spjd
2030168404Spjd	pool_list_free(list);
2031168404Spjd
2032168404Spjd	return (ret);
2033168404Spjd}
2034168404Spjd
2035168404Spjdtypedef struct list_cbdata {
2036168404Spjd	boolean_t	cb_scripted;
2037168404Spjd	boolean_t	cb_first;
2038185029Spjd	zprop_list_t	*cb_proplist;
2039168404Spjd} list_cbdata_t;
2040168404Spjd
2041168404Spjd/*
2042168404Spjd * Given a list of columns to display, output appropriate headers for each one.
2043168404Spjd */
2044185029Spjdstatic void
2045185029Spjdprint_header(zprop_list_t *pl)
2046168404Spjd{
2047185029Spjd	const char *header;
2048185029Spjd	boolean_t first = B_TRUE;
2049185029Spjd	boolean_t right_justify;
2050168404Spjd
2051185029Spjd	for (; pl != NULL; pl = pl->pl_next) {
2052185029Spjd		if (pl->pl_prop == ZPROP_INVAL)
2053185029Spjd			continue;
2054185029Spjd
2055185029Spjd		if (!first)
2056168404Spjd			(void) printf("  ");
2057168404Spjd		else
2058185029Spjd			first = B_FALSE;
2059168404Spjd
2060185029Spjd		header = zpool_prop_column_name(pl->pl_prop);
2061185029Spjd		right_justify = zpool_prop_align_right(pl->pl_prop);
2062185029Spjd
2063185029Spjd		if (pl->pl_next == NULL && !right_justify)
2064185029Spjd			(void) printf("%s", header);
2065185029Spjd		else if (right_justify)
2066185029Spjd			(void) printf("%*s", pl->pl_width, header);
2067185029Spjd		else
2068185029Spjd			(void) printf("%-*s", pl->pl_width, header);
2069168404Spjd	}
2070168404Spjd
2071168404Spjd	(void) printf("\n");
2072168404Spjd}
2073168404Spjd
2074185029Spjd/*
2075185029Spjd * Given a pool and a list of properties, print out all the properties according
2076185029Spjd * to the described layout.
2077185029Spjd */
2078185029Spjdstatic void
2079185029Spjdprint_pool(zpool_handle_t *zhp, zprop_list_t *pl, int scripted)
2080168404Spjd{
2081185029Spjd	boolean_t first = B_TRUE;
2082185029Spjd	char property[ZPOOL_MAXPROPLEN];
2083185029Spjd	char *propstr;
2084185029Spjd	boolean_t right_justify;
2085185029Spjd	int width;
2086168404Spjd
2087185029Spjd	for (; pl != NULL; pl = pl->pl_next) {
2088185029Spjd		if (!first) {
2089185029Spjd			if (scripted)
2090168404Spjd				(void) printf("\t");
2091168404Spjd			else
2092168404Spjd				(void) printf("  ");
2093185029Spjd		} else {
2094185029Spjd			first = B_FALSE;
2095168404Spjd		}
2096168404Spjd
2097185029Spjd		right_justify = B_FALSE;
2098185029Spjd		if (pl->pl_prop != ZPROP_INVAL) {
2099185029Spjd			if (zpool_get_prop(zhp, pl->pl_prop, property,
2100185029Spjd			    sizeof (property), NULL) != 0)
2101185029Spjd				propstr = "-";
2102168404Spjd			else
2103185029Spjd				propstr = property;
2104168404Spjd
2105185029Spjd			right_justify = zpool_prop_align_right(pl->pl_prop);
2106185029Spjd		} else {
2107185029Spjd			propstr = "-";
2108185029Spjd		}
2109168404Spjd
2110185029Spjd		width = pl->pl_width;
2111168404Spjd
2112185029Spjd		/*
2113185029Spjd		 * If this is being called in scripted mode, or if this is the
2114185029Spjd		 * last column and it is left-justified, don't include a width
2115185029Spjd		 * format specifier.
2116185029Spjd		 */
2117185029Spjd		if (scripted || (pl->pl_next == NULL && !right_justify))
2118185029Spjd			(void) printf("%s", propstr);
2119185029Spjd		else if (right_justify)
2120185029Spjd			(void) printf("%*s", width, propstr);
2121185029Spjd		else
2122185029Spjd			(void) printf("%-*s", width, propstr);
2123185029Spjd	}
2124168404Spjd
2125185029Spjd	(void) printf("\n");
2126185029Spjd}
2127168404Spjd
2128185029Spjd/*
2129185029Spjd * Generic callback function to list a pool.
2130185029Spjd */
2131185029Spjdint
2132185029Spjdlist_callback(zpool_handle_t *zhp, void *data)
2133185029Spjd{
2134185029Spjd	list_cbdata_t *cbp = data;
2135168404Spjd
2136185029Spjd	if (cbp->cb_first) {
2137185029Spjd		if (!cbp->cb_scripted)
2138185029Spjd			print_header(cbp->cb_proplist);
2139185029Spjd		cbp->cb_first = B_FALSE;
2140168404Spjd	}
2141168404Spjd
2142185029Spjd	print_pool(zhp, cbp->cb_proplist, cbp->cb_scripted);
2143168404Spjd
2144168404Spjd	return (0);
2145168404Spjd}
2146168404Spjd
2147168404Spjd/*
2148185029Spjd * zpool list [-H] [-o prop[,prop]*] [pool] ...
2149168404Spjd *
2150185029Spjd *	-H	Scripted mode.  Don't display headers, and separate properties
2151185029Spjd *		by a single tab.
2152185029Spjd *	-o	List of properties to display.  Defaults to
2153185029Spjd *		"name,size,used,available,capacity,health,altroot"
2154168404Spjd *
2155168404Spjd * List all pools in the system, whether or not they're healthy.  Output space
2156168404Spjd * statistics for each one, as well as health status summary.
2157168404Spjd */
2158168404Spjdint
2159168404Spjdzpool_do_list(int argc, char **argv)
2160168404Spjd{
2161168404Spjd	int c;
2162168404Spjd	int ret;
2163168404Spjd	list_cbdata_t cb = { 0 };
2164185029Spjd	static char default_props[] =
2165185029Spjd	    "name,size,used,available,capacity,health,altroot";
2166185029Spjd	char *props = default_props;
2167168404Spjd
2168168404Spjd	/* check options */
2169168404Spjd	while ((c = getopt(argc, argv, ":Ho:")) != -1) {
2170168404Spjd		switch (c) {
2171168404Spjd		case 'H':
2172168404Spjd			cb.cb_scripted = B_TRUE;
2173168404Spjd			break;
2174168404Spjd		case 'o':
2175185029Spjd			props = optarg;
2176168404Spjd			break;
2177168404Spjd		case ':':
2178168404Spjd			(void) fprintf(stderr, gettext("missing argument for "
2179168404Spjd			    "'%c' option\n"), optopt);
2180168404Spjd			usage(B_FALSE);
2181168404Spjd			break;
2182168404Spjd		case '?':
2183168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2184168404Spjd			    optopt);
2185168404Spjd			usage(B_FALSE);
2186168404Spjd		}
2187168404Spjd	}
2188168404Spjd
2189168404Spjd	argc -= optind;
2190168404Spjd	argv += optind;
2191168404Spjd
2192185029Spjd	if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
2193185029Spjd		usage(B_FALSE);
2194168404Spjd
2195185029Spjd	cb.cb_first = B_TRUE;
2196168404Spjd
2197185029Spjd	ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
2198185029Spjd	    list_callback, &cb);
2199168404Spjd
2200185029Spjd	zprop_free_list(cb.cb_proplist);
2201168404Spjd
2202185029Spjd	if (argc == 0 && cb.cb_first && !cb.cb_scripted) {
2203168404Spjd		(void) printf(gettext("no pools available\n"));
2204168404Spjd		return (0);
2205168404Spjd	}
2206168404Spjd
2207168404Spjd	return (ret);
2208168404Spjd}
2209168404Spjd
2210168404Spjdstatic nvlist_t *
2211168404Spjdzpool_get_vdev_by_name(nvlist_t *nv, char *name)
2212168404Spjd{
2213168404Spjd	nvlist_t **child;
2214168404Spjd	uint_t c, children;
2215168404Spjd	nvlist_t *match;
2216168404Spjd	char *path;
2217168404Spjd
2218168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2219168404Spjd	    &child, &children) != 0) {
2220168404Spjd		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2221168404Spjd		if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV)-1) == 0)
2222168404Spjd			name += sizeof(_PATH_DEV)-1;
2223168404Spjd		if (strncmp(path, _PATH_DEV, sizeof(_PATH_DEV)-1) == 0)
2224168404Spjd			path += sizeof(_PATH_DEV)-1;
2225168404Spjd		if (strcmp(name, path) == 0)
2226168404Spjd			return (nv);
2227168404Spjd		return (NULL);
2228168404Spjd	}
2229168404Spjd
2230168404Spjd	for (c = 0; c < children; c++)
2231168404Spjd		if ((match = zpool_get_vdev_by_name(child[c], name)) != NULL)
2232168404Spjd			return (match);
2233168404Spjd
2234168404Spjd	return (NULL);
2235168404Spjd}
2236168404Spjd
2237168404Spjdstatic int
2238168404Spjdzpool_do_attach_or_replace(int argc, char **argv, int replacing)
2239168404Spjd{
2240168404Spjd	boolean_t force = B_FALSE;
2241168404Spjd	int c;
2242168404Spjd	nvlist_t *nvroot;
2243168404Spjd	char *poolname, *old_disk, *new_disk;
2244168404Spjd	zpool_handle_t *zhp;
2245168404Spjd	int ret;
2246168404Spjd
2247168404Spjd	/* check options */
2248168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
2249168404Spjd		switch (c) {
2250168404Spjd		case 'f':
2251168404Spjd			force = B_TRUE;
2252168404Spjd			break;
2253168404Spjd		case '?':
2254168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2255168404Spjd			    optopt);
2256168404Spjd			usage(B_FALSE);
2257168404Spjd		}
2258168404Spjd	}
2259168404Spjd
2260168404Spjd	argc -= optind;
2261168404Spjd	argv += optind;
2262168404Spjd
2263168404Spjd	/* get pool name and check number of arguments */
2264168404Spjd	if (argc < 1) {
2265168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
2266168404Spjd		usage(B_FALSE);
2267168404Spjd	}
2268168404Spjd
2269168404Spjd	poolname = argv[0];
2270168404Spjd
2271168404Spjd	if (argc < 2) {
2272168404Spjd		(void) fprintf(stderr,
2273168404Spjd		    gettext("missing <device> specification\n"));
2274168404Spjd		usage(B_FALSE);
2275168404Spjd	}
2276168404Spjd
2277168404Spjd	old_disk = argv[1];
2278168404Spjd
2279168404Spjd	if (argc < 3) {
2280168404Spjd		if (!replacing) {
2281168404Spjd			(void) fprintf(stderr,
2282168404Spjd			    gettext("missing <new_device> specification\n"));
2283168404Spjd			usage(B_FALSE);
2284168404Spjd		}
2285168404Spjd		new_disk = old_disk;
2286168404Spjd		argc -= 1;
2287168404Spjd		argv += 1;
2288168404Spjd	} else {
2289168404Spjd		new_disk = argv[2];
2290168404Spjd		argc -= 2;
2291168404Spjd		argv += 2;
2292168404Spjd	}
2293168404Spjd
2294168404Spjd	if (argc > 1) {
2295168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
2296168404Spjd		usage(B_FALSE);
2297168404Spjd	}
2298168404Spjd
2299168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2300168404Spjd		return (1);
2301168404Spjd
2302185029Spjd	if (zpool_get_config(zhp, NULL) == NULL) {
2303168404Spjd		(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
2304168404Spjd		    poolname);
2305168404Spjd		zpool_close(zhp);
2306168404Spjd		return (1);
2307168404Spjd	}
2308168404Spjd
2309185029Spjd	nvroot = make_root_vdev(zhp, force, B_FALSE, replacing, B_FALSE,
2310185029Spjd	    argc, argv);
2311168404Spjd	if (nvroot == NULL) {
2312168404Spjd		zpool_close(zhp);
2313168404Spjd		return (1);
2314168404Spjd	}
2315168404Spjd
2316168404Spjd	ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
2317168404Spjd
2318168404Spjd	nvlist_free(nvroot);
2319168404Spjd	zpool_close(zhp);
2320168404Spjd
2321168404Spjd	return (ret);
2322168404Spjd}
2323168404Spjd
2324168404Spjd/*
2325168404Spjd * zpool replace [-f] <pool> <device> <new_device>
2326168404Spjd *
2327168404Spjd *	-f	Force attach, even if <new_device> appears to be in use.
2328168404Spjd *
2329168404Spjd * Replace <device> with <new_device>.
2330168404Spjd */
2331168404Spjd/* ARGSUSED */
2332168404Spjdint
2333168404Spjdzpool_do_replace(int argc, char **argv)
2334168404Spjd{
2335168404Spjd	return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
2336168404Spjd}
2337168404Spjd
2338168404Spjd/*
2339168404Spjd * zpool attach [-f] <pool> <device> <new_device>
2340168404Spjd *
2341168404Spjd *	-f	Force attach, even if <new_device> appears to be in use.
2342168404Spjd *
2343168404Spjd * Attach <new_device> to the mirror containing <device>.  If <device> is not
2344168404Spjd * part of a mirror, then <device> will be transformed into a mirror of
2345168404Spjd * <device> and <new_device>.  In either case, <new_device> will begin life
2346168404Spjd * with a DTL of [0, now], and will immediately begin to resilver itself.
2347168404Spjd */
2348168404Spjdint
2349168404Spjdzpool_do_attach(int argc, char **argv)
2350168404Spjd{
2351168404Spjd	return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
2352168404Spjd}
2353168404Spjd
2354168404Spjd/*
2355168404Spjd * zpool detach [-f] <pool> <device>
2356168404Spjd *
2357168404Spjd *	-f	Force detach of <device>, even if DTLs argue against it
2358168404Spjd *		(not supported yet)
2359168404Spjd *
2360168404Spjd * Detach a device from a mirror.  The operation will be refused if <device>
2361168404Spjd * is the last device in the mirror, or if the DTLs indicate that this device
2362168404Spjd * has the only valid copy of some data.
2363168404Spjd */
2364168404Spjd/* ARGSUSED */
2365168404Spjdint
2366168404Spjdzpool_do_detach(int argc, char **argv)
2367168404Spjd{
2368168404Spjd	int c;
2369168404Spjd	char *poolname, *path;
2370168404Spjd	zpool_handle_t *zhp;
2371168404Spjd	int ret;
2372168404Spjd
2373168404Spjd	/* check options */
2374168404Spjd	while ((c = getopt(argc, argv, "f")) != -1) {
2375168404Spjd		switch (c) {
2376168404Spjd		case 'f':
2377168404Spjd		case '?':
2378168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2379168404Spjd			    optopt);
2380168404Spjd			usage(B_FALSE);
2381168404Spjd		}
2382168404Spjd	}
2383168404Spjd
2384168404Spjd	argc -= optind;
2385168404Spjd	argv += optind;
2386168404Spjd
2387168404Spjd	/* get pool name and check number of arguments */
2388168404Spjd	if (argc < 1) {
2389168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
2390168404Spjd		usage(B_FALSE);
2391168404Spjd	}
2392168404Spjd
2393168404Spjd	if (argc < 2) {
2394168404Spjd		(void) fprintf(stderr,
2395168404Spjd		    gettext("missing <device> specification\n"));
2396168404Spjd		usage(B_FALSE);
2397168404Spjd	}
2398168404Spjd
2399168404Spjd	poolname = argv[0];
2400168404Spjd	path = argv[1];
2401168404Spjd
2402168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2403168404Spjd		return (1);
2404168404Spjd
2405168404Spjd	ret = zpool_vdev_detach(zhp, path);
2406168404Spjd
2407168404Spjd	zpool_close(zhp);
2408168404Spjd
2409168404Spjd	return (ret);
2410168404Spjd}
2411168404Spjd
2412168404Spjd/*
2413168404Spjd * zpool online <pool> <device> ...
2414168404Spjd */
2415168404Spjdint
2416168404Spjdzpool_do_online(int argc, char **argv)
2417168404Spjd{
2418168404Spjd	int c, i;
2419168404Spjd	char *poolname;
2420168404Spjd	zpool_handle_t *zhp;
2421168404Spjd	int ret = 0;
2422185029Spjd	vdev_state_t newstate;
2423168404Spjd
2424168404Spjd	/* check options */
2425168404Spjd	while ((c = getopt(argc, argv, "t")) != -1) {
2426168404Spjd		switch (c) {
2427168404Spjd		case 't':
2428168404Spjd		case '?':
2429168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2430168404Spjd			    optopt);
2431168404Spjd			usage(B_FALSE);
2432168404Spjd		}
2433168404Spjd	}
2434168404Spjd
2435168404Spjd	argc -= optind;
2436168404Spjd	argv += optind;
2437168404Spjd
2438168404Spjd	/* get pool name and check number of arguments */
2439168404Spjd	if (argc < 1) {
2440168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
2441168404Spjd		usage(B_FALSE);
2442168404Spjd	}
2443168404Spjd	if (argc < 2) {
2444168404Spjd		(void) fprintf(stderr, gettext("missing device name\n"));
2445168404Spjd		usage(B_FALSE);
2446168404Spjd	}
2447168404Spjd
2448168404Spjd	poolname = argv[0];
2449168404Spjd
2450168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2451168404Spjd		return (1);
2452168404Spjd
2453185029Spjd	for (i = 1; i < argc; i++) {
2454185029Spjd		if (zpool_vdev_online(zhp, argv[i], 0, &newstate) == 0) {
2455185029Spjd			if (newstate != VDEV_STATE_HEALTHY) {
2456185029Spjd				(void) printf(gettext("warning: device '%s' "
2457185029Spjd				    "onlined, but remains in faulted state\n"),
2458185029Spjd				    argv[i]);
2459185029Spjd				if (newstate == VDEV_STATE_FAULTED)
2460185029Spjd					(void) printf(gettext("use 'zpool "
2461185029Spjd					    "clear' to restore a faulted "
2462185029Spjd					    "device\n"));
2463185029Spjd				else
2464185029Spjd					(void) printf(gettext("use 'zpool "
2465185029Spjd					    "replace' to replace devices "
2466185029Spjd					    "that are no longer present\n"));
2467185029Spjd			}
2468185029Spjd		} else {
2469168404Spjd			ret = 1;
2470185029Spjd		}
2471185029Spjd	}
2472168404Spjd
2473168404Spjd	zpool_close(zhp);
2474168404Spjd
2475168404Spjd	return (ret);
2476168404Spjd}
2477168404Spjd
2478168404Spjd/*
2479168404Spjd * zpool offline [-ft] <pool> <device> ...
2480168404Spjd *
2481168404Spjd *	-f	Force the device into the offline state, even if doing
2482168404Spjd *		so would appear to compromise pool availability.
2483168404Spjd *		(not supported yet)
2484168404Spjd *
2485168404Spjd *	-t	Only take the device off-line temporarily.  The offline
2486168404Spjd *		state will not be persistent across reboots.
2487168404Spjd */
2488168404Spjd/* ARGSUSED */
2489168404Spjdint
2490168404Spjdzpool_do_offline(int argc, char **argv)
2491168404Spjd{
2492168404Spjd	int c, i;
2493168404Spjd	char *poolname;
2494168404Spjd	zpool_handle_t *zhp;
2495168404Spjd	int ret = 0;
2496168404Spjd	boolean_t istmp = B_FALSE;
2497168404Spjd
2498168404Spjd	/* check options */
2499168404Spjd	while ((c = getopt(argc, argv, "ft")) != -1) {
2500168404Spjd		switch (c) {
2501168404Spjd		case 't':
2502168404Spjd			istmp = B_TRUE;
2503168404Spjd			break;
2504168404Spjd		case 'f':
2505168404Spjd		case '?':
2506168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2507168404Spjd			    optopt);
2508168404Spjd			usage(B_FALSE);
2509168404Spjd		}
2510168404Spjd	}
2511168404Spjd
2512168404Spjd	argc -= optind;
2513168404Spjd	argv += optind;
2514168404Spjd
2515168404Spjd	/* get pool name and check number of arguments */
2516168404Spjd	if (argc < 1) {
2517168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
2518168404Spjd		usage(B_FALSE);
2519168404Spjd	}
2520168404Spjd	if (argc < 2) {
2521168404Spjd		(void) fprintf(stderr, gettext("missing device name\n"));
2522168404Spjd		usage(B_FALSE);
2523168404Spjd	}
2524168404Spjd
2525168404Spjd	poolname = argv[0];
2526168404Spjd
2527168404Spjd	if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
2528168404Spjd		return (1);
2529168404Spjd
2530185029Spjd	for (i = 1; i < argc; i++) {
2531185029Spjd		if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
2532168404Spjd			ret = 1;
2533185029Spjd	}
2534168404Spjd
2535168404Spjd	zpool_close(zhp);
2536168404Spjd
2537168404Spjd	return (ret);
2538168404Spjd}
2539168404Spjd
2540168404Spjd/*
2541168404Spjd * zpool clear <pool> [device]
2542168404Spjd *
2543168404Spjd * Clear all errors associated with a pool or a particular device.
2544168404Spjd */
2545168404Spjdint
2546168404Spjdzpool_do_clear(int argc, char **argv)
2547168404Spjd{
2548168404Spjd	int ret = 0;
2549168404Spjd	zpool_handle_t *zhp;
2550168404Spjd	char *pool, *device;
2551168404Spjd
2552168404Spjd	if (argc < 2) {
2553168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
2554168404Spjd		usage(B_FALSE);
2555168404Spjd	}
2556168404Spjd
2557168404Spjd	if (argc > 3) {
2558168404Spjd		(void) fprintf(stderr, gettext("too many arguments\n"));
2559168404Spjd		usage(B_FALSE);
2560168404Spjd	}
2561168404Spjd
2562168404Spjd	pool = argv[1];
2563168404Spjd	device = argc == 3 ? argv[2] : NULL;
2564168404Spjd
2565185029Spjd	if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
2566168404Spjd		return (1);
2567168404Spjd
2568168404Spjd	if (zpool_clear(zhp, device) != 0)
2569168404Spjd		ret = 1;
2570168404Spjd
2571168404Spjd	zpool_close(zhp);
2572168404Spjd
2573168404Spjd	return (ret);
2574168404Spjd}
2575168404Spjd
2576168404Spjdtypedef struct scrub_cbdata {
2577168404Spjd	int	cb_type;
2578168404Spjd	int	cb_argc;
2579168404Spjd	char	**cb_argv;
2580168404Spjd} scrub_cbdata_t;
2581168404Spjd
2582168404Spjdint
2583168404Spjdscrub_callback(zpool_handle_t *zhp, void *data)
2584168404Spjd{
2585168404Spjd	scrub_cbdata_t *cb = data;
2586168404Spjd	int err;
2587168404Spjd
2588168404Spjd	/*
2589168404Spjd	 * Ignore faulted pools.
2590168404Spjd	 */
2591168404Spjd	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
2592168404Spjd		(void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
2593168404Spjd		    "currently unavailable\n"), zpool_get_name(zhp));
2594168404Spjd		return (1);
2595168404Spjd	}
2596168404Spjd
2597168404Spjd	err = zpool_scrub(zhp, cb->cb_type);
2598168404Spjd
2599168404Spjd	return (err != 0);
2600168404Spjd}
2601168404Spjd
2602168404Spjd/*
2603168404Spjd * zpool scrub [-s] <pool> ...
2604168404Spjd *
2605168404Spjd *	-s	Stop.  Stops any in-progress scrub.
2606168404Spjd */
2607168404Spjdint
2608168404Spjdzpool_do_scrub(int argc, char **argv)
2609168404Spjd{
2610168404Spjd	int c;
2611168404Spjd	scrub_cbdata_t cb;
2612168404Spjd
2613168404Spjd	cb.cb_type = POOL_SCRUB_EVERYTHING;
2614168404Spjd
2615168404Spjd	/* check options */
2616168404Spjd	while ((c = getopt(argc, argv, "s")) != -1) {
2617168404Spjd		switch (c) {
2618168404Spjd		case 's':
2619168404Spjd			cb.cb_type = POOL_SCRUB_NONE;
2620168404Spjd			break;
2621168404Spjd		case '?':
2622168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
2623168404Spjd			    optopt);
2624168404Spjd			usage(B_FALSE);
2625168404Spjd		}
2626168404Spjd	}
2627168404Spjd
2628168404Spjd	cb.cb_argc = argc;
2629168404Spjd	cb.cb_argv = argv;
2630168404Spjd	argc -= optind;
2631168404Spjd	argv += optind;
2632168404Spjd
2633168404Spjd	if (argc < 1) {
2634168404Spjd		(void) fprintf(stderr, gettext("missing pool name argument\n"));
2635168404Spjd		usage(B_FALSE);
2636168404Spjd	}
2637168404Spjd
2638168404Spjd	return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
2639168404Spjd}
2640168404Spjd
2641168404Spjdtypedef struct status_cbdata {
2642168404Spjd	int		cb_count;
2643168404Spjd	boolean_t	cb_allpools;
2644168404Spjd	boolean_t	cb_verbose;
2645168404Spjd	boolean_t	cb_explain;
2646168404Spjd	boolean_t	cb_first;
2647168404Spjd} status_cbdata_t;
2648168404Spjd
2649168404Spjd/*
2650168404Spjd * Print out detailed scrub status.
2651168404Spjd */
2652168404Spjdvoid
2653168404Spjdprint_scrub_status(nvlist_t *nvroot)
2654168404Spjd{
2655168404Spjd	vdev_stat_t *vs;
2656168404Spjd	uint_t vsc;
2657168404Spjd	time_t start, end, now;
2658168404Spjd	double fraction_done;
2659185029Spjd	uint64_t examined, total, minutes_left, minutes_taken;
2660168404Spjd	char *scrub_type;
2661168404Spjd
2662168404Spjd	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
2663168404Spjd	    (uint64_t **)&vs, &vsc) == 0);
2664168404Spjd
2665168404Spjd	/*
2666168404Spjd	 * If there's never been a scrub, there's not much to say.
2667168404Spjd	 */
2668168404Spjd	if (vs->vs_scrub_end == 0 && vs->vs_scrub_type == POOL_SCRUB_NONE) {
2669168404Spjd		(void) printf(gettext("none requested\n"));
2670168404Spjd		return;
2671168404Spjd	}
2672168404Spjd
2673168404Spjd	scrub_type = (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2674168404Spjd	    "resilver" : "scrub";
2675168404Spjd
2676168404Spjd	start = vs->vs_scrub_start;
2677168404Spjd	end = vs->vs_scrub_end;
2678168404Spjd	now = time(NULL);
2679168404Spjd	examined = vs->vs_scrub_examined;
2680168404Spjd	total = vs->vs_alloc;
2681168404Spjd
2682168404Spjd	if (end != 0) {
2683185029Spjd		minutes_taken = (uint64_t)((end - start) / 60);
2684185029Spjd
2685185029Spjd		(void) printf(gettext("%s %s after %lluh%um with %llu errors "
2686185029Spjd		    "on %s"),
2687168404Spjd		    scrub_type, vs->vs_scrub_complete ? "completed" : "stopped",
2688185029Spjd		    (u_longlong_t)(minutes_taken / 60),
2689185029Spjd		    (uint_t)(minutes_taken % 60),
2690168404Spjd		    (u_longlong_t)vs->vs_scrub_errors, ctime(&end));
2691168404Spjd		return;
2692168404Spjd	}
2693168404Spjd
2694168404Spjd	if (examined == 0)
2695168404Spjd		examined = 1;
2696168404Spjd	if (examined > total)
2697168404Spjd		total = examined;
2698168404Spjd
2699168404Spjd	fraction_done = (double)examined / total;
2700168404Spjd	minutes_left = (uint64_t)((now - start) *
2701168404Spjd	    (1 - fraction_done) / fraction_done / 60);
2702185029Spjd	minutes_taken = (uint64_t)((now - start) / 60);
2703168404Spjd
2704185029Spjd	(void) printf(gettext("%s in progress for %lluh%um, %.2f%% done, "
2705185029Spjd	    "%lluh%um to go\n"),
2706185029Spjd	    scrub_type, (u_longlong_t)(minutes_taken / 60),
2707185029Spjd	    (uint_t)(minutes_taken % 60), 100 * fraction_done,
2708168404Spjd	    (u_longlong_t)(minutes_left / 60), (uint_t)(minutes_left % 60));
2709168404Spjd}
2710168404Spjd
2711168404Spjdtypedef struct spare_cbdata {
2712168404Spjd	uint64_t	cb_guid;
2713168404Spjd	zpool_handle_t	*cb_zhp;
2714168404Spjd} spare_cbdata_t;
2715168404Spjd
2716168404Spjdstatic boolean_t
2717168404Spjdfind_vdev(nvlist_t *nv, uint64_t search)
2718168404Spjd{
2719168404Spjd	uint64_t guid;
2720168404Spjd	nvlist_t **child;
2721168404Spjd	uint_t c, children;
2722168404Spjd
2723168404Spjd	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
2724168404Spjd	    search == guid)
2725168404Spjd		return (B_TRUE);
2726168404Spjd
2727168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2728168404Spjd	    &child, &children) == 0) {
2729168404Spjd		for (c = 0; c < children; c++)
2730168404Spjd			if (find_vdev(child[c], search))
2731168404Spjd				return (B_TRUE);
2732168404Spjd	}
2733168404Spjd
2734168404Spjd	return (B_FALSE);
2735168404Spjd}
2736168404Spjd
2737168404Spjdstatic int
2738168404Spjdfind_spare(zpool_handle_t *zhp, void *data)
2739168404Spjd{
2740168404Spjd	spare_cbdata_t *cbp = data;
2741168404Spjd	nvlist_t *config, *nvroot;
2742168404Spjd
2743168404Spjd	config = zpool_get_config(zhp, NULL);
2744168404Spjd	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2745168404Spjd	    &nvroot) == 0);
2746168404Spjd
2747168404Spjd	if (find_vdev(nvroot, cbp->cb_guid)) {
2748168404Spjd		cbp->cb_zhp = zhp;
2749168404Spjd		return (1);
2750168404Spjd	}
2751168404Spjd
2752168404Spjd	zpool_close(zhp);
2753168404Spjd	return (0);
2754168404Spjd}
2755168404Spjd
2756168404Spjd/*
2757168404Spjd * Print out configuration state as requested by status_callback.
2758168404Spjd */
2759168404Spjdvoid
2760168404Spjdprint_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
2761185029Spjd    int namewidth, int depth, boolean_t isspare, boolean_t print_logs)
2762168404Spjd{
2763168404Spjd	nvlist_t **child;
2764168404Spjd	uint_t c, children;
2765168404Spjd	vdev_stat_t *vs;
2766168404Spjd	char rbuf[6], wbuf[6], cbuf[6], repaired[7];
2767168404Spjd	char *vname;
2768168404Spjd	uint64_t notpresent;
2769168404Spjd	spare_cbdata_t cb;
2770185029Spjd	char *state;
2771168404Spjd
2772168404Spjd	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
2773168404Spjd	    (uint64_t **)&vs, &c) == 0);
2774168404Spjd
2775168404Spjd	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2776168404Spjd	    &child, &children) != 0)
2777168404Spjd		children = 0;
2778168404Spjd
2779185029Spjd	state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
2780168404Spjd	if (isspare) {
2781168404Spjd		/*
2782168404Spjd		 * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
2783168404Spjd		 * online drives.
2784168404Spjd		 */
2785168404Spjd		if (vs->vs_aux == VDEV_AUX_SPARED)
2786168404Spjd			state = "INUSE";
2787168404Spjd		else if (vs->vs_state == VDEV_STATE_HEALTHY)
2788168404Spjd			state = "AVAIL";
2789168404Spjd	}
2790168404Spjd
2791168404Spjd	(void) printf("\t%*s%-*s  %-8s", depth, "", namewidth - depth,
2792168404Spjd	    name, state);
2793168404Spjd
2794168404Spjd	if (!isspare) {
2795168404Spjd		zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
2796168404Spjd		zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
2797168404Spjd		zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
2798168404Spjd		(void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
2799168404Spjd	}
2800168404Spjd
2801168404Spjd	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2802168404Spjd	    &notpresent) == 0) {
2803168404Spjd		char *path;
2804168404Spjd		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
2805168404Spjd		(void) printf("  was %s", path);
2806168404Spjd	} else if (vs->vs_aux != 0) {
2807168404Spjd		(void) printf("  ");
2808168404Spjd
2809168404Spjd		switch (vs->vs_aux) {
2810168404Spjd		case VDEV_AUX_OPEN_FAILED:
2811168404Spjd			(void) printf(gettext("cannot open"));
2812168404Spjd			break;
2813168404Spjd
2814168404Spjd		case VDEV_AUX_BAD_GUID_SUM:
2815168404Spjd			(void) printf(gettext("missing device"));
2816168404Spjd			break;
2817168404Spjd
2818168404Spjd		case VDEV_AUX_NO_REPLICAS:
2819168404Spjd			(void) printf(gettext("insufficient replicas"));
2820168404Spjd			break;
2821168404Spjd
2822168404Spjd		case VDEV_AUX_VERSION_NEWER:
2823168404Spjd			(void) printf(gettext("newer version"));
2824168404Spjd			break;
2825168404Spjd
2826168404Spjd		case VDEV_AUX_SPARED:
2827168404Spjd			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
2828168404Spjd			    &cb.cb_guid) == 0);
2829168404Spjd			if (zpool_iter(g_zfs, find_spare, &cb) == 1) {
2830168404Spjd				if (strcmp(zpool_get_name(cb.cb_zhp),
2831168404Spjd				    zpool_get_name(zhp)) == 0)
2832168404Spjd					(void) printf(gettext("currently in "
2833168404Spjd					    "use"));
2834168404Spjd				else
2835168404Spjd					(void) printf(gettext("in use by "
2836168404Spjd					    "pool '%s'"),
2837168404Spjd					    zpool_get_name(cb.cb_zhp));
2838168404Spjd				zpool_close(cb.cb_zhp);
2839168404Spjd			} else {
2840168404Spjd				(void) printf(gettext("currently in use"));
2841168404Spjd			}
2842168404Spjd			break;
2843168404Spjd
2844185029Spjd		case VDEV_AUX_ERR_EXCEEDED:
2845185029Spjd			(void) printf(gettext("too many errors"));
2846185029Spjd			break;
2847185029Spjd
2848185029Spjd		case VDEV_AUX_IO_FAILURE:
2849185029Spjd			(void) printf(gettext("experienced I/O failures"));
2850185029Spjd			break;
2851185029Spjd
2852185029Spjd		case VDEV_AUX_BAD_LOG:
2853185029Spjd			(void) printf(gettext("bad intent log"));
2854185029Spjd			break;
2855185029Spjd
2856168404Spjd		default:
2857168404Spjd			(void) printf(gettext("corrupted data"));
2858168404Spjd			break;
2859168404Spjd		}
2860168404Spjd	} else if (vs->vs_scrub_repaired != 0 && children == 0) {
2861168404Spjd		/*
2862168404Spjd		 * Report bytes resilvered/repaired on leaf devices.
2863168404Spjd		 */
2864168404Spjd		zfs_nicenum(vs->vs_scrub_repaired, repaired, sizeof (repaired));
2865168404Spjd		(void) printf(gettext("  %s %s"), repaired,
2866168404Spjd		    (vs->vs_scrub_type == POOL_SCRUB_RESILVER) ?
2867168404Spjd		    "resilvered" : "repaired");
2868168404Spjd	}
2869168404Spjd
2870168404Spjd	(void) printf("\n");
2871168404Spjd
2872168404Spjd	for (c = 0; c < children; c++) {
2873185029Spjd		uint64_t is_log = B_FALSE;
2874185029Spjd
2875185029Spjd		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
2876185029Spjd		    &is_log);
2877185029Spjd		if ((is_log && !print_logs) || (!is_log && print_logs))
2878185029Spjd			continue;
2879168404Spjd		vname = zpool_vdev_name(g_zfs, zhp, child[c]);
2880168404Spjd		print_status_config(zhp, vname, child[c],
2881185029Spjd		    namewidth, depth + 2, isspare, B_FALSE);
2882168404Spjd		free(vname);
2883168404Spjd	}
2884168404Spjd}
2885168404Spjd
2886168404Spjdstatic void
2887168404Spjdprint_error_log(zpool_handle_t *zhp)
2888168404Spjd{
2889185029Spjd	nvlist_t *nverrlist = NULL;
2890168404Spjd	nvpair_t *elem;
2891168404Spjd	char *pathname;
2892168404Spjd	size_t len = MAXPATHLEN * 2;
2893168404Spjd
2894168404Spjd	if (zpool_get_errlog(zhp, &nverrlist) != 0) {
2895168404Spjd		(void) printf("errors: List of errors unavailable "
2896168404Spjd		    "(insufficient privileges)\n");
2897168404Spjd		return;
2898168404Spjd	}
2899168404Spjd
2900168404Spjd	(void) printf("errors: Permanent errors have been "
2901168404Spjd	    "detected in the following files:\n\n");
2902168404Spjd
2903168404Spjd	pathname = safe_malloc(len);
2904168404Spjd	elem = NULL;
2905168404Spjd	while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
2906168404Spjd		nvlist_t *nv;
2907168404Spjd		uint64_t dsobj, obj;
2908168404Spjd
2909168404Spjd		verify(nvpair_value_nvlist(elem, &nv) == 0);
2910168404Spjd		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
2911168404Spjd		    &dsobj) == 0);
2912168404Spjd		verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
2913168404Spjd		    &obj) == 0);
2914168404Spjd		zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
2915168404Spjd		(void) printf("%7s %s\n", "", pathname);
2916168404Spjd	}
2917168404Spjd	free(pathname);
2918168404Spjd	nvlist_free(nverrlist);
2919168404Spjd}
2920168404Spjd
2921168404Spjdstatic void
2922168404Spjdprint_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
2923168404Spjd    int namewidth)
2924168404Spjd{
2925168404Spjd	uint_t i;
2926168404Spjd	char *name;
2927168404Spjd
2928168404Spjd	if (nspares == 0)
2929168404Spjd		return;
2930168404Spjd
2931168404Spjd	(void) printf(gettext("\tspares\n"));
2932168404Spjd
2933168404Spjd	for (i = 0; i < nspares; i++) {
2934168404Spjd		name = zpool_vdev_name(g_zfs, zhp, spares[i]);
2935168404Spjd		print_status_config(zhp, name, spares[i],
2936185029Spjd		    namewidth, 2, B_TRUE, B_FALSE);
2937168404Spjd		free(name);
2938168404Spjd	}
2939168404Spjd}
2940168404Spjd
2941185029Spjdstatic void
2942185029Spjdprint_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
2943185029Spjd    int namewidth)
2944185029Spjd{
2945185029Spjd	uint_t i;
2946185029Spjd	char *name;
2947185029Spjd
2948185029Spjd	if (nl2cache == 0)
2949185029Spjd		return;
2950185029Spjd
2951185029Spjd	(void) printf(gettext("\tcache\n"));
2952185029Spjd
2953185029Spjd	for (i = 0; i < nl2cache; i++) {
2954185029Spjd		name = zpool_vdev_name(g_zfs, zhp, l2cache[i]);
2955185029Spjd		print_status_config(zhp, name, l2cache[i],
2956185029Spjd		    namewidth, 2, B_FALSE, B_FALSE);
2957185029Spjd		free(name);
2958185029Spjd	}
2959185029Spjd}
2960185029Spjd
2961168404Spjd/*
2962168404Spjd * Display a summary of pool status.  Displays a summary such as:
2963168404Spjd *
2964168404Spjd *        pool: tank
2965168404Spjd *	status: DEGRADED
2966168404Spjd *	reason: One or more devices ...
2967168404Spjd *         see: http://www.sun.com/msg/ZFS-xxxx-01
2968168404Spjd *	config:
2969168404Spjd *		mirror		DEGRADED
2970168404Spjd *                c1t0d0	OK
2971168404Spjd *                c2t0d0	UNAVAIL
2972168404Spjd *
2973168404Spjd * When given the '-v' option, we print out the complete config.  If the '-e'
2974168404Spjd * option is specified, then we print out error rate information as well.
2975168404Spjd */
2976168404Spjdint
2977168404Spjdstatus_callback(zpool_handle_t *zhp, void *data)
2978168404Spjd{
2979168404Spjd	status_cbdata_t *cbp = data;
2980168404Spjd	nvlist_t *config, *nvroot;
2981168404Spjd	char *msgid;
2982168404Spjd	int reason;
2983168404Spjd	const char *health;
2984168404Spjd	uint_t c;
2985168404Spjd	vdev_stat_t *vs;
2986168404Spjd
2987168404Spjd	config = zpool_get_config(zhp, NULL);
2988168404Spjd	reason = zpool_get_status(zhp, &msgid);
2989168404Spjd
2990168404Spjd	cbp->cb_count++;
2991168404Spjd
2992168404Spjd	/*
2993168404Spjd	 * If we were given 'zpool status -x', only report those pools with
2994168404Spjd	 * problems.
2995168404Spjd	 */
2996168404Spjd	if (reason == ZPOOL_STATUS_OK && cbp->cb_explain) {
2997168404Spjd		if (!cbp->cb_allpools) {
2998168404Spjd			(void) printf(gettext("pool '%s' is healthy\n"),
2999168404Spjd			    zpool_get_name(zhp));
3000168404Spjd			if (cbp->cb_first)
3001168404Spjd				cbp->cb_first = B_FALSE;
3002168404Spjd		}
3003168404Spjd		return (0);
3004168404Spjd	}
3005168404Spjd
3006168404Spjd	if (cbp->cb_first)
3007168404Spjd		cbp->cb_first = B_FALSE;
3008168404Spjd	else
3009168404Spjd		(void) printf("\n");
3010168404Spjd
3011168404Spjd	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
3012168404Spjd	    &nvroot) == 0);
3013168404Spjd	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
3014168404Spjd	    (uint64_t **)&vs, &c) == 0);
3015185029Spjd	health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
3016168404Spjd
3017168404Spjd	(void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
3018168404Spjd	(void) printf(gettext(" state: %s\n"), health);
3019168404Spjd
3020168404Spjd	switch (reason) {
3021168404Spjd	case ZPOOL_STATUS_MISSING_DEV_R:
3022168404Spjd		(void) printf(gettext("status: One or more devices could not "
3023168404Spjd		    "be opened.  Sufficient replicas exist for\n\tthe pool to "
3024168404Spjd		    "continue functioning in a degraded state.\n"));
3025168404Spjd		(void) printf(gettext("action: Attach the missing device and "
3026168404Spjd		    "online it using 'zpool online'.\n"));
3027168404Spjd		break;
3028168404Spjd
3029168404Spjd	case ZPOOL_STATUS_MISSING_DEV_NR:
3030168404Spjd		(void) printf(gettext("status: One or more devices could not "
3031168404Spjd		    "be opened.  There are insufficient\n\treplicas for the "
3032168404Spjd		    "pool to continue functioning.\n"));
3033168404Spjd		(void) printf(gettext("action: Attach the missing device and "
3034168404Spjd		    "online it using 'zpool online'.\n"));
3035168404Spjd		break;
3036168404Spjd
3037168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_R:
3038168404Spjd		(void) printf(gettext("status: One or more devices could not "
3039168404Spjd		    "be used because the label is missing or\n\tinvalid.  "
3040168404Spjd		    "Sufficient replicas exist for the pool to continue\n\t"
3041168404Spjd		    "functioning in a degraded state.\n"));
3042168404Spjd		(void) printf(gettext("action: Replace the device using "
3043168404Spjd		    "'zpool replace'.\n"));
3044168404Spjd		break;
3045168404Spjd
3046168404Spjd	case ZPOOL_STATUS_CORRUPT_LABEL_NR:
3047168404Spjd		(void) printf(gettext("status: One or more devices could not "
3048168404Spjd		    "be used because the label is missing \n\tor invalid.  "
3049168404Spjd		    "There are insufficient replicas for the pool to "
3050168404Spjd		    "continue\n\tfunctioning.\n"));
3051168404Spjd		(void) printf(gettext("action: Destroy and re-create the pool "
3052168404Spjd		    "from a backup source.\n"));
3053168404Spjd		break;
3054168404Spjd
3055168404Spjd	case ZPOOL_STATUS_FAILING_DEV:
3056168404Spjd		(void) printf(gettext("status: One or more devices has "
3057168404Spjd		    "experienced an unrecoverable error.  An\n\tattempt was "
3058168404Spjd		    "made to correct the error.  Applications are "
3059168404Spjd		    "unaffected.\n"));
3060168404Spjd		(void) printf(gettext("action: Determine if the device needs "
3061168404Spjd		    "to be replaced, and clear the errors\n\tusing "
3062168404Spjd		    "'zpool clear' or replace the device with 'zpool "
3063168404Spjd		    "replace'.\n"));
3064168404Spjd		break;
3065168404Spjd
3066168404Spjd	case ZPOOL_STATUS_OFFLINE_DEV:
3067168404Spjd		(void) printf(gettext("status: One or more devices has "
3068168404Spjd		    "been taken offline by the administrator.\n\tSufficient "
3069168404Spjd		    "replicas exist for the pool to continue functioning in "
3070168404Spjd		    "a\n\tdegraded state.\n"));
3071168404Spjd		(void) printf(gettext("action: Online the device using "
3072168404Spjd		    "'zpool online' or replace the device with\n\t'zpool "
3073168404Spjd		    "replace'.\n"));
3074168404Spjd		break;
3075168404Spjd
3076168404Spjd	case ZPOOL_STATUS_RESILVERING:
3077168404Spjd		(void) printf(gettext("status: One or more devices is "
3078168404Spjd		    "currently being resilvered.  The pool will\n\tcontinue "
3079168404Spjd		    "to function, possibly in a degraded state.\n"));
3080168404Spjd		(void) printf(gettext("action: Wait for the resilver to "
3081168404Spjd		    "complete.\n"));
3082168404Spjd		break;
3083168404Spjd
3084168404Spjd	case ZPOOL_STATUS_CORRUPT_DATA:
3085168404Spjd		(void) printf(gettext("status: One or more devices has "
3086168404Spjd		    "experienced an error resulting in data\n\tcorruption.  "
3087168404Spjd		    "Applications may be affected.\n"));
3088168404Spjd		(void) printf(gettext("action: Restore the file in question "
3089168404Spjd		    "if possible.  Otherwise restore the\n\tentire pool from "
3090168404Spjd		    "backup.\n"));
3091168404Spjd		break;
3092168404Spjd
3093168404Spjd	case ZPOOL_STATUS_CORRUPT_POOL:
3094168404Spjd		(void) printf(gettext("status: The pool metadata is corrupted "
3095168404Spjd		    "and the pool cannot be opened.\n"));
3096168404Spjd		(void) printf(gettext("action: Destroy and re-create the pool "
3097168404Spjd		    "from a backup source.\n"));
3098168404Spjd		break;
3099168404Spjd
3100168404Spjd	case ZPOOL_STATUS_VERSION_OLDER:
3101168404Spjd		(void) printf(gettext("status: The pool is formatted using an "
3102168404Spjd		    "older on-disk format.  The pool can\n\tstill be used, but "
3103168404Spjd		    "some features are unavailable.\n"));
3104168404Spjd		(void) printf(gettext("action: Upgrade the pool using 'zpool "
3105168404Spjd		    "upgrade'.  Once this is done, the\n\tpool will no longer "
3106168404Spjd		    "be accessible on older software versions.\n"));
3107168404Spjd		break;
3108168404Spjd
3109168404Spjd	case ZPOOL_STATUS_VERSION_NEWER:
3110168404Spjd		(void) printf(gettext("status: The pool has been upgraded to a "
3111168404Spjd		    "newer, incompatible on-disk version.\n\tThe pool cannot "
3112168404Spjd		    "be accessed on this system.\n"));
3113168404Spjd		(void) printf(gettext("action: Access the pool from a system "
3114168404Spjd		    "running more recent software, or\n\trestore the pool from "
3115168404Spjd		    "backup.\n"));
3116168404Spjd		break;
3117168404Spjd
3118185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_R:
3119185029Spjd		(void) printf(gettext("status: One or more devices are "
3120185029Spjd		    "faulted in response to persistent errors.\n\tSufficient "
3121185029Spjd		    "replicas exist for the pool to continue functioning "
3122185029Spjd		    "in a\n\tdegraded state.\n"));
3123185029Spjd		(void) printf(gettext("action: Replace the faulted device, "
3124185029Spjd		    "or use 'zpool clear' to mark the device\n\trepaired.\n"));
3125185029Spjd		break;
3126185029Spjd
3127185029Spjd	case ZPOOL_STATUS_FAULTED_DEV_NR:
3128185029Spjd		(void) printf(gettext("status: One or more devices are "
3129185029Spjd		    "faulted in response to persistent errors.  There are "
3130185029Spjd		    "insufficient replicas for the pool to\n\tcontinue "
3131185029Spjd		    "functioning.\n"));
3132185029Spjd		(void) printf(gettext("action: Destroy and re-create the pool "
3133185029Spjd		    "from a backup source.  Manually marking the device\n"
3134185029Spjd		    "\trepaired using 'zpool clear' may allow some data "
3135185029Spjd		    "to be recovered.\n"));
3136185029Spjd		break;
3137185029Spjd
3138185029Spjd	case ZPOOL_STATUS_IO_FAILURE_WAIT:
3139185029Spjd	case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
3140185029Spjd		(void) printf(gettext("status: One or more devices are "
3141185029Spjd		    "faulted in response to IO failures.\n"));
3142185029Spjd		(void) printf(gettext("action: Make sure the affected devices "
3143185029Spjd		    "are connected, then run 'zpool clear'.\n"));
3144185029Spjd		break;
3145185029Spjd
3146185029Spjd	case ZPOOL_STATUS_BAD_LOG:
3147185029Spjd		(void) printf(gettext("status: An intent log record "
3148185029Spjd		    "could not be read.\n"
3149185029Spjd		    "\tWaiting for adminstrator intervention to fix the "
3150185029Spjd		    "faulted pool.\n"));
3151185029Spjd		(void) printf(gettext("action: Either restore the affected "
3152185029Spjd		    "device(s) and run 'zpool online',\n"
3153185029Spjd		    "\tor ignore the intent log records by running "
3154185029Spjd		    "'zpool clear'.\n"));
3155185029Spjd		break;
3156185029Spjd
3157168404Spjd	default:
3158168404Spjd		/*
3159168404Spjd		 * The remaining errors can't actually be generated, yet.
3160168404Spjd		 */
3161168404Spjd		assert(reason == ZPOOL_STATUS_OK);
3162168404Spjd	}
3163168404Spjd
3164168404Spjd	if (msgid != NULL)
3165168404Spjd		(void) printf(gettext("   see: http://www.sun.com/msg/%s\n"),
3166168404Spjd		    msgid);
3167168404Spjd
3168168404Spjd	if (config != NULL) {
3169168404Spjd		int namewidth;
3170168404Spjd		uint64_t nerr;
3171185029Spjd		nvlist_t **spares, **l2cache;
3172185029Spjd		uint_t nspares, nl2cache;
3173168404Spjd
3174168404Spjd
3175168404Spjd		(void) printf(gettext(" scrub: "));
3176168404Spjd		print_scrub_status(nvroot);
3177168404Spjd
3178168404Spjd		namewidth = max_width(zhp, nvroot, 0, 0);
3179168404Spjd		if (namewidth < 10)
3180168404Spjd			namewidth = 10;
3181168404Spjd
3182168404Spjd		(void) printf(gettext("config:\n\n"));
3183168404Spjd		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
3184168404Spjd		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
3185168404Spjd		print_status_config(zhp, zpool_get_name(zhp), nvroot,
3186185029Spjd		    namewidth, 0, B_FALSE, B_FALSE);
3187185029Spjd		if (num_logs(nvroot) > 0)
3188185029Spjd			print_status_config(zhp, "logs", nvroot, namewidth, 0,
3189185029Spjd			    B_FALSE, B_TRUE);
3190168404Spjd
3191185029Spjd		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
3192185029Spjd		    &l2cache, &nl2cache) == 0)
3193185029Spjd			print_l2cache(zhp, l2cache, nl2cache, namewidth);
3194185029Spjd
3195168404Spjd		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
3196168404Spjd		    &spares, &nspares) == 0)
3197168404Spjd			print_spares(zhp, spares, nspares, namewidth);
3198168404Spjd
3199168404Spjd		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
3200168404Spjd		    &nerr) == 0) {
3201168404Spjd			nvlist_t *nverrlist = NULL;
3202168404Spjd
3203168404Spjd			/*
3204168404Spjd			 * If the approximate error count is small, get a
3205168404Spjd			 * precise count by fetching the entire log and
3206168404Spjd			 * uniquifying the results.
3207168404Spjd			 */
3208185029Spjd			if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
3209168404Spjd			    zpool_get_errlog(zhp, &nverrlist) == 0) {
3210168404Spjd				nvpair_t *elem;
3211168404Spjd
3212168404Spjd				elem = NULL;
3213168404Spjd				nerr = 0;
3214168404Spjd				while ((elem = nvlist_next_nvpair(nverrlist,
3215168404Spjd				    elem)) != NULL) {
3216168404Spjd					nerr++;
3217168404Spjd				}
3218168404Spjd			}
3219168404Spjd			nvlist_free(nverrlist);
3220168404Spjd
3221168404Spjd			(void) printf("\n");
3222168404Spjd
3223168404Spjd			if (nerr == 0)
3224168404Spjd				(void) printf(gettext("errors: No known data "
3225168404Spjd				    "errors\n"));
3226168404Spjd			else if (!cbp->cb_verbose)
3227168404Spjd				(void) printf(gettext("errors: %llu data "
3228168404Spjd				    "errors, use '-v' for a list\n"),
3229168404Spjd				    (u_longlong_t)nerr);
3230168404Spjd			else
3231168404Spjd				print_error_log(zhp);
3232168404Spjd		}
3233168404Spjd	} else {
3234168404Spjd		(void) printf(gettext("config: The configuration cannot be "
3235168404Spjd		    "determined.\n"));
3236168404Spjd	}
3237168404Spjd
3238168404Spjd	return (0);
3239168404Spjd}
3240168404Spjd
3241168404Spjd/*
3242168404Spjd * zpool status [-vx] [pool] ...
3243168404Spjd *
3244168404Spjd *	-v	Display complete error logs
3245168404Spjd *	-x	Display only pools with potential problems
3246168404Spjd *
3247168404Spjd * Describes the health status of all pools or some subset.
3248168404Spjd */
3249168404Spjdint
3250168404Spjdzpool_do_status(int argc, char **argv)
3251168404Spjd{
3252168404Spjd	int c;
3253168404Spjd	int ret;
3254168404Spjd	status_cbdata_t cb = { 0 };
3255168404Spjd
3256168404Spjd	/* check options */
3257168404Spjd	while ((c = getopt(argc, argv, "vx")) != -1) {
3258168404Spjd		switch (c) {
3259168404Spjd		case 'v':
3260168404Spjd			cb.cb_verbose = B_TRUE;
3261168404Spjd			break;
3262168404Spjd		case 'x':
3263168404Spjd			cb.cb_explain = B_TRUE;
3264168404Spjd			break;
3265168404Spjd		case '?':
3266168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3267168404Spjd			    optopt);
3268168404Spjd			usage(B_FALSE);
3269168404Spjd		}
3270168404Spjd	}
3271168404Spjd
3272168404Spjd	argc -= optind;
3273168404Spjd	argv += optind;
3274168404Spjd
3275168404Spjd	cb.cb_first = B_TRUE;
3276168404Spjd
3277168404Spjd	if (argc == 0)
3278168404Spjd		cb.cb_allpools = B_TRUE;
3279168404Spjd
3280168404Spjd	ret = for_each_pool(argc, argv, B_TRUE, NULL, status_callback, &cb);
3281168404Spjd
3282168404Spjd	if (argc == 0 && cb.cb_count == 0)
3283168404Spjd		(void) printf(gettext("no pools available\n"));
3284168404Spjd	else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
3285168404Spjd		(void) printf(gettext("all pools are healthy\n"));
3286168404Spjd
3287168404Spjd	return (ret);
3288168404Spjd}
3289168404Spjd
3290168404Spjdtypedef struct upgrade_cbdata {
3291168404Spjd	int	cb_all;
3292168404Spjd	int	cb_first;
3293168404Spjd	int	cb_newer;
3294168404Spjd	int	cb_argc;
3295185029Spjd	uint64_t cb_version;
3296168404Spjd	char	**cb_argv;
3297168404Spjd} upgrade_cbdata_t;
3298168404Spjd
3299168404Spjdstatic int
3300168404Spjdupgrade_cb(zpool_handle_t *zhp, void *arg)
3301168404Spjd{
3302168404Spjd	upgrade_cbdata_t *cbp = arg;
3303168404Spjd	nvlist_t *config;
3304168404Spjd	uint64_t version;
3305168404Spjd	int ret = 0;
3306168404Spjd
3307168404Spjd	config = zpool_get_config(zhp, NULL);
3308168404Spjd	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
3309168404Spjd	    &version) == 0);
3310168404Spjd
3311185029Spjd	if (!cbp->cb_newer && version < SPA_VERSION) {
3312168404Spjd		if (!cbp->cb_all) {
3313168404Spjd			if (cbp->cb_first) {
3314168404Spjd				(void) printf(gettext("The following pools are "
3315168404Spjd				    "out of date, and can be upgraded.  After "
3316168404Spjd				    "being\nupgraded, these pools will no "
3317168404Spjd				    "longer be accessible by older software "
3318168404Spjd				    "versions.\n\n"));
3319168404Spjd				(void) printf(gettext("VER  POOL\n"));
3320168404Spjd				(void) printf(gettext("---  ------------\n"));
3321168404Spjd				cbp->cb_first = B_FALSE;
3322168404Spjd			}
3323168404Spjd
3324168404Spjd			(void) printf("%2llu   %s\n", (u_longlong_t)version,
3325168404Spjd			    zpool_get_name(zhp));
3326168404Spjd		} else {
3327168404Spjd			cbp->cb_first = B_FALSE;
3328185029Spjd			ret = zpool_upgrade(zhp, cbp->cb_version);
3329168404Spjd			if (!ret) {
3330168404Spjd				(void) printf(gettext("Successfully upgraded "
3331185029Spjd				    "'%s'\n\n"), zpool_get_name(zhp));
3332168404Spjd			}
3333168404Spjd		}
3334185029Spjd	} else if (cbp->cb_newer && version > SPA_VERSION) {
3335168404Spjd		assert(!cbp->cb_all);
3336168404Spjd
3337168404Spjd		if (cbp->cb_first) {
3338168404Spjd			(void) printf(gettext("The following pools are "
3339168404Spjd			    "formatted using a newer software version and\n"
3340168404Spjd			    "cannot be accessed on the current system.\n\n"));
3341168404Spjd			(void) printf(gettext("VER  POOL\n"));
3342168404Spjd			(void) printf(gettext("---  ------------\n"));
3343168404Spjd			cbp->cb_first = B_FALSE;
3344168404Spjd		}
3345168404Spjd
3346168404Spjd		(void) printf("%2llu   %s\n", (u_longlong_t)version,
3347168404Spjd		    zpool_get_name(zhp));
3348168404Spjd	}
3349168404Spjd
3350168404Spjd	zpool_close(zhp);
3351168404Spjd	return (ret);
3352168404Spjd}
3353168404Spjd
3354168404Spjd/* ARGSUSED */
3355168404Spjdstatic int
3356168404Spjdupgrade_one(zpool_handle_t *zhp, void *data)
3357168404Spjd{
3358185029Spjd	upgrade_cbdata_t *cbp = data;
3359185029Spjd	uint64_t cur_version;
3360168404Spjd	int ret;
3361168404Spjd
3362185029Spjd	if (strcmp("log", zpool_get_name(zhp)) == 0) {
3363185029Spjd		(void) printf(gettext("'log' is now a reserved word\n"
3364185029Spjd		    "Pool 'log' must be renamed using export and import"
3365185029Spjd		    " to upgrade.\n"));
3366185029Spjd		return (1);
3367185029Spjd	}
3368168404Spjd
3369185029Spjd	cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
3370185029Spjd	if (cur_version > cbp->cb_version) {
3371168404Spjd		(void) printf(gettext("Pool '%s' is already formatted "
3372185029Spjd		    "using more current version '%llu'.\n"),
3373185029Spjd		    zpool_get_name(zhp), cur_version);
3374185029Spjd		return (0);
3375185029Spjd	}
3376185029Spjd	if (cur_version == cbp->cb_version) {
3377185029Spjd		(void) printf(gettext("Pool '%s' is already formatted "
3378168404Spjd		    "using the current version.\n"), zpool_get_name(zhp));
3379168404Spjd		return (0);
3380168404Spjd	}
3381168404Spjd
3382185029Spjd	ret = zpool_upgrade(zhp, cbp->cb_version);
3383168404Spjd
3384168404Spjd	if (!ret) {
3385168404Spjd		(void) printf(gettext("Successfully upgraded '%s' "
3386185029Spjd		    "from version %llu to version %llu\n\n"),
3387185029Spjd		    zpool_get_name(zhp), (u_longlong_t)cur_version,
3388185029Spjd		    (u_longlong_t)cbp->cb_version);
3389168404Spjd	}
3390168404Spjd
3391168404Spjd	return (ret != 0);
3392168404Spjd}
3393168404Spjd
3394168404Spjd/*
3395168404Spjd * zpool upgrade
3396168404Spjd * zpool upgrade -v
3397185029Spjd * zpool upgrade [-V version] <-a | pool ...>
3398168404Spjd *
3399168404Spjd * With no arguments, display downrev'd ZFS pool available for upgrade.
3400168404Spjd * Individual pools can be upgraded by specifying the pool, and '-a' will
3401168404Spjd * upgrade all pools.
3402168404Spjd */
3403168404Spjdint
3404168404Spjdzpool_do_upgrade(int argc, char **argv)
3405168404Spjd{
3406168404Spjd	int c;
3407168404Spjd	upgrade_cbdata_t cb = { 0 };
3408168404Spjd	int ret = 0;
3409168404Spjd	boolean_t showversions = B_FALSE;
3410185029Spjd	char *end;
3411168404Spjd
3412185029Spjd
3413168404Spjd	/* check options */
3414185029Spjd	while ((c = getopt(argc, argv, "avV:")) != -1) {
3415168404Spjd		switch (c) {
3416168404Spjd		case 'a':
3417168404Spjd			cb.cb_all = B_TRUE;
3418168404Spjd			break;
3419168404Spjd		case 'v':
3420168404Spjd			showversions = B_TRUE;
3421168404Spjd			break;
3422185029Spjd		case 'V':
3423185029Spjd			cb.cb_version = strtoll(optarg, &end, 10);
3424185029Spjd			if (*end != '\0' || cb.cb_version > SPA_VERSION ||
3425185029Spjd			    cb.cb_version < SPA_VERSION_1) {
3426185029Spjd				(void) fprintf(stderr,
3427185029Spjd				    gettext("invalid version '%s'\n"), optarg);
3428185029Spjd				usage(B_FALSE);
3429185029Spjd			}
3430185029Spjd			break;
3431168404Spjd		case '?':
3432168404Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3433168404Spjd			    optopt);
3434168404Spjd			usage(B_FALSE);
3435168404Spjd		}
3436168404Spjd	}
3437168404Spjd
3438168404Spjd	cb.cb_argc = argc;
3439168404Spjd	cb.cb_argv = argv;
3440168404Spjd	argc -= optind;
3441168404Spjd	argv += optind;
3442168404Spjd
3443185029Spjd	if (cb.cb_version == 0) {
3444185029Spjd		cb.cb_version = SPA_VERSION;
3445185029Spjd	} else if (!cb.cb_all && argc == 0) {
3446185029Spjd		(void) fprintf(stderr, gettext("-V option is "
3447185029Spjd		    "incompatible with other arguments\n"));
3448185029Spjd		usage(B_FALSE);
3449185029Spjd	}
3450185029Spjd
3451168404Spjd	if (showversions) {
3452168404Spjd		if (cb.cb_all || argc != 0) {
3453168404Spjd			(void) fprintf(stderr, gettext("-v option is "
3454168404Spjd			    "incompatible with other arguments\n"));
3455168404Spjd			usage(B_FALSE);
3456168404Spjd		}
3457168404Spjd	} else if (cb.cb_all) {
3458168404Spjd		if (argc != 0) {
3459185029Spjd			(void) fprintf(stderr, gettext("-a option should not "
3460185029Spjd			    "be used along with a pool name\n"));
3461168404Spjd			usage(B_FALSE);
3462168404Spjd		}
3463168404Spjd	}
3464168404Spjd
3465185029Spjd	(void) printf(gettext("This system is currently running "
3466185029Spjd	    "ZFS pool version %llu.\n\n"), SPA_VERSION);
3467168404Spjd	cb.cb_first = B_TRUE;
3468168404Spjd	if (showversions) {
3469168404Spjd		(void) printf(gettext("The following versions are "
3470168404Spjd		    "supported:\n\n"));
3471168404Spjd		(void) printf(gettext("VER  DESCRIPTION\n"));
3472168404Spjd		(void) printf("---  -----------------------------------------"
3473168404Spjd		    "---------------\n");
3474168404Spjd		(void) printf(gettext(" 1   Initial ZFS version\n"));
3475168404Spjd		(void) printf(gettext(" 2   Ditto blocks "
3476168404Spjd		    "(replicated metadata)\n"));
3477168404Spjd		(void) printf(gettext(" 3   Hot spares and double parity "
3478168404Spjd		    "RAID-Z\n"));
3479168404Spjd		(void) printf(gettext(" 4   zpool history\n"));
3480168404Spjd		(void) printf(gettext(" 5   Compression using the gzip "
3481168404Spjd		    "algorithm\n"));
3482185029Spjd		(void) printf(gettext(" 6   bootfs pool property\n"));
3483185029Spjd		(void) printf(gettext(" 7   Separate intent log devices\n"));
3484185029Spjd		(void) printf(gettext(" 8   Delegated administration\n"));
3485185029Spjd		(void) printf(gettext(" 9   refquota and refreservation "
3486185029Spjd		    "properties\n"));
3487185029Spjd		(void) printf(gettext(" 10  Cache devices\n"));
3488185029Spjd		(void) printf(gettext(" 11  Improved scrub performance\n"));
3489185029Spjd		(void) printf(gettext(" 12  Snapshot properties\n"));
3490185029Spjd		(void) printf(gettext(" 13  snapused property\n"));
3491185029Spjd		(void) printf(gettext("For more information on a particular "
3492168404Spjd		    "version, including supported releases, see:\n\n"));
3493168404Spjd		(void) printf("http://www.opensolaris.org/os/community/zfs/"
3494168404Spjd		    "version/N\n\n");
3495168404Spjd		(void) printf(gettext("Where 'N' is the version number.\n"));
3496168404Spjd	} else if (argc == 0) {
3497168404Spjd		int notfound;
3498168404Spjd
3499168404Spjd		ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3500168404Spjd		notfound = cb.cb_first;
3501168404Spjd
3502168404Spjd		if (!cb.cb_all && ret == 0) {
3503168404Spjd			if (!cb.cb_first)
3504168404Spjd				(void) printf("\n");
3505168404Spjd			cb.cb_first = B_TRUE;
3506168404Spjd			cb.cb_newer = B_TRUE;
3507168404Spjd			ret = zpool_iter(g_zfs, upgrade_cb, &cb);
3508168404Spjd			if (!cb.cb_first) {
3509168404Spjd				notfound = B_FALSE;
3510168404Spjd				(void) printf("\n");
3511168404Spjd			}
3512168404Spjd		}
3513168404Spjd
3514168404Spjd		if (ret == 0) {
3515168404Spjd			if (notfound)
3516168404Spjd				(void) printf(gettext("All pools are formatted "
3517168404Spjd				    "using this version.\n"));
3518168404Spjd			else if (!cb.cb_all)
3519168404Spjd				(void) printf(gettext("Use 'zpool upgrade -v' "
3520168404Spjd				    "for a list of available versions and "
3521168404Spjd				    "their associated\nfeatures.\n"));
3522168404Spjd		}
3523168404Spjd	} else {
3524168404Spjd		ret = for_each_pool(argc, argv, B_FALSE, NULL,
3525168404Spjd		    upgrade_one, &cb);
3526168404Spjd	}
3527168404Spjd
3528168404Spjd	return (ret);
3529168404Spjd}
3530168404Spjd
3531185029Spjdtypedef struct hist_cbdata {
3532185029Spjd	boolean_t first;
3533185029Spjd	int longfmt;
3534185029Spjd	int internal;
3535185029Spjd} hist_cbdata_t;
3536185029Spjd
3537185029Spjdchar *hist_event_table[LOG_END] = {
3538185029Spjd	"invalid event",
3539185029Spjd	"pool create",
3540185029Spjd	"vdev add",
3541185029Spjd	"pool remove",
3542185029Spjd	"pool destroy",
3543185029Spjd	"pool export",
3544185029Spjd	"pool import",
3545185029Spjd	"vdev attach",
3546185029Spjd	"vdev replace",
3547185029Spjd	"vdev detach",
3548185029Spjd	"vdev online",
3549185029Spjd	"vdev offline",
3550185029Spjd	"vdev upgrade",
3551185029Spjd	"pool clear",
3552185029Spjd	"pool scrub",
3553185029Spjd	"pool property set",
3554185029Spjd	"create",
3555185029Spjd	"clone",
3556185029Spjd	"destroy",
3557185029Spjd	"destroy_begin_sync",
3558185029Spjd	"inherit",
3559185029Spjd	"property set",
3560185029Spjd	"quota set",
3561185029Spjd	"permission update",
3562185029Spjd	"permission remove",
3563185029Spjd	"permission who remove",
3564185029Spjd	"promote",
3565185029Spjd	"receive",
3566185029Spjd	"rename",
3567185029Spjd	"reservation set",
3568185029Spjd	"replay_inc_sync",
3569185029Spjd	"replay_full_sync",
3570185029Spjd	"rollback",
3571185029Spjd	"snapshot",
3572185029Spjd	"filesystem version upgrade",
3573185029Spjd	"refquota set",
3574185029Spjd	"refreservation set",
3575185029Spjd	"pool scrub done",
3576185029Spjd};
3577185029Spjd
3578168404Spjd/*
3579168404Spjd * Print out the command history for a specific pool.
3580168404Spjd */
3581168404Spjdstatic int
3582168404Spjdget_history_one(zpool_handle_t *zhp, void *data)
3583168404Spjd{
3584168404Spjd	nvlist_t *nvhis;
3585168404Spjd	nvlist_t **records;
3586168404Spjd	uint_t numrecords;
3587168404Spjd	char *cmdstr;
3588185029Spjd	char *pathstr;
3589168404Spjd	uint64_t dst_time;
3590168404Spjd	time_t tsec;
3591168404Spjd	struct tm t;
3592168404Spjd	char tbuf[30];
3593168404Spjd	int ret, i;
3594185029Spjd	uint64_t who;
3595185029Spjd	struct passwd *pwd;
3596185029Spjd	char *hostname;
3597185029Spjd	char *zonename;
3598185029Spjd	char internalstr[MAXPATHLEN];
3599185029Spjd	hist_cbdata_t *cb = (hist_cbdata_t *)data;
3600185029Spjd	uint64_t txg;
3601185029Spjd	uint64_t ievent;
3602168404Spjd
3603185029Spjd	cb->first = B_FALSE;
3604168404Spjd
3605168404Spjd	(void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
3606168404Spjd
3607168404Spjd	if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
3608168404Spjd		return (ret);
3609168404Spjd
3610168404Spjd	verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
3611168404Spjd	    &records, &numrecords) == 0);
3612168404Spjd	for (i = 0; i < numrecords; i++) {
3613168404Spjd		if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
3614185029Spjd		    &dst_time) != 0)
3615185029Spjd			continue;
3616185029Spjd
3617185029Spjd		/* is it an internal event or a standard event? */
3618185029Spjd		if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
3619185029Spjd		    &cmdstr) != 0) {
3620185029Spjd			if (cb->internal == 0)
3621185029Spjd				continue;
3622185029Spjd
3623185029Spjd			if (nvlist_lookup_uint64(records[i],
3624185029Spjd			    ZPOOL_HIST_INT_EVENT, &ievent) != 0)
3625185029Spjd				continue;
3626185029Spjd			verify(nvlist_lookup_uint64(records[i],
3627185029Spjd			    ZPOOL_HIST_TXG, &txg) == 0);
3628185029Spjd			verify(nvlist_lookup_string(records[i],
3629185029Spjd			    ZPOOL_HIST_INT_STR, &pathstr) == 0);
3630185029Spjd			if (ievent >= LOG_END)
3631185029Spjd				continue;
3632185029Spjd			(void) snprintf(internalstr,
3633185029Spjd			    sizeof (internalstr),
3634185029Spjd			    "[internal %s txg:%lld] %s",
3635185029Spjd			    hist_event_table[ievent], txg,
3636185029Spjd			    pathstr);
3637185029Spjd			cmdstr = internalstr;
3638168404Spjd		}
3639185029Spjd		tsec = dst_time;
3640185029Spjd		(void) localtime_r(&tsec, &t);
3641185029Spjd		(void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
3642185029Spjd		(void) printf("%s %s", tbuf, cmdstr);
3643185029Spjd
3644185029Spjd		if (!cb->longfmt) {
3645185029Spjd			(void) printf("\n");
3646185029Spjd			continue;
3647185029Spjd		}
3648185029Spjd		(void) printf(" [");
3649185029Spjd		if (nvlist_lookup_uint64(records[i],
3650185029Spjd		    ZPOOL_HIST_WHO, &who) == 0) {
3651185029Spjd			pwd = getpwuid((uid_t)who);
3652185029Spjd			if (pwd)
3653185029Spjd				(void) printf("user %s on",
3654185029Spjd				    pwd->pw_name);
3655185029Spjd			else
3656185029Spjd				(void) printf("user %d on",
3657185029Spjd				    (int)who);
3658185029Spjd		} else {
3659185029Spjd			(void) printf(gettext("no info]\n"));
3660185029Spjd			continue;
3661185029Spjd		}
3662185029Spjd		if (nvlist_lookup_string(records[i],
3663185029Spjd		    ZPOOL_HIST_HOST, &hostname) == 0) {
3664185029Spjd			(void) printf(" %s", hostname);
3665185029Spjd		}
3666185029Spjd		if (nvlist_lookup_string(records[i],
3667185029Spjd		    ZPOOL_HIST_ZONE, &zonename) == 0) {
3668185029Spjd			(void) printf(":%s", zonename);
3669185029Spjd		}
3670185029Spjd
3671185029Spjd		(void) printf("]");
3672185029Spjd		(void) printf("\n");
3673168404Spjd	}
3674168404Spjd	(void) printf("\n");
3675168404Spjd	nvlist_free(nvhis);
3676168404Spjd
3677168404Spjd	return (ret);
3678168404Spjd}
3679168404Spjd
3680168404Spjd/*
3681168404Spjd * zpool history <pool>
3682168404Spjd *
3683168404Spjd * Displays the history of commands that modified pools.
3684168404Spjd */
3685185029Spjd
3686185029Spjd
3687168404Spjdint
3688168404Spjdzpool_do_history(int argc, char **argv)
3689168404Spjd{
3690185029Spjd	hist_cbdata_t cbdata = { 0 };
3691168404Spjd	int ret;
3692185029Spjd	int c;
3693168404Spjd
3694185029Spjd	cbdata.first = B_TRUE;
3695185029Spjd	/* check options */
3696185029Spjd	while ((c = getopt(argc, argv, "li")) != -1) {
3697185029Spjd		switch (c) {
3698185029Spjd		case 'l':
3699185029Spjd			cbdata.longfmt = 1;
3700185029Spjd			break;
3701185029Spjd		case 'i':
3702185029Spjd			cbdata.internal = 1;
3703185029Spjd			break;
3704185029Spjd		case '?':
3705185029Spjd			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3706185029Spjd			    optopt);
3707185029Spjd			usage(B_FALSE);
3708185029Spjd		}
3709185029Spjd	}
3710168404Spjd	argc -= optind;
3711168404Spjd	argv += optind;
3712168404Spjd
3713168404Spjd	ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
3714185029Spjd	    &cbdata);
3715168404Spjd
3716185029Spjd	if (argc == 0 && cbdata.first == B_TRUE) {
3717168404Spjd		(void) printf(gettext("no pools available\n"));
3718168404Spjd		return (0);
3719168404Spjd	}
3720168404Spjd
3721168404Spjd	return (ret);
3722168404Spjd}
3723168404Spjd
3724168404Spjdstatic int
3725168404Spjdget_callback(zpool_handle_t *zhp, void *data)
3726168404Spjd{
3727185029Spjd	zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
3728168404Spjd	char value[MAXNAMELEN];
3729185029Spjd	zprop_source_t srctype;
3730185029Spjd	zprop_list_t *pl;
3731168404Spjd
3732168404Spjd	for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
3733168404Spjd
3734168404Spjd		/*
3735185029Spjd		 * Skip the special fake placeholder. This will also skip
3736185029Spjd		 * over the name property when 'all' is specified.
3737168404Spjd		 */
3738185029Spjd		if (pl->pl_prop == ZPOOL_PROP_NAME &&
3739168404Spjd		    pl == cbp->cb_proplist)
3740168404Spjd			continue;
3741168404Spjd
3742168404Spjd		if (zpool_get_prop(zhp, pl->pl_prop,
3743168404Spjd		    value, sizeof (value), &srctype) != 0)
3744168404Spjd			continue;
3745168404Spjd
3746185029Spjd		zprop_print_one_property(zpool_get_name(zhp), cbp,
3747168404Spjd		    zpool_prop_to_name(pl->pl_prop), value, srctype, NULL);
3748168404Spjd	}
3749168404Spjd	return (0);
3750168404Spjd}
3751168404Spjd
3752168404Spjdint
3753168404Spjdzpool_do_get(int argc, char **argv)
3754168404Spjd{
3755185029Spjd	zprop_get_cbdata_t cb = { 0 };
3756185029Spjd	zprop_list_t fake_name = { 0 };
3757168404Spjd	int ret;
3758168404Spjd
3759168404Spjd	if (argc < 3)
3760168404Spjd		usage(B_FALSE);
3761168404Spjd
3762168404Spjd	cb.cb_first = B_TRUE;
3763185029Spjd	cb.cb_sources = ZPROP_SRC_ALL;
3764168404Spjd	cb.cb_columns[0] = GET_COL_NAME;
3765168404Spjd	cb.cb_columns[1] = GET_COL_PROPERTY;
3766168404Spjd	cb.cb_columns[2] = GET_COL_VALUE;
3767168404Spjd	cb.cb_columns[3] = GET_COL_SOURCE;
3768185029Spjd	cb.cb_type = ZFS_TYPE_POOL;
3769168404Spjd
3770185029Spjd	if (zprop_get_list(g_zfs, argv[1],  &cb.cb_proplist,
3771185029Spjd	    ZFS_TYPE_POOL) != 0)
3772168404Spjd		usage(B_FALSE);
3773168404Spjd
3774168404Spjd	if (cb.cb_proplist != NULL) {
3775185029Spjd		fake_name.pl_prop = ZPOOL_PROP_NAME;
3776168404Spjd		fake_name.pl_width = strlen(gettext("NAME"));
3777168404Spjd		fake_name.pl_next = cb.cb_proplist;
3778168404Spjd		cb.cb_proplist = &fake_name;
3779168404Spjd	}
3780168404Spjd
3781168404Spjd	ret = for_each_pool(argc - 2, argv + 2, B_TRUE, &cb.cb_proplist,
3782168404Spjd	    get_callback, &cb);
3783168404Spjd
3784168404Spjd	if (cb.cb_proplist == &fake_name)
3785185029Spjd		zprop_free_list(fake_name.pl_next);
3786168404Spjd	else
3787185029Spjd		zprop_free_list(cb.cb_proplist);
3788168404Spjd
3789168404Spjd	return (ret);
3790168404Spjd}
3791168404Spjd
3792168404Spjdtypedef struct set_cbdata {
3793168404Spjd	char *cb_propname;
3794168404Spjd	char *cb_value;
3795168404Spjd	boolean_t cb_any_successful;
3796168404Spjd} set_cbdata_t;
3797168404Spjd
3798168404Spjdint
3799168404Spjdset_callback(zpool_handle_t *zhp, void *data)
3800168404Spjd{
3801168404Spjd	int error;
3802168404Spjd	set_cbdata_t *cb = (set_cbdata_t *)data;
3803168404Spjd
3804168404Spjd	error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
3805168404Spjd
3806168404Spjd	if (!error)
3807168404Spjd		cb->cb_any_successful = B_TRUE;
3808168404Spjd
3809168404Spjd	return (error);
3810168404Spjd}
3811168404Spjd
3812168404Spjdint
3813168404Spjdzpool_do_set(int argc, char **argv)
3814168404Spjd{
3815168404Spjd	set_cbdata_t cb = { 0 };
3816168404Spjd	int error;
3817168404Spjd
3818168404Spjd	if (argc > 1 && argv[1][0] == '-') {
3819168404Spjd		(void) fprintf(stderr, gettext("invalid option '%c'\n"),
3820168404Spjd		    argv[1][1]);
3821168404Spjd		usage(B_FALSE);
3822168404Spjd	}
3823168404Spjd
3824168404Spjd	if (argc < 2) {
3825168404Spjd		(void) fprintf(stderr, gettext("missing property=value "
3826168404Spjd		    "argument\n"));
3827168404Spjd		usage(B_FALSE);
3828168404Spjd	}
3829168404Spjd
3830168404Spjd	if (argc < 3) {
3831168404Spjd		(void) fprintf(stderr, gettext("missing pool name\n"));
3832168404Spjd		usage(B_FALSE);
3833168404Spjd	}
3834168404Spjd
3835168404Spjd	if (argc > 3) {
3836168404Spjd		(void) fprintf(stderr, gettext("too many pool names\n"));
3837168404Spjd		usage(B_FALSE);
3838168404Spjd	}
3839168404Spjd
3840168404Spjd	cb.cb_propname = argv[1];
3841168404Spjd	cb.cb_value = strchr(cb.cb_propname, '=');
3842168404Spjd	if (cb.cb_value == NULL) {
3843168404Spjd		(void) fprintf(stderr, gettext("missing value in "
3844168404Spjd		    "property=value argument\n"));
3845168404Spjd		usage(B_FALSE);
3846168404Spjd	}
3847168404Spjd
3848168404Spjd	*(cb.cb_value) = '\0';
3849168404Spjd	cb.cb_value++;
3850168404Spjd
3851168404Spjd	error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
3852168404Spjd	    set_callback, &cb);
3853168404Spjd
3854168404Spjd	return (error);
3855168404Spjd}
3856168404Spjd
3857168404Spjdstatic int
3858168404Spjdfind_command_idx(char *command, int *idx)
3859168404Spjd{
3860168404Spjd	int i;
3861168404Spjd
3862168404Spjd	for (i = 0; i < NCOMMAND; i++) {
3863168404Spjd		if (command_table[i].name == NULL)
3864168404Spjd			continue;
3865168404Spjd
3866168404Spjd		if (strcmp(command, command_table[i].name) == 0) {
3867168404Spjd			*idx = i;
3868168404Spjd			return (0);
3869168404Spjd		}
3870168404Spjd	}
3871168404Spjd	return (1);
3872168404Spjd}
3873168404Spjd
3874168404Spjdint
3875168404Spjdmain(int argc, char **argv)
3876168404Spjd{
3877168404Spjd	int ret;
3878168404Spjd	int i;
3879168404Spjd	char *cmdname;
3880168404Spjd
3881168404Spjd	(void) setlocale(LC_ALL, "");
3882168404Spjd	(void) textdomain(TEXT_DOMAIN);
3883168404Spjd
3884168404Spjd	if ((g_zfs = libzfs_init()) == NULL) {
3885168404Spjd		(void) fprintf(stderr, gettext("internal error: failed to "
3886168404Spjd		    "initialize ZFS library\n"));
3887168404Spjd		return (1);
3888168404Spjd	}
3889168404Spjd
3890168404Spjd	libzfs_print_on_error(g_zfs, B_TRUE);
3891168404Spjd
3892168404Spjd	opterr = 0;
3893168404Spjd
3894168404Spjd	/*
3895168404Spjd	 * Make sure the user has specified some command.
3896168404Spjd	 */
3897168404Spjd	if (argc < 2) {
3898168404Spjd		(void) fprintf(stderr, gettext("missing command\n"));
3899168404Spjd		usage(B_FALSE);
3900168404Spjd	}
3901168404Spjd
3902168404Spjd	cmdname = argv[1];
3903168404Spjd
3904168404Spjd	/*
3905168404Spjd	 * Special case '-?'
3906168404Spjd	 */
3907168404Spjd	if (strcmp(cmdname, "-?") == 0)
3908168404Spjd		usage(B_TRUE);
3909168404Spjd
3910185029Spjd	zpool_set_history_str("zpool", argc, argv, history_str);
3911185029Spjd	verify(zpool_stage_history(g_zfs, history_str) == 0);
3912185029Spjd
3913168404Spjd	/*
3914168404Spjd	 * Run the appropriate command.
3915168404Spjd	 */
3916168404Spjd	if (find_command_idx(cmdname, &i) == 0) {
3917168404Spjd		current_command = &command_table[i];
3918168404Spjd		ret = command_table[i].func(argc - 1, argv + 1);
3919185029Spjd	} else if (strchr(cmdname, '=')) {
3920185029Spjd		verify(find_command_idx("set", &i) == 0);
3921185029Spjd		current_command = &command_table[i];
3922185029Spjd		ret = command_table[i].func(argc, argv);
3923185029Spjd	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
3924185029Spjd		/*
3925185029Spjd		 * 'freeze' is a vile debugging abomination, so we treat
3926185029Spjd		 * it as such.
3927185029Spjd		 */
3928168404Spjd		char buf[16384];
3929168404Spjd		int fd = open(ZFS_DEV, O_RDWR);
3930168404Spjd		(void) strcpy((void *)buf, argv[2]);
3931168404Spjd		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
3932185029Spjd	} else {
3933168404Spjd		(void) fprintf(stderr, gettext("unrecognized "
3934168404Spjd		    "command '%s'\n"), cmdname);
3935168404Spjd		usage(B_FALSE);
3936168404Spjd	}
3937168404Spjd
3938168404Spjd	libzfs_fini(g_zfs);
3939168404Spjd
3940168404Spjd	/*
3941168404Spjd	 * The 'ZFS_ABORT' environment variable causes us to dump core on exit
3942168404Spjd	 * for the purposes of running ::findleaks.
3943168404Spjd	 */
3944168404Spjd	if (getenv("ZFS_ABORT") != NULL) {
3945168404Spjd		(void) printf("dumping core by request\n");
3946168404Spjd		abort();
3947168404Spjd	}
3948168404Spjd
3949168404Spjd	return (ret);
3950168404Spjd}
3951