1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5441d80aaSlling  * Common Development and Distribution License (the "License").
6441d80aaSlling  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
2199653d4eSeschrock 
22fa9e4066Sahrens /*
23379c004dSEric Schrock  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #include <ctype.h>
28fa9e4066Sahrens #include <errno.h>
29fa9e4066Sahrens #include <devid.h>
30fa9e4066Sahrens #include <fcntl.h>
31fa9e4066Sahrens #include <libintl.h>
32fa9e4066Sahrens #include <stdio.h>
33fa9e4066Sahrens #include <stdlib.h>
34f3861e1aSahl #include <strings.h>
35fa9e4066Sahrens #include <unistd.h>
368488aeb5Staylor #include <sys/efi_partition.h>
378488aeb5Staylor #include <sys/vtoc.h>
38fa9e4066Sahrens #include <sys/zfs_ioctl.h>
39573ca77eSGeorge Wilson #include <dlfcn.h>
40fa9e4066Sahrens 
41fa9e4066Sahrens #include "zfs_namecheck.h"
42b1b8ab34Slling #include "zfs_prop.h"
43fa9e4066Sahrens #include "libzfs_impl.h"
44468c413aSTim Haley #include "zfs_comutil.h"
45fa9e4066Sahrens 
468f18d1faSGeorge Wilson const char *hist_event_table[LOG_END] = {
478f18d1faSGeorge Wilson 	"invalid event",
488f18d1faSGeorge Wilson 	"pool create",
498f18d1faSGeorge Wilson 	"vdev add",
508f18d1faSGeorge Wilson 	"pool remove",
518f18d1faSGeorge Wilson 	"pool destroy",
528f18d1faSGeorge Wilson 	"pool export",
538f18d1faSGeorge Wilson 	"pool import",
548f18d1faSGeorge Wilson 	"vdev attach",
558f18d1faSGeorge Wilson 	"vdev replace",
568f18d1faSGeorge Wilson 	"vdev detach",
578f18d1faSGeorge Wilson 	"vdev online",
588f18d1faSGeorge Wilson 	"vdev offline",
598f18d1faSGeorge Wilson 	"vdev upgrade",
608f18d1faSGeorge Wilson 	"pool clear",
618f18d1faSGeorge Wilson 	"pool scrub",
628f18d1faSGeorge Wilson 	"pool property set",
638f18d1faSGeorge Wilson 	"create",
648f18d1faSGeorge Wilson 	"clone",
658f18d1faSGeorge Wilson 	"destroy",
668f18d1faSGeorge Wilson 	"destroy_begin_sync",
678f18d1faSGeorge Wilson 	"inherit",
688f18d1faSGeorge Wilson 	"property set",
698f18d1faSGeorge Wilson 	"quota set",
708f18d1faSGeorge Wilson 	"permission update",
718f18d1faSGeorge Wilson 	"permission remove",
728f18d1faSGeorge Wilson 	"permission who remove",
738f18d1faSGeorge Wilson 	"promote",
748f18d1faSGeorge Wilson 	"receive",
758f18d1faSGeorge Wilson 	"rename",
768f18d1faSGeorge Wilson 	"reservation set",
778f18d1faSGeorge Wilson 	"replay_inc_sync",
788f18d1faSGeorge Wilson 	"replay_full_sync",
798f18d1faSGeorge Wilson 	"rollback",
808f18d1faSGeorge Wilson 	"snapshot",
818f18d1faSGeorge Wilson 	"filesystem version upgrade",
828f18d1faSGeorge Wilson 	"refquota set",
838f18d1faSGeorge Wilson 	"refreservation set",
848f18d1faSGeorge Wilson 	"pool scrub done",
858f18d1faSGeorge Wilson 	"user hold",
868f18d1faSGeorge Wilson 	"user release",
878f18d1faSGeorge Wilson };
888f18d1faSGeorge Wilson 
8915e6edf1Sgw static int read_efi_label(nvlist_t *config, diskaddr_t *sb);
90990b4856Slling 
91b5b76fecSGeorge Wilson #if defined(__i386) || defined(__amd64)
92b5b76fecSGeorge Wilson #define	BOOTCMD	"installgrub(1M)"
93b5b76fecSGeorge Wilson #else
94b5b76fecSGeorge Wilson #define	BOOTCMD	"installboot(1M)"
95b5b76fecSGeorge Wilson #endif
96b5b76fecSGeorge Wilson 
97573ca77eSGeorge Wilson #define	DISK_ROOT	"/dev/dsk"
98573ca77eSGeorge Wilson #define	RDISK_ROOT	"/dev/rdsk"
99573ca77eSGeorge Wilson #define	BACKUP_SLICE	"s2"
100573ca77eSGeorge Wilson 
101990b4856Slling /*
102990b4856Slling  * ====================================================================
103990b4856Slling  *   zpool property functions
104990b4856Slling  * ====================================================================
105990b4856Slling  */
106990b4856Slling 
107990b4856Slling static int
108990b4856Slling zpool_get_all_props(zpool_handle_t *zhp)
109990b4856Slling {
110990b4856Slling 	zfs_cmd_t zc = { 0 };
111990b4856Slling 	libzfs_handle_t *hdl = zhp->zpool_hdl;
112990b4856Slling 
113990b4856Slling 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
114990b4856Slling 
115990b4856Slling 	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
116990b4856Slling 		return (-1);
117990b4856Slling 
118990b4856Slling 	while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) {
119990b4856Slling 		if (errno == ENOMEM) {
120990b4856Slling 			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
121990b4856Slling 				zcmd_free_nvlists(&zc);
122990b4856Slling 				return (-1);
123990b4856Slling 			}
124990b4856Slling 		} else {
125990b4856Slling 			zcmd_free_nvlists(&zc);
126990b4856Slling 			return (-1);
127990b4856Slling 		}
128990b4856Slling 	}
129990b4856Slling 
130990b4856Slling 	if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) {
131990b4856Slling 		zcmd_free_nvlists(&zc);
132990b4856Slling 		return (-1);
133990b4856Slling 	}
134990b4856Slling 
135990b4856Slling 	zcmd_free_nvlists(&zc);
136990b4856Slling 
137990b4856Slling 	return (0);
138990b4856Slling }
139990b4856Slling 
140990b4856Slling static int
141990b4856Slling zpool_props_refresh(zpool_handle_t *zhp)
142990b4856Slling {
143990b4856Slling 	nvlist_t *old_props;
144990b4856Slling 
145990b4856Slling 	old_props = zhp->zpool_props;
146990b4856Slling 
147990b4856Slling 	if (zpool_get_all_props(zhp) != 0)
148990b4856Slling 		return (-1);
149990b4856Slling 
150990b4856Slling 	nvlist_free(old_props);
151990b4856Slling 	return (0);
152990b4856Slling }
153990b4856Slling 
154990b4856Slling static char *
155990b4856Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop,
156990b4856Slling     zprop_source_t *src)
157990b4856Slling {
158990b4856Slling 	nvlist_t *nv, *nvl;
159990b4856Slling 	uint64_t ival;
160990b4856Slling 	char *value;
161990b4856Slling 	zprop_source_t source;
162990b4856Slling 
163990b4856Slling 	nvl = zhp->zpool_props;
164990b4856Slling 	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
165990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0);
166990b4856Slling 		source = ival;
167990b4856Slling 		verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
168990b4856Slling 	} else {
169990b4856Slling 		source = ZPROP_SRC_DEFAULT;
170990b4856Slling 		if ((value = (char *)zpool_prop_default_string(prop)) == NULL)
171990b4856Slling 			value = "-";
172990b4856Slling 	}
173990b4856Slling 
174990b4856Slling 	if (src)
175990b4856Slling 		*src = source;
176990b4856Slling 
177990b4856Slling 	return (value);
178990b4856Slling }
179990b4856Slling 
180990b4856Slling uint64_t
181990b4856Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src)
182990b4856Slling {
183990b4856Slling 	nvlist_t *nv, *nvl;
184990b4856Slling 	uint64_t value;
185990b4856Slling 	zprop_source_t source;
186990b4856Slling 
187b87f3af3Sperrin 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) {
188b87f3af3Sperrin 		/*
189b87f3af3Sperrin 		 * zpool_get_all_props() has most likely failed because
190b87f3af3Sperrin 		 * the pool is faulted, but if all we need is the top level
191b87f3af3Sperrin 		 * vdev's guid then get it from the zhp config nvlist.
192b87f3af3Sperrin 		 */
193b87f3af3Sperrin 		if ((prop == ZPOOL_PROP_GUID) &&
194b87f3af3Sperrin 		    (nvlist_lookup_nvlist(zhp->zpool_config,
195b87f3af3Sperrin 		    ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) &&
196b87f3af3Sperrin 		    (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value)
197b87f3af3Sperrin 		    == 0)) {
198b87f3af3Sperrin 			return (value);
199b87f3af3Sperrin 		}
200990b4856Slling 		return (zpool_prop_default_numeric(prop));
201b87f3af3Sperrin 	}
202990b4856Slling 
203990b4856Slling 	nvl = zhp->zpool_props;
204990b4856Slling 	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
205990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0);
206990b4856Slling 		source = value;
207990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
208990b4856Slling 	} else {
209990b4856Slling 		source = ZPROP_SRC_DEFAULT;
210990b4856Slling 		value = zpool_prop_default_numeric(prop);
211990b4856Slling 	}
212990b4856Slling 
213990b4856Slling 	if (src)
214990b4856Slling 		*src = source;
215990b4856Slling 
216990b4856Slling 	return (value);
217990b4856Slling }
218990b4856Slling 
219990b4856Slling /*
220990b4856Slling  * Map VDEV STATE to printed strings.
221990b4856Slling  */
222990b4856Slling char *
223990b4856Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
224990b4856Slling {
225990b4856Slling 	switch (state) {
226990b4856Slling 	case VDEV_STATE_CLOSED:
227990b4856Slling 	case VDEV_STATE_OFFLINE:
228990b4856Slling 		return (gettext("OFFLINE"));
229990b4856Slling 	case VDEV_STATE_REMOVED:
230990b4856Slling 		return (gettext("REMOVED"));
231990b4856Slling 	case VDEV_STATE_CANT_OPEN:
232b87f3af3Sperrin 		if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG)
233990b4856Slling 			return (gettext("FAULTED"));
234990b4856Slling 		else
235990b4856Slling 			return (gettext("UNAVAIL"));
236990b4856Slling 	case VDEV_STATE_FAULTED:
237990b4856Slling 		return (gettext("FAULTED"));
238990b4856Slling 	case VDEV_STATE_DEGRADED:
239990b4856Slling 		return (gettext("DEGRADED"));
240990b4856Slling 	case VDEV_STATE_HEALTHY:
241990b4856Slling 		return (gettext("ONLINE"));
242990b4856Slling 	}
243990b4856Slling 
244990b4856Slling 	return (gettext("UNKNOWN"));
245990b4856Slling }
246990b4856Slling 
247990b4856Slling /*
248990b4856Slling  * Get a zpool property value for 'prop' and return the value in
249990b4856Slling  * a pre-allocated buffer.
250990b4856Slling  */
251990b4856Slling int
252990b4856Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
253990b4856Slling     zprop_source_t *srctype)
254990b4856Slling {
255990b4856Slling 	uint64_t intval;
256990b4856Slling 	const char *strval;
257990b4856Slling 	zprop_source_t src = ZPROP_SRC_NONE;
258990b4856Slling 	nvlist_t *nvroot;
259990b4856Slling 	vdev_stat_t *vs;
260990b4856Slling 	uint_t vsc;
261990b4856Slling 
262990b4856Slling 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
263379c004dSEric Schrock 		switch (prop) {
264379c004dSEric Schrock 		case ZPOOL_PROP_NAME:
265990b4856Slling 			(void) strlcpy(buf, zpool_get_name(zhp), len);
266379c004dSEric Schrock 			break;
267379c004dSEric Schrock 
268379c004dSEric Schrock 		case ZPOOL_PROP_HEALTH:
269990b4856Slling 			(void) strlcpy(buf, "FAULTED", len);
270379c004dSEric Schrock 			break;
271379c004dSEric Schrock 
272379c004dSEric Schrock 		case ZPOOL_PROP_GUID:
273379c004dSEric Schrock 			intval = zpool_get_prop_int(zhp, prop, &src);
274379c004dSEric Schrock 			(void) snprintf(buf, len, "%llu", intval);
275379c004dSEric Schrock 			break;
276379c004dSEric Schrock 
277379c004dSEric Schrock 		case ZPOOL_PROP_ALTROOT:
278379c004dSEric Schrock 		case ZPOOL_PROP_CACHEFILE:
279379c004dSEric Schrock 			if (zhp->zpool_props != NULL ||
280379c004dSEric Schrock 			    zpool_get_all_props(zhp) == 0) {
281379c004dSEric Schrock 				(void) strlcpy(buf,
282379c004dSEric Schrock 				    zpool_get_prop_string(zhp, prop, &src),
283379c004dSEric Schrock 				    len);
284379c004dSEric Schrock 				if (srctype != NULL)
285379c004dSEric Schrock 					*srctype = src;
286379c004dSEric Schrock 				return (0);
287379c004dSEric Schrock 			}
288379c004dSEric Schrock 			/* FALLTHROUGH */
289379c004dSEric Schrock 		default:
290990b4856Slling 			(void) strlcpy(buf, "-", len);
291379c004dSEric Schrock 			break;
292379c004dSEric Schrock 		}
293379c004dSEric Schrock 
294379c004dSEric Schrock 		if (srctype != NULL)
295379c004dSEric Schrock 			*srctype = src;
296990b4856Slling 		return (0);
297990b4856Slling 	}
298990b4856Slling 
299990b4856Slling 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) &&
300990b4856Slling 	    prop != ZPOOL_PROP_NAME)
301990b4856Slling 		return (-1);
302990b4856Slling 
303990b4856Slling 	switch (zpool_prop_get_type(prop)) {
304990b4856Slling 	case PROP_TYPE_STRING:
305990b4856Slling 		(void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src),
306990b4856Slling 		    len);
307990b4856Slling 		break;
308990b4856Slling 
309990b4856Slling 	case PROP_TYPE_NUMBER:
310990b4856Slling 		intval = zpool_get_prop_int(zhp, prop, &src);
311990b4856Slling 
312990b4856Slling 		switch (prop) {
313990b4856Slling 		case ZPOOL_PROP_SIZE:
314990b4856Slling 		case ZPOOL_PROP_USED:
315990b4856Slling 		case ZPOOL_PROP_AVAILABLE:
316990b4856Slling 			(void) zfs_nicenum(intval, buf, len);
317990b4856Slling 			break;
318990b4856Slling 
319990b4856Slling 		case ZPOOL_PROP_CAPACITY:
320990b4856Slling 			(void) snprintf(buf, len, "%llu%%",
321990b4856Slling 			    (u_longlong_t)intval);
322990b4856Slling 			break;
323990b4856Slling 
324*b24ab676SJeff Bonwick 		case ZPOOL_PROP_DEDUPRATIO:
325*b24ab676SJeff Bonwick 			(void) snprintf(buf, len, "%llu.%02llux",
326*b24ab676SJeff Bonwick 			    (u_longlong_t)(intval / 100),
327*b24ab676SJeff Bonwick 			    (u_longlong_t)(intval % 100));
328*b24ab676SJeff Bonwick 			break;
329*b24ab676SJeff Bonwick 
330990b4856Slling 		case ZPOOL_PROP_HEALTH:
331990b4856Slling 			verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
332990b4856Slling 			    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
333990b4856Slling 			verify(nvlist_lookup_uint64_array(nvroot,
334990b4856Slling 			    ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0);
335990b4856Slling 
336990b4856Slling 			(void) strlcpy(buf, zpool_state_to_name(intval,
337990b4856Slling 			    vs->vs_aux), len);
338990b4856Slling 			break;
339990b4856Slling 		default:
340990b4856Slling 			(void) snprintf(buf, len, "%llu", intval);
341990b4856Slling 		}
342990b4856Slling 		break;
343990b4856Slling 
344990b4856Slling 	case PROP_TYPE_INDEX:
345990b4856Slling 		intval = zpool_get_prop_int(zhp, prop, &src);
346990b4856Slling 		if (zpool_prop_index_to_string(prop, intval, &strval)
347990b4856Slling 		    != 0)
348990b4856Slling 			return (-1);
349990b4856Slling 		(void) strlcpy(buf, strval, len);
350990b4856Slling 		break;
351990b4856Slling 
352990b4856Slling 	default:
353990b4856Slling 		abort();
354990b4856Slling 	}
355990b4856Slling 
356990b4856Slling 	if (srctype)
357990b4856Slling 		*srctype = src;
358990b4856Slling 
359990b4856Slling 	return (0);
360990b4856Slling }
361990b4856Slling 
362990b4856Slling /*
363990b4856Slling  * Check if the bootfs name has the same pool name as it is set to.
364990b4856Slling  * Assuming bootfs is a valid dataset name.
365990b4856Slling  */
366990b4856Slling static boolean_t
367990b4856Slling bootfs_name_valid(const char *pool, char *bootfs)
368990b4856Slling {
369990b4856Slling 	int len = strlen(pool);
370990b4856Slling 
371fe3e2633SEric Taylor 	if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
372990b4856Slling 		return (B_FALSE);
373990b4856Slling 
374990b4856Slling 	if (strncmp(pool, bootfs, len) == 0 &&
375990b4856Slling 	    (bootfs[len] == '/' || bootfs[len] == '\0'))
376990b4856Slling 		return (B_TRUE);
377990b4856Slling 
378990b4856Slling 	return (B_FALSE);
379990b4856Slling }
380990b4856Slling 
38115e6edf1Sgw /*
38215e6edf1Sgw  * Inspect the configuration to determine if any of the devices contain
38315e6edf1Sgw  * an EFI label.
38415e6edf1Sgw  */
38515e6edf1Sgw static boolean_t
38615e6edf1Sgw pool_uses_efi(nvlist_t *config)
38715e6edf1Sgw {
38815e6edf1Sgw 	nvlist_t **child;
38915e6edf1Sgw 	uint_t c, children;
39015e6edf1Sgw 
39115e6edf1Sgw 	if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
39215e6edf1Sgw 	    &child, &children) != 0)
39315e6edf1Sgw 		return (read_efi_label(config, NULL) >= 0);
39415e6edf1Sgw 
39515e6edf1Sgw 	for (c = 0; c < children; c++) {
39615e6edf1Sgw 		if (pool_uses_efi(child[c]))
39715e6edf1Sgw 			return (B_TRUE);
39815e6edf1Sgw 	}
39915e6edf1Sgw 	return (B_FALSE);
40015e6edf1Sgw }
40115e6edf1Sgw 
402b5b76fecSGeorge Wilson static boolean_t
403b5b76fecSGeorge Wilson pool_is_bootable(zpool_handle_t *zhp)
404b5b76fecSGeorge Wilson {
405b5b76fecSGeorge Wilson 	char bootfs[ZPOOL_MAXNAMELEN];
406b5b76fecSGeorge Wilson 
407b5b76fecSGeorge Wilson 	return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
408b5b76fecSGeorge Wilson 	    sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-",
409b5b76fecSGeorge Wilson 	    sizeof (bootfs)) != 0);
410b5b76fecSGeorge Wilson }
411b5b76fecSGeorge Wilson 
412b5b76fecSGeorge Wilson 
413990b4856Slling /*
414990b4856Slling  * Given an nvlist of zpool properties to be set, validate that they are
415990b4856Slling  * correct, and parse any numeric properties (index, boolean, etc) if they are
416990b4856Slling  * specified as strings.
417990b4856Slling  */
418990b4856Slling static nvlist_t *
4190a48a24eStimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
420990b4856Slling     nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf)
421990b4856Slling {
422990b4856Slling 	nvpair_t *elem;
423990b4856Slling 	nvlist_t *retprops;
424990b4856Slling 	zpool_prop_t prop;
425990b4856Slling 	char *strval;
426990b4856Slling 	uint64_t intval;
4272f8aaab3Seschrock 	char *slash;
4282f8aaab3Seschrock 	struct stat64 statbuf;
42915e6edf1Sgw 	zpool_handle_t *zhp;
43015e6edf1Sgw 	nvlist_t *nvroot;
431990b4856Slling 
432990b4856Slling 	if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
433990b4856Slling 		(void) no_memory(hdl);
434990b4856Slling 		return (NULL);
435990b4856Slling 	}
436990b4856Slling 
437990b4856Slling 	elem = NULL;
438990b4856Slling 	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
439990b4856Slling 		const char *propname = nvpair_name(elem);
440990b4856Slling 
441990b4856Slling 		/*
442990b4856Slling 		 * Make sure this property is valid and applies to this type.
443990b4856Slling 		 */
444990b4856Slling 		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
445990b4856Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
446990b4856Slling 			    "invalid property '%s'"), propname);
447990b4856Slling 			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
448990b4856Slling 			goto error;
449990b4856Slling 		}
450990b4856Slling 
451990b4856Slling 		if (zpool_prop_readonly(prop)) {
452990b4856Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
453990b4856Slling 			    "is readonly"), propname);
454990b4856Slling 			(void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
455990b4856Slling 			goto error;
456990b4856Slling 		}
457990b4856Slling 
458990b4856Slling 		if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops,
459990b4856Slling 		    &strval, &intval, errbuf) != 0)
460990b4856Slling 			goto error;
461990b4856Slling 
462990b4856Slling 		/*
463990b4856Slling 		 * Perform additional checking for specific properties.
464990b4856Slling 		 */
465990b4856Slling 		switch (prop) {
466990b4856Slling 		case ZPOOL_PROP_VERSION:
467990b4856Slling 			if (intval < version || intval > SPA_VERSION) {
468990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
469990b4856Slling 				    "property '%s' number %d is invalid."),
470990b4856Slling 				    propname, intval);
471990b4856Slling 				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
472990b4856Slling 				goto error;
473990b4856Slling 			}
474990b4856Slling 			break;
475990b4856Slling 
476990b4856Slling 		case ZPOOL_PROP_BOOTFS:
477990b4856Slling 			if (create_or_import) {
478990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
479990b4856Slling 				    "property '%s' cannot be set at creation "
480990b4856Slling 				    "or import time"), propname);
481990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
482990b4856Slling 				goto error;
483990b4856Slling 			}
484990b4856Slling 
485990b4856Slling 			if (version < SPA_VERSION_BOOTFS) {
486990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
487990b4856Slling 				    "pool must be upgraded to support "
488990b4856Slling 				    "'%s' property"), propname);
489990b4856Slling 				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
490990b4856Slling 				goto error;
491990b4856Slling 			}
492990b4856Slling 
493990b4856Slling 			/*
494990b4856Slling 			 * bootfs property value has to be a dataset name and
495990b4856Slling 			 * the dataset has to be in the same pool as it sets to.
496990b4856Slling 			 */
497990b4856Slling 			if (strval[0] != '\0' && !bootfs_name_valid(poolname,
498990b4856Slling 			    strval)) {
499990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
500990b4856Slling 				    "is an invalid name"), strval);
501990b4856Slling 				(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
502990b4856Slling 				goto error;
503990b4856Slling 			}
50415e6edf1Sgw 
50515e6edf1Sgw 			if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) {
50615e6edf1Sgw 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
50715e6edf1Sgw 				    "could not open pool '%s'"), poolname);
50815e6edf1Sgw 				(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
50915e6edf1Sgw 				goto error;
51015e6edf1Sgw 			}
51115e6edf1Sgw 			verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
51215e6edf1Sgw 			    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
51315e6edf1Sgw 
51415e6edf1Sgw 			/*
51515e6edf1Sgw 			 * bootfs property cannot be set on a disk which has
51615e6edf1Sgw 			 * been EFI labeled.
51715e6edf1Sgw 			 */
51815e6edf1Sgw 			if (pool_uses_efi(nvroot)) {
51915e6edf1Sgw 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
52015e6edf1Sgw 				    "property '%s' not supported on "
52115e6edf1Sgw 				    "EFI labeled devices"), propname);
52215e6edf1Sgw 				(void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf);
52315e6edf1Sgw 				zpool_close(zhp);
52415e6edf1Sgw 				goto error;
52515e6edf1Sgw 			}
52615e6edf1Sgw 			zpool_close(zhp);
527990b4856Slling 			break;
528990b4856Slling 
5292f8aaab3Seschrock 		case ZPOOL_PROP_ALTROOT:
530990b4856Slling 			if (!create_or_import) {
531990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
532990b4856Slling 				    "property '%s' can only be set during pool "
533990b4856Slling 				    "creation or import"), propname);
534990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
535990b4856Slling 				goto error;
536990b4856Slling 			}
537990b4856Slling 
5382f8aaab3Seschrock 			if (strval[0] != '/') {
539990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5402f8aaab3Seschrock 				    "bad alternate root '%s'"), strval);
5412f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
542990b4856Slling 				goto error;
543990b4856Slling 			}
5442f8aaab3Seschrock 			break;
5452f8aaab3Seschrock 
5462f8aaab3Seschrock 		case ZPOOL_PROP_CACHEFILE:
5472f8aaab3Seschrock 			if (strval[0] == '\0')
5482f8aaab3Seschrock 				break;
5492f8aaab3Seschrock 
5502f8aaab3Seschrock 			if (strcmp(strval, "none") == 0)
5512f8aaab3Seschrock 				break;
552990b4856Slling 
553990b4856Slling 			if (strval[0] != '/') {
554990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5552f8aaab3Seschrock 				    "property '%s' must be empty, an "
5562f8aaab3Seschrock 				    "absolute path, or 'none'"), propname);
557990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
558990b4856Slling 				goto error;
559990b4856Slling 			}
560990b4856Slling 
5612f8aaab3Seschrock 			slash = strrchr(strval, '/');
562990b4856Slling 
5632f8aaab3Seschrock 			if (slash[1] == '\0' || strcmp(slash, "/.") == 0 ||
5642f8aaab3Seschrock 			    strcmp(slash, "/..") == 0) {
5652f8aaab3Seschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5662f8aaab3Seschrock 				    "'%s' is not a valid file"), strval);
5672f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
5682f8aaab3Seschrock 				goto error;
5692f8aaab3Seschrock 			}
570990b4856Slling 
5712f8aaab3Seschrock 			*slash = '\0';
5722f8aaab3Seschrock 
5732c32020fSeschrock 			if (strval[0] != '\0' &&
5742c32020fSeschrock 			    (stat64(strval, &statbuf) != 0 ||
5752c32020fSeschrock 			    !S_ISDIR(statbuf.st_mode))) {
5762f8aaab3Seschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5772f8aaab3Seschrock 				    "'%s' is not a valid directory"),
5782f8aaab3Seschrock 				    strval);
5792f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
5802f8aaab3Seschrock 				goto error;
5812f8aaab3Seschrock 			}
5822f8aaab3Seschrock 
5832f8aaab3Seschrock 			*slash = '/';
5842f8aaab3Seschrock 			break;
585990b4856Slling 		}
586990b4856Slling 	}
587990b4856Slling 
588990b4856Slling 	return (retprops);
589990b4856Slling error:
590990b4856Slling 	nvlist_free(retprops);
591990b4856Slling 	return (NULL);
592990b4856Slling }
593990b4856Slling 
594990b4856Slling /*
595990b4856Slling  * Set zpool property : propname=propval.
596990b4856Slling  */
597990b4856Slling int
598990b4856Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
599990b4856Slling {
600990b4856Slling 	zfs_cmd_t zc = { 0 };
601990b4856Slling 	int ret = -1;
602990b4856Slling 	char errbuf[1024];
603990b4856Slling 	nvlist_t *nvl = NULL;
604990b4856Slling 	nvlist_t *realprops;
605990b4856Slling 	uint64_t version;
606990b4856Slling 
607990b4856Slling 	(void) snprintf(errbuf, sizeof (errbuf),
608990b4856Slling 	    dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
609990b4856Slling 	    zhp->zpool_name);
610990b4856Slling 
611990b4856Slling 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
612990b4856Slling 		return (no_memory(zhp->zpool_hdl));
613990b4856Slling 
614990b4856Slling 	if (nvlist_add_string(nvl, propname, propval) != 0) {
615990b4856Slling 		nvlist_free(nvl);
616990b4856Slling 		return (no_memory(zhp->zpool_hdl));
617990b4856Slling 	}
618990b4856Slling 
619990b4856Slling 	version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
6200a48a24eStimh 	if ((realprops = zpool_valid_proplist(zhp->zpool_hdl,
621990b4856Slling 	    zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) {
622990b4856Slling 		nvlist_free(nvl);
623990b4856Slling 		return (-1);
624990b4856Slling 	}
625990b4856Slling 
626990b4856Slling 	nvlist_free(nvl);
627990b4856Slling 	nvl = realprops;
628990b4856Slling 
629990b4856Slling 	/*
630990b4856Slling 	 * Execute the corresponding ioctl() to set this property.
631990b4856Slling 	 */
632990b4856Slling 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
633990b4856Slling 
634990b4856Slling 	if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
635990b4856Slling 		nvlist_free(nvl);
636990b4856Slling 		return (-1);
637990b4856Slling 	}
638990b4856Slling 
639990b4856Slling 	ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc);
640990b4856Slling 
641990b4856Slling 	zcmd_free_nvlists(&zc);
642990b4856Slling 	nvlist_free(nvl);
643990b4856Slling 
644990b4856Slling 	if (ret)
645990b4856Slling 		(void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf);
646990b4856Slling 	else
647990b4856Slling 		(void) zpool_props_refresh(zhp);
648990b4856Slling 
649990b4856Slling 	return (ret);
650990b4856Slling }
651990b4856Slling 
652990b4856Slling int
653990b4856Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp)
654990b4856Slling {
655990b4856Slling 	libzfs_handle_t *hdl = zhp->zpool_hdl;
656990b4856Slling 	zprop_list_t *entry;
657990b4856Slling 	char buf[ZFS_MAXPROPLEN];
658990b4856Slling 
659990b4856Slling 	if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0)
660990b4856Slling 		return (-1);
661990b4856Slling 
662990b4856Slling 	for (entry = *plp; entry != NULL; entry = entry->pl_next) {
663990b4856Slling 
664990b4856Slling 		if (entry->pl_fixed)
665990b4856Slling 			continue;
666990b4856Slling 
667990b4856Slling 		if (entry->pl_prop != ZPROP_INVAL &&
668990b4856Slling 		    zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf),
669990b4856Slling 		    NULL) == 0) {
670990b4856Slling 			if (strlen(buf) > entry->pl_width)
671990b4856Slling 				entry->pl_width = strlen(buf);
672990b4856Slling 		}
673990b4856Slling 	}
674990b4856Slling 
675990b4856Slling 	return (0);
676990b4856Slling }
677990b4856Slling 
678990b4856Slling 
679573ca77eSGeorge Wilson /*
680573ca77eSGeorge Wilson  * Don't start the slice at the default block of 34; many storage
681573ca77eSGeorge Wilson  * devices will use a stripe width of 128k, so start there instead.
682573ca77eSGeorge Wilson  */
683573ca77eSGeorge Wilson #define	NEW_START_BLOCK	256
684573ca77eSGeorge Wilson 
685fa9e4066Sahrens /*
686fa9e4066Sahrens  * Validate the given pool name, optionally putting an extended error message in
687fa9e4066Sahrens  * 'buf'.
688fa9e4066Sahrens  */
689e7cbe64fSgw boolean_t
69099653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool)
691fa9e4066Sahrens {
692fa9e4066Sahrens 	namecheck_err_t why;
693fa9e4066Sahrens 	char what;
694b468a217Seschrock 	int ret;
695b468a217Seschrock 
696b468a217Seschrock 	ret = pool_namecheck(pool, &why, &what);
697b468a217Seschrock 
698b468a217Seschrock 	/*
699b468a217Seschrock 	 * The rules for reserved pool names were extended at a later point.
700b468a217Seschrock 	 * But we need to support users with existing pools that may now be
701b468a217Seschrock 	 * invalid.  So we only check for this expanded set of names during a
702b468a217Seschrock 	 * create (or import), and only in userland.
703b468a217Seschrock 	 */
704b468a217Seschrock 	if (ret == 0 && !isopen &&
705b468a217Seschrock 	    (strncmp(pool, "mirror", 6) == 0 ||
706b468a217Seschrock 	    strncmp(pool, "raidz", 5) == 0 ||
7078654d025Sperrin 	    strncmp(pool, "spare", 5) == 0 ||
7088654d025Sperrin 	    strcmp(pool, "log") == 0)) {
709e7cbe64fSgw 		if (hdl != NULL)
710e7cbe64fSgw 			zfs_error_aux(hdl,
711e7cbe64fSgw 			    dgettext(TEXT_DOMAIN, "name is reserved"));
71299653d4eSeschrock 		return (B_FALSE);
713b468a217Seschrock 	}
714b468a217Seschrock 
715fa9e4066Sahrens 
716b468a217Seschrock 	if (ret != 0) {
71799653d4eSeschrock 		if (hdl != NULL) {
718fa9e4066Sahrens 			switch (why) {
719b81d61a6Slling 			case NAME_ERR_TOOLONG:
72099653d4eSeschrock 				zfs_error_aux(hdl,
721b81d61a6Slling 				    dgettext(TEXT_DOMAIN, "name is too long"));
722b81d61a6Slling 				break;
723b81d61a6Slling 
724fa9e4066Sahrens 			case NAME_ERR_INVALCHAR:
72599653d4eSeschrock 				zfs_error_aux(hdl,
726fa9e4066Sahrens 				    dgettext(TEXT_DOMAIN, "invalid character "
727fa9e4066Sahrens 				    "'%c' in pool name"), what);
728fa9e4066Sahrens 				break;
729fa9e4066Sahrens 
730fa9e4066Sahrens 			case NAME_ERR_NOLETTER:
73199653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
73299653d4eSeschrock 				    "name must begin with a letter"));
733fa9e4066Sahrens 				break;
734fa9e4066Sahrens 
735fa9e4066Sahrens 			case NAME_ERR_RESERVED:
73699653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
73799653d4eSeschrock 				    "name is reserved"));
738fa9e4066Sahrens 				break;
739fa9e4066Sahrens 
740fa9e4066Sahrens 			case NAME_ERR_DISKLIKE:
74199653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
74299653d4eSeschrock 				    "pool name is reserved"));
743fa9e4066Sahrens 				break;
7445ad82045Snd 
7455ad82045Snd 			case NAME_ERR_LEADING_SLASH:
7465ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
7475ad82045Snd 				    "leading slash in name"));
7485ad82045Snd 				break;
7495ad82045Snd 
7505ad82045Snd 			case NAME_ERR_EMPTY_COMPONENT:
7515ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
7525ad82045Snd 				    "empty component in name"));
7535ad82045Snd 				break;
7545ad82045Snd 
7555ad82045Snd 			case NAME_ERR_TRAILING_SLASH:
7565ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
7575ad82045Snd 				    "trailing slash in name"));
7585ad82045Snd 				break;
7595ad82045Snd 
7605ad82045Snd 			case NAME_ERR_MULTIPLE_AT:
7615ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
7625ad82045Snd 				    "multiple '@' delimiters in name"));
7635ad82045Snd 				break;
7645ad82045Snd 
765fa9e4066Sahrens 			}
766fa9e4066Sahrens 		}
76799653d4eSeschrock 		return (B_FALSE);
768fa9e4066Sahrens 	}
769fa9e4066Sahrens 
77099653d4eSeschrock 	return (B_TRUE);
771fa9e4066Sahrens }
772fa9e4066Sahrens 
773fa9e4066Sahrens /*
774fa9e4066Sahrens  * Open a handle to the given pool, even if the pool is currently in the FAULTED
775fa9e4066Sahrens  * state.
776fa9e4066Sahrens  */
777fa9e4066Sahrens zpool_handle_t *
77899653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool)
779fa9e4066Sahrens {
780fa9e4066Sahrens 	zpool_handle_t *zhp;
78194de1d4cSeschrock 	boolean_t missing;
782fa9e4066Sahrens 
783fa9e4066Sahrens 	/*
784fa9e4066Sahrens 	 * Make sure the pool name is valid.
785fa9e4066Sahrens 	 */
78699653d4eSeschrock 	if (!zpool_name_valid(hdl, B_TRUE, pool)) {
787ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_INVALIDNAME,
78899653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"),
78999653d4eSeschrock 		    pool);
790fa9e4066Sahrens 		return (NULL);
791fa9e4066Sahrens 	}
792fa9e4066Sahrens 
79399653d4eSeschrock 	if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
79499653d4eSeschrock 		return (NULL);
795fa9e4066Sahrens 
79699653d4eSeschrock 	zhp->zpool_hdl = hdl;
797fa9e4066Sahrens 	(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
798fa9e4066Sahrens 
79994de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0) {
80094de1d4cSeschrock 		zpool_close(zhp);
80194de1d4cSeschrock 		return (NULL);
80294de1d4cSeschrock 	}
80394de1d4cSeschrock 
80494de1d4cSeschrock 	if (missing) {
805990b4856Slling 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool"));
806ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_NOENT,
807990b4856Slling 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool);
80894de1d4cSeschrock 		zpool_close(zhp);
80994de1d4cSeschrock 		return (NULL);
810fa9e4066Sahrens 	}
811fa9e4066Sahrens 
812fa9e4066Sahrens 	return (zhp);
813fa9e4066Sahrens }
814fa9e4066Sahrens 
815fa9e4066Sahrens /*
816fa9e4066Sahrens  * Like the above, but silent on error.  Used when iterating over pools (because
817fa9e4066Sahrens  * the configuration cache may be out of date).
818fa9e4066Sahrens  */
81994de1d4cSeschrock int
82094de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret)
821fa9e4066Sahrens {
822fa9e4066Sahrens 	zpool_handle_t *zhp;
82394de1d4cSeschrock 	boolean_t missing;
824fa9e4066Sahrens 
82594de1d4cSeschrock 	if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
82694de1d4cSeschrock 		return (-1);
827fa9e4066Sahrens 
82899653d4eSeschrock 	zhp->zpool_hdl = hdl;
829fa9e4066Sahrens 	(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
830fa9e4066Sahrens 
83194de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0) {
83294de1d4cSeschrock 		zpool_close(zhp);
83394de1d4cSeschrock 		return (-1);
834fa9e4066Sahrens 	}
835fa9e4066Sahrens 
83694de1d4cSeschrock 	if (missing) {
83794de1d4cSeschrock 		zpool_close(zhp);
83894de1d4cSeschrock 		*ret = NULL;
83994de1d4cSeschrock 		return (0);
84094de1d4cSeschrock 	}
84194de1d4cSeschrock 
84294de1d4cSeschrock 	*ret = zhp;
84394de1d4cSeschrock 	return (0);
844fa9e4066Sahrens }
845fa9e4066Sahrens 
846fa9e4066Sahrens /*
847fa9e4066Sahrens  * Similar to zpool_open_canfail(), but refuses to open pools in the faulted
848fa9e4066Sahrens  * state.
849fa9e4066Sahrens  */
850fa9e4066Sahrens zpool_handle_t *
85199653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool)
852fa9e4066Sahrens {
853fa9e4066Sahrens 	zpool_handle_t *zhp;
854fa9e4066Sahrens 
85599653d4eSeschrock 	if ((zhp = zpool_open_canfail(hdl, pool)) == NULL)
856fa9e4066Sahrens 		return (NULL);
857fa9e4066Sahrens 
858fa9e4066Sahrens 	if (zhp->zpool_state == POOL_STATE_UNAVAIL) {
859ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL,
86099653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name);
861fa9e4066Sahrens 		zpool_close(zhp);
862fa9e4066Sahrens 		return (NULL);
863fa9e4066Sahrens 	}
864fa9e4066Sahrens 
865fa9e4066Sahrens 	return (zhp);
866fa9e4066Sahrens }
867fa9e4066Sahrens 
868fa9e4066Sahrens /*
869fa9e4066Sahrens  * Close the handle.  Simply frees the memory associated with the handle.
870fa9e4066Sahrens  */
871fa9e4066Sahrens void
872fa9e4066Sahrens zpool_close(zpool_handle_t *zhp)
873fa9e4066Sahrens {
874fa9e4066Sahrens 	if (zhp->zpool_config)
875fa9e4066Sahrens 		nvlist_free(zhp->zpool_config);
876088e9d47Seschrock 	if (zhp->zpool_old_config)
877088e9d47Seschrock 		nvlist_free(zhp->zpool_old_config);
878b1b8ab34Slling 	if (zhp->zpool_props)
879b1b8ab34Slling 		nvlist_free(zhp->zpool_props);
880fa9e4066Sahrens 	free(zhp);
881fa9e4066Sahrens }
882fa9e4066Sahrens 
883fa9e4066Sahrens /*
884fa9e4066Sahrens  * Return the name of the pool.
885fa9e4066Sahrens  */
886fa9e4066Sahrens const char *
887fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp)
888fa9e4066Sahrens {
889fa9e4066Sahrens 	return (zhp->zpool_name);
890fa9e4066Sahrens }
891fa9e4066Sahrens 
892fa9e4066Sahrens 
893fa9e4066Sahrens /*
894fa9e4066Sahrens  * Return the state of the pool (ACTIVE or UNAVAILABLE)
895fa9e4066Sahrens  */
896fa9e4066Sahrens int
897fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp)
898fa9e4066Sahrens {
899fa9e4066Sahrens 	return (zhp->zpool_state);
900fa9e4066Sahrens }
901fa9e4066Sahrens 
902fa9e4066Sahrens /*
903fa9e4066Sahrens  * Create the named pool, using the provided vdev list.  It is assumed
904fa9e4066Sahrens  * that the consumer has already validated the contents of the nvlist, so we
905fa9e4066Sahrens  * don't have to worry about error semantics.
906fa9e4066Sahrens  */
907fa9e4066Sahrens int
90899653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
9090a48a24eStimh     nvlist_t *props, nvlist_t *fsprops)
910fa9e4066Sahrens {
911fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
9120a48a24eStimh 	nvlist_t *zc_fsprops = NULL;
9130a48a24eStimh 	nvlist_t *zc_props = NULL;
91499653d4eSeschrock 	char msg[1024];
915990b4856Slling 	char *altroot;
9160a48a24eStimh 	int ret = -1;
917fa9e4066Sahrens 
91899653d4eSeschrock 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
91999653d4eSeschrock 	    "cannot create '%s'"), pool);
920fa9e4066Sahrens 
92199653d4eSeschrock 	if (!zpool_name_valid(hdl, B_FALSE, pool))
92299653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
923fa9e4066Sahrens 
924351420b3Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
925990b4856Slling 		return (-1);
926fa9e4066Sahrens 
9270a48a24eStimh 	if (props) {
9280a48a24eStimh 		if ((zc_props = zpool_valid_proplist(hdl, pool, props,
9290a48a24eStimh 		    SPA_VERSION_1, B_TRUE, msg)) == NULL) {
9300a48a24eStimh 			goto create_failed;
9310a48a24eStimh 		}
9320a48a24eStimh 	}
93399653d4eSeschrock 
9340a48a24eStimh 	if (fsprops) {
9350a48a24eStimh 		uint64_t zoned;
9360a48a24eStimh 		char *zonestr;
9370a48a24eStimh 
9380a48a24eStimh 		zoned = ((nvlist_lookup_string(fsprops,
9390a48a24eStimh 		    zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) &&
9400a48a24eStimh 		    strcmp(zonestr, "on") == 0);
9410a48a24eStimh 
9420a48a24eStimh 		if ((zc_fsprops = zfs_valid_proplist(hdl,
9430a48a24eStimh 		    ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) {
9440a48a24eStimh 			goto create_failed;
9450a48a24eStimh 		}
9460a48a24eStimh 		if (!zc_props &&
9470a48a24eStimh 		    (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) {
9480a48a24eStimh 			goto create_failed;
9490a48a24eStimh 		}
9500a48a24eStimh 		if (nvlist_add_nvlist(zc_props,
9510a48a24eStimh 		    ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) {
9520a48a24eStimh 			goto create_failed;
9530a48a24eStimh 		}
954351420b3Slling 	}
955fa9e4066Sahrens 
9560a48a24eStimh 	if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
9570a48a24eStimh 		goto create_failed;
9580a48a24eStimh 
959990b4856Slling 	(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
960fa9e4066Sahrens 
9610a48a24eStimh 	if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) {
962351420b3Slling 
963e9dbad6fSeschrock 		zcmd_free_nvlists(&zc);
9640a48a24eStimh 		nvlist_free(zc_props);
9650a48a24eStimh 		nvlist_free(zc_fsprops);
966fa9e4066Sahrens 
96799653d4eSeschrock 		switch (errno) {
968fa9e4066Sahrens 		case EBUSY:
969fa9e4066Sahrens 			/*
970fa9e4066Sahrens 			 * This can happen if the user has specified the same
971fa9e4066Sahrens 			 * device multiple times.  We can't reliably detect this
972fa9e4066Sahrens 			 * until we try to add it and see we already have a
973fa9e4066Sahrens 			 * label.
974fa9e4066Sahrens 			 */
97599653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
97699653d4eSeschrock 			    "one or more vdevs refer to the same device"));
97799653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
978fa9e4066Sahrens 
979fa9e4066Sahrens 		case EOVERFLOW:
980fa9e4066Sahrens 			/*
98199653d4eSeschrock 			 * This occurs when one of the devices is below
982fa9e4066Sahrens 			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
983fa9e4066Sahrens 			 * device was the problem device since there's no
984fa9e4066Sahrens 			 * reliable way to determine device size from userland.
985fa9e4066Sahrens 			 */
986fa9e4066Sahrens 			{
987fa9e4066Sahrens 				char buf[64];
988fa9e4066Sahrens 
989fa9e4066Sahrens 				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
990fa9e4066Sahrens 
99199653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
99299653d4eSeschrock 				    "one or more devices is less than the "
99399653d4eSeschrock 				    "minimum size (%s)"), buf);
994fa9e4066Sahrens 			}
99599653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
996fa9e4066Sahrens 
997fa9e4066Sahrens 		case ENOSPC:
99899653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
99999653d4eSeschrock 			    "one or more devices is out of space"));
100099653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
1001fa9e4066Sahrens 
1002fa94a07fSbrendan 		case ENOTBLK:
1003fa94a07fSbrendan 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1004fa94a07fSbrendan 			    "cache device must be a disk or disk slice"));
1005fa94a07fSbrendan 			return (zfs_error(hdl, EZFS_BADDEV, msg));
1006fa94a07fSbrendan 
1007fa9e4066Sahrens 		default:
100899653d4eSeschrock 			return (zpool_standard_error(hdl, errno, msg));
1009fa9e4066Sahrens 		}
1010fa9e4066Sahrens 	}
1011fa9e4066Sahrens 
1012fa9e4066Sahrens 	/*
1013fa9e4066Sahrens 	 * If this is an alternate root pool, then we automatically set the
1014e9dbad6fSeschrock 	 * mountpoint of the root dataset to be '/'.
1015fa9e4066Sahrens 	 */
1016990b4856Slling 	if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT),
1017990b4856Slling 	    &altroot) == 0) {
1018fa9e4066Sahrens 		zfs_handle_t *zhp;
1019fa9e4066Sahrens 
1020990b4856Slling 		verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL);
1021e9dbad6fSeschrock 		verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1022e9dbad6fSeschrock 		    "/") == 0);
1023fa9e4066Sahrens 
1024fa9e4066Sahrens 		zfs_close(zhp);
1025fa9e4066Sahrens 	}
1026fa9e4066Sahrens 
10270a48a24eStimh create_failed:
1028351420b3Slling 	zcmd_free_nvlists(&zc);
10290a48a24eStimh 	nvlist_free(zc_props);
10300a48a24eStimh 	nvlist_free(zc_fsprops);
10310a48a24eStimh 	return (ret);
1032fa9e4066Sahrens }
1033fa9e4066Sahrens 
1034fa9e4066Sahrens /*
1035fa9e4066Sahrens  * Destroy the given pool.  It is up to the caller to ensure that there are no
1036fa9e4066Sahrens  * datasets left in the pool.
1037fa9e4066Sahrens  */
1038fa9e4066Sahrens int
1039fa9e4066Sahrens zpool_destroy(zpool_handle_t *zhp)
1040fa9e4066Sahrens {
1041fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1042fa9e4066Sahrens 	zfs_handle_t *zfp = NULL;
104399653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
104499653d4eSeschrock 	char msg[1024];
1045fa9e4066Sahrens 
1046fa9e4066Sahrens 	if (zhp->zpool_state == POOL_STATE_ACTIVE &&
104799653d4eSeschrock 	    (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name,
104899653d4eSeschrock 	    ZFS_TYPE_FILESYSTEM)) == NULL)
1049fa9e4066Sahrens 		return (-1);
1050fa9e4066Sahrens 
1051fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1052fa9e4066Sahrens 
1053ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
105499653d4eSeschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
105599653d4eSeschrock 		    "cannot destroy '%s'"), zhp->zpool_name);
1056fa9e4066Sahrens 
105799653d4eSeschrock 		if (errno == EROFS) {
105899653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
105999653d4eSeschrock 			    "one or more devices is read only"));
106099653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
106199653d4eSeschrock 		} else {
106299653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, msg);
1063fa9e4066Sahrens 		}
1064fa9e4066Sahrens 
1065fa9e4066Sahrens 		if (zfp)
1066fa9e4066Sahrens 			zfs_close(zfp);
1067fa9e4066Sahrens 		return (-1);
1068fa9e4066Sahrens 	}
1069fa9e4066Sahrens 
1070fa9e4066Sahrens 	if (zfp) {
1071fa9e4066Sahrens 		remove_mountpoint(zfp);
1072fa9e4066Sahrens 		zfs_close(zfp);
1073fa9e4066Sahrens 	}
1074fa9e4066Sahrens 
1075fa9e4066Sahrens 	return (0);
1076fa9e4066Sahrens }
1077fa9e4066Sahrens 
1078fa9e4066Sahrens /*
1079fa9e4066Sahrens  * Add the given vdevs to the pool.  The caller must have already performed the
1080fa9e4066Sahrens  * necessary verification to ensure that the vdev specification is well-formed.
1081fa9e4066Sahrens  */
1082fa9e4066Sahrens int
1083fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
1084fa9e4066Sahrens {
1085e9dbad6fSeschrock 	zfs_cmd_t zc = { 0 };
108699653d4eSeschrock 	int ret;
108799653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
108899653d4eSeschrock 	char msg[1024];
1089fa94a07fSbrendan 	nvlist_t **spares, **l2cache;
1090fa94a07fSbrendan 	uint_t nspares, nl2cache;
109199653d4eSeschrock 
109299653d4eSeschrock 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
109399653d4eSeschrock 	    "cannot add to '%s'"), zhp->zpool_name);
109499653d4eSeschrock 
1095fa94a07fSbrendan 	if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
1096fa94a07fSbrendan 	    SPA_VERSION_SPARES &&
109799653d4eSeschrock 	    nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
109899653d4eSeschrock 	    &spares, &nspares) == 0) {
109999653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
110099653d4eSeschrock 		    "upgraded to add hot spares"));
110199653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
110299653d4eSeschrock 	}
1103fa9e4066Sahrens 
1104b5b76fecSGeorge Wilson 	if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot,
1105b5b76fecSGeorge Wilson 	    ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) {
1106b5b76fecSGeorge Wilson 		uint64_t s;
1107b5b76fecSGeorge Wilson 
1108b5b76fecSGeorge Wilson 		for (s = 0; s < nspares; s++) {
1109b5b76fecSGeorge Wilson 			char *path;
1110b5b76fecSGeorge Wilson 
1111b5b76fecSGeorge Wilson 			if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH,
1112b5b76fecSGeorge Wilson 			    &path) == 0 && pool_uses_efi(spares[s])) {
1113b5b76fecSGeorge Wilson 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1114b5b76fecSGeorge Wilson 				    "device '%s' contains an EFI label and "
1115b5b76fecSGeorge Wilson 				    "cannot be used on root pools."),
111688ecc943SGeorge Wilson 				    zpool_vdev_name(hdl, NULL, spares[s],
111788ecc943SGeorge Wilson 				    B_FALSE));
1118b5b76fecSGeorge Wilson 				return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
1119b5b76fecSGeorge Wilson 			}
1120b5b76fecSGeorge Wilson 		}
1121b5b76fecSGeorge Wilson 	}
1122b5b76fecSGeorge Wilson 
1123fa94a07fSbrendan 	if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
1124fa94a07fSbrendan 	    SPA_VERSION_L2CACHE &&
1125fa94a07fSbrendan 	    nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
1126fa94a07fSbrendan 	    &l2cache, &nl2cache) == 0) {
1127fa94a07fSbrendan 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
1128fa94a07fSbrendan 		    "upgraded to add cache devices"));
1129fa94a07fSbrendan 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
1130fa94a07fSbrendan 	}
1131fa94a07fSbrendan 
1132990b4856Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
113399653d4eSeschrock 		return (-1);
1134fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1135fa9e4066Sahrens 
1136ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) {
1137fa9e4066Sahrens 		switch (errno) {
1138fa9e4066Sahrens 		case EBUSY:
1139fa9e4066Sahrens 			/*
1140fa9e4066Sahrens 			 * This can happen if the user has specified the same
1141fa9e4066Sahrens 			 * device multiple times.  We can't reliably detect this
1142fa9e4066Sahrens 			 * until we try to add it and see we already have a
1143fa9e4066Sahrens 			 * label.
1144fa9e4066Sahrens 			 */
114599653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
114699653d4eSeschrock 			    "one or more vdevs refer to the same device"));
114799653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
1148fa9e4066Sahrens 			break;
1149fa9e4066Sahrens 
1150fa9e4066Sahrens 		case EOVERFLOW:
1151fa9e4066Sahrens 			/*
1152fa9e4066Sahrens 			 * This occurrs when one of the devices is below
1153fa9e4066Sahrens 			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
1154fa9e4066Sahrens 			 * device was the problem device since there's no
1155fa9e4066Sahrens 			 * reliable way to determine device size from userland.
1156fa9e4066Sahrens 			 */
1157fa9e4066Sahrens 			{
1158fa9e4066Sahrens 				char buf[64];
1159fa9e4066Sahrens 
1160fa9e4066Sahrens 				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
1161fa9e4066Sahrens 
116299653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
116399653d4eSeschrock 				    "device is less than the minimum "
116499653d4eSeschrock 				    "size (%s)"), buf);
1165fa9e4066Sahrens 			}
116699653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
116799653d4eSeschrock 			break;
116899653d4eSeschrock 
116999653d4eSeschrock 		case ENOTSUP:
117099653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
11718654d025Sperrin 			    "pool must be upgraded to add these vdevs"));
117299653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADVERSION, msg);
1173fa9e4066Sahrens 			break;
1174fa9e4066Sahrens 
1175b1b8ab34Slling 		case EDOM:
1176b1b8ab34Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
11778654d025Sperrin 			    "root pool can not have multiple vdevs"
11788654d025Sperrin 			    " or separate logs"));
1179b1b8ab34Slling 			(void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg);
1180b1b8ab34Slling 			break;
1181b1b8ab34Slling 
1182fa94a07fSbrendan 		case ENOTBLK:
1183fa94a07fSbrendan 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1184fa94a07fSbrendan 			    "cache device must be a disk or disk slice"));
1185fa94a07fSbrendan 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
1186fa94a07fSbrendan 			break;
1187fa94a07fSbrendan 
1188fa9e4066Sahrens 		default:
118999653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, msg);
1190fa9e4066Sahrens 		}
1191fa9e4066Sahrens 
119299653d4eSeschrock 		ret = -1;
119399653d4eSeschrock 	} else {
119499653d4eSeschrock 		ret = 0;
1195fa9e4066Sahrens 	}
1196fa9e4066Sahrens 
1197e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
1198fa9e4066Sahrens 
119999653d4eSeschrock 	return (ret);
1200fa9e4066Sahrens }
1201fa9e4066Sahrens 
1202fa9e4066Sahrens /*
1203fa9e4066Sahrens  * Exports the pool from the system.  The caller must ensure that there are no
1204fa9e4066Sahrens  * mounted datasets in the pool.
1205fa9e4066Sahrens  */
1206fa9e4066Sahrens int
1207394ab0cbSGeorge Wilson zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce)
1208fa9e4066Sahrens {
1209fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
121089a89ebfSlling 	char msg[1024];
1211fa9e4066Sahrens 
121289a89ebfSlling 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
121389a89ebfSlling 	    "cannot export '%s'"), zhp->zpool_name);
121489a89ebfSlling 
1215fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
121689a89ebfSlling 	zc.zc_cookie = force;
1217394ab0cbSGeorge Wilson 	zc.zc_guid = hardforce;
121889a89ebfSlling 
121989a89ebfSlling 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
122089a89ebfSlling 		switch (errno) {
122189a89ebfSlling 		case EXDEV:
122289a89ebfSlling 			zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN,
122389a89ebfSlling 			    "use '-f' to override the following errors:\n"
122489a89ebfSlling 			    "'%s' has an active shared spare which could be"
122589a89ebfSlling 			    " used by other pools once '%s' is exported."),
122689a89ebfSlling 			    zhp->zpool_name, zhp->zpool_name);
122789a89ebfSlling 			return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE,
122889a89ebfSlling 			    msg));
122989a89ebfSlling 		default:
123089a89ebfSlling 			return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
123189a89ebfSlling 			    msg));
123289a89ebfSlling 		}
123389a89ebfSlling 	}
1234fa9e4066Sahrens 
1235fa9e4066Sahrens 	return (0);
1236fa9e4066Sahrens }
1237fa9e4066Sahrens 
1238394ab0cbSGeorge Wilson int
1239394ab0cbSGeorge Wilson zpool_export(zpool_handle_t *zhp, boolean_t force)
1240394ab0cbSGeorge Wilson {
1241394ab0cbSGeorge Wilson 	return (zpool_export_common(zhp, force, B_FALSE));
1242394ab0cbSGeorge Wilson }
1243394ab0cbSGeorge Wilson 
1244394ab0cbSGeorge Wilson int
1245394ab0cbSGeorge Wilson zpool_export_force(zpool_handle_t *zhp)
1246394ab0cbSGeorge Wilson {
1247394ab0cbSGeorge Wilson 	return (zpool_export_common(zhp, B_TRUE, B_TRUE));
1248394ab0cbSGeorge Wilson }
1249394ab0cbSGeorge Wilson 
1250468c413aSTim Haley static void
1251468c413aSTim Haley zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun,
1252468c413aSTim Haley     nvlist_t *rbi)
1253468c413aSTim Haley {
1254468c413aSTim Haley 	uint64_t rewindto;
1255468c413aSTim Haley 	int64_t loss = -1;
1256468c413aSTim Haley 	struct tm t;
1257468c413aSTim Haley 	char timestr[128];
1258468c413aSTim Haley 
1259468c413aSTim Haley 	if (!hdl->libzfs_printerr || rbi == NULL)
1260468c413aSTim Haley 		return;
1261468c413aSTim Haley 
1262468c413aSTim Haley 	if (nvlist_lookup_uint64(rbi, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
1263468c413aSTim Haley 		return;
1264468c413aSTim Haley 	(void) nvlist_lookup_int64(rbi, ZPOOL_CONFIG_REWIND_TIME, &loss);
1265468c413aSTim Haley 
1266468c413aSTim Haley 	if (localtime_r((time_t *)&rewindto, &t) != NULL &&
1267468c413aSTim Haley 	    strftime(timestr, 128, 0, &t) != 0) {
1268468c413aSTim Haley 		if (dryrun) {
1269468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1270468c413aSTim Haley 			    "Would be able to return %s "
1271468c413aSTim Haley 			    "to its state as of %s.\n"),
1272468c413aSTim Haley 			    name, timestr);
1273468c413aSTim Haley 		} else {
1274468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1275468c413aSTim Haley 			    "Pool %s returned to its state as of %s.\n"),
1276468c413aSTim Haley 			    name, timestr);
1277468c413aSTim Haley 		}
1278468c413aSTim Haley 		if (loss > 120) {
1279468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1280468c413aSTim Haley 			    "%s approximately %lld "),
1281468c413aSTim Haley 			    dryrun ? "Would discard" : "Discarded",
1282468c413aSTim Haley 			    (loss + 30) / 60);
1283468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1284468c413aSTim Haley 			    "minutes of transactions.\n"));
1285468c413aSTim Haley 		} else if (loss > 0) {
1286468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1287468c413aSTim Haley 			    "%s approximately %lld "),
1288468c413aSTim Haley 			    dryrun ? "Would discard" : "Discarded", loss);
1289468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1290468c413aSTim Haley 			    "seconds of transactions.\n"));
1291468c413aSTim Haley 		}
1292468c413aSTim Haley 	}
1293468c413aSTim Haley }
1294468c413aSTim Haley 
1295468c413aSTim Haley void
1296468c413aSTim Haley zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason,
1297468c413aSTim Haley     nvlist_t *config)
1298468c413aSTim Haley {
1299468c413aSTim Haley 	int64_t loss = -1;
1300468c413aSTim Haley 	uint64_t edata = UINT64_MAX;
1301468c413aSTim Haley 	uint64_t rewindto;
1302468c413aSTim Haley 	struct tm t;
1303468c413aSTim Haley 	char timestr[128];
1304468c413aSTim Haley 
1305468c413aSTim Haley 	if (!hdl->libzfs_printerr)
1306468c413aSTim Haley 		return;
1307468c413aSTim Haley 
1308468c413aSTim Haley 	if (reason >= 0)
1309468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN, "action: "));
1310468c413aSTim Haley 	else
1311468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN, "\t"));
1312468c413aSTim Haley 
1313468c413aSTim Haley 	/* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */
1314468c413aSTim Haley 	if (nvlist_lookup_uint64(config,
1315468c413aSTim Haley 	    ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
1316468c413aSTim Haley 		goto no_info;
1317468c413aSTim Haley 
1318468c413aSTim Haley 	(void) nvlist_lookup_int64(config, ZPOOL_CONFIG_REWIND_TIME, &loss);
1319468c413aSTim Haley 	(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_LOAD_DATA_ERRORS,
1320468c413aSTim Haley 	    &edata);
1321468c413aSTim Haley 
1322468c413aSTim Haley 	(void) printf(dgettext(TEXT_DOMAIN,
1323468c413aSTim Haley 	    "Recovery is possible, but will result in some data loss.\n"));
1324468c413aSTim Haley 
1325468c413aSTim Haley 	if (localtime_r((time_t *)&rewindto, &t) != NULL &&
1326468c413aSTim Haley 	    strftime(timestr, 128, 0, &t) != 0) {
1327468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN,
1328468c413aSTim Haley 		    "\tReturning the pool to its state as of %s\n"
1329468c413aSTim Haley 		    "\tshould correct the problem.  "),
1330468c413aSTim Haley 		    timestr);
1331468c413aSTim Haley 	} else {
1332468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN,
1333468c413aSTim Haley 		    "\tReverting the pool to an earlier state "
1334468c413aSTim Haley 		    "should correct the problem.\n\t"));
1335468c413aSTim Haley 	}
1336468c413aSTim Haley 
1337468c413aSTim Haley 	if (loss > 120) {
1338468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN,
1339468c413aSTim Haley 		    "Approximately %lld minutes of data\n"
1340468c413aSTim Haley 		    "\tmust be discarded, irreversibly.  "), (loss + 30) / 60);
1341468c413aSTim Haley 	} else if (loss > 0) {
1342468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN,
1343468c413aSTim Haley 		    "Approximately %lld seconds of data\n"
1344468c413aSTim Haley 		    "\tmust be discarded, irreversibly.  "), loss);
1345468c413aSTim Haley 	}
1346468c413aSTim Haley 	if (edata != 0 && edata != UINT64_MAX) {
1347468c413aSTim Haley 		if (edata == 1) {
1348468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1349468c413aSTim Haley 			    "After rewind, at least\n"
1350468c413aSTim Haley 			    "\tone persistent user-data error will remain.  "));
1351468c413aSTim Haley 		} else {
1352468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1353468c413aSTim Haley 			    "After rewind, several\n"
1354468c413aSTim Haley 			    "\tpersistent user-data errors will remain.  "));
1355468c413aSTim Haley 		}
1356468c413aSTim Haley 	}
1357468c413aSTim Haley 	(void) printf(dgettext(TEXT_DOMAIN,
1358468c413aSTim Haley 	    "Recovery can be\n\tattempted by executing "
1359468c413aSTim Haley 	    "'zpool %s -F %s'.  "), reason >= 0 ? "clear" : "import", name);
1360468c413aSTim Haley 
1361468c413aSTim Haley 	(void) printf(dgettext(TEXT_DOMAIN,
1362468c413aSTim Haley 	    "A scrub of the pool\n"
1363468c413aSTim Haley 	    "\tis strongly recommended after recovery.\n"));
1364468c413aSTim Haley 	return;
1365468c413aSTim Haley 
1366468c413aSTim Haley no_info:
1367468c413aSTim Haley 	(void) printf(dgettext(TEXT_DOMAIN,
1368468c413aSTim Haley 	    "Destroy and re-create the pool from\n\ta backup source.\n"));
1369468c413aSTim Haley }
1370468c413aSTim Haley 
1371fa9e4066Sahrens /*
1372990b4856Slling  * zpool_import() is a contracted interface. Should be kept the same
1373990b4856Slling  * if possible.
1374990b4856Slling  *
1375990b4856Slling  * Applications should use zpool_import_props() to import a pool with
1376990b4856Slling  * new properties value to be set.
1377fa9e4066Sahrens  */
1378fa9e4066Sahrens int
137999653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
1380990b4856Slling     char *altroot)
1381990b4856Slling {
1382990b4856Slling 	nvlist_t *props = NULL;
1383990b4856Slling 	int ret;
1384990b4856Slling 
1385990b4856Slling 	if (altroot != NULL) {
1386990b4856Slling 		if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
1387990b4856Slling 			return (zfs_error_fmt(hdl, EZFS_NOMEM,
1388990b4856Slling 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1389990b4856Slling 			    newname));
1390990b4856Slling 		}
1391990b4856Slling 
1392990b4856Slling 		if (nvlist_add_string(props,
1393352d8027SGeorge Wilson 		    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 ||
1394352d8027SGeorge Wilson 		    nvlist_add_string(props,
1395352d8027SGeorge Wilson 		    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) {
1396990b4856Slling 			nvlist_free(props);
1397990b4856Slling 			return (zfs_error_fmt(hdl, EZFS_NOMEM,
1398990b4856Slling 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1399990b4856Slling 			    newname));
1400990b4856Slling 		}
1401990b4856Slling 	}
1402990b4856Slling 
1403c5904d13Seschrock 	ret = zpool_import_props(hdl, config, newname, props, B_FALSE);
1404990b4856Slling 	if (props)
1405990b4856Slling 		nvlist_free(props);
1406990b4856Slling 	return (ret);
1407990b4856Slling }
1408990b4856Slling 
1409990b4856Slling /*
1410990b4856Slling  * Import the given pool using the known configuration and a list of
1411990b4856Slling  * properties to be set. The configuration should have come from
1412990b4856Slling  * zpool_find_import(). The 'newname' parameters control whether the pool
1413990b4856Slling  * is imported with a different name.
1414990b4856Slling  */
1415990b4856Slling int
1416990b4856Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
1417c5904d13Seschrock     nvlist_t *props, boolean_t importfaulted)
1418fa9e4066Sahrens {
1419e9dbad6fSeschrock 	zfs_cmd_t zc = { 0 };
1420468c413aSTim Haley 	zpool_rewind_policy_t policy;
1421468c413aSTim Haley 	nvlist_t *nvi = NULL;
1422fa9e4066Sahrens 	char *thename;
1423fa9e4066Sahrens 	char *origname;
1424468c413aSTim Haley 	uint64_t returned_size;
1425fa9e4066Sahrens 	int ret;
1426990b4856Slling 	char errbuf[1024];
1427fa9e4066Sahrens 
1428fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1429fa9e4066Sahrens 	    &origname) == 0);
1430fa9e4066Sahrens 
1431990b4856Slling 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
1432990b4856Slling 	    "cannot import pool '%s'"), origname);
1433990b4856Slling 
1434fa9e4066Sahrens 	if (newname != NULL) {
143599653d4eSeschrock 		if (!zpool_name_valid(hdl, B_FALSE, newname))
1436ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_INVALIDNAME,
143799653d4eSeschrock 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
143899653d4eSeschrock 			    newname));
1439fa9e4066Sahrens 		thename = (char *)newname;
1440fa9e4066Sahrens 	} else {
1441fa9e4066Sahrens 		thename = origname;
1442fa9e4066Sahrens 	}
1443fa9e4066Sahrens 
1444990b4856Slling 	if (props) {
1445990b4856Slling 		uint64_t version;
1446fa9e4066Sahrens 
1447990b4856Slling 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
1448990b4856Slling 		    &version) == 0);
1449fa9e4066Sahrens 
14500a48a24eStimh 		if ((props = zpool_valid_proplist(hdl, origname,
1451351420b3Slling 		    props, version, B_TRUE, errbuf)) == NULL) {
1452990b4856Slling 			return (-1);
1453351420b3Slling 		} else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
1454351420b3Slling 			nvlist_free(props);
1455990b4856Slling 			return (-1);
1456351420b3Slling 		}
1457990b4856Slling 	}
1458990b4856Slling 
1459990b4856Slling 	(void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name));
1460fa9e4066Sahrens 
1461fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1462ea8dc4b6Seschrock 	    &zc.zc_guid) == 0);
1463fa9e4066Sahrens 
1464351420b3Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) {
1465351420b3Slling 		nvlist_free(props);
146699653d4eSeschrock 		return (-1);
1467351420b3Slling 	}
1468468c413aSTim Haley 	returned_size =  zc.zc_nvlist_conf_size + 512;
1469468c413aSTim Haley 	if (zcmd_alloc_dst_nvlist(hdl, &zc, returned_size) != 0) {
1470468c413aSTim Haley 		nvlist_free(props);
1471468c413aSTim Haley 		return (-1);
1472468c413aSTim Haley 	}
1473fa9e4066Sahrens 
1474c5904d13Seschrock 	zc.zc_cookie = (uint64_t)importfaulted;
1475fa9e4066Sahrens 	ret = 0;
1476ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) {
1477fa9e4066Sahrens 		char desc[1024];
1478468c413aSTim Haley 
1479468c413aSTim Haley 		(void) zcmd_read_dst_nvlist(hdl, &zc, &nvi);
1480468c413aSTim Haley 		zpool_get_rewind_policy(config, &policy);
1481468c413aSTim Haley 		/*
1482468c413aSTim Haley 		 * Dry-run failed, but we print out what success
1483468c413aSTim Haley 		 * looks like if we found a best txg
1484468c413aSTim Haley 		 */
1485468c413aSTim Haley 		if ((policy.zrp_request & ZPOOL_TRY_REWIND) && nvi) {
1486468c413aSTim Haley 			zpool_rewind_exclaim(hdl, newname ? origname : thename,
1487468c413aSTim Haley 			    B_TRUE, nvi);
1488468c413aSTim Haley 			nvlist_free(nvi);
1489468c413aSTim Haley 			return (-1);
1490468c413aSTim Haley 		}
1491468c413aSTim Haley 
1492fa9e4066Sahrens 		if (newname == NULL)
1493fa9e4066Sahrens 			(void) snprintf(desc, sizeof (desc),
1494fa9e4066Sahrens 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1495fa9e4066Sahrens 			    thename);
1496fa9e4066Sahrens 		else
1497fa9e4066Sahrens 			(void) snprintf(desc, sizeof (desc),
1498fa9e4066Sahrens 			    dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"),
1499fa9e4066Sahrens 			    origname, thename);
1500fa9e4066Sahrens 
1501fa9e4066Sahrens 		switch (errno) {
1502ea8dc4b6Seschrock 		case ENOTSUP:
1503ea8dc4b6Seschrock 			/*
1504ea8dc4b6Seschrock 			 * Unsupported version.
1505ea8dc4b6Seschrock 			 */
150699653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADVERSION, desc);
1507ea8dc4b6Seschrock 			break;
1508ea8dc4b6Seschrock 
1509b5989ec7Seschrock 		case EINVAL:
1510b5989ec7Seschrock 			(void) zfs_error(hdl, EZFS_INVALCONFIG, desc);
1511b5989ec7Seschrock 			break;
1512b5989ec7Seschrock 
1513fa9e4066Sahrens 		default:
1514468c413aSTim Haley 			(void) zcmd_read_dst_nvlist(hdl, &zc, &nvi);
151599653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, desc);
1516468c413aSTim Haley 			zpool_explain_recover(hdl,
1517468c413aSTim Haley 			    newname ? origname : thename, -errno, nvi);
1518468c413aSTim Haley 			nvlist_free(nvi);
1519468c413aSTim Haley 			break;
1520fa9e4066Sahrens 		}
1521fa9e4066Sahrens 
1522fa9e4066Sahrens 		ret = -1;
1523fa9e4066Sahrens 	} else {
1524fa9e4066Sahrens 		zpool_handle_t *zhp;
1525ecd6cf80Smarks 
1526fa9e4066Sahrens 		/*
1527fa9e4066Sahrens 		 * This should never fail, but play it safe anyway.
1528fa9e4066Sahrens 		 */
1529681d9761SEric Taylor 		if (zpool_open_silent(hdl, thename, &zhp) != 0)
153094de1d4cSeschrock 			ret = -1;
1531681d9761SEric Taylor 		else if (zhp != NULL)
1532fa9e4066Sahrens 			zpool_close(zhp);
1533468c413aSTim Haley 		(void) zcmd_read_dst_nvlist(hdl, &zc, &nvi);
1534468c413aSTim Haley 		zpool_get_rewind_policy(config, &policy);
1535468c413aSTim Haley 		if (policy.zrp_request &
1536468c413aSTim Haley 		    (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) {
1537468c413aSTim Haley 			zpool_rewind_exclaim(hdl, newname ? origname : thename,
1538468c413aSTim Haley 			    ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0),
1539468c413aSTim Haley 			    nvi);
1540468c413aSTim Haley 		}
1541468c413aSTim Haley 		nvlist_free(nvi);
1542468c413aSTim Haley 		return (0);
1543fa9e4066Sahrens 	}
1544fa9e4066Sahrens 
1545e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
1546351420b3Slling 	nvlist_free(props);
1547351420b3Slling 
1548fa9e4066Sahrens 	return (ret);
1549fa9e4066Sahrens }
1550fa9e4066Sahrens 
1551fa9e4066Sahrens /*
1552fa9e4066Sahrens  * Scrub the pool.
1553fa9e4066Sahrens  */
1554fa9e4066Sahrens int
1555fa9e4066Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type)
1556fa9e4066Sahrens {
1557fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1558fa9e4066Sahrens 	char msg[1024];
155999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1560fa9e4066Sahrens 
1561fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1562fa9e4066Sahrens 	zc.zc_cookie = type;
1563fa9e4066Sahrens 
1564ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0)
1565fa9e4066Sahrens 		return (0);
1566fa9e4066Sahrens 
1567fa9e4066Sahrens 	(void) snprintf(msg, sizeof (msg),
1568fa9e4066Sahrens 	    dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name);
1569fa9e4066Sahrens 
157099653d4eSeschrock 	if (errno == EBUSY)
157199653d4eSeschrock 		return (zfs_error(hdl, EZFS_RESILVERING, msg));
157299653d4eSeschrock 	else
157399653d4eSeschrock 		return (zpool_standard_error(hdl, errno, msg));
1574fa9e4066Sahrens }
1575fa9e4066Sahrens 
1576a43d325bSek /*
1577573ca77eSGeorge Wilson  * Find a vdev that matches the search criteria specified. We use the
1578573ca77eSGeorge Wilson  * the nvpair name to determine how we should look for the device.
1579a43d325bSek  * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL
1580a43d325bSek  * spare; but FALSE if its an INUSE spare.
1581a43d325bSek  */
158299653d4eSeschrock static nvlist_t *
1583573ca77eSGeorge Wilson vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
1584573ca77eSGeorge Wilson     boolean_t *l2cache, boolean_t *log)
1585ea8dc4b6Seschrock {
1586ea8dc4b6Seschrock 	uint_t c, children;
1587ea8dc4b6Seschrock 	nvlist_t **child;
158899653d4eSeschrock 	nvlist_t *ret;
1589ee0eb9f2SEric Schrock 	uint64_t is_log;
1590573ca77eSGeorge Wilson 	char *srchkey;
1591573ca77eSGeorge Wilson 	nvpair_t *pair = nvlist_next_nvpair(search, NULL);
1592573ca77eSGeorge Wilson 
1593573ca77eSGeorge Wilson 	/* Nothing to look for */
1594573ca77eSGeorge Wilson 	if (search == NULL || pair == NULL)
1595573ca77eSGeorge Wilson 		return (NULL);
1596ea8dc4b6Seschrock 
1597573ca77eSGeorge Wilson 	/* Obtain the key we will use to search */
1598573ca77eSGeorge Wilson 	srchkey = nvpair_name(pair);
1599573ca77eSGeorge Wilson 
1600573ca77eSGeorge Wilson 	switch (nvpair_type(pair)) {
1601573ca77eSGeorge Wilson 	case DATA_TYPE_UINT64: {
1602573ca77eSGeorge Wilson 		uint64_t srchval, theguid, present;
1603573ca77eSGeorge Wilson 
1604573ca77eSGeorge Wilson 		verify(nvpair_value_uint64(pair, &srchval) == 0);
1605573ca77eSGeorge Wilson 		if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) {
1606573ca77eSGeorge Wilson 			if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1607573ca77eSGeorge Wilson 			    &present) == 0) {
1608573ca77eSGeorge Wilson 				/*
1609573ca77eSGeorge Wilson 				 * If the device has never been present since
1610573ca77eSGeorge Wilson 				 * import, the only reliable way to match the
1611573ca77eSGeorge Wilson 				 * vdev is by GUID.
1612573ca77eSGeorge Wilson 				 */
1613573ca77eSGeorge Wilson 				verify(nvlist_lookup_uint64(nv,
1614573ca77eSGeorge Wilson 				    ZPOOL_CONFIG_GUID, &theguid) == 0);
1615573ca77eSGeorge Wilson 				if (theguid == srchval)
1616573ca77eSGeorge Wilson 					return (nv);
1617573ca77eSGeorge Wilson 			}
1618573ca77eSGeorge Wilson 		}
1619573ca77eSGeorge Wilson 		break;
1620573ca77eSGeorge Wilson 	}
1621573ca77eSGeorge Wilson 
1622573ca77eSGeorge Wilson 	case DATA_TYPE_STRING: {
1623573ca77eSGeorge Wilson 		char *srchval, *val;
1624573ca77eSGeorge Wilson 
1625573ca77eSGeorge Wilson 		verify(nvpair_value_string(pair, &srchval) == 0);
1626573ca77eSGeorge Wilson 		if (nvlist_lookup_string(nv, srchkey, &val) != 0)
1627573ca77eSGeorge Wilson 			break;
1628ea8dc4b6Seschrock 
1629ea8dc4b6Seschrock 		/*
1630573ca77eSGeorge Wilson 		 * Search for the requested value. We special case the search
163188ecc943SGeorge Wilson 		 * for ZPOOL_CONFIG_PATH when it's a wholedisk and when
163288ecc943SGeorge Wilson 		 * Looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE).
163388ecc943SGeorge Wilson 		 * Otherwise, all other searches are simple string compares.
1634ea8dc4b6Seschrock 		 */
1635573ca77eSGeorge Wilson 		if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && val) {
1636573ca77eSGeorge Wilson 			uint64_t wholedisk = 0;
1637573ca77eSGeorge Wilson 
1638573ca77eSGeorge Wilson 			(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
1639573ca77eSGeorge Wilson 			    &wholedisk);
1640573ca77eSGeorge Wilson 			if (wholedisk) {
1641573ca77eSGeorge Wilson 				/*
1642573ca77eSGeorge Wilson 				 * For whole disks, the internal path has 's0',
1643573ca77eSGeorge Wilson 				 * but the path passed in by the user doesn't.
1644573ca77eSGeorge Wilson 				 */
1645573ca77eSGeorge Wilson 				if (strlen(srchval) == strlen(val) - 2 &&
1646573ca77eSGeorge Wilson 				    strncmp(srchval, val, strlen(srchval)) == 0)
1647573ca77eSGeorge Wilson 					return (nv);
1648573ca77eSGeorge Wilson 				break;
1649573ca77eSGeorge Wilson 			}
165088ecc943SGeorge Wilson 		} else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) {
165188ecc943SGeorge Wilson 			char *type, *idx, *end, *p;
165288ecc943SGeorge Wilson 			uint64_t id, vdev_id;
165388ecc943SGeorge Wilson 
165488ecc943SGeorge Wilson 			/*
165588ecc943SGeorge Wilson 			 * Determine our vdev type, keeping in mind
165688ecc943SGeorge Wilson 			 * that the srchval is composed of a type and
165788ecc943SGeorge Wilson 			 * vdev id pair (i.e. mirror-4).
165888ecc943SGeorge Wilson 			 */
165988ecc943SGeorge Wilson 			if ((type = strdup(srchval)) == NULL)
166088ecc943SGeorge Wilson 				return (NULL);
166188ecc943SGeorge Wilson 
166288ecc943SGeorge Wilson 			if ((p = strrchr(type, '-')) == NULL) {
166388ecc943SGeorge Wilson 				free(type);
166488ecc943SGeorge Wilson 				break;
166588ecc943SGeorge Wilson 			}
166688ecc943SGeorge Wilson 			idx = p + 1;
166788ecc943SGeorge Wilson 			*p = '\0';
166888ecc943SGeorge Wilson 
166988ecc943SGeorge Wilson 			/*
167088ecc943SGeorge Wilson 			 * If the types don't match then keep looking.
167188ecc943SGeorge Wilson 			 */
167288ecc943SGeorge Wilson 			if (strncmp(val, type, strlen(val)) != 0) {
167388ecc943SGeorge Wilson 				free(type);
167488ecc943SGeorge Wilson 				break;
167588ecc943SGeorge Wilson 			}
167688ecc943SGeorge Wilson 
167788ecc943SGeorge Wilson 			verify(strncmp(type, VDEV_TYPE_RAIDZ,
167888ecc943SGeorge Wilson 			    strlen(VDEV_TYPE_RAIDZ)) == 0 ||
167988ecc943SGeorge Wilson 			    strncmp(type, VDEV_TYPE_MIRROR,
168088ecc943SGeorge Wilson 			    strlen(VDEV_TYPE_MIRROR)) == 0);
168188ecc943SGeorge Wilson 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
168288ecc943SGeorge Wilson 			    &id) == 0);
168388ecc943SGeorge Wilson 
168488ecc943SGeorge Wilson 			errno = 0;
168588ecc943SGeorge Wilson 			vdev_id = strtoull(idx, &end, 10);
168688ecc943SGeorge Wilson 
168788ecc943SGeorge Wilson 			free(type);
168888ecc943SGeorge Wilson 			if (errno != 0)
168988ecc943SGeorge Wilson 				return (NULL);
169088ecc943SGeorge Wilson 
169188ecc943SGeorge Wilson 			/*
169288ecc943SGeorge Wilson 			 * Now verify that we have the correct vdev id.
169388ecc943SGeorge Wilson 			 */
169488ecc943SGeorge Wilson 			if (vdev_id == id)
169588ecc943SGeorge Wilson 				return (nv);
1696ea8dc4b6Seschrock 		}
1697573ca77eSGeorge Wilson 
1698573ca77eSGeorge Wilson 		/*
1699573ca77eSGeorge Wilson 		 * Common case
1700573ca77eSGeorge Wilson 		 */
1701573ca77eSGeorge Wilson 		if (strcmp(srchval, val) == 0)
1702573ca77eSGeorge Wilson 			return (nv);
1703573ca77eSGeorge Wilson 		break;
1704573ca77eSGeorge Wilson 	}
1705573ca77eSGeorge Wilson 
1706573ca77eSGeorge Wilson 	default:
1707573ca77eSGeorge Wilson 		break;
1708ea8dc4b6Seschrock 	}
1709ea8dc4b6Seschrock 
1710ea8dc4b6Seschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1711ea8dc4b6Seschrock 	    &child, &children) != 0)
171299653d4eSeschrock 		return (NULL);
1713ea8dc4b6Seschrock 
1714ee0eb9f2SEric Schrock 	for (c = 0; c < children; c++) {
1715573ca77eSGeorge Wilson 		if ((ret = vdev_to_nvlist_iter(child[c], search,
1716ee0eb9f2SEric Schrock 		    avail_spare, l2cache, NULL)) != NULL) {
1717ee0eb9f2SEric Schrock 			/*
1718ee0eb9f2SEric Schrock 			 * The 'is_log' value is only set for the toplevel
1719ee0eb9f2SEric Schrock 			 * vdev, not the leaf vdevs.  So we always lookup the
1720ee0eb9f2SEric Schrock 			 * log device from the root of the vdev tree (where
1721ee0eb9f2SEric Schrock 			 * 'log' is non-NULL).
1722ee0eb9f2SEric Schrock 			 */
1723ee0eb9f2SEric Schrock 			if (log != NULL &&
1724ee0eb9f2SEric Schrock 			    nvlist_lookup_uint64(child[c],
1725ee0eb9f2SEric Schrock 			    ZPOOL_CONFIG_IS_LOG, &is_log) == 0 &&
1726ee0eb9f2SEric Schrock 			    is_log) {
1727ee0eb9f2SEric Schrock 				*log = B_TRUE;
1728ee0eb9f2SEric Schrock 			}
1729ea8dc4b6Seschrock 			return (ret);
1730ee0eb9f2SEric Schrock 		}
1731ee0eb9f2SEric Schrock 	}
1732ea8dc4b6Seschrock 
173399653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
173499653d4eSeschrock 	    &child, &children) == 0) {
173599653d4eSeschrock 		for (c = 0; c < children; c++) {
1736573ca77eSGeorge Wilson 			if ((ret = vdev_to_nvlist_iter(child[c], search,
1737ee0eb9f2SEric Schrock 			    avail_spare, l2cache, NULL)) != NULL) {
1738a43d325bSek 				*avail_spare = B_TRUE;
173999653d4eSeschrock 				return (ret);
174099653d4eSeschrock 			}
174199653d4eSeschrock 		}
174299653d4eSeschrock 	}
174399653d4eSeschrock 
1744fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1745fa94a07fSbrendan 	    &child, &children) == 0) {
1746fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1747573ca77eSGeorge Wilson 			if ((ret = vdev_to_nvlist_iter(child[c], search,
1748ee0eb9f2SEric Schrock 			    avail_spare, l2cache, NULL)) != NULL) {
1749fa94a07fSbrendan 				*l2cache = B_TRUE;
1750fa94a07fSbrendan 				return (ret);
1751fa94a07fSbrendan 			}
1752fa94a07fSbrendan 		}
1753fa94a07fSbrendan 	}
1754fa94a07fSbrendan 
175599653d4eSeschrock 	return (NULL);
1756ea8dc4b6Seschrock }
1757ea8dc4b6Seschrock 
1758573ca77eSGeorge Wilson /*
1759573ca77eSGeorge Wilson  * Given a physical path (minus the "/devices" prefix), find the
1760573ca77eSGeorge Wilson  * associated vdev.
1761573ca77eSGeorge Wilson  */
1762573ca77eSGeorge Wilson nvlist_t *
1763573ca77eSGeorge Wilson zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath,
1764573ca77eSGeorge Wilson     boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log)
1765573ca77eSGeorge Wilson {
1766573ca77eSGeorge Wilson 	nvlist_t *search, *nvroot, *ret;
1767573ca77eSGeorge Wilson 
1768573ca77eSGeorge Wilson 	verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1769573ca77eSGeorge Wilson 	verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0);
1770573ca77eSGeorge Wilson 
1771573ca77eSGeorge Wilson 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
1772573ca77eSGeorge Wilson 	    &nvroot) == 0);
1773573ca77eSGeorge Wilson 
1774573ca77eSGeorge Wilson 	*avail_spare = B_FALSE;
1775573ca77eSGeorge Wilson 	ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
1776573ca77eSGeorge Wilson 	nvlist_free(search);
1777573ca77eSGeorge Wilson 
1778573ca77eSGeorge Wilson 	return (ret);
1779573ca77eSGeorge Wilson }
1780573ca77eSGeorge Wilson 
178188ecc943SGeorge Wilson /*
178288ecc943SGeorge Wilson  * Determine if we have an "interior" top-level vdev (i.e mirror/raidz).
178388ecc943SGeorge Wilson  */
178488ecc943SGeorge Wilson boolean_t
178588ecc943SGeorge Wilson zpool_vdev_is_interior(const char *name)
178688ecc943SGeorge Wilson {
178788ecc943SGeorge Wilson 	if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 ||
178888ecc943SGeorge Wilson 	    strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0)
178988ecc943SGeorge Wilson 		return (B_TRUE);
179088ecc943SGeorge Wilson 	return (B_FALSE);
179188ecc943SGeorge Wilson }
179288ecc943SGeorge Wilson 
179399653d4eSeschrock nvlist_t *
1794fa94a07fSbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
1795ee0eb9f2SEric Schrock     boolean_t *l2cache, boolean_t *log)
1796ea8dc4b6Seschrock {
1797ea8dc4b6Seschrock 	char buf[MAXPATHLEN];
1798ea8dc4b6Seschrock 	char *end;
1799573ca77eSGeorge Wilson 	nvlist_t *nvroot, *search, *ret;
1800ea8dc4b6Seschrock 	uint64_t guid;
1801ea8dc4b6Seschrock 
1802573ca77eSGeorge Wilson 	verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1803573ca77eSGeorge Wilson 
18040917b783Seschrock 	guid = strtoull(path, &end, 10);
1805ea8dc4b6Seschrock 	if (guid != 0 && *end == '\0') {
1806573ca77eSGeorge Wilson 		verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0);
180788ecc943SGeorge Wilson 	} else if (zpool_vdev_is_interior(path)) {
180888ecc943SGeorge Wilson 		verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0);
1809ea8dc4b6Seschrock 	} else if (path[0] != '/') {
1810ea8dc4b6Seschrock 		(void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path);
1811573ca77eSGeorge Wilson 		verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0);
1812ea8dc4b6Seschrock 	} else {
1813573ca77eSGeorge Wilson 		verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0);
1814ea8dc4b6Seschrock 	}
1815ea8dc4b6Seschrock 
1816ea8dc4b6Seschrock 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
1817ea8dc4b6Seschrock 	    &nvroot) == 0);
1818ea8dc4b6Seschrock 
1819a43d325bSek 	*avail_spare = B_FALSE;
1820fa94a07fSbrendan 	*l2cache = B_FALSE;
1821ee0eb9f2SEric Schrock 	if (log != NULL)
1822ee0eb9f2SEric Schrock 		*log = B_FALSE;
1823573ca77eSGeorge Wilson 	ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
1824573ca77eSGeorge Wilson 	nvlist_free(search);
1825573ca77eSGeorge Wilson 
1826573ca77eSGeorge Wilson 	return (ret);
1827a43d325bSek }
1828a43d325bSek 
182919397407SSherry Moore static int
183019397407SSherry Moore vdev_online(nvlist_t *nv)
183119397407SSherry Moore {
183219397407SSherry Moore 	uint64_t ival;
183319397407SSherry Moore 
183419397407SSherry Moore 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 ||
183519397407SSherry Moore 	    nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 ||
183619397407SSherry Moore 	    nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0)
183719397407SSherry Moore 		return (0);
183819397407SSherry Moore 
183919397407SSherry Moore 	return (1);
184019397407SSherry Moore }
184119397407SSherry Moore 
184219397407SSherry Moore /*
184321ecdf64SLin Ling  * Helper function for zpool_get_physpaths().
184419397407SSherry Moore  */
1845753a6d45SSherry Moore static int
184621ecdf64SLin Ling vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size,
1847753a6d45SSherry Moore     size_t *bytes_written)
184819397407SSherry Moore {
1849753a6d45SSherry Moore 	size_t bytes_left, pos, rsz;
1850753a6d45SSherry Moore 	char *tmppath;
1851753a6d45SSherry Moore 	const char *format;
1852753a6d45SSherry Moore 
1853753a6d45SSherry Moore 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH,
1854753a6d45SSherry Moore 	    &tmppath) != 0)
1855753a6d45SSherry Moore 		return (EZFS_NODEVICE);
1856753a6d45SSherry Moore 
1857753a6d45SSherry Moore 	pos = *bytes_written;
1858753a6d45SSherry Moore 	bytes_left = physpath_size - pos;
1859753a6d45SSherry Moore 	format = (pos == 0) ? "%s" : " %s";
1860753a6d45SSherry Moore 
1861753a6d45SSherry Moore 	rsz = snprintf(physpath + pos, bytes_left, format, tmppath);
1862753a6d45SSherry Moore 	*bytes_written += rsz;
1863753a6d45SSherry Moore 
1864753a6d45SSherry Moore 	if (rsz >= bytes_left) {
1865753a6d45SSherry Moore 		/* if physpath was not copied properly, clear it */
1866753a6d45SSherry Moore 		if (bytes_left != 0) {
1867753a6d45SSherry Moore 			physpath[pos] = 0;
1868753a6d45SSherry Moore 		}
1869753a6d45SSherry Moore 		return (EZFS_NOSPC);
1870753a6d45SSherry Moore 	}
1871753a6d45SSherry Moore 	return (0);
1872753a6d45SSherry Moore }
1873753a6d45SSherry Moore 
187421ecdf64SLin Ling static int
187521ecdf64SLin Ling vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size,
187621ecdf64SLin Ling     size_t *rsz, boolean_t is_spare)
187721ecdf64SLin Ling {
187821ecdf64SLin Ling 	char *type;
187921ecdf64SLin Ling 	int ret;
188021ecdf64SLin Ling 
188121ecdf64SLin Ling 	if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0)
188221ecdf64SLin Ling 		return (EZFS_INVALCONFIG);
188321ecdf64SLin Ling 
188421ecdf64SLin Ling 	if (strcmp(type, VDEV_TYPE_DISK) == 0) {
188521ecdf64SLin Ling 		/*
188621ecdf64SLin Ling 		 * An active spare device has ZPOOL_CONFIG_IS_SPARE set.
188721ecdf64SLin Ling 		 * For a spare vdev, we only want to boot from the active
188821ecdf64SLin Ling 		 * spare device.
188921ecdf64SLin Ling 		 */
189021ecdf64SLin Ling 		if (is_spare) {
189121ecdf64SLin Ling 			uint64_t spare = 0;
189221ecdf64SLin Ling 			(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE,
189321ecdf64SLin Ling 			    &spare);
189421ecdf64SLin Ling 			if (!spare)
189521ecdf64SLin Ling 				return (EZFS_INVALCONFIG);
189621ecdf64SLin Ling 		}
189721ecdf64SLin Ling 
189821ecdf64SLin Ling 		if (vdev_online(nv)) {
189921ecdf64SLin Ling 			if ((ret = vdev_get_one_physpath(nv, physpath,
190021ecdf64SLin Ling 			    phypath_size, rsz)) != 0)
190121ecdf64SLin Ling 				return (ret);
190221ecdf64SLin Ling 		}
190321ecdf64SLin Ling 	} else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 ||
190421ecdf64SLin Ling 	    strcmp(type, VDEV_TYPE_REPLACING) == 0 ||
190521ecdf64SLin Ling 	    (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) {
190621ecdf64SLin Ling 		nvlist_t **child;
190721ecdf64SLin Ling 		uint_t count;
190821ecdf64SLin Ling 		int i, ret;
190921ecdf64SLin Ling 
191021ecdf64SLin Ling 		if (nvlist_lookup_nvlist_array(nv,
191121ecdf64SLin Ling 		    ZPOOL_CONFIG_CHILDREN, &child, &count) != 0)
191221ecdf64SLin Ling 			return (EZFS_INVALCONFIG);
191321ecdf64SLin Ling 
191421ecdf64SLin Ling 		for (i = 0; i < count; i++) {
191521ecdf64SLin Ling 			ret = vdev_get_physpaths(child[i], physpath,
191621ecdf64SLin Ling 			    phypath_size, rsz, is_spare);
191721ecdf64SLin Ling 			if (ret == EZFS_NOSPC)
191821ecdf64SLin Ling 				return (ret);
191921ecdf64SLin Ling 		}
192021ecdf64SLin Ling 	}
192121ecdf64SLin Ling 
192221ecdf64SLin Ling 	return (EZFS_POOL_INVALARG);
192321ecdf64SLin Ling }
192421ecdf64SLin Ling 
1925753a6d45SSherry Moore /*
1926753a6d45SSherry Moore  * Get phys_path for a root pool config.
1927753a6d45SSherry Moore  * Return 0 on success; non-zero on failure.
1928753a6d45SSherry Moore  */
1929753a6d45SSherry Moore static int
1930753a6d45SSherry Moore zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size)
1931753a6d45SSherry Moore {
1932753a6d45SSherry Moore 	size_t rsz;
193319397407SSherry Moore 	nvlist_t *vdev_root;
193419397407SSherry Moore 	nvlist_t **child;
193519397407SSherry Moore 	uint_t count;
1936753a6d45SSherry Moore 	char *type;
1937753a6d45SSherry Moore 
1938753a6d45SSherry Moore 	rsz = 0;
1939753a6d45SSherry Moore 
1940753a6d45SSherry Moore 	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1941753a6d45SSherry Moore 	    &vdev_root) != 0)
1942753a6d45SSherry Moore 		return (EZFS_INVALCONFIG);
1943753a6d45SSherry Moore 
1944753a6d45SSherry Moore 	if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 ||
1945753a6d45SSherry Moore 	    nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN,
1946753a6d45SSherry Moore 	    &child, &count) != 0)
1947753a6d45SSherry Moore 		return (EZFS_INVALCONFIG);
194819397407SSherry Moore 
194919397407SSherry Moore 	/*
1950753a6d45SSherry Moore 	 * root pool can not have EFI labeled disks and can only have
1951753a6d45SSherry Moore 	 * a single top-level vdev.
195219397407SSherry Moore 	 */
1953753a6d45SSherry Moore 	if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 ||
1954753a6d45SSherry Moore 	    pool_uses_efi(vdev_root))
1955753a6d45SSherry Moore 		return (EZFS_POOL_INVALARG);
195619397407SSherry Moore 
195721ecdf64SLin Ling 	(void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz,
195821ecdf64SLin Ling 	    B_FALSE);
195919397407SSherry Moore 
1960753a6d45SSherry Moore 	/* No online devices */
1961753a6d45SSherry Moore 	if (rsz == 0)
1962753a6d45SSherry Moore 		return (EZFS_NODEVICE);
1963753a6d45SSherry Moore 
196419397407SSherry Moore 	return (0);
196519397407SSherry Moore }
196619397407SSherry Moore 
1967753a6d45SSherry Moore /*
1968753a6d45SSherry Moore  * Get phys_path for a root pool
1969753a6d45SSherry Moore  * Return 0 on success; non-zero on failure.
1970753a6d45SSherry Moore  */
1971753a6d45SSherry Moore int
1972753a6d45SSherry Moore zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size)
1973753a6d45SSherry Moore {
1974753a6d45SSherry Moore 	return (zpool_get_config_physpath(zhp->zpool_config, physpath,
1975753a6d45SSherry Moore 	    phypath_size));
1976753a6d45SSherry Moore }
1977753a6d45SSherry Moore 
1978573ca77eSGeorge Wilson /*
1979573ca77eSGeorge Wilson  * If the device has being dynamically expanded then we need to relabel
1980573ca77eSGeorge Wilson  * the disk to use the new unallocated space.
1981573ca77eSGeorge Wilson  */
1982573ca77eSGeorge Wilson static int
1983573ca77eSGeorge Wilson zpool_relabel_disk(libzfs_handle_t *hdl, const char *name)
1984573ca77eSGeorge Wilson {
1985573ca77eSGeorge Wilson 	char path[MAXPATHLEN];
1986573ca77eSGeorge Wilson 	char errbuf[1024];
1987573ca77eSGeorge Wilson 	int fd, error;
1988573ca77eSGeorge Wilson 	int (*_efi_use_whole_disk)(int);
1989573ca77eSGeorge Wilson 
1990573ca77eSGeorge Wilson 	if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT,
1991573ca77eSGeorge Wilson 	    "efi_use_whole_disk")) == NULL)
1992573ca77eSGeorge Wilson 		return (-1);
1993573ca77eSGeorge Wilson 
1994573ca77eSGeorge Wilson 	(void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name);
1995573ca77eSGeorge Wilson 
1996573ca77eSGeorge Wilson 	if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) {
1997573ca77eSGeorge Wilson 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
1998573ca77eSGeorge Wilson 		    "relabel '%s': unable to open device"), name);
1999573ca77eSGeorge Wilson 		return (zfs_error(hdl, EZFS_OPENFAILED, errbuf));
2000573ca77eSGeorge Wilson 	}
2001573ca77eSGeorge Wilson 
2002573ca77eSGeorge Wilson 	/*
2003573ca77eSGeorge Wilson 	 * It's possible that we might encounter an error if the device
2004573ca77eSGeorge Wilson 	 * does not have any unallocated space left. If so, we simply
2005573ca77eSGeorge Wilson 	 * ignore that error and continue on.
2006573ca77eSGeorge Wilson 	 */
2007573ca77eSGeorge Wilson 	error = _efi_use_whole_disk(fd);
2008573ca77eSGeorge Wilson 	(void) close(fd);
2009573ca77eSGeorge Wilson 	if (error && error != VT_ENOSPC) {
2010573ca77eSGeorge Wilson 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
2011573ca77eSGeorge Wilson 		    "relabel '%s': unable to read disk capacity"), name);
2012573ca77eSGeorge Wilson 		return (zfs_error(hdl, EZFS_NOCAP, errbuf));
2013573ca77eSGeorge Wilson 	}
2014573ca77eSGeorge Wilson 	return (0);
2015573ca77eSGeorge Wilson }
2016573ca77eSGeorge Wilson 
2017fa9e4066Sahrens /*
20183d7072f8Seschrock  * Bring the specified vdev online.   The 'flags' parameter is a set of the
20193d7072f8Seschrock  * ZFS_ONLINE_* flags.
2020fa9e4066Sahrens  */
2021fa9e4066Sahrens int
20223d7072f8Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
20233d7072f8Seschrock     vdev_state_t *newstate)
2024fa9e4066Sahrens {
2025fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2026fa9e4066Sahrens 	char msg[1024];
202799653d4eSeschrock 	nvlist_t *tgt;
2028573ca77eSGeorge Wilson 	boolean_t avail_spare, l2cache, islog;
202999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2030fa9e4066Sahrens 
2031573ca77eSGeorge Wilson 	if (flags & ZFS_ONLINE_EXPAND) {
2032573ca77eSGeorge Wilson 		(void) snprintf(msg, sizeof (msg),
2033573ca77eSGeorge Wilson 		    dgettext(TEXT_DOMAIN, "cannot expand %s"), path);
2034573ca77eSGeorge Wilson 	} else {
2035573ca77eSGeorge Wilson 		(void) snprintf(msg, sizeof (msg),
2036573ca77eSGeorge Wilson 		    dgettext(TEXT_DOMAIN, "cannot online %s"), path);
2037573ca77eSGeorge Wilson 	}
2038ea8dc4b6Seschrock 
2039fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2040ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
2041573ca77eSGeorge Wilson 	    &islog)) == NULL)
204299653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
2043fa9e4066Sahrens 
204499653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2045fa9e4066Sahrens 
2046069f55e2SEric Schrock 	if (avail_spare)
2047a43d325bSek 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
2048a43d325bSek 
2049573ca77eSGeorge Wilson 	if (flags & ZFS_ONLINE_EXPAND ||
2050573ca77eSGeorge Wilson 	    zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) {
2051573ca77eSGeorge Wilson 		char *pathname = NULL;
2052573ca77eSGeorge Wilson 		uint64_t wholedisk = 0;
2053573ca77eSGeorge Wilson 
2054573ca77eSGeorge Wilson 		(void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
2055573ca77eSGeorge Wilson 		    &wholedisk);
2056573ca77eSGeorge Wilson 		verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH,
2057573ca77eSGeorge Wilson 		    &pathname) == 0);
2058573ca77eSGeorge Wilson 
2059573ca77eSGeorge Wilson 		/*
2060573ca77eSGeorge Wilson 		 * XXX - L2ARC 1.0 devices can't support expansion.
2061573ca77eSGeorge Wilson 		 */
2062573ca77eSGeorge Wilson 		if (l2cache) {
2063573ca77eSGeorge Wilson 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2064573ca77eSGeorge Wilson 			    "cannot expand cache devices"));
2065573ca77eSGeorge Wilson 			return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg));
2066573ca77eSGeorge Wilson 		}
2067573ca77eSGeorge Wilson 
2068573ca77eSGeorge Wilson 		if (wholedisk) {
2069573ca77eSGeorge Wilson 			pathname += strlen(DISK_ROOT) + 1;
2070573ca77eSGeorge Wilson 			(void) zpool_relabel_disk(zhp->zpool_hdl, pathname);
2071573ca77eSGeorge Wilson 		}
2072573ca77eSGeorge Wilson 	}
2073573ca77eSGeorge Wilson 
20743d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_ONLINE;
20753d7072f8Seschrock 	zc.zc_obj = flags;
2076fa9e4066Sahrens 
2077ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0)
20783d7072f8Seschrock 		return (zpool_standard_error(hdl, errno, msg));
20793d7072f8Seschrock 
20803d7072f8Seschrock 	*newstate = zc.zc_cookie;
20813d7072f8Seschrock 	return (0);
2082fa9e4066Sahrens }
2083fa9e4066Sahrens 
2084fa9e4066Sahrens /*
2085fa9e4066Sahrens  * Take the specified vdev offline
2086fa9e4066Sahrens  */
2087fa9e4066Sahrens int
20883d7072f8Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp)
2089fa9e4066Sahrens {
2090fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2091fa9e4066Sahrens 	char msg[1024];
209299653d4eSeschrock 	nvlist_t *tgt;
2093fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
209499653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2095fa9e4066Sahrens 
2096ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
2097ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot offline %s"), path);
2098ea8dc4b6Seschrock 
2099fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2100ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
2101ee0eb9f2SEric Schrock 	    NULL)) == NULL)
210299653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
210399653d4eSeschrock 
210499653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2105fa9e4066Sahrens 
2106069f55e2SEric Schrock 	if (avail_spare)
2107a43d325bSek 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
2108a43d325bSek 
21093d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_OFFLINE;
21103d7072f8Seschrock 	zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0;
21113d7072f8Seschrock 
2112ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
21133d7072f8Seschrock 		return (0);
21143d7072f8Seschrock 
21153d7072f8Seschrock 	switch (errno) {
21163d7072f8Seschrock 	case EBUSY:
21173d7072f8Seschrock 
21183d7072f8Seschrock 		/*
21193d7072f8Seschrock 		 * There are no other replicas of this device.
21203d7072f8Seschrock 		 */
21213d7072f8Seschrock 		return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
21223d7072f8Seschrock 
2123e6ca193dSGeorge Wilson 	case EEXIST:
2124e6ca193dSGeorge Wilson 		/*
2125e6ca193dSGeorge Wilson 		 * The log device has unplayed logs
2126e6ca193dSGeorge Wilson 		 */
2127e6ca193dSGeorge Wilson 		return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg));
2128e6ca193dSGeorge Wilson 
21293d7072f8Seschrock 	default:
21303d7072f8Seschrock 		return (zpool_standard_error(hdl, errno, msg));
21313d7072f8Seschrock 	}
21323d7072f8Seschrock }
21333d7072f8Seschrock 
21343d7072f8Seschrock /*
21353d7072f8Seschrock  * Mark the given vdev faulted.
21363d7072f8Seschrock  */
21373d7072f8Seschrock int
2138069f55e2SEric Schrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux)
21393d7072f8Seschrock {
21403d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
21413d7072f8Seschrock 	char msg[1024];
21423d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
21433d7072f8Seschrock 
21443d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
21453d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid);
2146441d80aaSlling 
21473d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
21483d7072f8Seschrock 	zc.zc_guid = guid;
21493d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_FAULTED;
2150069f55e2SEric Schrock 	zc.zc_obj = aux;
21513d7072f8Seschrock 
21523d7072f8Seschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
2153fa9e4066Sahrens 		return (0);
2154fa9e4066Sahrens 
2155fa9e4066Sahrens 	switch (errno) {
215699653d4eSeschrock 	case EBUSY:
2157fa9e4066Sahrens 
2158fa9e4066Sahrens 		/*
2159fa9e4066Sahrens 		 * There are no other replicas of this device.
2160fa9e4066Sahrens 		 */
216199653d4eSeschrock 		return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
2162fa9e4066Sahrens 
216399653d4eSeschrock 	default:
216499653d4eSeschrock 		return (zpool_standard_error(hdl, errno, msg));
2165fa9e4066Sahrens 	}
21663d7072f8Seschrock 
21673d7072f8Seschrock }
21683d7072f8Seschrock 
21693d7072f8Seschrock /*
21703d7072f8Seschrock  * Mark the given vdev degraded.
21713d7072f8Seschrock  */
21723d7072f8Seschrock int
2173069f55e2SEric Schrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux)
21743d7072f8Seschrock {
21753d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
21763d7072f8Seschrock 	char msg[1024];
21773d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
21783d7072f8Seschrock 
21793d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
21803d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid);
21813d7072f8Seschrock 
21823d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
21833d7072f8Seschrock 	zc.zc_guid = guid;
21843d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_DEGRADED;
2185069f55e2SEric Schrock 	zc.zc_obj = aux;
21863d7072f8Seschrock 
21873d7072f8Seschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
21883d7072f8Seschrock 		return (0);
21893d7072f8Seschrock 
21903d7072f8Seschrock 	return (zpool_standard_error(hdl, errno, msg));
219199653d4eSeschrock }
219299653d4eSeschrock 
219399653d4eSeschrock /*
219499653d4eSeschrock  * Returns TRUE if the given nvlist is a vdev that was originally swapped in as
219599653d4eSeschrock  * a hot spare.
219699653d4eSeschrock  */
219799653d4eSeschrock static boolean_t
219899653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which)
219999653d4eSeschrock {
220099653d4eSeschrock 	nvlist_t **child;
220199653d4eSeschrock 	uint_t c, children;
220299653d4eSeschrock 	char *type;
220399653d4eSeschrock 
220499653d4eSeschrock 	if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child,
220599653d4eSeschrock 	    &children) == 0) {
220699653d4eSeschrock 		verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE,
220799653d4eSeschrock 		    &type) == 0);
220899653d4eSeschrock 
220999653d4eSeschrock 		if (strcmp(type, VDEV_TYPE_SPARE) == 0 &&
221099653d4eSeschrock 		    children == 2 && child[which] == tgt)
221199653d4eSeschrock 			return (B_TRUE);
221299653d4eSeschrock 
221399653d4eSeschrock 		for (c = 0; c < children; c++)
221499653d4eSeschrock 			if (is_replacing_spare(child[c], tgt, which))
221599653d4eSeschrock 				return (B_TRUE);
221699653d4eSeschrock 	}
221799653d4eSeschrock 
221899653d4eSeschrock 	return (B_FALSE);
2219fa9e4066Sahrens }
2220fa9e4066Sahrens 
2221fa9e4066Sahrens /*
2222fa9e4066Sahrens  * Attach new_disk (fully described by nvroot) to old_disk.
22238654d025Sperrin  * If 'replacing' is specified, the new disk will replace the old one.
2224fa9e4066Sahrens  */
2225fa9e4066Sahrens int
2226fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp,
2227fa9e4066Sahrens     const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing)
2228fa9e4066Sahrens {
2229fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2230fa9e4066Sahrens 	char msg[1024];
2231fa9e4066Sahrens 	int ret;
223299653d4eSeschrock 	nvlist_t *tgt;
2233ee0eb9f2SEric Schrock 	boolean_t avail_spare, l2cache, islog;
2234ee0eb9f2SEric Schrock 	uint64_t val;
22350430f8daSeschrock 	char *path, *newname;
223699653d4eSeschrock 	nvlist_t **child;
223799653d4eSeschrock 	uint_t children;
223899653d4eSeschrock 	nvlist_t *config_root;
223999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2240b5b76fecSGeorge Wilson 	boolean_t rootpool = pool_is_bootable(zhp);
2241fa9e4066Sahrens 
2242ea8dc4b6Seschrock 	if (replacing)
2243ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
2244ea8dc4b6Seschrock 		    "cannot replace %s with %s"), old_disk, new_disk);
2245ea8dc4b6Seschrock 	else
2246ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
2247ea8dc4b6Seschrock 		    "cannot attach %s to %s"), new_disk, old_disk);
2248ea8dc4b6Seschrock 
2249b5b76fecSGeorge Wilson 	/*
2250b5b76fecSGeorge Wilson 	 * If this is a root pool, make sure that we're not attaching an
2251b5b76fecSGeorge Wilson 	 * EFI labeled device.
2252b5b76fecSGeorge Wilson 	 */
2253b5b76fecSGeorge Wilson 	if (rootpool && pool_uses_efi(nvroot)) {
2254b5b76fecSGeorge Wilson 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2255b5b76fecSGeorge Wilson 		    "EFI labeled devices are not supported on root pools."));
2256b5b76fecSGeorge Wilson 		return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
2257b5b76fecSGeorge Wilson 	}
2258b5b76fecSGeorge Wilson 
2259fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2260ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
2261ee0eb9f2SEric Schrock 	    &islog)) == 0)
226299653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
226399653d4eSeschrock 
2264a43d325bSek 	if (avail_spare)
226599653d4eSeschrock 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
226699653d4eSeschrock 
2267fa94a07fSbrendan 	if (l2cache)
2268fa94a07fSbrendan 		return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
2269fa94a07fSbrendan 
227099653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2271fa9e4066Sahrens 	zc.zc_cookie = replacing;
2272fa9e4066Sahrens 
227399653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
227499653d4eSeschrock 	    &child, &children) != 0 || children != 1) {
227599653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
227699653d4eSeschrock 		    "new device must be a single disk"));
227799653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALCONFIG, msg));
227899653d4eSeschrock 	}
227999653d4eSeschrock 
228099653d4eSeschrock 	verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
228199653d4eSeschrock 	    ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);
228299653d4eSeschrock 
228388ecc943SGeorge Wilson 	if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL)
22840430f8daSeschrock 		return (-1);
22850430f8daSeschrock 
228699653d4eSeschrock 	/*
228799653d4eSeschrock 	 * If the target is a hot spare that has been swapped in, we can only
228899653d4eSeschrock 	 * replace it with another hot spare.
228999653d4eSeschrock 	 */
229099653d4eSeschrock 	if (replacing &&
229199653d4eSeschrock 	    nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
2292ee0eb9f2SEric Schrock 	    (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache,
2293ee0eb9f2SEric Schrock 	    NULL) == NULL || !avail_spare) &&
2294ee0eb9f2SEric Schrock 	    is_replacing_spare(config_root, tgt, 1)) {
229599653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
229699653d4eSeschrock 		    "can only be replaced by another hot spare"));
22970430f8daSeschrock 		free(newname);
229899653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTARGET, msg));
229999653d4eSeschrock 	}
230099653d4eSeschrock 
230199653d4eSeschrock 	/*
230299653d4eSeschrock 	 * If we are attempting to replace a spare, it canot be applied to an
230399653d4eSeschrock 	 * already spared device.
230499653d4eSeschrock 	 */
230599653d4eSeschrock 	if (replacing &&
230699653d4eSeschrock 	    nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
2307ee0eb9f2SEric Schrock 	    zpool_find_vdev(zhp, newname, &avail_spare,
2308ee0eb9f2SEric Schrock 	    &l2cache, NULL) != NULL && avail_spare &&
2309ee0eb9f2SEric Schrock 	    is_replacing_spare(config_root, tgt, 0)) {
231099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
231199653d4eSeschrock 		    "device has already been replaced with a spare"));
23120430f8daSeschrock 		free(newname);
231399653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTARGET, msg));
231499653d4eSeschrock 	}
231599653d4eSeschrock 
23160430f8daSeschrock 	free(newname);
23170430f8daSeschrock 
2318990b4856Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
231999653d4eSeschrock 		return (-1);
2320fa9e4066Sahrens 
2321ecd6cf80Smarks 	ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc);
2322fa9e4066Sahrens 
2323e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
2324fa9e4066Sahrens 
2325b5b76fecSGeorge Wilson 	if (ret == 0) {
2326b5b76fecSGeorge Wilson 		if (rootpool) {
2327b5b76fecSGeorge Wilson 			/*
2328b5b76fecSGeorge Wilson 			 * XXX - This should be removed once we can
2329b5b76fecSGeorge Wilson 			 * automatically install the bootblocks on the
2330b5b76fecSGeorge Wilson 			 * newly attached disk.
2331b5b76fecSGeorge Wilson 			 */
2332b5b76fecSGeorge Wilson 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please "
2333b5b76fecSGeorge Wilson 			    "be sure to invoke %s to make '%s' bootable.\n"),
2334b5b76fecSGeorge Wilson 			    BOOTCMD, new_disk);
233521ecdf64SLin Ling 
233621ecdf64SLin Ling 			/*
233721ecdf64SLin Ling 			 * XXX need a better way to prevent user from
233821ecdf64SLin Ling 			 * booting up a half-baked vdev.
233921ecdf64SLin Ling 			 */
234021ecdf64SLin Ling 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make "
234121ecdf64SLin Ling 			    "sure to wait until resilver is done "
234221ecdf64SLin Ling 			    "before rebooting.\n"));
2343b5b76fecSGeorge Wilson 		}
2344fa9e4066Sahrens 		return (0);
2345b5b76fecSGeorge Wilson 	}
2346fa9e4066Sahrens 
2347fa9e4066Sahrens 	switch (errno) {
2348ea8dc4b6Seschrock 	case ENOTSUP:
2349fa9e4066Sahrens 		/*
2350fa9e4066Sahrens 		 * Can't attach to or replace this type of vdev.
2351fa9e4066Sahrens 		 */
23528654d025Sperrin 		if (replacing) {
2353ee0eb9f2SEric Schrock 			if (islog)
23548654d025Sperrin 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
23558654d025Sperrin 				    "cannot replace a log with a spare"));
23568654d025Sperrin 			else
23578654d025Sperrin 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
23588654d025Sperrin 				    "cannot replace a replacing device"));
23598654d025Sperrin 		} else {
236099653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
236199653d4eSeschrock 			    "can only attach to mirrors and top-level "
236299653d4eSeschrock 			    "disks"));
23638654d025Sperrin 		}
236499653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADTARGET, msg);
2365fa9e4066Sahrens 		break;
2366fa9e4066Sahrens 
2367ea8dc4b6Seschrock 	case EINVAL:
2368fa9e4066Sahrens 		/*
2369fa9e4066Sahrens 		 * The new device must be a single disk.
2370fa9e4066Sahrens 		 */
237199653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
237299653d4eSeschrock 		    "new device must be a single disk"));
237399653d4eSeschrock 		(void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
2374fa9e4066Sahrens 		break;
2375fa9e4066Sahrens 
2376ea8dc4b6Seschrock 	case EBUSY:
237799653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"),
237899653d4eSeschrock 		    new_disk);
237999653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
2380fa9e4066Sahrens 		break;
2381fa9e4066Sahrens 
2382ea8dc4b6Seschrock 	case EOVERFLOW:
2383fa9e4066Sahrens 		/*
2384fa9e4066Sahrens 		 * The new device is too small.
2385fa9e4066Sahrens 		 */
238699653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
238799653d4eSeschrock 		    "device is too small"));
238899653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
2389fa9e4066Sahrens 		break;
2390fa9e4066Sahrens 
2391ea8dc4b6Seschrock 	case EDOM:
2392fa9e4066Sahrens 		/*
2393fa9e4066Sahrens 		 * The new device has a different alignment requirement.
2394fa9e4066Sahrens 		 */
239599653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
239699653d4eSeschrock 		    "devices have different sector alignment"));
239799653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
2398fa9e4066Sahrens 		break;
2399fa9e4066Sahrens 
2400ea8dc4b6Seschrock 	case ENAMETOOLONG:
2401fa9e4066Sahrens 		/*
2402fa9e4066Sahrens 		 * The resulting top-level vdev spec won't fit in the label.
2403fa9e4066Sahrens 		 */
240499653d4eSeschrock 		(void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg);
2405fa9e4066Sahrens 		break;
2406fa9e4066Sahrens 
2407ea8dc4b6Seschrock 	default:
240899653d4eSeschrock 		(void) zpool_standard_error(hdl, errno, msg);
2409fa9e4066Sahrens 	}
2410fa9e4066Sahrens 
241199653d4eSeschrock 	return (-1);
2412fa9e4066Sahrens }
2413fa9e4066Sahrens 
2414fa9e4066Sahrens /*
2415fa9e4066Sahrens  * Detach the specified device.
2416fa9e4066Sahrens  */
2417fa9e4066Sahrens int
2418fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
2419fa9e4066Sahrens {
2420fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2421fa9e4066Sahrens 	char msg[1024];
242299653d4eSeschrock 	nvlist_t *tgt;
2423fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
242499653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2425fa9e4066Sahrens 
2426ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
2427ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot detach %s"), path);
2428ea8dc4b6Seschrock 
2429fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2430ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
2431ee0eb9f2SEric Schrock 	    NULL)) == 0)
243299653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
2433fa9e4066Sahrens 
2434a43d325bSek 	if (avail_spare)
243599653d4eSeschrock 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
243699653d4eSeschrock 
2437fa94a07fSbrendan 	if (l2cache)
2438fa94a07fSbrendan 		return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
2439fa94a07fSbrendan 
244099653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
244199653d4eSeschrock 
2442ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0)
2443fa9e4066Sahrens 		return (0);
2444fa9e4066Sahrens 
2445fa9e4066Sahrens 	switch (errno) {
2446fa9e4066Sahrens 
2447ea8dc4b6Seschrock 	case ENOTSUP:
2448fa9e4066Sahrens 		/*
2449fa9e4066Sahrens 		 * Can't detach from this type of vdev.
2450fa9e4066Sahrens 		 */
245199653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only "
245299653d4eSeschrock 		    "applicable to mirror and replacing vdevs"));
245399653d4eSeschrock 		(void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg);
2454fa9e4066Sahrens 		break;
2455fa9e4066Sahrens 
2456ea8dc4b6Seschrock 	case EBUSY:
2457fa9e4066Sahrens 		/*
2458fa9e4066Sahrens 		 * There are no other replicas of this device.
2459fa9e4066Sahrens 		 */
246099653d4eSeschrock 		(void) zfs_error(hdl, EZFS_NOREPLICAS, msg);
2461fa9e4066Sahrens 		break;
2462fa9e4066Sahrens 
2463ea8dc4b6Seschrock 	default:
246499653d4eSeschrock 		(void) zpool_standard_error(hdl, errno, msg);
2465ea8dc4b6Seschrock 	}
2466ea8dc4b6Seschrock 
246799653d4eSeschrock 	return (-1);
246899653d4eSeschrock }
246999653d4eSeschrock 
247099653d4eSeschrock /*
2471fa94a07fSbrendan  * Remove the given device.  Currently, this is supported only for hot spares
2472fa94a07fSbrendan  * and level 2 cache devices.
247399653d4eSeschrock  */
247499653d4eSeschrock int
247599653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
247699653d4eSeschrock {
247799653d4eSeschrock 	zfs_cmd_t zc = { 0 };
247899653d4eSeschrock 	char msg[1024];
247999653d4eSeschrock 	nvlist_t *tgt;
248088ecc943SGeorge Wilson 	boolean_t avail_spare, l2cache, islog;
248199653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
248288ecc943SGeorge Wilson 	uint64_t version;
248399653d4eSeschrock 
248499653d4eSeschrock 	(void) snprintf(msg, sizeof (msg),
248599653d4eSeschrock 	    dgettext(TEXT_DOMAIN, "cannot remove %s"), path);
248699653d4eSeschrock 
248799653d4eSeschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2488ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
248988ecc943SGeorge Wilson 	    &islog)) == 0)
249099653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
249188ecc943SGeorge Wilson 	/*
249288ecc943SGeorge Wilson 	 * XXX - this should just go away.
249388ecc943SGeorge Wilson 	 */
249488ecc943SGeorge Wilson 	if (!avail_spare && !l2cache && !islog) {
249599653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
249688ecc943SGeorge Wilson 		    "only inactive hot spares, cache, top-level, "
249788ecc943SGeorge Wilson 		    "or log devices can be removed"));
249899653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
249999653d4eSeschrock 	}
250099653d4eSeschrock 
250188ecc943SGeorge Wilson 	version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
250288ecc943SGeorge Wilson 	if (islog && version < SPA_VERSION_HOLES) {
250388ecc943SGeorge Wilson 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
250488ecc943SGeorge Wilson 		    "pool must be upgrade to support log removal"));
250588ecc943SGeorge Wilson 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
250688ecc943SGeorge Wilson 	}
250788ecc943SGeorge Wilson 
250899653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
250999653d4eSeschrock 
2510ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
251199653d4eSeschrock 		return (0);
251299653d4eSeschrock 
251399653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
2514ea8dc4b6Seschrock }
2515ea8dc4b6Seschrock 
2516ea8dc4b6Seschrock /*
2517ea8dc4b6Seschrock  * Clear the errors for the pool, or the particular device if specified.
2518ea8dc4b6Seschrock  */
2519ea8dc4b6Seschrock int
2520468c413aSTim Haley zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl)
2521ea8dc4b6Seschrock {
2522ea8dc4b6Seschrock 	zfs_cmd_t zc = { 0 };
2523ea8dc4b6Seschrock 	char msg[1024];
252499653d4eSeschrock 	nvlist_t *tgt;
2525468c413aSTim Haley 	zpool_rewind_policy_t policy;
2526fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
252799653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2528468c413aSTim Haley 	nvlist_t *nvi = NULL;
2529ea8dc4b6Seschrock 
2530ea8dc4b6Seschrock 	if (path)
2531ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg),
2532ea8dc4b6Seschrock 		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
2533e9dbad6fSeschrock 		    path);
2534ea8dc4b6Seschrock 	else
2535ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg),
2536ea8dc4b6Seschrock 		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
2537ea8dc4b6Seschrock 		    zhp->zpool_name);
2538ea8dc4b6Seschrock 
2539ea8dc4b6Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
254099653d4eSeschrock 	if (path) {
2541fa94a07fSbrendan 		if ((tgt = zpool_find_vdev(zhp, path, &avail_spare,
2542ee0eb9f2SEric Schrock 		    &l2cache, NULL)) == 0)
254399653d4eSeschrock 			return (zfs_error(hdl, EZFS_NODEVICE, msg));
2544ea8dc4b6Seschrock 
2545fa94a07fSbrendan 		/*
2546fa94a07fSbrendan 		 * Don't allow error clearing for hot spares.  Do allow
2547fa94a07fSbrendan 		 * error clearing for l2cache devices.
2548fa94a07fSbrendan 		 */
2549a43d325bSek 		if (avail_spare)
255099653d4eSeschrock 			return (zfs_error(hdl, EZFS_ISSPARE, msg));
2551ea8dc4b6Seschrock 
255299653d4eSeschrock 		verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
255399653d4eSeschrock 		    &zc.zc_guid) == 0);
2554fa9e4066Sahrens 	}
2555fa9e4066Sahrens 
2556468c413aSTim Haley 	zpool_get_rewind_policy(rewindnvl, &policy);
2557468c413aSTim Haley 	zc.zc_cookie = policy.zrp_request;
2558468c413aSTim Haley 
2559468c413aSTim Haley 	if (zcmd_alloc_dst_nvlist(hdl, &zc, 8192) != 0)
2560468c413aSTim Haley 		return (-1);
2561468c413aSTim Haley 
2562468c413aSTim Haley 	if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, rewindnvl) != 0)
2563468c413aSTim Haley 		return (-1);
2564468c413aSTim Haley 
2565468c413aSTim Haley 	if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0 ||
2566468c413aSTim Haley 	    ((policy.zrp_request & ZPOOL_TRY_REWIND) &&
2567468c413aSTim Haley 	    errno != EPERM && errno != EACCES)) {
2568468c413aSTim Haley 		if (policy.zrp_request &
2569468c413aSTim Haley 		    (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) {
2570468c413aSTim Haley 			(void) zcmd_read_dst_nvlist(hdl, &zc, &nvi);
2571468c413aSTim Haley 			zpool_rewind_exclaim(hdl, zc.zc_name,
2572468c413aSTim Haley 			    ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0),
2573468c413aSTim Haley 			    nvi);
2574468c413aSTim Haley 			nvlist_free(nvi);
2575468c413aSTim Haley 		}
2576468c413aSTim Haley 		zcmd_free_nvlists(&zc);
257799653d4eSeschrock 		return (0);
2578468c413aSTim Haley 	}
257999653d4eSeschrock 
2580468c413aSTim Haley 	zcmd_free_nvlists(&zc);
258199653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
2582fa9e4066Sahrens }
2583fa9e4066Sahrens 
25843d7072f8Seschrock /*
25853d7072f8Seschrock  * Similar to zpool_clear(), but takes a GUID (used by fmd).
25863d7072f8Seschrock  */
25873d7072f8Seschrock int
25883d7072f8Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid)
25893d7072f8Seschrock {
25903d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
25913d7072f8Seschrock 	char msg[1024];
25923d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
25933d7072f8Seschrock 
25943d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
25953d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"),
25963d7072f8Seschrock 	    guid);
25973d7072f8Seschrock 
25983d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
25993d7072f8Seschrock 	zc.zc_guid = guid;
26003d7072f8Seschrock 
26013d7072f8Seschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0)
26023d7072f8Seschrock 		return (0);
26033d7072f8Seschrock 
26043d7072f8Seschrock 	return (zpool_standard_error(hdl, errno, msg));
26053d7072f8Seschrock }
26063d7072f8Seschrock 
2607c67d9675Seschrock /*
2608c67d9675Seschrock  * Convert from a devid string to a path.
2609c67d9675Seschrock  */
2610c67d9675Seschrock static char *
2611c67d9675Seschrock devid_to_path(char *devid_str)
2612c67d9675Seschrock {
2613c67d9675Seschrock 	ddi_devid_t devid;
2614c67d9675Seschrock 	char *minor;
2615c67d9675Seschrock 	char *path;
2616c67d9675Seschrock 	devid_nmlist_t *list = NULL;
2617c67d9675Seschrock 	int ret;
2618c67d9675Seschrock 
2619c67d9675Seschrock 	if (devid_str_decode(devid_str, &devid, &minor) != 0)
2620c67d9675Seschrock 		return (NULL);
2621c67d9675Seschrock 
2622c67d9675Seschrock 	ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list);
2623c67d9675Seschrock 
2624c67d9675Seschrock 	devid_str_free(minor);
2625c67d9675Seschrock 	devid_free(devid);
2626c67d9675Seschrock 
2627c67d9675Seschrock 	if (ret != 0)
2628c67d9675Seschrock 		return (NULL);
2629c67d9675Seschrock 
263099653d4eSeschrock 	if ((path = strdup(list[0].devname)) == NULL)
263199653d4eSeschrock 		return (NULL);
263299653d4eSeschrock 
2633c67d9675Seschrock 	devid_free_nmlist(list);
2634c67d9675Seschrock 
2635c67d9675Seschrock 	return (path);
2636c67d9675Seschrock }
2637c67d9675Seschrock 
2638c67d9675Seschrock /*
2639c67d9675Seschrock  * Convert from a path to a devid string.
2640c67d9675Seschrock  */
2641c67d9675Seschrock static char *
2642c67d9675Seschrock path_to_devid(const char *path)
2643c67d9675Seschrock {
2644c67d9675Seschrock 	int fd;
2645c67d9675Seschrock 	ddi_devid_t devid;
2646c67d9675Seschrock 	char *minor, *ret;
2647c67d9675Seschrock 
2648c67d9675Seschrock 	if ((fd = open(path, O_RDONLY)) < 0)
2649c67d9675Seschrock 		return (NULL);
2650c67d9675Seschrock 
2651c67d9675Seschrock 	minor = NULL;
2652c67d9675Seschrock 	ret = NULL;
2653c67d9675Seschrock 	if (devid_get(fd, &devid) == 0) {
2654c67d9675Seschrock 		if (devid_get_minor_name(fd, &minor) == 0)
2655c67d9675Seschrock 			ret = devid_str_encode(devid, minor);
2656c67d9675Seschrock 		if (minor != NULL)
2657c67d9675Seschrock 			devid_str_free(minor);
2658c67d9675Seschrock 		devid_free(devid);
2659c67d9675Seschrock 	}
2660c67d9675Seschrock 	(void) close(fd);
2661c67d9675Seschrock 
2662c67d9675Seschrock 	return (ret);
2663c67d9675Seschrock }
2664c67d9675Seschrock 
2665c67d9675Seschrock /*
2666c67d9675Seschrock  * Issue the necessary ioctl() to update the stored path value for the vdev.  We
2667c67d9675Seschrock  * ignore any failure here, since a common case is for an unprivileged user to
2668c67d9675Seschrock  * type 'zpool status', and we'll display the correct information anyway.
2669c67d9675Seschrock  */
2670c67d9675Seschrock static void
2671c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
2672c67d9675Seschrock {
2673c67d9675Seschrock 	zfs_cmd_t zc = { 0 };
2674c67d9675Seschrock 
2675c67d9675Seschrock 	(void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2676e9dbad6fSeschrock 	(void) strncpy(zc.zc_value, path, sizeof (zc.zc_value));
2677c67d9675Seschrock 	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
2678ea8dc4b6Seschrock 	    &zc.zc_guid) == 0);
2679c67d9675Seschrock 
268099653d4eSeschrock 	(void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc);
2681c67d9675Seschrock }
2682c67d9675Seschrock 
2683c67d9675Seschrock /*
2684c67d9675Seschrock  * Given a vdev, return the name to display in iostat.  If the vdev has a path,
2685c67d9675Seschrock  * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type.
2686c67d9675Seschrock  * We also check if this is a whole disk, in which case we strip off the
2687c67d9675Seschrock  * trailing 's0' slice name.
2688c67d9675Seschrock  *
2689c67d9675Seschrock  * This routine is also responsible for identifying when disks have been
2690c67d9675Seschrock  * reconfigured in a new location.  The kernel will have opened the device by
2691c67d9675Seschrock  * devid, but the path will still refer to the old location.  To catch this, we
2692c67d9675Seschrock  * first do a path -> devid translation (which is fast for the common case).  If
2693c67d9675Seschrock  * the devid matches, we're done.  If not, we do a reverse devid -> path
2694c67d9675Seschrock  * translation and issue the appropriate ioctl() to update the path of the vdev.
2695c67d9675Seschrock  * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any
2696c67d9675Seschrock  * of these checks.
2697c67d9675Seschrock  */
2698c67d9675Seschrock char *
269988ecc943SGeorge Wilson zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
270088ecc943SGeorge Wilson     boolean_t verbose)
2701c67d9675Seschrock {
2702c67d9675Seschrock 	char *path, *devid;
2703ea8dc4b6Seschrock 	uint64_t value;
2704ea8dc4b6Seschrock 	char buf[64];
27053d7072f8Seschrock 	vdev_stat_t *vs;
27063d7072f8Seschrock 	uint_t vsc;
2707c67d9675Seschrock 
2708ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2709ea8dc4b6Seschrock 	    &value) == 0) {
2710ea8dc4b6Seschrock 		verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
2711ea8dc4b6Seschrock 		    &value) == 0);
27125ad82045Snd 		(void) snprintf(buf, sizeof (buf), "%llu",
27135ad82045Snd 		    (u_longlong_t)value);
2714ea8dc4b6Seschrock 		path = buf;
2715ea8dc4b6Seschrock 	} else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
2716c67d9675Seschrock 
27173d7072f8Seschrock 		/*
27183d7072f8Seschrock 		 * If the device is dead (faulted, offline, etc) then don't
27193d7072f8Seschrock 		 * bother opening it.  Otherwise we may be forcing the user to
27203d7072f8Seschrock 		 * open a misbehaving device, which can have undesirable
27213d7072f8Seschrock 		 * effects.
27223d7072f8Seschrock 		 */
27233d7072f8Seschrock 		if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
27243d7072f8Seschrock 		    (uint64_t **)&vs, &vsc) != 0 ||
27253d7072f8Seschrock 		    vs->vs_state >= VDEV_STATE_DEGRADED) &&
27263d7072f8Seschrock 		    zhp != NULL &&
2727c67d9675Seschrock 		    nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) {
2728c67d9675Seschrock 			/*
2729c67d9675Seschrock 			 * Determine if the current path is correct.
2730c67d9675Seschrock 			 */
2731c67d9675Seschrock 			char *newdevid = path_to_devid(path);
2732c67d9675Seschrock 
2733c67d9675Seschrock 			if (newdevid == NULL ||
2734c67d9675Seschrock 			    strcmp(devid, newdevid) != 0) {
2735c67d9675Seschrock 				char *newpath;
2736c67d9675Seschrock 
2737c67d9675Seschrock 				if ((newpath = devid_to_path(devid)) != NULL) {
2738c67d9675Seschrock 					/*
2739c67d9675Seschrock 					 * Update the path appropriately.
2740c67d9675Seschrock 					 */
2741c67d9675Seschrock 					set_path(zhp, nv, newpath);
274299653d4eSeschrock 					if (nvlist_add_string(nv,
274399653d4eSeschrock 					    ZPOOL_CONFIG_PATH, newpath) == 0)
274499653d4eSeschrock 						verify(nvlist_lookup_string(nv,
274599653d4eSeschrock 						    ZPOOL_CONFIG_PATH,
274699653d4eSeschrock 						    &path) == 0);
2747c67d9675Seschrock 					free(newpath);
2748c67d9675Seschrock 				}
2749c67d9675Seschrock 			}
2750c67d9675Seschrock 
275199653d4eSeschrock 			if (newdevid)
275299653d4eSeschrock 				devid_str_free(newdevid);
2753c67d9675Seschrock 		}
2754c67d9675Seschrock 
2755c67d9675Seschrock 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2756c67d9675Seschrock 			path += 9;
2757c67d9675Seschrock 
2758c67d9675Seschrock 		if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
2759ea8dc4b6Seschrock 		    &value) == 0 && value) {
276099653d4eSeschrock 			char *tmp = zfs_strdup(hdl, path);
276199653d4eSeschrock 			if (tmp == NULL)
276299653d4eSeschrock 				return (NULL);
2763c67d9675Seschrock 			tmp[strlen(path) - 2] = '\0';
2764c67d9675Seschrock 			return (tmp);
2765c67d9675Seschrock 		}
2766c67d9675Seschrock 	} else {
2767c67d9675Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
276899653d4eSeschrock 
276999653d4eSeschrock 		/*
277099653d4eSeschrock 		 * If it's a raidz device, we need to stick in the parity level.
277199653d4eSeschrock 		 */
277299653d4eSeschrock 		if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) {
277399653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
277499653d4eSeschrock 			    &value) == 0);
277599653d4eSeschrock 			(void) snprintf(buf, sizeof (buf), "%s%llu", path,
27765ad82045Snd 			    (u_longlong_t)value);
277799653d4eSeschrock 			path = buf;
277899653d4eSeschrock 		}
277988ecc943SGeorge Wilson 
278088ecc943SGeorge Wilson 		/*
278188ecc943SGeorge Wilson 		 * We identify each top-level vdev by using a <type-id>
278288ecc943SGeorge Wilson 		 * naming convention.
278388ecc943SGeorge Wilson 		 */
278488ecc943SGeorge Wilson 		if (verbose) {
278588ecc943SGeorge Wilson 			uint64_t id;
278688ecc943SGeorge Wilson 
278788ecc943SGeorge Wilson 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
278888ecc943SGeorge Wilson 			    &id) == 0);
278988ecc943SGeorge Wilson 			(void) snprintf(buf, sizeof (buf), "%s-%llu", path,
279088ecc943SGeorge Wilson 			    (u_longlong_t)id);
279188ecc943SGeorge Wilson 			path = buf;
279288ecc943SGeorge Wilson 		}
2793c67d9675Seschrock 	}
2794c67d9675Seschrock 
279599653d4eSeschrock 	return (zfs_strdup(hdl, path));
2796c67d9675Seschrock }
2797ea8dc4b6Seschrock 
2798ea8dc4b6Seschrock static int
2799ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b)
2800ea8dc4b6Seschrock {
2801ea8dc4b6Seschrock 	return (memcmp(a, b, sizeof (zbookmark_t)));
2802ea8dc4b6Seschrock }
2803ea8dc4b6Seschrock 
2804ea8dc4b6Seschrock /*
2805ea8dc4b6Seschrock  * Retrieve the persistent error log, uniquify the members, and return to the
2806ea8dc4b6Seschrock  * caller.
2807ea8dc4b6Seschrock  */
2808ea8dc4b6Seschrock int
280955434c77Sek zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
2810ea8dc4b6Seschrock {
2811ea8dc4b6Seschrock 	zfs_cmd_t zc = { 0 };
2812ea8dc4b6Seschrock 	uint64_t count;
2813e9dbad6fSeschrock 	zbookmark_t *zb = NULL;
281455434c77Sek 	int i;
2815ea8dc4b6Seschrock 
2816ea8dc4b6Seschrock 	/*
2817ea8dc4b6Seschrock 	 * Retrieve the raw error list from the kernel.  If the number of errors
2818ea8dc4b6Seschrock 	 * has increased, allocate more space and continue until we get the
2819ea8dc4b6Seschrock 	 * entire list.
2820ea8dc4b6Seschrock 	 */
2821ea8dc4b6Seschrock 	verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT,
2822ea8dc4b6Seschrock 	    &count) == 0);
282375519f38Sek 	if (count == 0)
282475519f38Sek 		return (0);
2825e9dbad6fSeschrock 	if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
28265ad82045Snd 	    count * sizeof (zbookmark_t))) == (uintptr_t)NULL)
282799653d4eSeschrock 		return (-1);
2828e9dbad6fSeschrock 	zc.zc_nvlist_dst_size = count;
2829ea8dc4b6Seschrock 	(void) strcpy(zc.zc_name, zhp->zpool_name);
2830ea8dc4b6Seschrock 	for (;;) {
283199653d4eSeschrock 		if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG,
283299653d4eSeschrock 		    &zc) != 0) {
2833e9dbad6fSeschrock 			free((void *)(uintptr_t)zc.zc_nvlist_dst);
2834ea8dc4b6Seschrock 			if (errno == ENOMEM) {
2835bf561db0Svb 				count = zc.zc_nvlist_dst_size;
2836e9dbad6fSeschrock 				if ((zc.zc_nvlist_dst = (uintptr_t)
2837bf561db0Svb 				    zfs_alloc(zhp->zpool_hdl, count *
2838bf561db0Svb 				    sizeof (zbookmark_t))) == (uintptr_t)NULL)
283999653d4eSeschrock 					return (-1);
2840ea8dc4b6Seschrock 			} else {
2841ea8dc4b6Seschrock 				return (-1);
2842ea8dc4b6Seschrock 			}
2843ea8dc4b6Seschrock 		} else {
2844ea8dc4b6Seschrock 			break;
2845ea8dc4b6Seschrock 		}
2846ea8dc4b6Seschrock 	}
2847ea8dc4b6Seschrock 
2848ea8dc4b6Seschrock 	/*
2849ea8dc4b6Seschrock 	 * Sort the resulting bookmarks.  This is a little confusing due to the
2850ea8dc4b6Seschrock 	 * implementation of ZFS_IOC_ERROR_LOG.  The bookmarks are copied last
2851e9dbad6fSeschrock 	 * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks
2852ea8dc4b6Seschrock 	 * _not_ copied as part of the process.  So we point the start of our
2853ea8dc4b6Seschrock 	 * array appropriate and decrement the total number of elements.
2854ea8dc4b6Seschrock 	 */
2855e9dbad6fSeschrock 	zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) +
2856e9dbad6fSeschrock 	    zc.zc_nvlist_dst_size;
2857e9dbad6fSeschrock 	count -= zc.zc_nvlist_dst_size;
2858ea8dc4b6Seschrock 
2859ea8dc4b6Seschrock 	qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare);
2860ea8dc4b6Seschrock 
286155434c77Sek 	verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0);
2862ea8dc4b6Seschrock 
2863ea8dc4b6Seschrock 	/*
286455434c77Sek 	 * Fill in the nverrlistp with nvlist's of dataset and object numbers.
2865ea8dc4b6Seschrock 	 */
2866ea8dc4b6Seschrock 	for (i = 0; i < count; i++) {
2867ea8dc4b6Seschrock 		nvlist_t *nv;
2868ea8dc4b6Seschrock 
2869c0a81264Sek 		/* ignoring zb_blkid and zb_level for now */
2870c0a81264Sek 		if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset &&
2871c0a81264Sek 		    zb[i-1].zb_object == zb[i].zb_object)
2872ea8dc4b6Seschrock 			continue;
2873ea8dc4b6Seschrock 
287455434c77Sek 		if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0)
287555434c77Sek 			goto nomem;
287655434c77Sek 		if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET,
287755434c77Sek 		    zb[i].zb_objset) != 0) {
287855434c77Sek 			nvlist_free(nv);
287999653d4eSeschrock 			goto nomem;
2880ea8dc4b6Seschrock 		}
288155434c77Sek 		if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT,
288255434c77Sek 		    zb[i].zb_object) != 0) {
288355434c77Sek 			nvlist_free(nv);
288455434c77Sek 			goto nomem;
288555434c77Sek 		}
288655434c77Sek 		if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) {
288755434c77Sek 			nvlist_free(nv);
288855434c77Sek 			goto nomem;
288955434c77Sek 		}
289055434c77Sek 		nvlist_free(nv);
2891ea8dc4b6Seschrock 	}
2892ea8dc4b6Seschrock 
28933ccfa83cSahrens 	free((void *)(uintptr_t)zc.zc_nvlist_dst);
2894ea8dc4b6Seschrock 	return (0);
289599653d4eSeschrock 
289699653d4eSeschrock nomem:
2897e9dbad6fSeschrock 	free((void *)(uintptr_t)zc.zc_nvlist_dst);
289899653d4eSeschrock 	return (no_memory(zhp->zpool_hdl));
2899ea8dc4b6Seschrock }
2900eaca9bbdSeschrock 
2901eaca9bbdSeschrock /*
2902eaca9bbdSeschrock  * Upgrade a ZFS pool to the latest on-disk version.
2903eaca9bbdSeschrock  */
2904eaca9bbdSeschrock int
2905990b4856Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version)
2906eaca9bbdSeschrock {
2907eaca9bbdSeschrock 	zfs_cmd_t zc = { 0 };
290899653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2909eaca9bbdSeschrock 
2910eaca9bbdSeschrock 	(void) strcpy(zc.zc_name, zhp->zpool_name);
2911990b4856Slling 	zc.zc_cookie = new_version;
2912990b4856Slling 
2913ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0)
2914ece3d9b3Slling 		return (zpool_standard_error_fmt(hdl, errno,
291599653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"),
291699653d4eSeschrock 		    zhp->zpool_name));
2917eaca9bbdSeschrock 	return (0);
2918eaca9bbdSeschrock }
291906eeb2adSek 
292006eeb2adSek void
29212a6b87f0Sek zpool_set_history_str(const char *subcommand, int argc, char **argv,
29222a6b87f0Sek     char *history_str)
292306eeb2adSek {
292406eeb2adSek 	int i;
292506eeb2adSek 
29262a6b87f0Sek 	(void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN);
29272a6b87f0Sek 	for (i = 1; i < argc; i++) {
29282a6b87f0Sek 		if (strlen(history_str) + 1 + strlen(argv[i]) >
29292a6b87f0Sek 		    HIS_MAX_RECORD_LEN)
29302a6b87f0Sek 			break;
29312a6b87f0Sek 		(void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN);
29322a6b87f0Sek 		(void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN);
29332a6b87f0Sek 	}
29342a6b87f0Sek }
29352a6b87f0Sek 
29362a6b87f0Sek /*
29372a6b87f0Sek  * Stage command history for logging.
29382a6b87f0Sek  */
29392a6b87f0Sek int
29402a6b87f0Sek zpool_stage_history(libzfs_handle_t *hdl, const char *history_str)
29412a6b87f0Sek {
29422a6b87f0Sek 	if (history_str == NULL)
29432a6b87f0Sek 		return (EINVAL);
29442a6b87f0Sek 
29452a6b87f0Sek 	if (strlen(history_str) > HIS_MAX_RECORD_LEN)
29462a6b87f0Sek 		return (EINVAL);
29472a6b87f0Sek 
2948228975ccSek 	if (hdl->libzfs_log_str != NULL)
2949ecd6cf80Smarks 		free(hdl->libzfs_log_str);
295006eeb2adSek 
29512a6b87f0Sek 	if ((hdl->libzfs_log_str = strdup(history_str)) == NULL)
29522a6b87f0Sek 		return (no_memory(hdl));
295306eeb2adSek 
29542a6b87f0Sek 	return (0);
295506eeb2adSek }
295606eeb2adSek 
295706eeb2adSek /*
295806eeb2adSek  * Perform ioctl to get some command history of a pool.
295906eeb2adSek  *
296006eeb2adSek  * 'buf' is the buffer to fill up to 'len' bytes.  'off' is the
296106eeb2adSek  * logical offset of the history buffer to start reading from.
296206eeb2adSek  *
296306eeb2adSek  * Upon return, 'off' is the next logical offset to read from and
296406eeb2adSek  * 'len' is the actual amount of bytes read into 'buf'.
296506eeb2adSek  */
296606eeb2adSek static int
296706eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len)
296806eeb2adSek {
296906eeb2adSek 	zfs_cmd_t zc = { 0 };
297006eeb2adSek 	libzfs_handle_t *hdl = zhp->zpool_hdl;
297106eeb2adSek 
297206eeb2adSek 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
297306eeb2adSek 
297406eeb2adSek 	zc.zc_history = (uint64_t)(uintptr_t)buf;
297506eeb2adSek 	zc.zc_history_len = *len;
297606eeb2adSek 	zc.zc_history_offset = *off;
297706eeb2adSek 
297806eeb2adSek 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) {
297906eeb2adSek 		switch (errno) {
298006eeb2adSek 		case EPERM:
2981ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_PERM,
2982ece3d9b3Slling 			    dgettext(TEXT_DOMAIN,
298306eeb2adSek 			    "cannot show history for pool '%s'"),
298406eeb2adSek 			    zhp->zpool_name));
298506eeb2adSek 		case ENOENT:
2986ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_NOHISTORY,
298706eeb2adSek 			    dgettext(TEXT_DOMAIN, "cannot get history for pool "
298806eeb2adSek 			    "'%s'"), zhp->zpool_name));
2989d7306b64Sek 		case ENOTSUP:
2990d7306b64Sek 			return (zfs_error_fmt(hdl, EZFS_BADVERSION,
2991d7306b64Sek 			    dgettext(TEXT_DOMAIN, "cannot get history for pool "
2992d7306b64Sek 			    "'%s', pool must be upgraded"), zhp->zpool_name));
299306eeb2adSek 		default:
2994ece3d9b3Slling 			return (zpool_standard_error_fmt(hdl, errno,
299506eeb2adSek 			    dgettext(TEXT_DOMAIN,
299606eeb2adSek 			    "cannot get history for '%s'"), zhp->zpool_name));
299706eeb2adSek 		}
299806eeb2adSek 	}
299906eeb2adSek 
300006eeb2adSek 	*len = zc.zc_history_len;
300106eeb2adSek 	*off = zc.zc_history_offset;
300206eeb2adSek 
300306eeb2adSek 	return (0);
300406eeb2adSek }
300506eeb2adSek 
300606eeb2adSek /*
300706eeb2adSek  * Process the buffer of nvlists, unpacking and storing each nvlist record
300806eeb2adSek  * into 'records'.  'leftover' is set to the number of bytes that weren't
300906eeb2adSek  * processed as there wasn't a complete record.
301006eeb2adSek  */
30118f18d1faSGeorge Wilson int
301206eeb2adSek zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
301306eeb2adSek     nvlist_t ***records, uint_t *numrecords)
301406eeb2adSek {
301506eeb2adSek 	uint64_t reclen;
301606eeb2adSek 	nvlist_t *nv;
301706eeb2adSek 	int i;
301806eeb2adSek 
301906eeb2adSek 	while (bytes_read > sizeof (reclen)) {
302006eeb2adSek 
302106eeb2adSek 		/* get length of packed record (stored as little endian) */
302206eeb2adSek 		for (i = 0, reclen = 0; i < sizeof (reclen); i++)
302306eeb2adSek 			reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i);
302406eeb2adSek 
302506eeb2adSek 		if (bytes_read < sizeof (reclen) + reclen)
302606eeb2adSek 			break;
302706eeb2adSek 
302806eeb2adSek 		/* unpack record */
302906eeb2adSek 		if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0)
303006eeb2adSek 			return (ENOMEM);
303106eeb2adSek 		bytes_read -= sizeof (reclen) + reclen;
303206eeb2adSek 		buf += sizeof (reclen) + reclen;
303306eeb2adSek 
303406eeb2adSek 		/* add record to nvlist array */
303506eeb2adSek 		(*numrecords)++;
303606eeb2adSek 		if (ISP2(*numrecords + 1)) {
303706eeb2adSek 			*records = realloc(*records,
303806eeb2adSek 			    *numrecords * 2 * sizeof (nvlist_t *));
303906eeb2adSek 		}
304006eeb2adSek 		(*records)[*numrecords - 1] = nv;
304106eeb2adSek 	}
304206eeb2adSek 
304306eeb2adSek 	*leftover = bytes_read;
304406eeb2adSek 	return (0);
304506eeb2adSek }
304606eeb2adSek 
304706eeb2adSek #define	HIS_BUF_LEN	(128*1024)
304806eeb2adSek 
304906eeb2adSek /*
305006eeb2adSek  * Retrieve the command history of a pool.
305106eeb2adSek  */
305206eeb2adSek int
305306eeb2adSek zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
305406eeb2adSek {
305506eeb2adSek 	char buf[HIS_BUF_LEN];
305606eeb2adSek 	uint64_t off = 0;
305706eeb2adSek 	nvlist_t **records = NULL;
305806eeb2adSek 	uint_t numrecords = 0;
305906eeb2adSek 	int err, i;
306006eeb2adSek 
306106eeb2adSek 	do {
306206eeb2adSek 		uint64_t bytes_read = sizeof (buf);
306306eeb2adSek 		uint64_t leftover;
306406eeb2adSek 
306506eeb2adSek 		if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
306606eeb2adSek 			break;
306706eeb2adSek 
306806eeb2adSek 		/* if nothing else was read in, we're at EOF, just return */
306906eeb2adSek 		if (!bytes_read)
307006eeb2adSek 			break;
307106eeb2adSek 
307206eeb2adSek 		if ((err = zpool_history_unpack(buf, bytes_read,
307306eeb2adSek 		    &leftover, &records, &numrecords)) != 0)
307406eeb2adSek 			break;
307506eeb2adSek 		off -= leftover;
307606eeb2adSek 
307706eeb2adSek 		/* CONSTCOND */
307806eeb2adSek 	} while (1);
307906eeb2adSek 
308006eeb2adSek 	if (!err) {
308106eeb2adSek 		verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0);
308206eeb2adSek 		verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD,
308306eeb2adSek 		    records, numrecords) == 0);
308406eeb2adSek 	}
308506eeb2adSek 	for (i = 0; i < numrecords; i++)
308606eeb2adSek 		nvlist_free(records[i]);
308706eeb2adSek 	free(records);
308806eeb2adSek 
308906eeb2adSek 	return (err);
309006eeb2adSek }
309155434c77Sek 
309255434c77Sek void
309355434c77Sek zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
309455434c77Sek     char *pathname, size_t len)
309555434c77Sek {
309655434c77Sek 	zfs_cmd_t zc = { 0 };
309755434c77Sek 	boolean_t mounted = B_FALSE;
309855434c77Sek 	char *mntpnt = NULL;
309955434c77Sek 	char dsname[MAXNAMELEN];
310055434c77Sek 
310155434c77Sek 	if (dsobj == 0) {
310255434c77Sek 		/* special case for the MOS */
310355434c77Sek 		(void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj);
310455434c77Sek 		return;
310555434c77Sek 	}
310655434c77Sek 
310755434c77Sek 	/* get the dataset's name */
310855434c77Sek 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
310955434c77Sek 	zc.zc_obj = dsobj;
311055434c77Sek 	if (ioctl(zhp->zpool_hdl->libzfs_fd,
311155434c77Sek 	    ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) {
311255434c77Sek 		/* just write out a path of two object numbers */
311355434c77Sek 		(void) snprintf(pathname, len, "<0x%llx>:<0x%llx>",
311455434c77Sek 		    dsobj, obj);
311555434c77Sek 		return;
311655434c77Sek 	}
311755434c77Sek 	(void) strlcpy(dsname, zc.zc_value, sizeof (dsname));
311855434c77Sek 
311955434c77Sek 	/* find out if the dataset is mounted */
312055434c77Sek 	mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt);
312155434c77Sek 
312255434c77Sek 	/* get the corrupted object's path */
312355434c77Sek 	(void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
312455434c77Sek 	zc.zc_obj = obj;
312555434c77Sek 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH,
312655434c77Sek 	    &zc) == 0) {
312755434c77Sek 		if (mounted) {
312855434c77Sek 			(void) snprintf(pathname, len, "%s%s", mntpnt,
312955434c77Sek 			    zc.zc_value);
313055434c77Sek 		} else {
313155434c77Sek 			(void) snprintf(pathname, len, "%s:%s",
313255434c77Sek 			    dsname, zc.zc_value);
313355434c77Sek 		}
313455434c77Sek 	} else {
313555434c77Sek 		(void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj);
313655434c77Sek 	}
313755434c77Sek 	free(mntpnt);
313855434c77Sek }
3139b1b8ab34Slling 
314015e6edf1Sgw /*
314115e6edf1Sgw  * Read the EFI label from the config, if a label does not exist then
314215e6edf1Sgw  * pass back the error to the caller. If the caller has passed a non-NULL
314315e6edf1Sgw  * diskaddr argument then we set it to the starting address of the EFI
314415e6edf1Sgw  * partition.
314515e6edf1Sgw  */
314615e6edf1Sgw static int
314715e6edf1Sgw read_efi_label(nvlist_t *config, diskaddr_t *sb)
314815e6edf1Sgw {
314915e6edf1Sgw 	char *path;
315015e6edf1Sgw 	int fd;
315115e6edf1Sgw 	char diskname[MAXPATHLEN];
315215e6edf1Sgw 	int err = -1;
315315e6edf1Sgw 
315415e6edf1Sgw 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0)
315515e6edf1Sgw 		return (err);
315615e6edf1Sgw 
315715e6edf1Sgw 	(void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT,
315815e6edf1Sgw 	    strrchr(path, '/'));
315915e6edf1Sgw 	if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) {
316015e6edf1Sgw 		struct dk_gpt *vtoc;
316115e6edf1Sgw 
316215e6edf1Sgw 		if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) {
316315e6edf1Sgw 			if (sb != NULL)
316415e6edf1Sgw 				*sb = vtoc->efi_parts[0].p_start;
316515e6edf1Sgw 			efi_free(vtoc);
316615e6edf1Sgw 		}
316715e6edf1Sgw 		(void) close(fd);
316815e6edf1Sgw 	}
316915e6edf1Sgw 	return (err);
317015e6edf1Sgw }
317115e6edf1Sgw 
31728488aeb5Staylor /*
31738488aeb5Staylor  * determine where a partition starts on a disk in the current
31748488aeb5Staylor  * configuration
31758488aeb5Staylor  */
31768488aeb5Staylor static diskaddr_t
31778488aeb5Staylor find_start_block(nvlist_t *config)
31788488aeb5Staylor {
31798488aeb5Staylor 	nvlist_t **child;
31808488aeb5Staylor 	uint_t c, children;
31818488aeb5Staylor 	diskaddr_t sb = MAXOFFSET_T;
31828488aeb5Staylor 	uint64_t wholedisk;
31838488aeb5Staylor 
31848488aeb5Staylor 	if (nvlist_lookup_nvlist_array(config,
31858488aeb5Staylor 	    ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) {
31868488aeb5Staylor 		if (nvlist_lookup_uint64(config,
31878488aeb5Staylor 		    ZPOOL_CONFIG_WHOLE_DISK,
31888488aeb5Staylor 		    &wholedisk) != 0 || !wholedisk) {
31898488aeb5Staylor 			return (MAXOFFSET_T);
31908488aeb5Staylor 		}
319115e6edf1Sgw 		if (read_efi_label(config, &sb) < 0)
319215e6edf1Sgw 			sb = MAXOFFSET_T;
31938488aeb5Staylor 		return (sb);
31948488aeb5Staylor 	}
31958488aeb5Staylor 
31968488aeb5Staylor 	for (c = 0; c < children; c++) {
31978488aeb5Staylor 		sb = find_start_block(child[c]);
31988488aeb5Staylor 		if (sb != MAXOFFSET_T) {
31998488aeb5Staylor 			return (sb);
32008488aeb5Staylor 		}
32018488aeb5Staylor 	}
32028488aeb5Staylor 	return (MAXOFFSET_T);
32038488aeb5Staylor }
32048488aeb5Staylor 
32058488aeb5Staylor /*
32068488aeb5Staylor  * Label an individual disk.  The name provided is the short name,
32078488aeb5Staylor  * stripped of any leading /dev path.
32088488aeb5Staylor  */
32098488aeb5Staylor int
32108488aeb5Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name)
32118488aeb5Staylor {
32128488aeb5Staylor 	char path[MAXPATHLEN];
32138488aeb5Staylor 	struct dk_gpt *vtoc;
32148488aeb5Staylor 	int fd;
32158488aeb5Staylor 	size_t resv = EFI_MIN_RESV_SIZE;
32168488aeb5Staylor 	uint64_t slice_size;
32178488aeb5Staylor 	diskaddr_t start_block;
32188488aeb5Staylor 	char errbuf[1024];
32198488aeb5Staylor 
3220c6ef114fSmmusante 	/* prepare an error message just in case */
3221c6ef114fSmmusante 	(void) snprintf(errbuf, sizeof (errbuf),
3222c6ef114fSmmusante 	    dgettext(TEXT_DOMAIN, "cannot label '%s'"), name);
3223c6ef114fSmmusante 
32248488aeb5Staylor 	if (zhp) {
32258488aeb5Staylor 		nvlist_t *nvroot;
32268488aeb5Staylor 
3227b5b76fecSGeorge Wilson 		if (pool_is_bootable(zhp)) {
3228b5b76fecSGeorge Wilson 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3229b5b76fecSGeorge Wilson 			    "EFI labeled devices are not supported on root "
3230b5b76fecSGeorge Wilson 			    "pools."));
3231b5b76fecSGeorge Wilson 			return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf));
3232b5b76fecSGeorge Wilson 		}
3233b5b76fecSGeorge Wilson 
32348488aeb5Staylor 		verify(nvlist_lookup_nvlist(zhp->zpool_config,
32358488aeb5Staylor 		    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
32368488aeb5Staylor 
32378488aeb5Staylor 		if (zhp->zpool_start_block == 0)
32388488aeb5Staylor 			start_block = find_start_block(nvroot);
32398488aeb5Staylor 		else
32408488aeb5Staylor 			start_block = zhp->zpool_start_block;
32418488aeb5Staylor 		zhp->zpool_start_block = start_block;
32428488aeb5Staylor 	} else {
32438488aeb5Staylor 		/* new pool */
32448488aeb5Staylor 		start_block = NEW_START_BLOCK;
32458488aeb5Staylor 	}
32468488aeb5Staylor 
32478488aeb5Staylor 	(void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name,
32488488aeb5Staylor 	    BACKUP_SLICE);
32498488aeb5Staylor 
32508488aeb5Staylor 	if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) {
32518488aeb5Staylor 		/*
32528488aeb5Staylor 		 * This shouldn't happen.  We've long since verified that this
32538488aeb5Staylor 		 * is a valid device.
32548488aeb5Staylor 		 */
3255c6ef114fSmmusante 		zfs_error_aux(hdl,
3256c6ef114fSmmusante 		    dgettext(TEXT_DOMAIN, "unable to open device"));
32578488aeb5Staylor 		return (zfs_error(hdl, EZFS_OPENFAILED, errbuf));
32588488aeb5Staylor 	}
32598488aeb5Staylor 
32608488aeb5Staylor 	if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) {
32618488aeb5Staylor 		/*
32628488aeb5Staylor 		 * The only way this can fail is if we run out of memory, or we
32638488aeb5Staylor 		 * were unable to read the disk's capacity
32648488aeb5Staylor 		 */
32658488aeb5Staylor 		if (errno == ENOMEM)
32668488aeb5Staylor 			(void) no_memory(hdl);
32678488aeb5Staylor 
32688488aeb5Staylor 		(void) close(fd);
3269c6ef114fSmmusante 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3270c6ef114fSmmusante 		    "unable to read disk capacity"), name);
32718488aeb5Staylor 
32728488aeb5Staylor 		return (zfs_error(hdl, EZFS_NOCAP, errbuf));
32738488aeb5Staylor 	}
32748488aeb5Staylor 
32758488aeb5Staylor 	slice_size = vtoc->efi_last_u_lba + 1;
32768488aeb5Staylor 	slice_size -= EFI_MIN_RESV_SIZE;
32778488aeb5Staylor 	if (start_block == MAXOFFSET_T)
32788488aeb5Staylor 		start_block = NEW_START_BLOCK;
32798488aeb5Staylor 	slice_size -= start_block;
32808488aeb5Staylor 
32818488aeb5Staylor 	vtoc->efi_parts[0].p_start = start_block;
32828488aeb5Staylor 	vtoc->efi_parts[0].p_size = slice_size;
32838488aeb5Staylor 
32848488aeb5Staylor 	/*
32858488aeb5Staylor 	 * Why we use V_USR: V_BACKUP confuses users, and is considered
32868488aeb5Staylor 	 * disposable by some EFI utilities (since EFI doesn't have a backup
32878488aeb5Staylor 	 * slice).  V_UNASSIGNED is supposed to be used only for zero size
32888488aeb5Staylor 	 * partitions, and efi_write() will fail if we use it.  V_ROOT, V_BOOT,
32898488aeb5Staylor 	 * etc. were all pretty specific.  V_USR is as close to reality as we
32908488aeb5Staylor 	 * can get, in the absence of V_OTHER.
32918488aeb5Staylor 	 */
32928488aeb5Staylor 	vtoc->efi_parts[0].p_tag = V_USR;
32938488aeb5Staylor 	(void) strcpy(vtoc->efi_parts[0].p_name, "zfs");
32948488aeb5Staylor 
32958488aeb5Staylor 	vtoc->efi_parts[8].p_start = slice_size + start_block;
32968488aeb5Staylor 	vtoc->efi_parts[8].p_size = resv;
32978488aeb5Staylor 	vtoc->efi_parts[8].p_tag = V_RESERVED;
32988488aeb5Staylor 
32998488aeb5Staylor 	if (efi_write(fd, vtoc) != 0) {
33008488aeb5Staylor 		/*
33018488aeb5Staylor 		 * Some block drivers (like pcata) may not support EFI
33028488aeb5Staylor 		 * GPT labels.  Print out a helpful error message dir-
33038488aeb5Staylor 		 * ecting the user to manually label the disk and give
33048488aeb5Staylor 		 * a specific slice.
33058488aeb5Staylor 		 */
33068488aeb5Staylor 		(void) close(fd);
33078488aeb5Staylor 		efi_free(vtoc);
33088488aeb5Staylor 
33098488aeb5Staylor 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3310c6ef114fSmmusante 		    "try using fdisk(1M) and then provide a specific slice"));
33118488aeb5Staylor 		return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
33128488aeb5Staylor 	}
33138488aeb5Staylor 
33148488aeb5Staylor 	(void) close(fd);
33158488aeb5Staylor 	efi_free(vtoc);
33168488aeb5Staylor 	return (0);
33178488aeb5Staylor }
3318e7cbe64fSgw 
3319e7cbe64fSgw static boolean_t
3320e7cbe64fSgw supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf)
3321e7cbe64fSgw {
3322e7cbe64fSgw 	char *type;
3323e7cbe64fSgw 	nvlist_t **child;
3324e7cbe64fSgw 	uint_t children, c;
3325e7cbe64fSgw 
3326e7cbe64fSgw 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0);
3327e7cbe64fSgw 	if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 ||
3328e7cbe64fSgw 	    strcmp(type, VDEV_TYPE_FILE) == 0 ||
3329e7cbe64fSgw 	    strcmp(type, VDEV_TYPE_LOG) == 0 ||
333088ecc943SGeorge Wilson 	    strcmp(type, VDEV_TYPE_HOLE) == 0 ||
3331e7cbe64fSgw 	    strcmp(type, VDEV_TYPE_MISSING) == 0) {
3332e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3333e7cbe64fSgw 		    "vdev type '%s' is not supported"), type);
3334e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf);
3335e7cbe64fSgw 		return (B_FALSE);
3336e7cbe64fSgw 	}
3337e7cbe64fSgw 	if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
3338e7cbe64fSgw 	    &child, &children) == 0) {
3339e7cbe64fSgw 		for (c = 0; c < children; c++) {
3340e7cbe64fSgw 			if (!supported_dump_vdev_type(hdl, child[c], errbuf))
3341e7cbe64fSgw 				return (B_FALSE);
3342e7cbe64fSgw 		}
3343e7cbe64fSgw 	}
3344e7cbe64fSgw 	return (B_TRUE);
3345e7cbe64fSgw }
3346e7cbe64fSgw 
3347e7cbe64fSgw /*
3348e7cbe64fSgw  * check if this zvol is allowable for use as a dump device; zero if
3349e7cbe64fSgw  * it is, > 0 if it isn't, < 0 if it isn't a zvol
3350e7cbe64fSgw  */
3351e7cbe64fSgw int
3352e7cbe64fSgw zvol_check_dump_config(char *arg)
3353e7cbe64fSgw {
3354e7cbe64fSgw 	zpool_handle_t *zhp = NULL;
3355e7cbe64fSgw 	nvlist_t *config, *nvroot;
3356e7cbe64fSgw 	char *p, *volname;
3357e7cbe64fSgw 	nvlist_t **top;
3358e7cbe64fSgw 	uint_t toplevels;
3359e7cbe64fSgw 	libzfs_handle_t *hdl;
3360e7cbe64fSgw 	char errbuf[1024];
3361e7cbe64fSgw 	char poolname[ZPOOL_MAXNAMELEN];
3362e7cbe64fSgw 	int pathlen = strlen(ZVOL_FULL_DEV_DIR);
3363e7cbe64fSgw 	int ret = 1;
3364e7cbe64fSgw 
3365e7cbe64fSgw 	if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) {
3366e7cbe64fSgw 		return (-1);
3367e7cbe64fSgw 	}
3368e7cbe64fSgw 
3369e7cbe64fSgw 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3370e7cbe64fSgw 	    "dump is not supported on device '%s'"), arg);
3371e7cbe64fSgw 
3372e7cbe64fSgw 	if ((hdl = libzfs_init()) == NULL)
3373e7cbe64fSgw 		return (1);
3374e7cbe64fSgw 	libzfs_print_on_error(hdl, B_TRUE);
3375e7cbe64fSgw 
3376e7cbe64fSgw 	volname = arg + pathlen;
3377e7cbe64fSgw 
3378e7cbe64fSgw 	/* check the configuration of the pool */
3379e7cbe64fSgw 	if ((p = strchr(volname, '/')) == NULL) {
3380e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3381e7cbe64fSgw 		    "malformed dataset name"));
3382e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
3383e7cbe64fSgw 		return (1);
3384e7cbe64fSgw 	} else if (p - volname >= ZFS_MAXNAMELEN) {
3385e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3386e7cbe64fSgw 		    "dataset name is too long"));
3387e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf);
3388e7cbe64fSgw 		return (1);
3389e7cbe64fSgw 	} else {
3390e7cbe64fSgw 		(void) strncpy(poolname, volname, p - volname);
3391e7cbe64fSgw 		poolname[p - volname] = '\0';
3392e7cbe64fSgw 	}
3393e7cbe64fSgw 
3394e7cbe64fSgw 	if ((zhp = zpool_open(hdl, poolname)) == NULL) {
3395e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3396e7cbe64fSgw 		    "could not open pool '%s'"), poolname);
3397e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
3398e7cbe64fSgw 		goto out;
3399e7cbe64fSgw 	}
3400e7cbe64fSgw 	config = zpool_get_config(zhp, NULL);
3401e7cbe64fSgw 	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
3402e7cbe64fSgw 	    &nvroot) != 0) {
3403e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3404e7cbe64fSgw 		    "could not obtain vdev configuration for  '%s'"), poolname);
3405e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf);
3406e7cbe64fSgw 		goto out;
3407e7cbe64fSgw 	}
3408e7cbe64fSgw 
3409e7cbe64fSgw 	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
3410e7cbe64fSgw 	    &top, &toplevels) == 0);
3411e7cbe64fSgw 	if (toplevels != 1) {
3412e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3413e7cbe64fSgw 		    "'%s' has multiple top level vdevs"), poolname);
3414e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf);
3415e7cbe64fSgw 		goto out;
3416e7cbe64fSgw 	}
3417e7cbe64fSgw 
3418e7cbe64fSgw 	if (!supported_dump_vdev_type(hdl, top[0], errbuf)) {
3419e7cbe64fSgw 		goto out;
3420e7cbe64fSgw 	}
3421e7cbe64fSgw 	ret = 0;
3422e7cbe64fSgw 
3423e7cbe64fSgw out:
3424e7cbe64fSgw 	if (zhp)
3425e7cbe64fSgw 		zpool_close(zhp);
3426e7cbe64fSgw 	libzfs_fini(hdl);
3427e7cbe64fSgw 	return (ret);
3428e7cbe64fSgw }
3429