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 /*
23c6ef114fSmmusante  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27f3861e1aSahl #include <alloca.h>
28fa9e4066Sahrens #include <assert.h>
29fa9e4066Sahrens #include <ctype.h>
30fa9e4066Sahrens #include <errno.h>
31fa9e4066Sahrens #include <devid.h>
32f3861e1aSahl #include <dirent.h>
33fa9e4066Sahrens #include <fcntl.h>
34fa9e4066Sahrens #include <libintl.h>
35fa9e4066Sahrens #include <stdio.h>
36fa9e4066Sahrens #include <stdlib.h>
37f3861e1aSahl #include <strings.h>
38fa9e4066Sahrens #include <unistd.h>
390a48a24eStimh #include <zone.h>
408488aeb5Staylor #include <sys/efi_partition.h>
418488aeb5Staylor #include <sys/vtoc.h>
42fa9e4066Sahrens #include <sys/zfs_ioctl.h>
43ea8dc4b6Seschrock #include <sys/zio.h>
4406eeb2adSek #include <strings.h>
45fa9e4066Sahrens 
46fa9e4066Sahrens #include "zfs_namecheck.h"
47b1b8ab34Slling #include "zfs_prop.h"
48fa9e4066Sahrens #include "libzfs_impl.h"
49fa9e4066Sahrens 
5015e6edf1Sgw static int read_efi_label(nvlist_t *config, diskaddr_t *sb);
51990b4856Slling 
52*b5b76fecSGeorge Wilson #if defined(__i386) || defined(__amd64)
53*b5b76fecSGeorge Wilson #define	BOOTCMD	"installgrub(1M)"
54*b5b76fecSGeorge Wilson #else
55*b5b76fecSGeorge Wilson #define	BOOTCMD	"installboot(1M)"
56*b5b76fecSGeorge Wilson #endif
57*b5b76fecSGeorge Wilson 
58990b4856Slling /*
59990b4856Slling  * ====================================================================
60990b4856Slling  *   zpool property functions
61990b4856Slling  * ====================================================================
62990b4856Slling  */
63990b4856Slling 
64990b4856Slling static int
65990b4856Slling zpool_get_all_props(zpool_handle_t *zhp)
66990b4856Slling {
67990b4856Slling 	zfs_cmd_t zc = { 0 };
68990b4856Slling 	libzfs_handle_t *hdl = zhp->zpool_hdl;
69990b4856Slling 
70990b4856Slling 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
71990b4856Slling 
72990b4856Slling 	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
73990b4856Slling 		return (-1);
74990b4856Slling 
75990b4856Slling 	while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) {
76990b4856Slling 		if (errno == ENOMEM) {
77990b4856Slling 			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
78990b4856Slling 				zcmd_free_nvlists(&zc);
79990b4856Slling 				return (-1);
80990b4856Slling 			}
81990b4856Slling 		} else {
82990b4856Slling 			zcmd_free_nvlists(&zc);
83990b4856Slling 			return (-1);
84990b4856Slling 		}
85990b4856Slling 	}
86990b4856Slling 
87990b4856Slling 	if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) {
88990b4856Slling 		zcmd_free_nvlists(&zc);
89990b4856Slling 		return (-1);
90990b4856Slling 	}
91990b4856Slling 
92990b4856Slling 	zcmd_free_nvlists(&zc);
93990b4856Slling 
94990b4856Slling 	return (0);
95990b4856Slling }
96990b4856Slling 
97990b4856Slling static int
98990b4856Slling zpool_props_refresh(zpool_handle_t *zhp)
99990b4856Slling {
100990b4856Slling 	nvlist_t *old_props;
101990b4856Slling 
102990b4856Slling 	old_props = zhp->zpool_props;
103990b4856Slling 
104990b4856Slling 	if (zpool_get_all_props(zhp) != 0)
105990b4856Slling 		return (-1);
106990b4856Slling 
107990b4856Slling 	nvlist_free(old_props);
108990b4856Slling 	return (0);
109990b4856Slling }
110990b4856Slling 
111990b4856Slling static char *
112990b4856Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop,
113990b4856Slling     zprop_source_t *src)
114990b4856Slling {
115990b4856Slling 	nvlist_t *nv, *nvl;
116990b4856Slling 	uint64_t ival;
117990b4856Slling 	char *value;
118990b4856Slling 	zprop_source_t source;
119990b4856Slling 
120990b4856Slling 	nvl = zhp->zpool_props;
121990b4856Slling 	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
122990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0);
123990b4856Slling 		source = ival;
124990b4856Slling 		verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
125990b4856Slling 	} else {
126990b4856Slling 		source = ZPROP_SRC_DEFAULT;
127990b4856Slling 		if ((value = (char *)zpool_prop_default_string(prop)) == NULL)
128990b4856Slling 			value = "-";
129990b4856Slling 	}
130990b4856Slling 
131990b4856Slling 	if (src)
132990b4856Slling 		*src = source;
133990b4856Slling 
134990b4856Slling 	return (value);
135990b4856Slling }
136990b4856Slling 
137990b4856Slling uint64_t
138990b4856Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src)
139990b4856Slling {
140990b4856Slling 	nvlist_t *nv, *nvl;
141990b4856Slling 	uint64_t value;
142990b4856Slling 	zprop_source_t source;
143990b4856Slling 
144b87f3af3Sperrin 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) {
145b87f3af3Sperrin 		/*
146b87f3af3Sperrin 		 * zpool_get_all_props() has most likely failed because
147b87f3af3Sperrin 		 * the pool is faulted, but if all we need is the top level
148b87f3af3Sperrin 		 * vdev's guid then get it from the zhp config nvlist.
149b87f3af3Sperrin 		 */
150b87f3af3Sperrin 		if ((prop == ZPOOL_PROP_GUID) &&
151b87f3af3Sperrin 		    (nvlist_lookup_nvlist(zhp->zpool_config,
152b87f3af3Sperrin 		    ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) &&
153b87f3af3Sperrin 		    (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value)
154b87f3af3Sperrin 		    == 0)) {
155b87f3af3Sperrin 			return (value);
156b87f3af3Sperrin 		}
157990b4856Slling 		return (zpool_prop_default_numeric(prop));
158b87f3af3Sperrin 	}
159990b4856Slling 
160990b4856Slling 	nvl = zhp->zpool_props;
161990b4856Slling 	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
162990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0);
163990b4856Slling 		source = value;
164990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
165990b4856Slling 	} else {
166990b4856Slling 		source = ZPROP_SRC_DEFAULT;
167990b4856Slling 		value = zpool_prop_default_numeric(prop);
168990b4856Slling 	}
169990b4856Slling 
170990b4856Slling 	if (src)
171990b4856Slling 		*src = source;
172990b4856Slling 
173990b4856Slling 	return (value);
174990b4856Slling }
175990b4856Slling 
176990b4856Slling /*
177990b4856Slling  * Map VDEV STATE to printed strings.
178990b4856Slling  */
179990b4856Slling char *
180990b4856Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
181990b4856Slling {
182990b4856Slling 	switch (state) {
183990b4856Slling 	case VDEV_STATE_CLOSED:
184990b4856Slling 	case VDEV_STATE_OFFLINE:
185990b4856Slling 		return (gettext("OFFLINE"));
186990b4856Slling 	case VDEV_STATE_REMOVED:
187990b4856Slling 		return (gettext("REMOVED"));
188990b4856Slling 	case VDEV_STATE_CANT_OPEN:
189b87f3af3Sperrin 		if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG)
190990b4856Slling 			return (gettext("FAULTED"));
191990b4856Slling 		else
192990b4856Slling 			return (gettext("UNAVAIL"));
193990b4856Slling 	case VDEV_STATE_FAULTED:
194990b4856Slling 		return (gettext("FAULTED"));
195990b4856Slling 	case VDEV_STATE_DEGRADED:
196990b4856Slling 		return (gettext("DEGRADED"));
197990b4856Slling 	case VDEV_STATE_HEALTHY:
198990b4856Slling 		return (gettext("ONLINE"));
199990b4856Slling 	}
200990b4856Slling 
201990b4856Slling 	return (gettext("UNKNOWN"));
202990b4856Slling }
203990b4856Slling 
204990b4856Slling /*
205990b4856Slling  * Get a zpool property value for 'prop' and return the value in
206990b4856Slling  * a pre-allocated buffer.
207990b4856Slling  */
208990b4856Slling int
209990b4856Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
210990b4856Slling     zprop_source_t *srctype)
211990b4856Slling {
212990b4856Slling 	uint64_t intval;
213990b4856Slling 	const char *strval;
214990b4856Slling 	zprop_source_t src = ZPROP_SRC_NONE;
215990b4856Slling 	nvlist_t *nvroot;
216990b4856Slling 	vdev_stat_t *vs;
217990b4856Slling 	uint_t vsc;
218990b4856Slling 
219990b4856Slling 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
220990b4856Slling 		if (prop == ZPOOL_PROP_NAME)
221990b4856Slling 			(void) strlcpy(buf, zpool_get_name(zhp), len);
222990b4856Slling 		else if (prop == ZPOOL_PROP_HEALTH)
223990b4856Slling 			(void) strlcpy(buf, "FAULTED", len);
224990b4856Slling 		else
225990b4856Slling 			(void) strlcpy(buf, "-", len);
226990b4856Slling 		return (0);
227990b4856Slling 	}
228990b4856Slling 
229990b4856Slling 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) &&
230990b4856Slling 	    prop != ZPOOL_PROP_NAME)
231990b4856Slling 		return (-1);
232990b4856Slling 
233990b4856Slling 	switch (zpool_prop_get_type(prop)) {
234990b4856Slling 	case PROP_TYPE_STRING:
235990b4856Slling 		(void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src),
236990b4856Slling 		    len);
237990b4856Slling 		break;
238990b4856Slling 
239990b4856Slling 	case PROP_TYPE_NUMBER:
240990b4856Slling 		intval = zpool_get_prop_int(zhp, prop, &src);
241990b4856Slling 
242990b4856Slling 		switch (prop) {
243990b4856Slling 		case ZPOOL_PROP_SIZE:
244990b4856Slling 		case ZPOOL_PROP_USED:
245990b4856Slling 		case ZPOOL_PROP_AVAILABLE:
246990b4856Slling 			(void) zfs_nicenum(intval, buf, len);
247990b4856Slling 			break;
248990b4856Slling 
249990b4856Slling 		case ZPOOL_PROP_CAPACITY:
250990b4856Slling 			(void) snprintf(buf, len, "%llu%%",
251990b4856Slling 			    (u_longlong_t)intval);
252990b4856Slling 			break;
253990b4856Slling 
254990b4856Slling 		case ZPOOL_PROP_HEALTH:
255990b4856Slling 			verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
256990b4856Slling 			    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
257990b4856Slling 			verify(nvlist_lookup_uint64_array(nvroot,
258990b4856Slling 			    ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0);
259990b4856Slling 
260990b4856Slling 			(void) strlcpy(buf, zpool_state_to_name(intval,
261990b4856Slling 			    vs->vs_aux), len);
262990b4856Slling 			break;
263990b4856Slling 		default:
264990b4856Slling 			(void) snprintf(buf, len, "%llu", intval);
265990b4856Slling 		}
266990b4856Slling 		break;
267990b4856Slling 
268990b4856Slling 	case PROP_TYPE_INDEX:
269990b4856Slling 		intval = zpool_get_prop_int(zhp, prop, &src);
270990b4856Slling 		if (zpool_prop_index_to_string(prop, intval, &strval)
271990b4856Slling 		    != 0)
272990b4856Slling 			return (-1);
273990b4856Slling 		(void) strlcpy(buf, strval, len);
274990b4856Slling 		break;
275990b4856Slling 
276990b4856Slling 	default:
277990b4856Slling 		abort();
278990b4856Slling 	}
279990b4856Slling 
280990b4856Slling 	if (srctype)
281990b4856Slling 		*srctype = src;
282990b4856Slling 
283990b4856Slling 	return (0);
284990b4856Slling }
285990b4856Slling 
286990b4856Slling /*
287990b4856Slling  * Check if the bootfs name has the same pool name as it is set to.
288990b4856Slling  * Assuming bootfs is a valid dataset name.
289990b4856Slling  */
290990b4856Slling static boolean_t
291990b4856Slling bootfs_name_valid(const char *pool, char *bootfs)
292990b4856Slling {
293990b4856Slling 	int len = strlen(pool);
294990b4856Slling 
295fe3e2633SEric Taylor 	if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
296990b4856Slling 		return (B_FALSE);
297990b4856Slling 
298990b4856Slling 	if (strncmp(pool, bootfs, len) == 0 &&
299990b4856Slling 	    (bootfs[len] == '/' || bootfs[len] == '\0'))
300990b4856Slling 		return (B_TRUE);
301990b4856Slling 
302990b4856Slling 	return (B_FALSE);
303990b4856Slling }
304990b4856Slling 
30515e6edf1Sgw /*
30615e6edf1Sgw  * Inspect the configuration to determine if any of the devices contain
30715e6edf1Sgw  * an EFI label.
30815e6edf1Sgw  */
30915e6edf1Sgw static boolean_t
31015e6edf1Sgw pool_uses_efi(nvlist_t *config)
31115e6edf1Sgw {
31215e6edf1Sgw 	nvlist_t **child;
31315e6edf1Sgw 	uint_t c, children;
31415e6edf1Sgw 
31515e6edf1Sgw 	if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
31615e6edf1Sgw 	    &child, &children) != 0)
31715e6edf1Sgw 		return (read_efi_label(config, NULL) >= 0);
31815e6edf1Sgw 
31915e6edf1Sgw 	for (c = 0; c < children; c++) {
32015e6edf1Sgw 		if (pool_uses_efi(child[c]))
32115e6edf1Sgw 			return (B_TRUE);
32215e6edf1Sgw 	}
32315e6edf1Sgw 	return (B_FALSE);
32415e6edf1Sgw }
32515e6edf1Sgw 
326*b5b76fecSGeorge Wilson static boolean_t
327*b5b76fecSGeorge Wilson pool_is_bootable(zpool_handle_t *zhp)
328*b5b76fecSGeorge Wilson {
329*b5b76fecSGeorge Wilson 	char bootfs[ZPOOL_MAXNAMELEN];
330*b5b76fecSGeorge Wilson 
331*b5b76fecSGeorge Wilson 	return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
332*b5b76fecSGeorge Wilson 	    sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-",
333*b5b76fecSGeorge Wilson 	    sizeof (bootfs)) != 0);
334*b5b76fecSGeorge Wilson }
335*b5b76fecSGeorge Wilson 
336*b5b76fecSGeorge Wilson 
337990b4856Slling /*
338990b4856Slling  * Given an nvlist of zpool properties to be set, validate that they are
339990b4856Slling  * correct, and parse any numeric properties (index, boolean, etc) if they are
340990b4856Slling  * specified as strings.
341990b4856Slling  */
342990b4856Slling static nvlist_t *
3430a48a24eStimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
344990b4856Slling     nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf)
345990b4856Slling {
346990b4856Slling 	nvpair_t *elem;
347990b4856Slling 	nvlist_t *retprops;
348990b4856Slling 	zpool_prop_t prop;
349990b4856Slling 	char *strval;
350990b4856Slling 	uint64_t intval;
3512f8aaab3Seschrock 	char *slash;
3522f8aaab3Seschrock 	struct stat64 statbuf;
35315e6edf1Sgw 	zpool_handle_t *zhp;
35415e6edf1Sgw 	nvlist_t *nvroot;
355990b4856Slling 
356990b4856Slling 	if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
357990b4856Slling 		(void) no_memory(hdl);
358990b4856Slling 		return (NULL);
359990b4856Slling 	}
360990b4856Slling 
361990b4856Slling 	elem = NULL;
362990b4856Slling 	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
363990b4856Slling 		const char *propname = nvpair_name(elem);
364990b4856Slling 
365990b4856Slling 		/*
366990b4856Slling 		 * Make sure this property is valid and applies to this type.
367990b4856Slling 		 */
368990b4856Slling 		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
369990b4856Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
370990b4856Slling 			    "invalid property '%s'"), propname);
371990b4856Slling 			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
372990b4856Slling 			goto error;
373990b4856Slling 		}
374990b4856Slling 
375990b4856Slling 		if (zpool_prop_readonly(prop)) {
376990b4856Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
377990b4856Slling 			    "is readonly"), propname);
378990b4856Slling 			(void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
379990b4856Slling 			goto error;
380990b4856Slling 		}
381990b4856Slling 
382990b4856Slling 		if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops,
383990b4856Slling 		    &strval, &intval, errbuf) != 0)
384990b4856Slling 			goto error;
385990b4856Slling 
386990b4856Slling 		/*
387990b4856Slling 		 * Perform additional checking for specific properties.
388990b4856Slling 		 */
389990b4856Slling 		switch (prop) {
390990b4856Slling 		case ZPOOL_PROP_VERSION:
391990b4856Slling 			if (intval < version || intval > SPA_VERSION) {
392990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
393990b4856Slling 				    "property '%s' number %d is invalid."),
394990b4856Slling 				    propname, intval);
395990b4856Slling 				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
396990b4856Slling 				goto error;
397990b4856Slling 			}
398990b4856Slling 			break;
399990b4856Slling 
400990b4856Slling 		case ZPOOL_PROP_BOOTFS:
401990b4856Slling 			if (create_or_import) {
402990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
403990b4856Slling 				    "property '%s' cannot be set at creation "
404990b4856Slling 				    "or import time"), propname);
405990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
406990b4856Slling 				goto error;
407990b4856Slling 			}
408990b4856Slling 
409990b4856Slling 			if (version < SPA_VERSION_BOOTFS) {
410990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
411990b4856Slling 				    "pool must be upgraded to support "
412990b4856Slling 				    "'%s' property"), propname);
413990b4856Slling 				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
414990b4856Slling 				goto error;
415990b4856Slling 			}
416990b4856Slling 
417990b4856Slling 			/*
418990b4856Slling 			 * bootfs property value has to be a dataset name and
419990b4856Slling 			 * the dataset has to be in the same pool as it sets to.
420990b4856Slling 			 */
421990b4856Slling 			if (strval[0] != '\0' && !bootfs_name_valid(poolname,
422990b4856Slling 			    strval)) {
423990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
424990b4856Slling 				    "is an invalid name"), strval);
425990b4856Slling 				(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
426990b4856Slling 				goto error;
427990b4856Slling 			}
42815e6edf1Sgw 
42915e6edf1Sgw 			if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) {
43015e6edf1Sgw 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
43115e6edf1Sgw 				    "could not open pool '%s'"), poolname);
43215e6edf1Sgw 				(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
43315e6edf1Sgw 				goto error;
43415e6edf1Sgw 			}
43515e6edf1Sgw 			verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
43615e6edf1Sgw 			    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
43715e6edf1Sgw 
43815e6edf1Sgw 			/*
43915e6edf1Sgw 			 * bootfs property cannot be set on a disk which has
44015e6edf1Sgw 			 * been EFI labeled.
44115e6edf1Sgw 			 */
44215e6edf1Sgw 			if (pool_uses_efi(nvroot)) {
44315e6edf1Sgw 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
44415e6edf1Sgw 				    "property '%s' not supported on "
44515e6edf1Sgw 				    "EFI labeled devices"), propname);
44615e6edf1Sgw 				(void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf);
44715e6edf1Sgw 				zpool_close(zhp);
44815e6edf1Sgw 				goto error;
44915e6edf1Sgw 			}
45015e6edf1Sgw 			zpool_close(zhp);
451990b4856Slling 			break;
452990b4856Slling 
4532f8aaab3Seschrock 		case ZPOOL_PROP_ALTROOT:
454990b4856Slling 			if (!create_or_import) {
455990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
456990b4856Slling 				    "property '%s' can only be set during pool "
457990b4856Slling 				    "creation or import"), propname);
458990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
459990b4856Slling 				goto error;
460990b4856Slling 			}
461990b4856Slling 
4622f8aaab3Seschrock 			if (strval[0] != '/') {
463990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4642f8aaab3Seschrock 				    "bad alternate root '%s'"), strval);
4652f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
466990b4856Slling 				goto error;
467990b4856Slling 			}
4682f8aaab3Seschrock 			break;
4692f8aaab3Seschrock 
4702f8aaab3Seschrock 		case ZPOOL_PROP_CACHEFILE:
4712f8aaab3Seschrock 			if (strval[0] == '\0')
4722f8aaab3Seschrock 				break;
4732f8aaab3Seschrock 
4742f8aaab3Seschrock 			if (strcmp(strval, "none") == 0)
4752f8aaab3Seschrock 				break;
476990b4856Slling 
477990b4856Slling 			if (strval[0] != '/') {
478990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4792f8aaab3Seschrock 				    "property '%s' must be empty, an "
4802f8aaab3Seschrock 				    "absolute path, or 'none'"), propname);
481990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
482990b4856Slling 				goto error;
483990b4856Slling 			}
484990b4856Slling 
4852f8aaab3Seschrock 			slash = strrchr(strval, '/');
486990b4856Slling 
4872f8aaab3Seschrock 			if (slash[1] == '\0' || strcmp(slash, "/.") == 0 ||
4882f8aaab3Seschrock 			    strcmp(slash, "/..") == 0) {
4892f8aaab3Seschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4902f8aaab3Seschrock 				    "'%s' is not a valid file"), strval);
4912f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
4922f8aaab3Seschrock 				goto error;
4932f8aaab3Seschrock 			}
494990b4856Slling 
4952f8aaab3Seschrock 			*slash = '\0';
4962f8aaab3Seschrock 
4972c32020fSeschrock 			if (strval[0] != '\0' &&
4982c32020fSeschrock 			    (stat64(strval, &statbuf) != 0 ||
4992c32020fSeschrock 			    !S_ISDIR(statbuf.st_mode))) {
5002f8aaab3Seschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5012f8aaab3Seschrock 				    "'%s' is not a valid directory"),
5022f8aaab3Seschrock 				    strval);
5032f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
5042f8aaab3Seschrock 				goto error;
5052f8aaab3Seschrock 			}
5062f8aaab3Seschrock 
5072f8aaab3Seschrock 			*slash = '/';
5082f8aaab3Seschrock 			break;
509990b4856Slling 		}
510990b4856Slling 	}
511990b4856Slling 
512990b4856Slling 	return (retprops);
513990b4856Slling error:
514990b4856Slling 	nvlist_free(retprops);
515990b4856Slling 	return (NULL);
516990b4856Slling }
517990b4856Slling 
518990b4856Slling /*
519990b4856Slling  * Set zpool property : propname=propval.
520990b4856Slling  */
521990b4856Slling int
522990b4856Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
523990b4856Slling {
524990b4856Slling 	zfs_cmd_t zc = { 0 };
525990b4856Slling 	int ret = -1;
526990b4856Slling 	char errbuf[1024];
527990b4856Slling 	nvlist_t *nvl = NULL;
528990b4856Slling 	nvlist_t *realprops;
529990b4856Slling 	uint64_t version;
530990b4856Slling 
531990b4856Slling 	(void) snprintf(errbuf, sizeof (errbuf),
532990b4856Slling 	    dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
533990b4856Slling 	    zhp->zpool_name);
534990b4856Slling 
535990b4856Slling 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp))
536990b4856Slling 		return (zfs_error(zhp->zpool_hdl, EZFS_POOLPROPS, errbuf));
537990b4856Slling 
538990b4856Slling 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
539990b4856Slling 		return (no_memory(zhp->zpool_hdl));
540990b4856Slling 
541990b4856Slling 	if (nvlist_add_string(nvl, propname, propval) != 0) {
542990b4856Slling 		nvlist_free(nvl);
543990b4856Slling 		return (no_memory(zhp->zpool_hdl));
544990b4856Slling 	}
545990b4856Slling 
546990b4856Slling 	version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
5470a48a24eStimh 	if ((realprops = zpool_valid_proplist(zhp->zpool_hdl,
548990b4856Slling 	    zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) {
549990b4856Slling 		nvlist_free(nvl);
550990b4856Slling 		return (-1);
551990b4856Slling 	}
552990b4856Slling 
553990b4856Slling 	nvlist_free(nvl);
554990b4856Slling 	nvl = realprops;
555990b4856Slling 
556990b4856Slling 	/*
557990b4856Slling 	 * Execute the corresponding ioctl() to set this property.
558990b4856Slling 	 */
559990b4856Slling 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
560990b4856Slling 
561990b4856Slling 	if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
562990b4856Slling 		nvlist_free(nvl);
563990b4856Slling 		return (-1);
564990b4856Slling 	}
565990b4856Slling 
566990b4856Slling 	ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc);
567990b4856Slling 
568990b4856Slling 	zcmd_free_nvlists(&zc);
569990b4856Slling 	nvlist_free(nvl);
570990b4856Slling 
571990b4856Slling 	if (ret)
572990b4856Slling 		(void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf);
573990b4856Slling 	else
574990b4856Slling 		(void) zpool_props_refresh(zhp);
575990b4856Slling 
576990b4856Slling 	return (ret);
577990b4856Slling }
578990b4856Slling 
579990b4856Slling int
580990b4856Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp)
581990b4856Slling {
582990b4856Slling 	libzfs_handle_t *hdl = zhp->zpool_hdl;
583990b4856Slling 	zprop_list_t *entry;
584990b4856Slling 	char buf[ZFS_MAXPROPLEN];
585990b4856Slling 
586990b4856Slling 	if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0)
587990b4856Slling 		return (-1);
588990b4856Slling 
589990b4856Slling 	for (entry = *plp; entry != NULL; entry = entry->pl_next) {
590990b4856Slling 
591990b4856Slling 		if (entry->pl_fixed)
592990b4856Slling 			continue;
593990b4856Slling 
594990b4856Slling 		if (entry->pl_prop != ZPROP_INVAL &&
595990b4856Slling 		    zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf),
596990b4856Slling 		    NULL) == 0) {
597990b4856Slling 			if (strlen(buf) > entry->pl_width)
598990b4856Slling 				entry->pl_width = strlen(buf);
599990b4856Slling 		}
600990b4856Slling 	}
601990b4856Slling 
602990b4856Slling 	return (0);
603990b4856Slling }
604990b4856Slling 
605990b4856Slling 
606fa9e4066Sahrens /*
607fa9e4066Sahrens  * Validate the given pool name, optionally putting an extended error message in
608fa9e4066Sahrens  * 'buf'.
609fa9e4066Sahrens  */
610e7cbe64fSgw boolean_t
61199653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool)
612fa9e4066Sahrens {
613fa9e4066Sahrens 	namecheck_err_t why;
614fa9e4066Sahrens 	char what;
615b468a217Seschrock 	int ret;
616b468a217Seschrock 
617b468a217Seschrock 	ret = pool_namecheck(pool, &why, &what);
618b468a217Seschrock 
619b468a217Seschrock 	/*
620b468a217Seschrock 	 * The rules for reserved pool names were extended at a later point.
621b468a217Seschrock 	 * But we need to support users with existing pools that may now be
622b468a217Seschrock 	 * invalid.  So we only check for this expanded set of names during a
623b468a217Seschrock 	 * create (or import), and only in userland.
624b468a217Seschrock 	 */
625b468a217Seschrock 	if (ret == 0 && !isopen &&
626b468a217Seschrock 	    (strncmp(pool, "mirror", 6) == 0 ||
627b468a217Seschrock 	    strncmp(pool, "raidz", 5) == 0 ||
6288654d025Sperrin 	    strncmp(pool, "spare", 5) == 0 ||
6298654d025Sperrin 	    strcmp(pool, "log") == 0)) {
630e7cbe64fSgw 		if (hdl != NULL)
631e7cbe64fSgw 			zfs_error_aux(hdl,
632e7cbe64fSgw 			    dgettext(TEXT_DOMAIN, "name is reserved"));
63399653d4eSeschrock 		return (B_FALSE);
634b468a217Seschrock 	}
635b468a217Seschrock 
636fa9e4066Sahrens 
637b468a217Seschrock 	if (ret != 0) {
63899653d4eSeschrock 		if (hdl != NULL) {
639fa9e4066Sahrens 			switch (why) {
640b81d61a6Slling 			case NAME_ERR_TOOLONG:
64199653d4eSeschrock 				zfs_error_aux(hdl,
642b81d61a6Slling 				    dgettext(TEXT_DOMAIN, "name is too long"));
643b81d61a6Slling 				break;
644b81d61a6Slling 
645fa9e4066Sahrens 			case NAME_ERR_INVALCHAR:
64699653d4eSeschrock 				zfs_error_aux(hdl,
647fa9e4066Sahrens 				    dgettext(TEXT_DOMAIN, "invalid character "
648fa9e4066Sahrens 				    "'%c' in pool name"), what);
649fa9e4066Sahrens 				break;
650fa9e4066Sahrens 
651fa9e4066Sahrens 			case NAME_ERR_NOLETTER:
65299653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
65399653d4eSeschrock 				    "name must begin with a letter"));
654fa9e4066Sahrens 				break;
655fa9e4066Sahrens 
656fa9e4066Sahrens 			case NAME_ERR_RESERVED:
65799653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
65899653d4eSeschrock 				    "name is reserved"));
659fa9e4066Sahrens 				break;
660fa9e4066Sahrens 
661fa9e4066Sahrens 			case NAME_ERR_DISKLIKE:
66299653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
66399653d4eSeschrock 				    "pool name is reserved"));
664fa9e4066Sahrens 				break;
6655ad82045Snd 
6665ad82045Snd 			case NAME_ERR_LEADING_SLASH:
6675ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6685ad82045Snd 				    "leading slash in name"));
6695ad82045Snd 				break;
6705ad82045Snd 
6715ad82045Snd 			case NAME_ERR_EMPTY_COMPONENT:
6725ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6735ad82045Snd 				    "empty component in name"));
6745ad82045Snd 				break;
6755ad82045Snd 
6765ad82045Snd 			case NAME_ERR_TRAILING_SLASH:
6775ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6785ad82045Snd 				    "trailing slash in name"));
6795ad82045Snd 				break;
6805ad82045Snd 
6815ad82045Snd 			case NAME_ERR_MULTIPLE_AT:
6825ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6835ad82045Snd 				    "multiple '@' delimiters in name"));
6845ad82045Snd 				break;
6855ad82045Snd 
686fa9e4066Sahrens 			}
687fa9e4066Sahrens 		}
68899653d4eSeschrock 		return (B_FALSE);
689fa9e4066Sahrens 	}
690fa9e4066Sahrens 
69199653d4eSeschrock 	return (B_TRUE);
692fa9e4066Sahrens }
693fa9e4066Sahrens 
694fa9e4066Sahrens /*
695fa9e4066Sahrens  * Open a handle to the given pool, even if the pool is currently in the FAULTED
696fa9e4066Sahrens  * state.
697fa9e4066Sahrens  */
698fa9e4066Sahrens zpool_handle_t *
69999653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool)
700fa9e4066Sahrens {
701fa9e4066Sahrens 	zpool_handle_t *zhp;
70294de1d4cSeschrock 	boolean_t missing;
703fa9e4066Sahrens 
704fa9e4066Sahrens 	/*
705fa9e4066Sahrens 	 * Make sure the pool name is valid.
706fa9e4066Sahrens 	 */
70799653d4eSeschrock 	if (!zpool_name_valid(hdl, B_TRUE, pool)) {
708ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_INVALIDNAME,
70999653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"),
71099653d4eSeschrock 		    pool);
711fa9e4066Sahrens 		return (NULL);
712fa9e4066Sahrens 	}
713fa9e4066Sahrens 
71499653d4eSeschrock 	if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
71599653d4eSeschrock 		return (NULL);
716fa9e4066Sahrens 
71799653d4eSeschrock 	zhp->zpool_hdl = hdl;
718fa9e4066Sahrens 	(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
719fa9e4066Sahrens 
72094de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0) {
72194de1d4cSeschrock 		zpool_close(zhp);
72294de1d4cSeschrock 		return (NULL);
72394de1d4cSeschrock 	}
72494de1d4cSeschrock 
72594de1d4cSeschrock 	if (missing) {
726990b4856Slling 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool"));
727ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_NOENT,
728990b4856Slling 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool);
72994de1d4cSeschrock 		zpool_close(zhp);
73094de1d4cSeschrock 		return (NULL);
731fa9e4066Sahrens 	}
732fa9e4066Sahrens 
733fa9e4066Sahrens 	return (zhp);
734fa9e4066Sahrens }
735fa9e4066Sahrens 
736fa9e4066Sahrens /*
737fa9e4066Sahrens  * Like the above, but silent on error.  Used when iterating over pools (because
738fa9e4066Sahrens  * the configuration cache may be out of date).
739fa9e4066Sahrens  */
74094de1d4cSeschrock int
74194de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret)
742fa9e4066Sahrens {
743fa9e4066Sahrens 	zpool_handle_t *zhp;
74494de1d4cSeschrock 	boolean_t missing;
745fa9e4066Sahrens 
74694de1d4cSeschrock 	if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
74794de1d4cSeschrock 		return (-1);
748fa9e4066Sahrens 
74999653d4eSeschrock 	zhp->zpool_hdl = hdl;
750fa9e4066Sahrens 	(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
751fa9e4066Sahrens 
75294de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0) {
75394de1d4cSeschrock 		zpool_close(zhp);
75494de1d4cSeschrock 		return (-1);
755fa9e4066Sahrens 	}
756fa9e4066Sahrens 
75794de1d4cSeschrock 	if (missing) {
75894de1d4cSeschrock 		zpool_close(zhp);
75994de1d4cSeschrock 		*ret = NULL;
76094de1d4cSeschrock 		return (0);
76194de1d4cSeschrock 	}
76294de1d4cSeschrock 
76394de1d4cSeschrock 	*ret = zhp;
76494de1d4cSeschrock 	return (0);
765fa9e4066Sahrens }
766fa9e4066Sahrens 
767fa9e4066Sahrens /*
768fa9e4066Sahrens  * Similar to zpool_open_canfail(), but refuses to open pools in the faulted
769fa9e4066Sahrens  * state.
770fa9e4066Sahrens  */
771fa9e4066Sahrens zpool_handle_t *
77299653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool)
773fa9e4066Sahrens {
774fa9e4066Sahrens 	zpool_handle_t *zhp;
775fa9e4066Sahrens 
77699653d4eSeschrock 	if ((zhp = zpool_open_canfail(hdl, pool)) == NULL)
777fa9e4066Sahrens 		return (NULL);
778fa9e4066Sahrens 
779fa9e4066Sahrens 	if (zhp->zpool_state == POOL_STATE_UNAVAIL) {
780ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL,
78199653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name);
782fa9e4066Sahrens 		zpool_close(zhp);
783fa9e4066Sahrens 		return (NULL);
784fa9e4066Sahrens 	}
785fa9e4066Sahrens 
786fa9e4066Sahrens 	return (zhp);
787fa9e4066Sahrens }
788fa9e4066Sahrens 
789fa9e4066Sahrens /*
790fa9e4066Sahrens  * Close the handle.  Simply frees the memory associated with the handle.
791fa9e4066Sahrens  */
792fa9e4066Sahrens void
793fa9e4066Sahrens zpool_close(zpool_handle_t *zhp)
794fa9e4066Sahrens {
795fa9e4066Sahrens 	if (zhp->zpool_config)
796fa9e4066Sahrens 		nvlist_free(zhp->zpool_config);
797088e9d47Seschrock 	if (zhp->zpool_old_config)
798088e9d47Seschrock 		nvlist_free(zhp->zpool_old_config);
799b1b8ab34Slling 	if (zhp->zpool_props)
800b1b8ab34Slling 		nvlist_free(zhp->zpool_props);
801fa9e4066Sahrens 	free(zhp);
802fa9e4066Sahrens }
803fa9e4066Sahrens 
804fa9e4066Sahrens /*
805fa9e4066Sahrens  * Return the name of the pool.
806fa9e4066Sahrens  */
807fa9e4066Sahrens const char *
808fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp)
809fa9e4066Sahrens {
810fa9e4066Sahrens 	return (zhp->zpool_name);
811fa9e4066Sahrens }
812fa9e4066Sahrens 
813fa9e4066Sahrens 
814fa9e4066Sahrens /*
815fa9e4066Sahrens  * Return the state of the pool (ACTIVE or UNAVAILABLE)
816fa9e4066Sahrens  */
817fa9e4066Sahrens int
818fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp)
819fa9e4066Sahrens {
820fa9e4066Sahrens 	return (zhp->zpool_state);
821fa9e4066Sahrens }
822fa9e4066Sahrens 
823fa9e4066Sahrens /*
824fa9e4066Sahrens  * Create the named pool, using the provided vdev list.  It is assumed
825fa9e4066Sahrens  * that the consumer has already validated the contents of the nvlist, so we
826fa9e4066Sahrens  * don't have to worry about error semantics.
827fa9e4066Sahrens  */
828fa9e4066Sahrens int
82999653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
8300a48a24eStimh     nvlist_t *props, nvlist_t *fsprops)
831fa9e4066Sahrens {
832fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
8330a48a24eStimh 	nvlist_t *zc_fsprops = NULL;
8340a48a24eStimh 	nvlist_t *zc_props = NULL;
83599653d4eSeschrock 	char msg[1024];
836990b4856Slling 	char *altroot;
8370a48a24eStimh 	int ret = -1;
838fa9e4066Sahrens 
83999653d4eSeschrock 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
84099653d4eSeschrock 	    "cannot create '%s'"), pool);
841fa9e4066Sahrens 
84299653d4eSeschrock 	if (!zpool_name_valid(hdl, B_FALSE, pool))
84399653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
844fa9e4066Sahrens 
845351420b3Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
846990b4856Slling 		return (-1);
847fa9e4066Sahrens 
8480a48a24eStimh 	if (props) {
8490a48a24eStimh 		if ((zc_props = zpool_valid_proplist(hdl, pool, props,
8500a48a24eStimh 		    SPA_VERSION_1, B_TRUE, msg)) == NULL) {
8510a48a24eStimh 			goto create_failed;
8520a48a24eStimh 		}
8530a48a24eStimh 	}
85499653d4eSeschrock 
8550a48a24eStimh 	if (fsprops) {
8560a48a24eStimh 		uint64_t zoned;
8570a48a24eStimh 		char *zonestr;
8580a48a24eStimh 
8590a48a24eStimh 		zoned = ((nvlist_lookup_string(fsprops,
8600a48a24eStimh 		    zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) &&
8610a48a24eStimh 		    strcmp(zonestr, "on") == 0);
8620a48a24eStimh 
8630a48a24eStimh 		if ((zc_fsprops = zfs_valid_proplist(hdl,
8640a48a24eStimh 		    ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) {
8650a48a24eStimh 			goto create_failed;
8660a48a24eStimh 		}
8670a48a24eStimh 		if (!zc_props &&
8680a48a24eStimh 		    (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) {
8690a48a24eStimh 			goto create_failed;
8700a48a24eStimh 		}
8710a48a24eStimh 		if (nvlist_add_nvlist(zc_props,
8720a48a24eStimh 		    ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) {
8730a48a24eStimh 			goto create_failed;
8740a48a24eStimh 		}
875351420b3Slling 	}
876fa9e4066Sahrens 
8770a48a24eStimh 	if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
8780a48a24eStimh 		goto create_failed;
8790a48a24eStimh 
880990b4856Slling 	(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
881fa9e4066Sahrens 
8820a48a24eStimh 	if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) {
883351420b3Slling 
884e9dbad6fSeschrock 		zcmd_free_nvlists(&zc);
8850a48a24eStimh 		nvlist_free(zc_props);
8860a48a24eStimh 		nvlist_free(zc_fsprops);
887fa9e4066Sahrens 
88899653d4eSeschrock 		switch (errno) {
889fa9e4066Sahrens 		case EBUSY:
890fa9e4066Sahrens 			/*
891fa9e4066Sahrens 			 * This can happen if the user has specified the same
892fa9e4066Sahrens 			 * device multiple times.  We can't reliably detect this
893fa9e4066Sahrens 			 * until we try to add it and see we already have a
894fa9e4066Sahrens 			 * label.
895fa9e4066Sahrens 			 */
89699653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
89799653d4eSeschrock 			    "one or more vdevs refer to the same device"));
89899653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
899fa9e4066Sahrens 
900fa9e4066Sahrens 		case EOVERFLOW:
901fa9e4066Sahrens 			/*
90299653d4eSeschrock 			 * This occurs when one of the devices is below
903fa9e4066Sahrens 			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
904fa9e4066Sahrens 			 * device was the problem device since there's no
905fa9e4066Sahrens 			 * reliable way to determine device size from userland.
906fa9e4066Sahrens 			 */
907fa9e4066Sahrens 			{
908fa9e4066Sahrens 				char buf[64];
909fa9e4066Sahrens 
910fa9e4066Sahrens 				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
911fa9e4066Sahrens 
91299653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
91399653d4eSeschrock 				    "one or more devices is less than the "
91499653d4eSeschrock 				    "minimum size (%s)"), buf);
915fa9e4066Sahrens 			}
91699653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
917fa9e4066Sahrens 
918fa9e4066Sahrens 		case ENOSPC:
91999653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
92099653d4eSeschrock 			    "one or more devices is out of space"));
92199653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
922fa9e4066Sahrens 
923fa94a07fSbrendan 		case ENOTBLK:
924fa94a07fSbrendan 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
925fa94a07fSbrendan 			    "cache device must be a disk or disk slice"));
926fa94a07fSbrendan 			return (zfs_error(hdl, EZFS_BADDEV, msg));
927fa94a07fSbrendan 
928fa9e4066Sahrens 		default:
92999653d4eSeschrock 			return (zpool_standard_error(hdl, errno, msg));
930fa9e4066Sahrens 		}
931fa9e4066Sahrens 	}
932fa9e4066Sahrens 
933fa9e4066Sahrens 	/*
934fa9e4066Sahrens 	 * If this is an alternate root pool, then we automatically set the
935e9dbad6fSeschrock 	 * mountpoint of the root dataset to be '/'.
936fa9e4066Sahrens 	 */
937990b4856Slling 	if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT),
938990b4856Slling 	    &altroot) == 0) {
939fa9e4066Sahrens 		zfs_handle_t *zhp;
940fa9e4066Sahrens 
941990b4856Slling 		verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL);
942e9dbad6fSeschrock 		verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
943e9dbad6fSeschrock 		    "/") == 0);
944fa9e4066Sahrens 
945fa9e4066Sahrens 		zfs_close(zhp);
946fa9e4066Sahrens 	}
947fa9e4066Sahrens 
9480a48a24eStimh create_failed:
949351420b3Slling 	zcmd_free_nvlists(&zc);
9500a48a24eStimh 	nvlist_free(zc_props);
9510a48a24eStimh 	nvlist_free(zc_fsprops);
9520a48a24eStimh 	return (ret);
953fa9e4066Sahrens }
954fa9e4066Sahrens 
955fa9e4066Sahrens /*
956fa9e4066Sahrens  * Destroy the given pool.  It is up to the caller to ensure that there are no
957fa9e4066Sahrens  * datasets left in the pool.
958fa9e4066Sahrens  */
959fa9e4066Sahrens int
960fa9e4066Sahrens zpool_destroy(zpool_handle_t *zhp)
961fa9e4066Sahrens {
962fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
963fa9e4066Sahrens 	zfs_handle_t *zfp = NULL;
96499653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
96599653d4eSeschrock 	char msg[1024];
966fa9e4066Sahrens 
967fa9e4066Sahrens 	if (zhp->zpool_state == POOL_STATE_ACTIVE &&
96899653d4eSeschrock 	    (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name,
96999653d4eSeschrock 	    ZFS_TYPE_FILESYSTEM)) == NULL)
970fa9e4066Sahrens 		return (-1);
971fa9e4066Sahrens 
9725ad82045Snd 	if (zpool_remove_zvol_links(zhp) != 0)
973fa9e4066Sahrens 		return (-1);
974fa9e4066Sahrens 
975fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
976fa9e4066Sahrens 
977ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
97899653d4eSeschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
97999653d4eSeschrock 		    "cannot destroy '%s'"), zhp->zpool_name);
980fa9e4066Sahrens 
98199653d4eSeschrock 		if (errno == EROFS) {
98299653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
98399653d4eSeschrock 			    "one or more devices is read only"));
98499653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
98599653d4eSeschrock 		} else {
98699653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, msg);
987fa9e4066Sahrens 		}
988fa9e4066Sahrens 
989fa9e4066Sahrens 		if (zfp)
990fa9e4066Sahrens 			zfs_close(zfp);
991fa9e4066Sahrens 		return (-1);
992fa9e4066Sahrens 	}
993fa9e4066Sahrens 
994fa9e4066Sahrens 	if (zfp) {
995fa9e4066Sahrens 		remove_mountpoint(zfp);
996fa9e4066Sahrens 		zfs_close(zfp);
997fa9e4066Sahrens 	}
998fa9e4066Sahrens 
999fa9e4066Sahrens 	return (0);
1000fa9e4066Sahrens }
1001fa9e4066Sahrens 
1002fa9e4066Sahrens /*
1003fa9e4066Sahrens  * Add the given vdevs to the pool.  The caller must have already performed the
1004fa9e4066Sahrens  * necessary verification to ensure that the vdev specification is well-formed.
1005fa9e4066Sahrens  */
1006fa9e4066Sahrens int
1007fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
1008fa9e4066Sahrens {
1009e9dbad6fSeschrock 	zfs_cmd_t zc = { 0 };
101099653d4eSeschrock 	int ret;
101199653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
101299653d4eSeschrock 	char msg[1024];
1013fa94a07fSbrendan 	nvlist_t **spares, **l2cache;
1014fa94a07fSbrendan 	uint_t nspares, nl2cache;
101599653d4eSeschrock 
101699653d4eSeschrock 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
101799653d4eSeschrock 	    "cannot add to '%s'"), zhp->zpool_name);
101899653d4eSeschrock 
1019fa94a07fSbrendan 	if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
1020fa94a07fSbrendan 	    SPA_VERSION_SPARES &&
102199653d4eSeschrock 	    nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
102299653d4eSeschrock 	    &spares, &nspares) == 0) {
102399653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
102499653d4eSeschrock 		    "upgraded to add hot spares"));
102599653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
102699653d4eSeschrock 	}
1027fa9e4066Sahrens 
1028*b5b76fecSGeorge Wilson 	if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot,
1029*b5b76fecSGeorge Wilson 	    ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) {
1030*b5b76fecSGeorge Wilson 		uint64_t s;
1031*b5b76fecSGeorge Wilson 
1032*b5b76fecSGeorge Wilson 		for (s = 0; s < nspares; s++) {
1033*b5b76fecSGeorge Wilson 			char *path;
1034*b5b76fecSGeorge Wilson 
1035*b5b76fecSGeorge Wilson 			if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH,
1036*b5b76fecSGeorge Wilson 			    &path) == 0 && pool_uses_efi(spares[s])) {
1037*b5b76fecSGeorge Wilson 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1038*b5b76fecSGeorge Wilson 				    "device '%s' contains an EFI label and "
1039*b5b76fecSGeorge Wilson 				    "cannot be used on root pools."),
1040*b5b76fecSGeorge Wilson 				    zpool_vdev_name(hdl, NULL, spares[s]));
1041*b5b76fecSGeorge Wilson 				return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
1042*b5b76fecSGeorge Wilson 			}
1043*b5b76fecSGeorge Wilson 		}
1044*b5b76fecSGeorge Wilson 	}
1045*b5b76fecSGeorge Wilson 
1046fa94a07fSbrendan 	if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
1047fa94a07fSbrendan 	    SPA_VERSION_L2CACHE &&
1048fa94a07fSbrendan 	    nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
1049fa94a07fSbrendan 	    &l2cache, &nl2cache) == 0) {
1050fa94a07fSbrendan 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
1051fa94a07fSbrendan 		    "upgraded to add cache devices"));
1052fa94a07fSbrendan 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
1053fa94a07fSbrendan 	}
1054fa94a07fSbrendan 
1055990b4856Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
105699653d4eSeschrock 		return (-1);
1057fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1058fa9e4066Sahrens 
1059ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) {
1060fa9e4066Sahrens 		switch (errno) {
1061fa9e4066Sahrens 		case EBUSY:
1062fa9e4066Sahrens 			/*
1063fa9e4066Sahrens 			 * This can happen if the user has specified the same
1064fa9e4066Sahrens 			 * device multiple times.  We can't reliably detect this
1065fa9e4066Sahrens 			 * until we try to add it and see we already have a
1066fa9e4066Sahrens 			 * label.
1067fa9e4066Sahrens 			 */
106899653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
106999653d4eSeschrock 			    "one or more vdevs refer to the same device"));
107099653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
1071fa9e4066Sahrens 			break;
1072fa9e4066Sahrens 
1073fa9e4066Sahrens 		case EOVERFLOW:
1074fa9e4066Sahrens 			/*
1075fa9e4066Sahrens 			 * This occurrs when one of the devices is below
1076fa9e4066Sahrens 			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
1077fa9e4066Sahrens 			 * device was the problem device since there's no
1078fa9e4066Sahrens 			 * reliable way to determine device size from userland.
1079fa9e4066Sahrens 			 */
1080fa9e4066Sahrens 			{
1081fa9e4066Sahrens 				char buf[64];
1082fa9e4066Sahrens 
1083fa9e4066Sahrens 				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
1084fa9e4066Sahrens 
108599653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
108699653d4eSeschrock 				    "device is less than the minimum "
108799653d4eSeschrock 				    "size (%s)"), buf);
1088fa9e4066Sahrens 			}
108999653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
109099653d4eSeschrock 			break;
109199653d4eSeschrock 
109299653d4eSeschrock 		case ENOTSUP:
109399653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
10948654d025Sperrin 			    "pool must be upgraded to add these vdevs"));
109599653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADVERSION, msg);
1096fa9e4066Sahrens 			break;
1097fa9e4066Sahrens 
1098b1b8ab34Slling 		case EDOM:
1099b1b8ab34Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
11008654d025Sperrin 			    "root pool can not have multiple vdevs"
11018654d025Sperrin 			    " or separate logs"));
1102b1b8ab34Slling 			(void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg);
1103b1b8ab34Slling 			break;
1104b1b8ab34Slling 
1105fa94a07fSbrendan 		case ENOTBLK:
1106fa94a07fSbrendan 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1107fa94a07fSbrendan 			    "cache device must be a disk or disk slice"));
1108fa94a07fSbrendan 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
1109fa94a07fSbrendan 			break;
1110fa94a07fSbrendan 
1111fa9e4066Sahrens 		default:
111299653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, msg);
1113fa9e4066Sahrens 		}
1114fa9e4066Sahrens 
111599653d4eSeschrock 		ret = -1;
111699653d4eSeschrock 	} else {
111799653d4eSeschrock 		ret = 0;
1118fa9e4066Sahrens 	}
1119fa9e4066Sahrens 
1120e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
1121fa9e4066Sahrens 
112299653d4eSeschrock 	return (ret);
1123fa9e4066Sahrens }
1124fa9e4066Sahrens 
1125fa9e4066Sahrens /*
1126fa9e4066Sahrens  * Exports the pool from the system.  The caller must ensure that there are no
1127fa9e4066Sahrens  * mounted datasets in the pool.
1128fa9e4066Sahrens  */
1129fa9e4066Sahrens int
113089a89ebfSlling zpool_export(zpool_handle_t *zhp, boolean_t force)
1131fa9e4066Sahrens {
1132fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
113389a89ebfSlling 	char msg[1024];
1134fa9e4066Sahrens 
1135fa9e4066Sahrens 	if (zpool_remove_zvol_links(zhp) != 0)
1136fa9e4066Sahrens 		return (-1);
1137fa9e4066Sahrens 
113889a89ebfSlling 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
113989a89ebfSlling 	    "cannot export '%s'"), zhp->zpool_name);
114089a89ebfSlling 
1141fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
114289a89ebfSlling 	zc.zc_cookie = force;
114389a89ebfSlling 
114489a89ebfSlling 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
114589a89ebfSlling 		switch (errno) {
114689a89ebfSlling 		case EXDEV:
114789a89ebfSlling 			zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN,
114889a89ebfSlling 			    "use '-f' to override the following errors:\n"
114989a89ebfSlling 			    "'%s' has an active shared spare which could be"
115089a89ebfSlling 			    " used by other pools once '%s' is exported."),
115189a89ebfSlling 			    zhp->zpool_name, zhp->zpool_name);
115289a89ebfSlling 			return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE,
115389a89ebfSlling 			    msg));
115489a89ebfSlling 		default:
115589a89ebfSlling 			return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
115689a89ebfSlling 			    msg));
115789a89ebfSlling 		}
115889a89ebfSlling 	}
1159fa9e4066Sahrens 
1160fa9e4066Sahrens 	return (0);
1161fa9e4066Sahrens }
1162fa9e4066Sahrens 
1163fa9e4066Sahrens /*
1164990b4856Slling  * zpool_import() is a contracted interface. Should be kept the same
1165990b4856Slling  * if possible.
1166990b4856Slling  *
1167990b4856Slling  * Applications should use zpool_import_props() to import a pool with
1168990b4856Slling  * new properties value to be set.
1169fa9e4066Sahrens  */
1170fa9e4066Sahrens int
117199653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
1172990b4856Slling     char *altroot)
1173990b4856Slling {
1174990b4856Slling 	nvlist_t *props = NULL;
1175990b4856Slling 	int ret;
1176990b4856Slling 
1177990b4856Slling 	if (altroot != NULL) {
1178990b4856Slling 		if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
1179990b4856Slling 			return (zfs_error_fmt(hdl, EZFS_NOMEM,
1180990b4856Slling 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1181990b4856Slling 			    newname));
1182990b4856Slling 		}
1183990b4856Slling 
1184990b4856Slling 		if (nvlist_add_string(props,
1185990b4856Slling 		    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0) {
1186990b4856Slling 			nvlist_free(props);
1187990b4856Slling 			return (zfs_error_fmt(hdl, EZFS_NOMEM,
1188990b4856Slling 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1189990b4856Slling 			    newname));
1190990b4856Slling 		}
1191990b4856Slling 	}
1192990b4856Slling 
1193c5904d13Seschrock 	ret = zpool_import_props(hdl, config, newname, props, B_FALSE);
1194990b4856Slling 	if (props)
1195990b4856Slling 		nvlist_free(props);
1196990b4856Slling 	return (ret);
1197990b4856Slling }
1198990b4856Slling 
1199990b4856Slling /*
1200990b4856Slling  * Import the given pool using the known configuration and a list of
1201990b4856Slling  * properties to be set. The configuration should have come from
1202990b4856Slling  * zpool_find_import(). The 'newname' parameters control whether the pool
1203990b4856Slling  * is imported with a different name.
1204990b4856Slling  */
1205990b4856Slling int
1206990b4856Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
1207c5904d13Seschrock     nvlist_t *props, boolean_t importfaulted)
1208fa9e4066Sahrens {
1209e9dbad6fSeschrock 	zfs_cmd_t zc = { 0 };
1210fa9e4066Sahrens 	char *thename;
1211fa9e4066Sahrens 	char *origname;
1212fa9e4066Sahrens 	int ret;
1213990b4856Slling 	char errbuf[1024];
1214fa9e4066Sahrens 
1215fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1216fa9e4066Sahrens 	    &origname) == 0);
1217fa9e4066Sahrens 
1218990b4856Slling 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
1219990b4856Slling 	    "cannot import pool '%s'"), origname);
1220990b4856Slling 
1221fa9e4066Sahrens 	if (newname != NULL) {
122299653d4eSeschrock 		if (!zpool_name_valid(hdl, B_FALSE, newname))
1223ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_INVALIDNAME,
122499653d4eSeschrock 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
122599653d4eSeschrock 			    newname));
1226fa9e4066Sahrens 		thename = (char *)newname;
1227fa9e4066Sahrens 	} else {
1228fa9e4066Sahrens 		thename = origname;
1229fa9e4066Sahrens 	}
1230fa9e4066Sahrens 
1231990b4856Slling 	if (props) {
1232990b4856Slling 		uint64_t version;
1233fa9e4066Sahrens 
1234990b4856Slling 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
1235990b4856Slling 		    &version) == 0);
1236fa9e4066Sahrens 
12370a48a24eStimh 		if ((props = zpool_valid_proplist(hdl, origname,
1238351420b3Slling 		    props, version, B_TRUE, errbuf)) == NULL) {
1239990b4856Slling 			return (-1);
1240351420b3Slling 		} else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
1241351420b3Slling 			nvlist_free(props);
1242990b4856Slling 			return (-1);
1243351420b3Slling 		}
1244990b4856Slling 	}
1245990b4856Slling 
1246990b4856Slling 	(void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name));
1247fa9e4066Sahrens 
1248fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1249ea8dc4b6Seschrock 	    &zc.zc_guid) == 0);
1250fa9e4066Sahrens 
1251351420b3Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) {
1252351420b3Slling 		nvlist_free(props);
125399653d4eSeschrock 		return (-1);
1254351420b3Slling 	}
1255fa9e4066Sahrens 
1256c5904d13Seschrock 	zc.zc_cookie = (uint64_t)importfaulted;
1257fa9e4066Sahrens 	ret = 0;
1258ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) {
1259fa9e4066Sahrens 		char desc[1024];
1260fa9e4066Sahrens 		if (newname == NULL)
1261fa9e4066Sahrens 			(void) snprintf(desc, sizeof (desc),
1262fa9e4066Sahrens 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1263fa9e4066Sahrens 			    thename);
1264fa9e4066Sahrens 		else
1265fa9e4066Sahrens 			(void) snprintf(desc, sizeof (desc),
1266fa9e4066Sahrens 			    dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"),
1267fa9e4066Sahrens 			    origname, thename);
1268fa9e4066Sahrens 
1269fa9e4066Sahrens 		switch (errno) {
1270ea8dc4b6Seschrock 		case ENOTSUP:
1271ea8dc4b6Seschrock 			/*
1272ea8dc4b6Seschrock 			 * Unsupported version.
1273ea8dc4b6Seschrock 			 */
127499653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADVERSION, desc);
1275ea8dc4b6Seschrock 			break;
1276ea8dc4b6Seschrock 
1277b5989ec7Seschrock 		case EINVAL:
1278b5989ec7Seschrock 			(void) zfs_error(hdl, EZFS_INVALCONFIG, desc);
1279b5989ec7Seschrock 			break;
1280b5989ec7Seschrock 
1281fa9e4066Sahrens 		default:
128299653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, desc);
1283fa9e4066Sahrens 		}
1284fa9e4066Sahrens 
1285fa9e4066Sahrens 		ret = -1;
1286fa9e4066Sahrens 	} else {
1287fa9e4066Sahrens 		zpool_handle_t *zhp;
1288ecd6cf80Smarks 
1289fa9e4066Sahrens 		/*
1290fa9e4066Sahrens 		 * This should never fail, but play it safe anyway.
1291fa9e4066Sahrens 		 */
129294de1d4cSeschrock 		if (zpool_open_silent(hdl, thename, &zhp) != 0) {
129394de1d4cSeschrock 			ret = -1;
129494de1d4cSeschrock 		} else if (zhp != NULL) {
1295fa9e4066Sahrens 			ret = zpool_create_zvol_links(zhp);
1296fa9e4066Sahrens 			zpool_close(zhp);
1297fa9e4066Sahrens 		}
1298ecd6cf80Smarks 
1299fa9e4066Sahrens 	}
1300fa9e4066Sahrens 
1301e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
1302351420b3Slling 	nvlist_free(props);
1303351420b3Slling 
1304fa9e4066Sahrens 	return (ret);
1305fa9e4066Sahrens }
1306fa9e4066Sahrens 
1307fa9e4066Sahrens /*
1308fa9e4066Sahrens  * Scrub the pool.
1309fa9e4066Sahrens  */
1310fa9e4066Sahrens int
1311fa9e4066Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type)
1312fa9e4066Sahrens {
1313fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1314fa9e4066Sahrens 	char msg[1024];
131599653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1316fa9e4066Sahrens 
1317fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1318fa9e4066Sahrens 	zc.zc_cookie = type;
1319fa9e4066Sahrens 
1320ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0)
1321fa9e4066Sahrens 		return (0);
1322fa9e4066Sahrens 
1323fa9e4066Sahrens 	(void) snprintf(msg, sizeof (msg),
1324fa9e4066Sahrens 	    dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name);
1325fa9e4066Sahrens 
132699653d4eSeschrock 	if (errno == EBUSY)
132799653d4eSeschrock 		return (zfs_error(hdl, EZFS_RESILVERING, msg));
132899653d4eSeschrock 	else
132999653d4eSeschrock 		return (zpool_standard_error(hdl, errno, msg));
1330fa9e4066Sahrens }
1331fa9e4066Sahrens 
1332a43d325bSek /*
1333a43d325bSek  * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL
1334a43d325bSek  * spare; but FALSE if its an INUSE spare.
1335a43d325bSek  */
133699653d4eSeschrock static nvlist_t *
133799653d4eSeschrock vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid,
1338ee0eb9f2SEric Schrock     boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log)
1339ea8dc4b6Seschrock {
1340ea8dc4b6Seschrock 	uint_t c, children;
1341ea8dc4b6Seschrock 	nvlist_t **child;
134299653d4eSeschrock 	uint64_t theguid, present;
1343ea8dc4b6Seschrock 	char *path;
1344ea8dc4b6Seschrock 	uint64_t wholedisk = 0;
134599653d4eSeschrock 	nvlist_t *ret;
1346ee0eb9f2SEric Schrock 	uint64_t is_log;
1347ea8dc4b6Seschrock 
134899653d4eSeschrock 	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &theguid) == 0);
1349ea8dc4b6Seschrock 
1350ea8dc4b6Seschrock 	if (search == NULL &&
1351ea8dc4b6Seschrock 	    nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &present) == 0) {
1352ea8dc4b6Seschrock 		/*
1353ea8dc4b6Seschrock 		 * If the device has never been present since import, the only
1354ea8dc4b6Seschrock 		 * reliable way to match the vdev is by GUID.
1355ea8dc4b6Seschrock 		 */
135699653d4eSeschrock 		if (theguid == guid)
135799653d4eSeschrock 			return (nv);
1358ea8dc4b6Seschrock 	} else if (search != NULL &&
1359ea8dc4b6Seschrock 	    nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
1360ea8dc4b6Seschrock 		(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
1361ea8dc4b6Seschrock 		    &wholedisk);
1362ea8dc4b6Seschrock 		if (wholedisk) {
1363ea8dc4b6Seschrock 			/*
1364ea8dc4b6Seschrock 			 * For whole disks, the internal path has 's0', but the
1365ea8dc4b6Seschrock 			 * path passed in by the user doesn't.
1366ea8dc4b6Seschrock 			 */
1367ea8dc4b6Seschrock 			if (strlen(search) == strlen(path) - 2 &&
1368ea8dc4b6Seschrock 			    strncmp(search, path, strlen(search)) == 0)
136999653d4eSeschrock 				return (nv);
1370ea8dc4b6Seschrock 		} else if (strcmp(search, path) == 0) {
137199653d4eSeschrock 			return (nv);
1372ea8dc4b6Seschrock 		}
1373ea8dc4b6Seschrock 	}
1374ea8dc4b6Seschrock 
1375ea8dc4b6Seschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1376ea8dc4b6Seschrock 	    &child, &children) != 0)
137799653d4eSeschrock 		return (NULL);
1378ea8dc4b6Seschrock 
1379ee0eb9f2SEric Schrock 	for (c = 0; c < children; c++) {
138099653d4eSeschrock 		if ((ret = vdev_to_nvlist_iter(child[c], search, guid,
1381ee0eb9f2SEric Schrock 		    avail_spare, l2cache, NULL)) != NULL) {
1382ee0eb9f2SEric Schrock 			/*
1383ee0eb9f2SEric Schrock 			 * The 'is_log' value is only set for the toplevel
1384ee0eb9f2SEric Schrock 			 * vdev, not the leaf vdevs.  So we always lookup the
1385ee0eb9f2SEric Schrock 			 * log device from the root of the vdev tree (where
1386ee0eb9f2SEric Schrock 			 * 'log' is non-NULL).
1387ee0eb9f2SEric Schrock 			 */
1388ee0eb9f2SEric Schrock 			if (log != NULL &&
1389ee0eb9f2SEric Schrock 			    nvlist_lookup_uint64(child[c],
1390ee0eb9f2SEric Schrock 			    ZPOOL_CONFIG_IS_LOG, &is_log) == 0 &&
1391ee0eb9f2SEric Schrock 			    is_log) {
1392ee0eb9f2SEric Schrock 				*log = B_TRUE;
1393ee0eb9f2SEric Schrock 			}
1394ea8dc4b6Seschrock 			return (ret);
1395ee0eb9f2SEric Schrock 		}
1396ee0eb9f2SEric Schrock 	}
1397ea8dc4b6Seschrock 
139899653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
139999653d4eSeschrock 	    &child, &children) == 0) {
140099653d4eSeschrock 		for (c = 0; c < children; c++) {
140199653d4eSeschrock 			if ((ret = vdev_to_nvlist_iter(child[c], search, guid,
1402ee0eb9f2SEric Schrock 			    avail_spare, l2cache, NULL)) != NULL) {
1403a43d325bSek 				*avail_spare = B_TRUE;
140499653d4eSeschrock 				return (ret);
140599653d4eSeschrock 			}
140699653d4eSeschrock 		}
140799653d4eSeschrock 	}
140899653d4eSeschrock 
1409fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1410fa94a07fSbrendan 	    &child, &children) == 0) {
1411fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1412fa94a07fSbrendan 			if ((ret = vdev_to_nvlist_iter(child[c], search, guid,
1413ee0eb9f2SEric Schrock 			    avail_spare, l2cache, NULL)) != NULL) {
1414fa94a07fSbrendan 				*l2cache = B_TRUE;
1415fa94a07fSbrendan 				return (ret);
1416fa94a07fSbrendan 			}
1417fa94a07fSbrendan 		}
1418fa94a07fSbrendan 	}
1419fa94a07fSbrendan 
142099653d4eSeschrock 	return (NULL);
1421ea8dc4b6Seschrock }
1422ea8dc4b6Seschrock 
142399653d4eSeschrock nvlist_t *
1424fa94a07fSbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
1425ee0eb9f2SEric Schrock     boolean_t *l2cache, boolean_t *log)
1426ea8dc4b6Seschrock {
1427ea8dc4b6Seschrock 	char buf[MAXPATHLEN];
1428ea8dc4b6Seschrock 	const char *search;
1429ea8dc4b6Seschrock 	char *end;
1430ea8dc4b6Seschrock 	nvlist_t *nvroot;
1431ea8dc4b6Seschrock 	uint64_t guid;
1432ea8dc4b6Seschrock 
14330917b783Seschrock 	guid = strtoull(path, &end, 10);
1434ea8dc4b6Seschrock 	if (guid != 0 && *end == '\0') {
1435ea8dc4b6Seschrock 		search = NULL;
1436ea8dc4b6Seschrock 	} else if (path[0] != '/') {
1437ea8dc4b6Seschrock 		(void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path);
1438ea8dc4b6Seschrock 		search = buf;
1439ea8dc4b6Seschrock 	} else {
1440ea8dc4b6Seschrock 		search = path;
1441ea8dc4b6Seschrock 	}
1442ea8dc4b6Seschrock 
1443ea8dc4b6Seschrock 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
1444ea8dc4b6Seschrock 	    &nvroot) == 0);
1445ea8dc4b6Seschrock 
1446a43d325bSek 	*avail_spare = B_FALSE;
1447fa94a07fSbrendan 	*l2cache = B_FALSE;
1448ee0eb9f2SEric Schrock 	if (log != NULL)
1449ee0eb9f2SEric Schrock 		*log = B_FALSE;
1450fa94a07fSbrendan 	return (vdev_to_nvlist_iter(nvroot, search, guid, avail_spare,
1451ee0eb9f2SEric Schrock 	    l2cache, log));
1452a43d325bSek }
1453a43d325bSek 
145419397407SSherry Moore static int
145519397407SSherry Moore vdev_online(nvlist_t *nv)
145619397407SSherry Moore {
145719397407SSherry Moore 	uint64_t ival;
145819397407SSherry Moore 
145919397407SSherry Moore 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 ||
146019397407SSherry Moore 	    nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 ||
146119397407SSherry Moore 	    nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0)
146219397407SSherry Moore 		return (0);
146319397407SSherry Moore 
146419397407SSherry Moore 	return (1);
146519397407SSherry Moore }
146619397407SSherry Moore 
146719397407SSherry Moore /*
146819397407SSherry Moore  * Get phys_path for a root pool
146919397407SSherry Moore  * Return 0 on success; non-zeron on failure.
147019397407SSherry Moore  */
147119397407SSherry Moore int
147219397407SSherry Moore zpool_get_physpath(zpool_handle_t *zhp, char *physpath)
147319397407SSherry Moore {
147419397407SSherry Moore 	nvlist_t *vdev_root;
147519397407SSherry Moore 	nvlist_t **child;
147619397407SSherry Moore 	uint_t count;
147719397407SSherry Moore 	int i;
147819397407SSherry Moore 
147919397407SSherry Moore 	/*
148019397407SSherry Moore 	 * Make sure this is a root pool, as phys_path doesn't mean
148119397407SSherry Moore 	 * anything to a non-root pool.
148219397407SSherry Moore 	 */
1483*b5b76fecSGeorge Wilson 	if (!pool_is_bootable(zhp))
148419397407SSherry Moore 		return (-1);
148519397407SSherry Moore 
148619397407SSherry Moore 	verify(nvlist_lookup_nvlist(zhp->zpool_config,
148719397407SSherry Moore 	    ZPOOL_CONFIG_VDEV_TREE, &vdev_root) == 0);
148819397407SSherry Moore 
148919397407SSherry Moore 	if (nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN,
149019397407SSherry Moore 	    &child, &count) != 0)
149119397407SSherry Moore 		return (-2);
149219397407SSherry Moore 
149319397407SSherry Moore 	for (i = 0; i < count; i++) {
149419397407SSherry Moore 		nvlist_t **child2;
149519397407SSherry Moore 		uint_t count2;
149619397407SSherry Moore 		char *type;
149719397407SSherry Moore 		char *tmppath;
149819397407SSherry Moore 		int j;
149919397407SSherry Moore 
150019397407SSherry Moore 		if (nvlist_lookup_string(child[i], ZPOOL_CONFIG_TYPE, &type)
150119397407SSherry Moore 		    != 0)
150219397407SSherry Moore 			return (-3);
150319397407SSherry Moore 
150419397407SSherry Moore 		if (strcmp(type, VDEV_TYPE_DISK) == 0) {
150519397407SSherry Moore 			if (!vdev_online(child[i]))
150619397407SSherry Moore 				return (-8);
150719397407SSherry Moore 			verify(nvlist_lookup_string(child[i],
150819397407SSherry Moore 			    ZPOOL_CONFIG_PHYS_PATH, &tmppath) == 0);
150919397407SSherry Moore 			(void) strncpy(physpath, tmppath, strlen(tmppath));
151019397407SSherry Moore 		} else if (strcmp(type, VDEV_TYPE_MIRROR) == 0) {
151119397407SSherry Moore 			if (nvlist_lookup_nvlist_array(child[i],
151219397407SSherry Moore 			    ZPOOL_CONFIG_CHILDREN, &child2, &count2) != 0)
151319397407SSherry Moore 				return (-4);
151419397407SSherry Moore 
151519397407SSherry Moore 			for (j = 0; j < count2; j++) {
151619397407SSherry Moore 				if (!vdev_online(child2[j]))
151719397407SSherry Moore 					return (-8);
151819397407SSherry Moore 				if (nvlist_lookup_string(child2[j],
151919397407SSherry Moore 				    ZPOOL_CONFIG_PHYS_PATH, &tmppath) != 0)
152019397407SSherry Moore 					return (-5);
152119397407SSherry Moore 
152219397407SSherry Moore 				if ((strlen(physpath) + strlen(tmppath)) >
152319397407SSherry Moore 				    MAXNAMELEN)
152419397407SSherry Moore 					return (-6);
152519397407SSherry Moore 
152619397407SSherry Moore 				if (strlen(physpath) == 0) {
152719397407SSherry Moore 					(void) strncpy(physpath, tmppath,
152819397407SSherry Moore 					    strlen(tmppath));
152919397407SSherry Moore 				} else {
153019397407SSherry Moore 					(void) strcat(physpath, " ");
153119397407SSherry Moore 					(void) strcat(physpath, tmppath);
153219397407SSherry Moore 				}
153319397407SSherry Moore 			}
153419397407SSherry Moore 		} else {
153519397407SSherry Moore 			return (-7);
153619397407SSherry Moore 		}
153719397407SSherry Moore 	}
153819397407SSherry Moore 
153919397407SSherry Moore 	return (0);
154019397407SSherry Moore }
154119397407SSherry Moore 
1542a43d325bSek /*
1543fa94a07fSbrendan  * Returns TRUE if the given guid corresponds to the given type.
1544fa94a07fSbrendan  * This is used to check for hot spares (INUSE or not), and level 2 cache
1545fa94a07fSbrendan  * devices.
1546a43d325bSek  */
1547a43d325bSek static boolean_t
1548fa94a07fSbrendan is_guid_type(zpool_handle_t *zhp, uint64_t guid, const char *type)
1549a43d325bSek {
1550fa94a07fSbrendan 	uint64_t target_guid;
1551a43d325bSek 	nvlist_t *nvroot;
1552fa94a07fSbrendan 	nvlist_t **list;
1553fa94a07fSbrendan 	uint_t count;
1554a43d325bSek 	int i;
1555a43d325bSek 
1556a43d325bSek 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
1557a43d325bSek 	    &nvroot) == 0);
1558fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nvroot, type, &list, &count) == 0) {
1559fa94a07fSbrendan 		for (i = 0; i < count; i++) {
1560fa94a07fSbrendan 			verify(nvlist_lookup_uint64(list[i], ZPOOL_CONFIG_GUID,
1561fa94a07fSbrendan 			    &target_guid) == 0);
1562fa94a07fSbrendan 			if (guid == target_guid)
1563a43d325bSek 				return (B_TRUE);
1564a43d325bSek 		}
1565a43d325bSek 	}
1566a43d325bSek 
1567a43d325bSek 	return (B_FALSE);
1568ea8dc4b6Seschrock }
1569ea8dc4b6Seschrock 
1570fa9e4066Sahrens /*
15713d7072f8Seschrock  * Bring the specified vdev online.   The 'flags' parameter is a set of the
15723d7072f8Seschrock  * ZFS_ONLINE_* flags.
1573fa9e4066Sahrens  */
1574fa9e4066Sahrens int
15753d7072f8Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
15763d7072f8Seschrock     vdev_state_t *newstate)
1577fa9e4066Sahrens {
1578fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1579fa9e4066Sahrens 	char msg[1024];
158099653d4eSeschrock 	nvlist_t *tgt;
1581fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
158299653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1583fa9e4066Sahrens 
1584ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
1585ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot online %s"), path);
1586ea8dc4b6Seschrock 
1587fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1588ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
1589ee0eb9f2SEric Schrock 	    NULL)) == NULL)
159099653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
1591fa9e4066Sahrens 
159299653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
1593fa9e4066Sahrens 
1594fa94a07fSbrendan 	if (avail_spare ||
1595fa94a07fSbrendan 	    is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE)
1596a43d325bSek 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
1597a43d325bSek 
15983d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_ONLINE;
15993d7072f8Seschrock 	zc.zc_obj = flags;
1600fa9e4066Sahrens 
1601ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0)
16023d7072f8Seschrock 		return (zpool_standard_error(hdl, errno, msg));
16033d7072f8Seschrock 
16043d7072f8Seschrock 	*newstate = zc.zc_cookie;
16053d7072f8Seschrock 	return (0);
1606fa9e4066Sahrens }
1607fa9e4066Sahrens 
1608fa9e4066Sahrens /*
1609fa9e4066Sahrens  * Take the specified vdev offline
1610fa9e4066Sahrens  */
1611fa9e4066Sahrens int
16123d7072f8Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp)
1613fa9e4066Sahrens {
1614fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1615fa9e4066Sahrens 	char msg[1024];
161699653d4eSeschrock 	nvlist_t *tgt;
1617fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
161899653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1619fa9e4066Sahrens 
1620ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
1621ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot offline %s"), path);
1622ea8dc4b6Seschrock 
1623fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1624ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
1625ee0eb9f2SEric Schrock 	    NULL)) == NULL)
162699653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
162799653d4eSeschrock 
162899653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
1629fa9e4066Sahrens 
1630fa94a07fSbrendan 	if (avail_spare ||
1631fa94a07fSbrendan 	    is_guid_type(zhp, zc.zc_guid, ZPOOL_CONFIG_SPARES) == B_TRUE)
1632a43d325bSek 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
1633a43d325bSek 
16343d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_OFFLINE;
16353d7072f8Seschrock 	zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0;
16363d7072f8Seschrock 
1637ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
16383d7072f8Seschrock 		return (0);
16393d7072f8Seschrock 
16403d7072f8Seschrock 	switch (errno) {
16413d7072f8Seschrock 	case EBUSY:
16423d7072f8Seschrock 
16433d7072f8Seschrock 		/*
16443d7072f8Seschrock 		 * There are no other replicas of this device.
16453d7072f8Seschrock 		 */
16463d7072f8Seschrock 		return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
16473d7072f8Seschrock 
16483d7072f8Seschrock 	default:
16493d7072f8Seschrock 		return (zpool_standard_error(hdl, errno, msg));
16503d7072f8Seschrock 	}
16513d7072f8Seschrock }
16523d7072f8Seschrock 
16533d7072f8Seschrock /*
16543d7072f8Seschrock  * Mark the given vdev faulted.
16553d7072f8Seschrock  */
16563d7072f8Seschrock int
16573d7072f8Seschrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid)
16583d7072f8Seschrock {
16593d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
16603d7072f8Seschrock 	char msg[1024];
16613d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
16623d7072f8Seschrock 
16633d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
16643d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid);
1665441d80aaSlling 
16663d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
16673d7072f8Seschrock 	zc.zc_guid = guid;
16683d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_FAULTED;
16693d7072f8Seschrock 
16703d7072f8Seschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
1671fa9e4066Sahrens 		return (0);
1672fa9e4066Sahrens 
1673fa9e4066Sahrens 	switch (errno) {
167499653d4eSeschrock 	case EBUSY:
1675fa9e4066Sahrens 
1676fa9e4066Sahrens 		/*
1677fa9e4066Sahrens 		 * There are no other replicas of this device.
1678fa9e4066Sahrens 		 */
167999653d4eSeschrock 		return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
1680fa9e4066Sahrens 
168199653d4eSeschrock 	default:
168299653d4eSeschrock 		return (zpool_standard_error(hdl, errno, msg));
1683fa9e4066Sahrens 	}
16843d7072f8Seschrock 
16853d7072f8Seschrock }
16863d7072f8Seschrock 
16873d7072f8Seschrock /*
16883d7072f8Seschrock  * Mark the given vdev degraded.
16893d7072f8Seschrock  */
16903d7072f8Seschrock int
16913d7072f8Seschrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid)
16923d7072f8Seschrock {
16933d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
16943d7072f8Seschrock 	char msg[1024];
16953d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
16963d7072f8Seschrock 
16973d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
16983d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid);
16993d7072f8Seschrock 
17003d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
17013d7072f8Seschrock 	zc.zc_guid = guid;
17023d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_DEGRADED;
17033d7072f8Seschrock 
17043d7072f8Seschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
17053d7072f8Seschrock 		return (0);
17063d7072f8Seschrock 
17073d7072f8Seschrock 	return (zpool_standard_error(hdl, errno, msg));
170899653d4eSeschrock }
170999653d4eSeschrock 
171099653d4eSeschrock /*
171199653d4eSeschrock  * Returns TRUE if the given nvlist is a vdev that was originally swapped in as
171299653d4eSeschrock  * a hot spare.
171399653d4eSeschrock  */
171499653d4eSeschrock static boolean_t
171599653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which)
171699653d4eSeschrock {
171799653d4eSeschrock 	nvlist_t **child;
171899653d4eSeschrock 	uint_t c, children;
171999653d4eSeschrock 	char *type;
172099653d4eSeschrock 
172199653d4eSeschrock 	if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child,
172299653d4eSeschrock 	    &children) == 0) {
172399653d4eSeschrock 		verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE,
172499653d4eSeschrock 		    &type) == 0);
172599653d4eSeschrock 
172699653d4eSeschrock 		if (strcmp(type, VDEV_TYPE_SPARE) == 0 &&
172799653d4eSeschrock 		    children == 2 && child[which] == tgt)
172899653d4eSeschrock 			return (B_TRUE);
172999653d4eSeschrock 
173099653d4eSeschrock 		for (c = 0; c < children; c++)
173199653d4eSeschrock 			if (is_replacing_spare(child[c], tgt, which))
173299653d4eSeschrock 				return (B_TRUE);
173399653d4eSeschrock 	}
173499653d4eSeschrock 
173599653d4eSeschrock 	return (B_FALSE);
1736fa9e4066Sahrens }
1737fa9e4066Sahrens 
1738fa9e4066Sahrens /*
1739fa9e4066Sahrens  * Attach new_disk (fully described by nvroot) to old_disk.
17408654d025Sperrin  * If 'replacing' is specified, the new disk will replace the old one.
1741fa9e4066Sahrens  */
1742fa9e4066Sahrens int
1743fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp,
1744fa9e4066Sahrens     const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing)
1745fa9e4066Sahrens {
1746fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1747fa9e4066Sahrens 	char msg[1024];
1748fa9e4066Sahrens 	int ret;
174999653d4eSeschrock 	nvlist_t *tgt;
1750ee0eb9f2SEric Schrock 	boolean_t avail_spare, l2cache, islog;
1751ee0eb9f2SEric Schrock 	uint64_t val;
17520430f8daSeschrock 	char *path, *newname;
175399653d4eSeschrock 	nvlist_t **child;
175499653d4eSeschrock 	uint_t children;
175599653d4eSeschrock 	nvlist_t *config_root;
175699653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1757*b5b76fecSGeorge Wilson 	boolean_t rootpool = pool_is_bootable(zhp);
1758fa9e4066Sahrens 
1759ea8dc4b6Seschrock 	if (replacing)
1760ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
1761ea8dc4b6Seschrock 		    "cannot replace %s with %s"), old_disk, new_disk);
1762ea8dc4b6Seschrock 	else
1763ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
1764ea8dc4b6Seschrock 		    "cannot attach %s to %s"), new_disk, old_disk);
1765ea8dc4b6Seschrock 
1766*b5b76fecSGeorge Wilson 	/*
1767*b5b76fecSGeorge Wilson 	 * If this is a root pool, make sure that we're not attaching an
1768*b5b76fecSGeorge Wilson 	 * EFI labeled device.
1769*b5b76fecSGeorge Wilson 	 */
1770*b5b76fecSGeorge Wilson 	if (rootpool && pool_uses_efi(nvroot)) {
1771*b5b76fecSGeorge Wilson 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1772*b5b76fecSGeorge Wilson 		    "EFI labeled devices are not supported on root pools."));
1773*b5b76fecSGeorge Wilson 		return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
1774*b5b76fecSGeorge Wilson 	}
1775*b5b76fecSGeorge Wilson 
1776fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1777ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
1778ee0eb9f2SEric Schrock 	    &islog)) == 0)
177999653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
178099653d4eSeschrock 
1781a43d325bSek 	if (avail_spare)
178299653d4eSeschrock 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
178399653d4eSeschrock 
1784fa94a07fSbrendan 	if (l2cache)
1785fa94a07fSbrendan 		return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
1786fa94a07fSbrendan 
178799653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
1788fa9e4066Sahrens 	zc.zc_cookie = replacing;
1789fa9e4066Sahrens 
179099653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
179199653d4eSeschrock 	    &child, &children) != 0 || children != 1) {
179299653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
179399653d4eSeschrock 		    "new device must be a single disk"));
179499653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALCONFIG, msg));
179599653d4eSeschrock 	}
179699653d4eSeschrock 
179799653d4eSeschrock 	verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
179899653d4eSeschrock 	    ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);
179999653d4eSeschrock 
18000430f8daSeschrock 	if ((newname = zpool_vdev_name(NULL, NULL, child[0])) == NULL)
18010430f8daSeschrock 		return (-1);
18020430f8daSeschrock 
180399653d4eSeschrock 	/*
180499653d4eSeschrock 	 * If the target is a hot spare that has been swapped in, we can only
180599653d4eSeschrock 	 * replace it with another hot spare.
180699653d4eSeschrock 	 */
180799653d4eSeschrock 	if (replacing &&
180899653d4eSeschrock 	    nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
1809ee0eb9f2SEric Schrock 	    (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache,
1810ee0eb9f2SEric Schrock 	    NULL) == NULL || !avail_spare) &&
1811ee0eb9f2SEric Schrock 	    is_replacing_spare(config_root, tgt, 1)) {
181299653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
181399653d4eSeschrock 		    "can only be replaced by another hot spare"));
18140430f8daSeschrock 		free(newname);
181599653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTARGET, msg));
181699653d4eSeschrock 	}
181799653d4eSeschrock 
181899653d4eSeschrock 	/*
181999653d4eSeschrock 	 * If we are attempting to replace a spare, it canot be applied to an
182099653d4eSeschrock 	 * already spared device.
182199653d4eSeschrock 	 */
182299653d4eSeschrock 	if (replacing &&
182399653d4eSeschrock 	    nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
1824ee0eb9f2SEric Schrock 	    zpool_find_vdev(zhp, newname, &avail_spare,
1825ee0eb9f2SEric Schrock 	    &l2cache, NULL) != NULL && avail_spare &&
1826ee0eb9f2SEric Schrock 	    is_replacing_spare(config_root, tgt, 0)) {
182799653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
182899653d4eSeschrock 		    "device has already been replaced with a spare"));
18290430f8daSeschrock 		free(newname);
183099653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTARGET, msg));
183199653d4eSeschrock 	}
183299653d4eSeschrock 
18330430f8daSeschrock 	free(newname);
18340430f8daSeschrock 
1835990b4856Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
183699653d4eSeschrock 		return (-1);
1837fa9e4066Sahrens 
1838ecd6cf80Smarks 	ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc);
1839fa9e4066Sahrens 
1840e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
1841fa9e4066Sahrens 
1842*b5b76fecSGeorge Wilson 	if (ret == 0) {
1843*b5b76fecSGeorge Wilson 		if (rootpool) {
1844*b5b76fecSGeorge Wilson 			/*
1845*b5b76fecSGeorge Wilson 			 * XXX - This should be removed once we can
1846*b5b76fecSGeorge Wilson 			 * automatically install the bootblocks on the
1847*b5b76fecSGeorge Wilson 			 * newly attached disk.
1848*b5b76fecSGeorge Wilson 			 */
1849*b5b76fecSGeorge Wilson 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please "
1850*b5b76fecSGeorge Wilson 			    "be sure to invoke %s to make '%s' bootable.\n"),
1851*b5b76fecSGeorge Wilson 			    BOOTCMD, new_disk);
1852*b5b76fecSGeorge Wilson 		}
1853fa9e4066Sahrens 		return (0);
1854*b5b76fecSGeorge Wilson 	}
1855fa9e4066Sahrens 
1856fa9e4066Sahrens 	switch (errno) {
1857ea8dc4b6Seschrock 	case ENOTSUP:
1858fa9e4066Sahrens 		/*
1859fa9e4066Sahrens 		 * Can't attach to or replace this type of vdev.
1860fa9e4066Sahrens 		 */
18618654d025Sperrin 		if (replacing) {
1862ee0eb9f2SEric Schrock 			if (islog)
18638654d025Sperrin 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
18648654d025Sperrin 				    "cannot replace a log with a spare"));
18658654d025Sperrin 			else
18668654d025Sperrin 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
18678654d025Sperrin 				    "cannot replace a replacing device"));
18688654d025Sperrin 		} else {
186999653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
187099653d4eSeschrock 			    "can only attach to mirrors and top-level "
187199653d4eSeschrock 			    "disks"));
18728654d025Sperrin 		}
187399653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADTARGET, msg);
1874fa9e4066Sahrens 		break;
1875fa9e4066Sahrens 
1876ea8dc4b6Seschrock 	case EINVAL:
1877fa9e4066Sahrens 		/*
1878fa9e4066Sahrens 		 * The new device must be a single disk.
1879fa9e4066Sahrens 		 */
188099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
188199653d4eSeschrock 		    "new device must be a single disk"));
188299653d4eSeschrock 		(void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
1883fa9e4066Sahrens 		break;
1884fa9e4066Sahrens 
1885ea8dc4b6Seschrock 	case EBUSY:
188699653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"),
188799653d4eSeschrock 		    new_disk);
188899653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
1889fa9e4066Sahrens 		break;
1890fa9e4066Sahrens 
1891ea8dc4b6Seschrock 	case EOVERFLOW:
1892fa9e4066Sahrens 		/*
1893fa9e4066Sahrens 		 * The new device is too small.
1894fa9e4066Sahrens 		 */
189599653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
189699653d4eSeschrock 		    "device is too small"));
189799653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
1898fa9e4066Sahrens 		break;
1899fa9e4066Sahrens 
1900ea8dc4b6Seschrock 	case EDOM:
1901fa9e4066Sahrens 		/*
1902fa9e4066Sahrens 		 * The new device has a different alignment requirement.
1903fa9e4066Sahrens 		 */
190499653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
190599653d4eSeschrock 		    "devices have different sector alignment"));
190699653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
1907fa9e4066Sahrens 		break;
1908fa9e4066Sahrens 
1909ea8dc4b6Seschrock 	case ENAMETOOLONG:
1910fa9e4066Sahrens 		/*
1911fa9e4066Sahrens 		 * The resulting top-level vdev spec won't fit in the label.
1912fa9e4066Sahrens 		 */
191399653d4eSeschrock 		(void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg);
1914fa9e4066Sahrens 		break;
1915fa9e4066Sahrens 
1916ea8dc4b6Seschrock 	default:
191799653d4eSeschrock 		(void) zpool_standard_error(hdl, errno, msg);
1918fa9e4066Sahrens 	}
1919fa9e4066Sahrens 
192099653d4eSeschrock 	return (-1);
1921fa9e4066Sahrens }
1922fa9e4066Sahrens 
1923fa9e4066Sahrens /*
1924fa9e4066Sahrens  * Detach the specified device.
1925fa9e4066Sahrens  */
1926fa9e4066Sahrens int
1927fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
1928fa9e4066Sahrens {
1929fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1930fa9e4066Sahrens 	char msg[1024];
193199653d4eSeschrock 	nvlist_t *tgt;
1932fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
193399653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1934fa9e4066Sahrens 
1935ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
1936ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot detach %s"), path);
1937ea8dc4b6Seschrock 
1938fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1939ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
1940ee0eb9f2SEric Schrock 	    NULL)) == 0)
194199653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
1942fa9e4066Sahrens 
1943a43d325bSek 	if (avail_spare)
194499653d4eSeschrock 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
194599653d4eSeschrock 
1946fa94a07fSbrendan 	if (l2cache)
1947fa94a07fSbrendan 		return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
1948fa94a07fSbrendan 
194999653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
195099653d4eSeschrock 
1951ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0)
1952fa9e4066Sahrens 		return (0);
1953fa9e4066Sahrens 
1954fa9e4066Sahrens 	switch (errno) {
1955fa9e4066Sahrens 
1956ea8dc4b6Seschrock 	case ENOTSUP:
1957fa9e4066Sahrens 		/*
1958fa9e4066Sahrens 		 * Can't detach from this type of vdev.
1959fa9e4066Sahrens 		 */
196099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only "
196199653d4eSeschrock 		    "applicable to mirror and replacing vdevs"));
196299653d4eSeschrock 		(void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg);
1963fa9e4066Sahrens 		break;
1964fa9e4066Sahrens 
1965ea8dc4b6Seschrock 	case EBUSY:
1966fa9e4066Sahrens 		/*
1967fa9e4066Sahrens 		 * There are no other replicas of this device.
1968fa9e4066Sahrens 		 */
196999653d4eSeschrock 		(void) zfs_error(hdl, EZFS_NOREPLICAS, msg);
1970fa9e4066Sahrens 		break;
1971fa9e4066Sahrens 
1972ea8dc4b6Seschrock 	default:
197399653d4eSeschrock 		(void) zpool_standard_error(hdl, errno, msg);
1974ea8dc4b6Seschrock 	}
1975ea8dc4b6Seschrock 
197699653d4eSeschrock 	return (-1);
197799653d4eSeschrock }
197899653d4eSeschrock 
197999653d4eSeschrock /*
1980fa94a07fSbrendan  * Remove the given device.  Currently, this is supported only for hot spares
1981fa94a07fSbrendan  * and level 2 cache devices.
198299653d4eSeschrock  */
198399653d4eSeschrock int
198499653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
198599653d4eSeschrock {
198699653d4eSeschrock 	zfs_cmd_t zc = { 0 };
198799653d4eSeschrock 	char msg[1024];
198899653d4eSeschrock 	nvlist_t *tgt;
1989fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
199099653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
199199653d4eSeschrock 
199299653d4eSeschrock 	(void) snprintf(msg, sizeof (msg),
199399653d4eSeschrock 	    dgettext(TEXT_DOMAIN, "cannot remove %s"), path);
199499653d4eSeschrock 
199599653d4eSeschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1996ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
1997ee0eb9f2SEric Schrock 	    NULL)) == 0)
199899653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
199999653d4eSeschrock 
2000fa94a07fSbrendan 	if (!avail_spare && !l2cache) {
200199653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2002fa94a07fSbrendan 		    "only inactive hot spares or cache devices "
2003fa94a07fSbrendan 		    "can be removed"));
200499653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
200599653d4eSeschrock 	}
200699653d4eSeschrock 
200799653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
200899653d4eSeschrock 
2009ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
201099653d4eSeschrock 		return (0);
201199653d4eSeschrock 
201299653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
2013ea8dc4b6Seschrock }
2014ea8dc4b6Seschrock 
2015ea8dc4b6Seschrock /*
2016ea8dc4b6Seschrock  * Clear the errors for the pool, or the particular device if specified.
2017ea8dc4b6Seschrock  */
2018ea8dc4b6Seschrock int
2019ea8dc4b6Seschrock zpool_clear(zpool_handle_t *zhp, const char *path)
2020ea8dc4b6Seschrock {
2021ea8dc4b6Seschrock 	zfs_cmd_t zc = { 0 };
2022ea8dc4b6Seschrock 	char msg[1024];
202399653d4eSeschrock 	nvlist_t *tgt;
2024fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
202599653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2026ea8dc4b6Seschrock 
2027ea8dc4b6Seschrock 	if (path)
2028ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg),
2029ea8dc4b6Seschrock 		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
2030e9dbad6fSeschrock 		    path);
2031ea8dc4b6Seschrock 	else
2032ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg),
2033ea8dc4b6Seschrock 		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
2034ea8dc4b6Seschrock 		    zhp->zpool_name);
2035ea8dc4b6Seschrock 
2036ea8dc4b6Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
203799653d4eSeschrock 	if (path) {
2038fa94a07fSbrendan 		if ((tgt = zpool_find_vdev(zhp, path, &avail_spare,
2039ee0eb9f2SEric Schrock 		    &l2cache, NULL)) == 0)
204099653d4eSeschrock 			return (zfs_error(hdl, EZFS_NODEVICE, msg));
2041ea8dc4b6Seschrock 
2042fa94a07fSbrendan 		/*
2043fa94a07fSbrendan 		 * Don't allow error clearing for hot spares.  Do allow
2044fa94a07fSbrendan 		 * error clearing for l2cache devices.
2045fa94a07fSbrendan 		 */
2046a43d325bSek 		if (avail_spare)
204799653d4eSeschrock 			return (zfs_error(hdl, EZFS_ISSPARE, msg));
2048ea8dc4b6Seschrock 
204999653d4eSeschrock 		verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
205099653d4eSeschrock 		    &zc.zc_guid) == 0);
2051fa9e4066Sahrens 	}
2052fa9e4066Sahrens 
2053ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0)
205499653d4eSeschrock 		return (0);
205599653d4eSeschrock 
205699653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
2057fa9e4066Sahrens }
2058fa9e4066Sahrens 
20593d7072f8Seschrock /*
20603d7072f8Seschrock  * Similar to zpool_clear(), but takes a GUID (used by fmd).
20613d7072f8Seschrock  */
20623d7072f8Seschrock int
20633d7072f8Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid)
20643d7072f8Seschrock {
20653d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
20663d7072f8Seschrock 	char msg[1024];
20673d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
20683d7072f8Seschrock 
20693d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
20703d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"),
20713d7072f8Seschrock 	    guid);
20723d7072f8Seschrock 
20733d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
20743d7072f8Seschrock 	zc.zc_guid = guid;
20753d7072f8Seschrock 
20763d7072f8Seschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0)
20773d7072f8Seschrock 		return (0);
20783d7072f8Seschrock 
20793d7072f8Seschrock 	return (zpool_standard_error(hdl, errno, msg));
20803d7072f8Seschrock }
20813d7072f8Seschrock 
2082f3861e1aSahl /*
2083f3861e1aSahl  * Iterate over all zvols in a given pool by walking the /dev/zvol/dsk/<pool>
2084f3861e1aSahl  * hierarchy.
2085f3861e1aSahl  */
2086f3861e1aSahl int
2087f3861e1aSahl zpool_iter_zvol(zpool_handle_t *zhp, int (*cb)(const char *, void *),
2088f3861e1aSahl     void *data)
2089fa9e4066Sahrens {
2090f3861e1aSahl 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2091f3861e1aSahl 	char (*paths)[MAXPATHLEN];
2092f3861e1aSahl 	size_t size = 4;
2093f3861e1aSahl 	int curr, fd, base, ret = 0;
2094f3861e1aSahl 	DIR *dirp;
2095f3861e1aSahl 	struct dirent *dp;
2096f3861e1aSahl 	struct stat st;
2097f3861e1aSahl 
2098f3861e1aSahl 	if ((base = open("/dev/zvol/dsk", O_RDONLY)) < 0)
2099f3861e1aSahl 		return (errno == ENOENT ? 0 : -1);
2100f3861e1aSahl 
2101f3861e1aSahl 	if (fstatat(base, zhp->zpool_name, &st, 0) != 0) {
2102f3861e1aSahl 		int err = errno;
2103f3861e1aSahl 		(void) close(base);
2104f3861e1aSahl 		return (err == ENOENT ? 0 : -1);
2105f3861e1aSahl 	}
2106fa9e4066Sahrens 
2107fa9e4066Sahrens 	/*
2108f3861e1aSahl 	 * Oddly this wasn't a directory -- ignore that failure since we
2109f3861e1aSahl 	 * know there are no links lower in the (non-existant) hierarchy.
2110fa9e4066Sahrens 	 */
2111f3861e1aSahl 	if (!S_ISDIR(st.st_mode)) {
2112f3861e1aSahl 		(void) close(base);
2113f3861e1aSahl 		return (0);
2114fa9e4066Sahrens 	}
2115fa9e4066Sahrens 
2116f3861e1aSahl 	if ((paths = zfs_alloc(hdl, size * sizeof (paths[0]))) == NULL) {
2117f3861e1aSahl 		(void) close(base);
2118f3861e1aSahl 		return (-1);
2119f3861e1aSahl 	}
2120f3861e1aSahl 
2121f3861e1aSahl 	(void) strlcpy(paths[0], zhp->zpool_name, sizeof (paths[0]));
2122f3861e1aSahl 	curr = 0;
2123f3861e1aSahl 
2124f3861e1aSahl 	while (curr >= 0) {
2125f3861e1aSahl 		if (fstatat(base, paths[curr], &st, AT_SYMLINK_NOFOLLOW) != 0)
2126f3861e1aSahl 			goto err;
2127f3861e1aSahl 
2128f3861e1aSahl 		if (S_ISDIR(st.st_mode)) {
2129f3861e1aSahl 			if ((fd = openat(base, paths[curr], O_RDONLY)) < 0)
2130f3861e1aSahl 				goto err;
2131f3861e1aSahl 
2132f3861e1aSahl 			if ((dirp = fdopendir(fd)) == NULL) {
2133f3861e1aSahl 				(void) close(fd);
2134f3861e1aSahl 				goto err;
2135f3861e1aSahl 			}
2136f3861e1aSahl 
2137f3861e1aSahl 			while ((dp = readdir(dirp)) != NULL) {
2138f3861e1aSahl 				if (dp->d_name[0] == '.')
2139f3861e1aSahl 					continue;
2140f3861e1aSahl 
2141f3861e1aSahl 				if (curr + 1 == size) {
2142f3861e1aSahl 					paths = zfs_realloc(hdl, paths,
2143f3861e1aSahl 					    size * sizeof (paths[0]),
2144f3861e1aSahl 					    size * 2 * sizeof (paths[0]));
2145f3861e1aSahl 					if (paths == NULL) {
2146f3861e1aSahl 						(void) closedir(dirp);
2147f3861e1aSahl 						(void) close(fd);
2148f3861e1aSahl 						goto err;
2149f3861e1aSahl 					}
2150f3861e1aSahl 
2151f3861e1aSahl 					size *= 2;
2152f3861e1aSahl 				}
2153f3861e1aSahl 
2154f3861e1aSahl 				(void) strlcpy(paths[curr + 1], paths[curr],
2155f3861e1aSahl 				    sizeof (paths[curr + 1]));
2156f3861e1aSahl 				(void) strlcat(paths[curr], "/",
2157f3861e1aSahl 				    sizeof (paths[curr]));
2158f3861e1aSahl 				(void) strlcat(paths[curr], dp->d_name,
2159f3861e1aSahl 				    sizeof (paths[curr]));
2160f3861e1aSahl 				curr++;
2161f3861e1aSahl 			}
2162f3861e1aSahl 
2163f3861e1aSahl 			(void) closedir(dirp);
2164f3861e1aSahl 
2165f3861e1aSahl 		} else {
2166f3861e1aSahl 			if ((ret = cb(paths[curr], data)) != 0)
2167f3861e1aSahl 				break;
2168f3861e1aSahl 		}
2169f3861e1aSahl 
2170f3861e1aSahl 		curr--;
2171f3861e1aSahl 	}
2172f3861e1aSahl 
2173f3861e1aSahl 	free(paths);
2174f3861e1aSahl 	(void) close(base);
2175f3861e1aSahl 
2176f3861e1aSahl 	return (ret);
2177f3861e1aSahl 
2178f3861e1aSahl err:
2179f3861e1aSahl 	free(paths);
2180f3861e1aSahl 	(void) close(base);
2181f3861e1aSahl 	return (-1);
2182f3861e1aSahl }
2183f3861e1aSahl 
2184f3861e1aSahl typedef struct zvol_cb {
2185f3861e1aSahl 	zpool_handle_t *zcb_pool;
2186f3861e1aSahl 	boolean_t zcb_create;
2187f3861e1aSahl } zvol_cb_t;
2188f3861e1aSahl 
2189f3861e1aSahl /*ARGSUSED*/
2190f3861e1aSahl static int
2191f3861e1aSahl do_zvol_create(zfs_handle_t *zhp, void *data)
2192f3861e1aSahl {
21933aefe2c7Sahrens 	int ret = 0;
2194f3861e1aSahl 
21953aefe2c7Sahrens 	if (ZFS_IS_VOLUME(zhp)) {
2196f3861e1aSahl 		(void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name);
21973aefe2c7Sahrens 		ret = zfs_iter_snapshots(zhp, do_zvol_create, NULL);
21983aefe2c7Sahrens 	}
2199f3861e1aSahl 
22003aefe2c7Sahrens 	if (ret == 0)
22013aefe2c7Sahrens 		ret = zfs_iter_filesystems(zhp, do_zvol_create, NULL);
2202fa9e4066Sahrens 
2203fa9e4066Sahrens 	zfs_close(zhp);
2204f3861e1aSahl 
2205fa9e4066Sahrens 	return (ret);
2206fa9e4066Sahrens }
2207fa9e4066Sahrens 
2208fa9e4066Sahrens /*
2209fa9e4066Sahrens  * Iterate over all zvols in the pool and make any necessary minor nodes.
2210fa9e4066Sahrens  */
2211fa9e4066Sahrens int
2212fa9e4066Sahrens zpool_create_zvol_links(zpool_handle_t *zhp)
2213fa9e4066Sahrens {
2214fa9e4066Sahrens 	zfs_handle_t *zfp;
2215fa9e4066Sahrens 	int ret;
2216fa9e4066Sahrens 
2217fa9e4066Sahrens 	/*
2218fa9e4066Sahrens 	 * If the pool is unavailable, just return success.
2219fa9e4066Sahrens 	 */
222099653d4eSeschrock 	if ((zfp = make_dataset_handle(zhp->zpool_hdl,
222199653d4eSeschrock 	    zhp->zpool_name)) == NULL)
2222fa9e4066Sahrens 		return (0);
2223fa9e4066Sahrens 
22243aefe2c7Sahrens 	ret = zfs_iter_filesystems(zfp, do_zvol_create, NULL);
2225fa9e4066Sahrens 
2226fa9e4066Sahrens 	zfs_close(zfp);
2227fa9e4066Sahrens 	return (ret);
2228fa9e4066Sahrens }
2229fa9e4066Sahrens 
2230f3861e1aSahl static int
2231f3861e1aSahl do_zvol_remove(const char *dataset, void *data)
2232f3861e1aSahl {
2233f3861e1aSahl 	zpool_handle_t *zhp = data;
2234f3861e1aSahl 
2235f3861e1aSahl 	return (zvol_remove_link(zhp->zpool_hdl, dataset));
2236f3861e1aSahl }
2237f3861e1aSahl 
2238fa9e4066Sahrens /*
2239f3861e1aSahl  * Iterate over all zvols in the pool and remove any minor nodes.  We iterate
2240f3861e1aSahl  * by examining the /dev links so that a corrupted pool doesn't impede this
2241f3861e1aSahl  * operation.
2242fa9e4066Sahrens  */
2243fa9e4066Sahrens int
2244fa9e4066Sahrens zpool_remove_zvol_links(zpool_handle_t *zhp)
2245fa9e4066Sahrens {
2246f3861e1aSahl 	return (zpool_iter_zvol(zhp, do_zvol_remove, zhp));
2247fa9e4066Sahrens }
2248c67d9675Seschrock 
2249c67d9675Seschrock /*
2250c67d9675Seschrock  * Convert from a devid string to a path.
2251c67d9675Seschrock  */
2252c67d9675Seschrock static char *
2253c67d9675Seschrock devid_to_path(char *devid_str)
2254c67d9675Seschrock {
2255c67d9675Seschrock 	ddi_devid_t devid;
2256c67d9675Seschrock 	char *minor;
2257c67d9675Seschrock 	char *path;
2258c67d9675Seschrock 	devid_nmlist_t *list = NULL;
2259c67d9675Seschrock 	int ret;
2260c67d9675Seschrock 
2261c67d9675Seschrock 	if (devid_str_decode(devid_str, &devid, &minor) != 0)
2262c67d9675Seschrock 		return (NULL);
2263c67d9675Seschrock 
2264c67d9675Seschrock 	ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list);
2265c67d9675Seschrock 
2266c67d9675Seschrock 	devid_str_free(minor);
2267c67d9675Seschrock 	devid_free(devid);
2268c67d9675Seschrock 
2269c67d9675Seschrock 	if (ret != 0)
2270c67d9675Seschrock 		return (NULL);
2271c67d9675Seschrock 
227299653d4eSeschrock 	if ((path = strdup(list[0].devname)) == NULL)
227399653d4eSeschrock 		return (NULL);
227499653d4eSeschrock 
2275c67d9675Seschrock 	devid_free_nmlist(list);
2276c67d9675Seschrock 
2277c67d9675Seschrock 	return (path);
2278c67d9675Seschrock }
2279c67d9675Seschrock 
2280c67d9675Seschrock /*
2281c67d9675Seschrock  * Convert from a path to a devid string.
2282c67d9675Seschrock  */
2283c67d9675Seschrock static char *
2284c67d9675Seschrock path_to_devid(const char *path)
2285c67d9675Seschrock {
2286c67d9675Seschrock 	int fd;
2287c67d9675Seschrock 	ddi_devid_t devid;
2288c67d9675Seschrock 	char *minor, *ret;
2289c67d9675Seschrock 
2290c67d9675Seschrock 	if ((fd = open(path, O_RDONLY)) < 0)
2291c67d9675Seschrock 		return (NULL);
2292c67d9675Seschrock 
2293c67d9675Seschrock 	minor = NULL;
2294c67d9675Seschrock 	ret = NULL;
2295c67d9675Seschrock 	if (devid_get(fd, &devid) == 0) {
2296c67d9675Seschrock 		if (devid_get_minor_name(fd, &minor) == 0)
2297c67d9675Seschrock 			ret = devid_str_encode(devid, minor);
2298c67d9675Seschrock 		if (minor != NULL)
2299c67d9675Seschrock 			devid_str_free(minor);
2300c67d9675Seschrock 		devid_free(devid);
2301c67d9675Seschrock 	}
2302c67d9675Seschrock 	(void) close(fd);
2303c67d9675Seschrock 
2304c67d9675Seschrock 	return (ret);
2305c67d9675Seschrock }
2306c67d9675Seschrock 
2307c67d9675Seschrock /*
2308c67d9675Seschrock  * Issue the necessary ioctl() to update the stored path value for the vdev.  We
2309c67d9675Seschrock  * ignore any failure here, since a common case is for an unprivileged user to
2310c67d9675Seschrock  * type 'zpool status', and we'll display the correct information anyway.
2311c67d9675Seschrock  */
2312c67d9675Seschrock static void
2313c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
2314c67d9675Seschrock {
2315c67d9675Seschrock 	zfs_cmd_t zc = { 0 };
2316c67d9675Seschrock 
2317c67d9675Seschrock 	(void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2318e9dbad6fSeschrock 	(void) strncpy(zc.zc_value, path, sizeof (zc.zc_value));
2319c67d9675Seschrock 	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
2320ea8dc4b6Seschrock 	    &zc.zc_guid) == 0);
2321c67d9675Seschrock 
232299653d4eSeschrock 	(void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc);
2323c67d9675Seschrock }
2324c67d9675Seschrock 
2325c67d9675Seschrock /*
2326c67d9675Seschrock  * Given a vdev, return the name to display in iostat.  If the vdev has a path,
2327c67d9675Seschrock  * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type.
2328c67d9675Seschrock  * We also check if this is a whole disk, in which case we strip off the
2329c67d9675Seschrock  * trailing 's0' slice name.
2330c67d9675Seschrock  *
2331c67d9675Seschrock  * This routine is also responsible for identifying when disks have been
2332c67d9675Seschrock  * reconfigured in a new location.  The kernel will have opened the device by
2333c67d9675Seschrock  * devid, but the path will still refer to the old location.  To catch this, we
2334c67d9675Seschrock  * first do a path -> devid translation (which is fast for the common case).  If
2335c67d9675Seschrock  * the devid matches, we're done.  If not, we do a reverse devid -> path
2336c67d9675Seschrock  * translation and issue the appropriate ioctl() to update the path of the vdev.
2337c67d9675Seschrock  * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any
2338c67d9675Seschrock  * of these checks.
2339c67d9675Seschrock  */
2340c67d9675Seschrock char *
234199653d4eSeschrock zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv)
2342c67d9675Seschrock {
2343c67d9675Seschrock 	char *path, *devid;
2344ea8dc4b6Seschrock 	uint64_t value;
2345ea8dc4b6Seschrock 	char buf[64];
23463d7072f8Seschrock 	vdev_stat_t *vs;
23473d7072f8Seschrock 	uint_t vsc;
2348c67d9675Seschrock 
2349ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2350ea8dc4b6Seschrock 	    &value) == 0) {
2351ea8dc4b6Seschrock 		verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
2352ea8dc4b6Seschrock 		    &value) == 0);
23535ad82045Snd 		(void) snprintf(buf, sizeof (buf), "%llu",
23545ad82045Snd 		    (u_longlong_t)value);
2355ea8dc4b6Seschrock 		path = buf;
2356ea8dc4b6Seschrock 	} else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
2357c67d9675Seschrock 
23583d7072f8Seschrock 		/*
23593d7072f8Seschrock 		 * If the device is dead (faulted, offline, etc) then don't
23603d7072f8Seschrock 		 * bother opening it.  Otherwise we may be forcing the user to
23613d7072f8Seschrock 		 * open a misbehaving device, which can have undesirable
23623d7072f8Seschrock 		 * effects.
23633d7072f8Seschrock 		 */
23643d7072f8Seschrock 		if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
23653d7072f8Seschrock 		    (uint64_t **)&vs, &vsc) != 0 ||
23663d7072f8Seschrock 		    vs->vs_state >= VDEV_STATE_DEGRADED) &&
23673d7072f8Seschrock 		    zhp != NULL &&
2368c67d9675Seschrock 		    nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) {
2369c67d9675Seschrock 			/*
2370c67d9675Seschrock 			 * Determine if the current path is correct.
2371c67d9675Seschrock 			 */
2372c67d9675Seschrock 			char *newdevid = path_to_devid(path);
2373c67d9675Seschrock 
2374c67d9675Seschrock 			if (newdevid == NULL ||
2375c67d9675Seschrock 			    strcmp(devid, newdevid) != 0) {
2376c67d9675Seschrock 				char *newpath;
2377c67d9675Seschrock 
2378c67d9675Seschrock 				if ((newpath = devid_to_path(devid)) != NULL) {
2379c67d9675Seschrock 					/*
2380c67d9675Seschrock 					 * Update the path appropriately.
2381c67d9675Seschrock 					 */
2382c67d9675Seschrock 					set_path(zhp, nv, newpath);
238399653d4eSeschrock 					if (nvlist_add_string(nv,
238499653d4eSeschrock 					    ZPOOL_CONFIG_PATH, newpath) == 0)
238599653d4eSeschrock 						verify(nvlist_lookup_string(nv,
238699653d4eSeschrock 						    ZPOOL_CONFIG_PATH,
238799653d4eSeschrock 						    &path) == 0);
2388c67d9675Seschrock 					free(newpath);
2389c67d9675Seschrock 				}
2390c67d9675Seschrock 			}
2391c67d9675Seschrock 
239299653d4eSeschrock 			if (newdevid)
239399653d4eSeschrock 				devid_str_free(newdevid);
2394c67d9675Seschrock 		}
2395c67d9675Seschrock 
2396c67d9675Seschrock 		if (strncmp(path, "/dev/dsk/", 9) == 0)
2397c67d9675Seschrock 			path += 9;
2398c67d9675Seschrock 
2399c67d9675Seschrock 		if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
2400ea8dc4b6Seschrock 		    &value) == 0 && value) {
240199653d4eSeschrock 			char *tmp = zfs_strdup(hdl, path);
240299653d4eSeschrock 			if (tmp == NULL)
240399653d4eSeschrock 				return (NULL);
2404c67d9675Seschrock 			tmp[strlen(path) - 2] = '\0';
2405c67d9675Seschrock 			return (tmp);
2406c67d9675Seschrock 		}
2407c67d9675Seschrock 	} else {
2408c67d9675Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
240999653d4eSeschrock 
241099653d4eSeschrock 		/*
241199653d4eSeschrock 		 * If it's a raidz device, we need to stick in the parity level.
241299653d4eSeschrock 		 */
241399653d4eSeschrock 		if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) {
241499653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
241599653d4eSeschrock 			    &value) == 0);
241699653d4eSeschrock 			(void) snprintf(buf, sizeof (buf), "%s%llu", path,
24175ad82045Snd 			    (u_longlong_t)value);
241899653d4eSeschrock 			path = buf;
241999653d4eSeschrock 		}
2420c67d9675Seschrock 	}
2421c67d9675Seschrock 
242299653d4eSeschrock 	return (zfs_strdup(hdl, path));
2423c67d9675Seschrock }
2424ea8dc4b6Seschrock 
2425ea8dc4b6Seschrock static int
2426ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b)
2427ea8dc4b6Seschrock {
2428ea8dc4b6Seschrock 	return (memcmp(a, b, sizeof (zbookmark_t)));
2429ea8dc4b6Seschrock }
2430ea8dc4b6Seschrock 
2431ea8dc4b6Seschrock /*
2432ea8dc4b6Seschrock  * Retrieve the persistent error log, uniquify the members, and return to the
2433ea8dc4b6Seschrock  * caller.
2434ea8dc4b6Seschrock  */
2435ea8dc4b6Seschrock int
243655434c77Sek zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
2437ea8dc4b6Seschrock {
2438ea8dc4b6Seschrock 	zfs_cmd_t zc = { 0 };
2439ea8dc4b6Seschrock 	uint64_t count;
2440e9dbad6fSeschrock 	zbookmark_t *zb = NULL;
244155434c77Sek 	int i;
2442ea8dc4b6Seschrock 
2443ea8dc4b6Seschrock 	/*
2444ea8dc4b6Seschrock 	 * Retrieve the raw error list from the kernel.  If the number of errors
2445ea8dc4b6Seschrock 	 * has increased, allocate more space and continue until we get the
2446ea8dc4b6Seschrock 	 * entire list.
2447ea8dc4b6Seschrock 	 */
2448ea8dc4b6Seschrock 	verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT,
2449ea8dc4b6Seschrock 	    &count) == 0);
245075519f38Sek 	if (count == 0)
245175519f38Sek 		return (0);
2452e9dbad6fSeschrock 	if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
24535ad82045Snd 	    count * sizeof (zbookmark_t))) == (uintptr_t)NULL)
245499653d4eSeschrock 		return (-1);
2455e9dbad6fSeschrock 	zc.zc_nvlist_dst_size = count;
2456ea8dc4b6Seschrock 	(void) strcpy(zc.zc_name, zhp->zpool_name);
2457ea8dc4b6Seschrock 	for (;;) {
245899653d4eSeschrock 		if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG,
245999653d4eSeschrock 		    &zc) != 0) {
2460e9dbad6fSeschrock 			free((void *)(uintptr_t)zc.zc_nvlist_dst);
2461ea8dc4b6Seschrock 			if (errno == ENOMEM) {
2462bf561db0Svb 				count = zc.zc_nvlist_dst_size;
2463e9dbad6fSeschrock 				if ((zc.zc_nvlist_dst = (uintptr_t)
2464bf561db0Svb 				    zfs_alloc(zhp->zpool_hdl, count *
2465bf561db0Svb 				    sizeof (zbookmark_t))) == (uintptr_t)NULL)
246699653d4eSeschrock 					return (-1);
2467ea8dc4b6Seschrock 			} else {
2468ea8dc4b6Seschrock 				return (-1);
2469ea8dc4b6Seschrock 			}
2470ea8dc4b6Seschrock 		} else {
2471ea8dc4b6Seschrock 			break;
2472ea8dc4b6Seschrock 		}
2473ea8dc4b6Seschrock 	}
2474ea8dc4b6Seschrock 
2475ea8dc4b6Seschrock 	/*
2476ea8dc4b6Seschrock 	 * Sort the resulting bookmarks.  This is a little confusing due to the
2477ea8dc4b6Seschrock 	 * implementation of ZFS_IOC_ERROR_LOG.  The bookmarks are copied last
2478e9dbad6fSeschrock 	 * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks
2479ea8dc4b6Seschrock 	 * _not_ copied as part of the process.  So we point the start of our
2480ea8dc4b6Seschrock 	 * array appropriate and decrement the total number of elements.
2481ea8dc4b6Seschrock 	 */
2482e9dbad6fSeschrock 	zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) +
2483e9dbad6fSeschrock 	    zc.zc_nvlist_dst_size;
2484e9dbad6fSeschrock 	count -= zc.zc_nvlist_dst_size;
2485ea8dc4b6Seschrock 
2486ea8dc4b6Seschrock 	qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare);
2487ea8dc4b6Seschrock 
248855434c77Sek 	verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0);
2489ea8dc4b6Seschrock 
2490ea8dc4b6Seschrock 	/*
249155434c77Sek 	 * Fill in the nverrlistp with nvlist's of dataset and object numbers.
2492ea8dc4b6Seschrock 	 */
2493ea8dc4b6Seschrock 	for (i = 0; i < count; i++) {
2494ea8dc4b6Seschrock 		nvlist_t *nv;
2495ea8dc4b6Seschrock 
2496c0a81264Sek 		/* ignoring zb_blkid and zb_level for now */
2497c0a81264Sek 		if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset &&
2498c0a81264Sek 		    zb[i-1].zb_object == zb[i].zb_object)
2499ea8dc4b6Seschrock 			continue;
2500ea8dc4b6Seschrock 
250155434c77Sek 		if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0)
250255434c77Sek 			goto nomem;
250355434c77Sek 		if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET,
250455434c77Sek 		    zb[i].zb_objset) != 0) {
250555434c77Sek 			nvlist_free(nv);
250699653d4eSeschrock 			goto nomem;
2507ea8dc4b6Seschrock 		}
250855434c77Sek 		if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT,
250955434c77Sek 		    zb[i].zb_object) != 0) {
251055434c77Sek 			nvlist_free(nv);
251155434c77Sek 			goto nomem;
251255434c77Sek 		}
251355434c77Sek 		if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) {
251455434c77Sek 			nvlist_free(nv);
251555434c77Sek 			goto nomem;
251655434c77Sek 		}
251755434c77Sek 		nvlist_free(nv);
2518ea8dc4b6Seschrock 	}
2519ea8dc4b6Seschrock 
25203ccfa83cSahrens 	free((void *)(uintptr_t)zc.zc_nvlist_dst);
2521ea8dc4b6Seschrock 	return (0);
252299653d4eSeschrock 
252399653d4eSeschrock nomem:
2524e9dbad6fSeschrock 	free((void *)(uintptr_t)zc.zc_nvlist_dst);
252599653d4eSeschrock 	return (no_memory(zhp->zpool_hdl));
2526ea8dc4b6Seschrock }
2527eaca9bbdSeschrock 
2528eaca9bbdSeschrock /*
2529eaca9bbdSeschrock  * Upgrade a ZFS pool to the latest on-disk version.
2530eaca9bbdSeschrock  */
2531eaca9bbdSeschrock int
2532990b4856Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version)
2533eaca9bbdSeschrock {
2534eaca9bbdSeschrock 	zfs_cmd_t zc = { 0 };
253599653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2536eaca9bbdSeschrock 
2537eaca9bbdSeschrock 	(void) strcpy(zc.zc_name, zhp->zpool_name);
2538990b4856Slling 	zc.zc_cookie = new_version;
2539990b4856Slling 
2540ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0)
2541ece3d9b3Slling 		return (zpool_standard_error_fmt(hdl, errno,
254299653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"),
254399653d4eSeschrock 		    zhp->zpool_name));
2544eaca9bbdSeschrock 	return (0);
2545eaca9bbdSeschrock }
254606eeb2adSek 
254706eeb2adSek void
25482a6b87f0Sek zpool_set_history_str(const char *subcommand, int argc, char **argv,
25492a6b87f0Sek     char *history_str)
255006eeb2adSek {
255106eeb2adSek 	int i;
255206eeb2adSek 
25532a6b87f0Sek 	(void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN);
25542a6b87f0Sek 	for (i = 1; i < argc; i++) {
25552a6b87f0Sek 		if (strlen(history_str) + 1 + strlen(argv[i]) >
25562a6b87f0Sek 		    HIS_MAX_RECORD_LEN)
25572a6b87f0Sek 			break;
25582a6b87f0Sek 		(void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN);
25592a6b87f0Sek 		(void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN);
25602a6b87f0Sek 	}
25612a6b87f0Sek }
25622a6b87f0Sek 
25632a6b87f0Sek /*
25642a6b87f0Sek  * Stage command history for logging.
25652a6b87f0Sek  */
25662a6b87f0Sek int
25672a6b87f0Sek zpool_stage_history(libzfs_handle_t *hdl, const char *history_str)
25682a6b87f0Sek {
25692a6b87f0Sek 	if (history_str == NULL)
25702a6b87f0Sek 		return (EINVAL);
25712a6b87f0Sek 
25722a6b87f0Sek 	if (strlen(history_str) > HIS_MAX_RECORD_LEN)
25732a6b87f0Sek 		return (EINVAL);
25742a6b87f0Sek 
2575228975ccSek 	if (hdl->libzfs_log_str != NULL)
2576ecd6cf80Smarks 		free(hdl->libzfs_log_str);
257706eeb2adSek 
25782a6b87f0Sek 	if ((hdl->libzfs_log_str = strdup(history_str)) == NULL)
25792a6b87f0Sek 		return (no_memory(hdl));
258006eeb2adSek 
25812a6b87f0Sek 	return (0);
258206eeb2adSek }
258306eeb2adSek 
258406eeb2adSek /*
258506eeb2adSek  * Perform ioctl to get some command history of a pool.
258606eeb2adSek  *
258706eeb2adSek  * 'buf' is the buffer to fill up to 'len' bytes.  'off' is the
258806eeb2adSek  * logical offset of the history buffer to start reading from.
258906eeb2adSek  *
259006eeb2adSek  * Upon return, 'off' is the next logical offset to read from and
259106eeb2adSek  * 'len' is the actual amount of bytes read into 'buf'.
259206eeb2adSek  */
259306eeb2adSek static int
259406eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len)
259506eeb2adSek {
259606eeb2adSek 	zfs_cmd_t zc = { 0 };
259706eeb2adSek 	libzfs_handle_t *hdl = zhp->zpool_hdl;
259806eeb2adSek 
259906eeb2adSek 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
260006eeb2adSek 
260106eeb2adSek 	zc.zc_history = (uint64_t)(uintptr_t)buf;
260206eeb2adSek 	zc.zc_history_len = *len;
260306eeb2adSek 	zc.zc_history_offset = *off;
260406eeb2adSek 
260506eeb2adSek 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) {
260606eeb2adSek 		switch (errno) {
260706eeb2adSek 		case EPERM:
2608ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_PERM,
2609ece3d9b3Slling 			    dgettext(TEXT_DOMAIN,
261006eeb2adSek 			    "cannot show history for pool '%s'"),
261106eeb2adSek 			    zhp->zpool_name));
261206eeb2adSek 		case ENOENT:
2613ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_NOHISTORY,
261406eeb2adSek 			    dgettext(TEXT_DOMAIN, "cannot get history for pool "
261506eeb2adSek 			    "'%s'"), zhp->zpool_name));
2616d7306b64Sek 		case ENOTSUP:
2617d7306b64Sek 			return (zfs_error_fmt(hdl, EZFS_BADVERSION,
2618d7306b64Sek 			    dgettext(TEXT_DOMAIN, "cannot get history for pool "
2619d7306b64Sek 			    "'%s', pool must be upgraded"), zhp->zpool_name));
262006eeb2adSek 		default:
2621ece3d9b3Slling 			return (zpool_standard_error_fmt(hdl, errno,
262206eeb2adSek 			    dgettext(TEXT_DOMAIN,
262306eeb2adSek 			    "cannot get history for '%s'"), zhp->zpool_name));
262406eeb2adSek 		}
262506eeb2adSek 	}
262606eeb2adSek 
262706eeb2adSek 	*len = zc.zc_history_len;
262806eeb2adSek 	*off = zc.zc_history_offset;
262906eeb2adSek 
263006eeb2adSek 	return (0);
263106eeb2adSek }
263206eeb2adSek 
263306eeb2adSek /*
263406eeb2adSek  * Process the buffer of nvlists, unpacking and storing each nvlist record
263506eeb2adSek  * into 'records'.  'leftover' is set to the number of bytes that weren't
263606eeb2adSek  * processed as there wasn't a complete record.
263706eeb2adSek  */
263806eeb2adSek static int
263906eeb2adSek zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
264006eeb2adSek     nvlist_t ***records, uint_t *numrecords)
264106eeb2adSek {
264206eeb2adSek 	uint64_t reclen;
264306eeb2adSek 	nvlist_t *nv;
264406eeb2adSek 	int i;
264506eeb2adSek 
264606eeb2adSek 	while (bytes_read > sizeof (reclen)) {
264706eeb2adSek 
264806eeb2adSek 		/* get length of packed record (stored as little endian) */
264906eeb2adSek 		for (i = 0, reclen = 0; i < sizeof (reclen); i++)
265006eeb2adSek 			reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i);
265106eeb2adSek 
265206eeb2adSek 		if (bytes_read < sizeof (reclen) + reclen)
265306eeb2adSek 			break;
265406eeb2adSek 
265506eeb2adSek 		/* unpack record */
265606eeb2adSek 		if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0)
265706eeb2adSek 			return (ENOMEM);
265806eeb2adSek 		bytes_read -= sizeof (reclen) + reclen;
265906eeb2adSek 		buf += sizeof (reclen) + reclen;
266006eeb2adSek 
266106eeb2adSek 		/* add record to nvlist array */
266206eeb2adSek 		(*numrecords)++;
266306eeb2adSek 		if (ISP2(*numrecords + 1)) {
266406eeb2adSek 			*records = realloc(*records,
266506eeb2adSek 			    *numrecords * 2 * sizeof (nvlist_t *));
266606eeb2adSek 		}
266706eeb2adSek 		(*records)[*numrecords - 1] = nv;
266806eeb2adSek 	}
266906eeb2adSek 
267006eeb2adSek 	*leftover = bytes_read;
267106eeb2adSek 	return (0);
267206eeb2adSek }
267306eeb2adSek 
267406eeb2adSek #define	HIS_BUF_LEN	(128*1024)
267506eeb2adSek 
267606eeb2adSek /*
267706eeb2adSek  * Retrieve the command history of a pool.
267806eeb2adSek  */
267906eeb2adSek int
268006eeb2adSek zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
268106eeb2adSek {
268206eeb2adSek 	char buf[HIS_BUF_LEN];
268306eeb2adSek 	uint64_t off = 0;
268406eeb2adSek 	nvlist_t **records = NULL;
268506eeb2adSek 	uint_t numrecords = 0;
268606eeb2adSek 	int err, i;
268706eeb2adSek 
268806eeb2adSek 	do {
268906eeb2adSek 		uint64_t bytes_read = sizeof (buf);
269006eeb2adSek 		uint64_t leftover;
269106eeb2adSek 
269206eeb2adSek 		if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
269306eeb2adSek 			break;
269406eeb2adSek 
269506eeb2adSek 		/* if nothing else was read in, we're at EOF, just return */
269606eeb2adSek 		if (!bytes_read)
269706eeb2adSek 			break;
269806eeb2adSek 
269906eeb2adSek 		if ((err = zpool_history_unpack(buf, bytes_read,
270006eeb2adSek 		    &leftover, &records, &numrecords)) != 0)
270106eeb2adSek 			break;
270206eeb2adSek 		off -= leftover;
270306eeb2adSek 
270406eeb2adSek 		/* CONSTCOND */
270506eeb2adSek 	} while (1);
270606eeb2adSek 
270706eeb2adSek 	if (!err) {
270806eeb2adSek 		verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0);
270906eeb2adSek 		verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD,
271006eeb2adSek 		    records, numrecords) == 0);
271106eeb2adSek 	}
271206eeb2adSek 	for (i = 0; i < numrecords; i++)
271306eeb2adSek 		nvlist_free(records[i]);
271406eeb2adSek 	free(records);
271506eeb2adSek 
271606eeb2adSek 	return (err);
271706eeb2adSek }
271855434c77Sek 
271955434c77Sek void
272055434c77Sek zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
272155434c77Sek     char *pathname, size_t len)
272255434c77Sek {
272355434c77Sek 	zfs_cmd_t zc = { 0 };
272455434c77Sek 	boolean_t mounted = B_FALSE;
272555434c77Sek 	char *mntpnt = NULL;
272655434c77Sek 	char dsname[MAXNAMELEN];
272755434c77Sek 
272855434c77Sek 	if (dsobj == 0) {
272955434c77Sek 		/* special case for the MOS */
273055434c77Sek 		(void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj);
273155434c77Sek 		return;
273255434c77Sek 	}
273355434c77Sek 
273455434c77Sek 	/* get the dataset's name */
273555434c77Sek 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
273655434c77Sek 	zc.zc_obj = dsobj;
273755434c77Sek 	if (ioctl(zhp->zpool_hdl->libzfs_fd,
273855434c77Sek 	    ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) {
273955434c77Sek 		/* just write out a path of two object numbers */
274055434c77Sek 		(void) snprintf(pathname, len, "<0x%llx>:<0x%llx>",
274155434c77Sek 		    dsobj, obj);
274255434c77Sek 		return;
274355434c77Sek 	}
274455434c77Sek 	(void) strlcpy(dsname, zc.zc_value, sizeof (dsname));
274555434c77Sek 
274655434c77Sek 	/* find out if the dataset is mounted */
274755434c77Sek 	mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt);
274855434c77Sek 
274955434c77Sek 	/* get the corrupted object's path */
275055434c77Sek 	(void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
275155434c77Sek 	zc.zc_obj = obj;
275255434c77Sek 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH,
275355434c77Sek 	    &zc) == 0) {
275455434c77Sek 		if (mounted) {
275555434c77Sek 			(void) snprintf(pathname, len, "%s%s", mntpnt,
275655434c77Sek 			    zc.zc_value);
275755434c77Sek 		} else {
275855434c77Sek 			(void) snprintf(pathname, len, "%s:%s",
275955434c77Sek 			    dsname, zc.zc_value);
276055434c77Sek 		}
276155434c77Sek 	} else {
276255434c77Sek 		(void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj);
276355434c77Sek 	}
276455434c77Sek 	free(mntpnt);
276555434c77Sek }
2766b1b8ab34Slling 
27678488aeb5Staylor #define	RDISK_ROOT	"/dev/rdsk"
27688488aeb5Staylor #define	BACKUP_SLICE	"s2"
27698488aeb5Staylor /*
27708488aeb5Staylor  * Don't start the slice at the default block of 34; many storage
27718488aeb5Staylor  * devices will use a stripe width of 128k, so start there instead.
27728488aeb5Staylor  */
27738488aeb5Staylor #define	NEW_START_BLOCK	256
27748488aeb5Staylor 
277515e6edf1Sgw /*
277615e6edf1Sgw  * Read the EFI label from the config, if a label does not exist then
277715e6edf1Sgw  * pass back the error to the caller. If the caller has passed a non-NULL
277815e6edf1Sgw  * diskaddr argument then we set it to the starting address of the EFI
277915e6edf1Sgw  * partition.
278015e6edf1Sgw  */
278115e6edf1Sgw static int
278215e6edf1Sgw read_efi_label(nvlist_t *config, diskaddr_t *sb)
278315e6edf1Sgw {
278415e6edf1Sgw 	char *path;
278515e6edf1Sgw 	int fd;
278615e6edf1Sgw 	char diskname[MAXPATHLEN];
278715e6edf1Sgw 	int err = -1;
278815e6edf1Sgw 
278915e6edf1Sgw 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0)
279015e6edf1Sgw 		return (err);
279115e6edf1Sgw 
279215e6edf1Sgw 	(void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT,
279315e6edf1Sgw 	    strrchr(path, '/'));
279415e6edf1Sgw 	if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) {
279515e6edf1Sgw 		struct dk_gpt *vtoc;
279615e6edf1Sgw 
279715e6edf1Sgw 		if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) {
279815e6edf1Sgw 			if (sb != NULL)
279915e6edf1Sgw 				*sb = vtoc->efi_parts[0].p_start;
280015e6edf1Sgw 			efi_free(vtoc);
280115e6edf1Sgw 		}
280215e6edf1Sgw 		(void) close(fd);
280315e6edf1Sgw 	}
280415e6edf1Sgw 	return (err);
280515e6edf1Sgw }
280615e6edf1Sgw 
28078488aeb5Staylor /*
28088488aeb5Staylor  * determine where a partition starts on a disk in the current
28098488aeb5Staylor  * configuration
28108488aeb5Staylor  */
28118488aeb5Staylor static diskaddr_t
28128488aeb5Staylor find_start_block(nvlist_t *config)
28138488aeb5Staylor {
28148488aeb5Staylor 	nvlist_t **child;
28158488aeb5Staylor 	uint_t c, children;
28168488aeb5Staylor 	diskaddr_t sb = MAXOFFSET_T;
28178488aeb5Staylor 	uint64_t wholedisk;
28188488aeb5Staylor 
28198488aeb5Staylor 	if (nvlist_lookup_nvlist_array(config,
28208488aeb5Staylor 	    ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) {
28218488aeb5Staylor 		if (nvlist_lookup_uint64(config,
28228488aeb5Staylor 		    ZPOOL_CONFIG_WHOLE_DISK,
28238488aeb5Staylor 		    &wholedisk) != 0 || !wholedisk) {
28248488aeb5Staylor 			return (MAXOFFSET_T);
28258488aeb5Staylor 		}
282615e6edf1Sgw 		if (read_efi_label(config, &sb) < 0)
282715e6edf1Sgw 			sb = MAXOFFSET_T;
28288488aeb5Staylor 		return (sb);
28298488aeb5Staylor 	}
28308488aeb5Staylor 
28318488aeb5Staylor 	for (c = 0; c < children; c++) {
28328488aeb5Staylor 		sb = find_start_block(child[c]);
28338488aeb5Staylor 		if (sb != MAXOFFSET_T) {
28348488aeb5Staylor 			return (sb);
28358488aeb5Staylor 		}
28368488aeb5Staylor 	}
28378488aeb5Staylor 	return (MAXOFFSET_T);
28388488aeb5Staylor }
28398488aeb5Staylor 
28408488aeb5Staylor /*
28418488aeb5Staylor  * Label an individual disk.  The name provided is the short name,
28428488aeb5Staylor  * stripped of any leading /dev path.
28438488aeb5Staylor  */
28448488aeb5Staylor int
28458488aeb5Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name)
28468488aeb5Staylor {
28478488aeb5Staylor 	char path[MAXPATHLEN];
28488488aeb5Staylor 	struct dk_gpt *vtoc;
28498488aeb5Staylor 	int fd;
28508488aeb5Staylor 	size_t resv = EFI_MIN_RESV_SIZE;
28518488aeb5Staylor 	uint64_t slice_size;
28528488aeb5Staylor 	diskaddr_t start_block;
28538488aeb5Staylor 	char errbuf[1024];
28548488aeb5Staylor 
2855c6ef114fSmmusante 	/* prepare an error message just in case */
2856c6ef114fSmmusante 	(void) snprintf(errbuf, sizeof (errbuf),
2857c6ef114fSmmusante 	    dgettext(TEXT_DOMAIN, "cannot label '%s'"), name);
2858c6ef114fSmmusante 
28598488aeb5Staylor 	if (zhp) {
28608488aeb5Staylor 		nvlist_t *nvroot;
28618488aeb5Staylor 
2862*b5b76fecSGeorge Wilson 		if (pool_is_bootable(zhp)) {
2863*b5b76fecSGeorge Wilson 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2864*b5b76fecSGeorge Wilson 			    "EFI labeled devices are not supported on root "
2865*b5b76fecSGeorge Wilson 			    "pools."));
2866*b5b76fecSGeorge Wilson 			return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf));
2867*b5b76fecSGeorge Wilson 		}
2868*b5b76fecSGeorge Wilson 
28698488aeb5Staylor 		verify(nvlist_lookup_nvlist(zhp->zpool_config,
28708488aeb5Staylor 		    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
28718488aeb5Staylor 
28728488aeb5Staylor 		if (zhp->zpool_start_block == 0)
28738488aeb5Staylor 			start_block = find_start_block(nvroot);
28748488aeb5Staylor 		else
28758488aeb5Staylor 			start_block = zhp->zpool_start_block;
28768488aeb5Staylor 		zhp->zpool_start_block = start_block;
28778488aeb5Staylor 	} else {
28788488aeb5Staylor 		/* new pool */
28798488aeb5Staylor 		start_block = NEW_START_BLOCK;
28808488aeb5Staylor 	}
28818488aeb5Staylor 
28828488aeb5Staylor 	(void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name,
28838488aeb5Staylor 	    BACKUP_SLICE);
28848488aeb5Staylor 
28858488aeb5Staylor 	if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) {
28868488aeb5Staylor 		/*
28878488aeb5Staylor 		 * This shouldn't happen.  We've long since verified that this
28888488aeb5Staylor 		 * is a valid device.
28898488aeb5Staylor 		 */
2890c6ef114fSmmusante 		zfs_error_aux(hdl,
2891c6ef114fSmmusante 		    dgettext(TEXT_DOMAIN, "unable to open device"));
28928488aeb5Staylor 		return (zfs_error(hdl, EZFS_OPENFAILED, errbuf));
28938488aeb5Staylor 	}
28948488aeb5Staylor 
28958488aeb5Staylor 	if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) {
28968488aeb5Staylor 		/*
28978488aeb5Staylor 		 * The only way this can fail is if we run out of memory, or we
28988488aeb5Staylor 		 * were unable to read the disk's capacity
28998488aeb5Staylor 		 */
29008488aeb5Staylor 		if (errno == ENOMEM)
29018488aeb5Staylor 			(void) no_memory(hdl);
29028488aeb5Staylor 
29038488aeb5Staylor 		(void) close(fd);
2904c6ef114fSmmusante 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2905c6ef114fSmmusante 		    "unable to read disk capacity"), name);
29068488aeb5Staylor 
29078488aeb5Staylor 		return (zfs_error(hdl, EZFS_NOCAP, errbuf));
29088488aeb5Staylor 	}
29098488aeb5Staylor 
29108488aeb5Staylor 	slice_size = vtoc->efi_last_u_lba + 1;
29118488aeb5Staylor 	slice_size -= EFI_MIN_RESV_SIZE;
29128488aeb5Staylor 	if (start_block == MAXOFFSET_T)
29138488aeb5Staylor 		start_block = NEW_START_BLOCK;
29148488aeb5Staylor 	slice_size -= start_block;
29158488aeb5Staylor 
29168488aeb5Staylor 	vtoc->efi_parts[0].p_start = start_block;
29178488aeb5Staylor 	vtoc->efi_parts[0].p_size = slice_size;
29188488aeb5Staylor 
29198488aeb5Staylor 	/*
29208488aeb5Staylor 	 * Why we use V_USR: V_BACKUP confuses users, and is considered
29218488aeb5Staylor 	 * disposable by some EFI utilities (since EFI doesn't have a backup
29228488aeb5Staylor 	 * slice).  V_UNASSIGNED is supposed to be used only for zero size
29238488aeb5Staylor 	 * partitions, and efi_write() will fail if we use it.  V_ROOT, V_BOOT,
29248488aeb5Staylor 	 * etc. were all pretty specific.  V_USR is as close to reality as we
29258488aeb5Staylor 	 * can get, in the absence of V_OTHER.
29268488aeb5Staylor 	 */
29278488aeb5Staylor 	vtoc->efi_parts[0].p_tag = V_USR;
29288488aeb5Staylor 	(void) strcpy(vtoc->efi_parts[0].p_name, "zfs");
29298488aeb5Staylor 
29308488aeb5Staylor 	vtoc->efi_parts[8].p_start = slice_size + start_block;
29318488aeb5Staylor 	vtoc->efi_parts[8].p_size = resv;
29328488aeb5Staylor 	vtoc->efi_parts[8].p_tag = V_RESERVED;
29338488aeb5Staylor 
29348488aeb5Staylor 	if (efi_write(fd, vtoc) != 0) {
29358488aeb5Staylor 		/*
29368488aeb5Staylor 		 * Some block drivers (like pcata) may not support EFI
29378488aeb5Staylor 		 * GPT labels.  Print out a helpful error message dir-
29388488aeb5Staylor 		 * ecting the user to manually label the disk and give
29398488aeb5Staylor 		 * a specific slice.
29408488aeb5Staylor 		 */
29418488aeb5Staylor 		(void) close(fd);
29428488aeb5Staylor 		efi_free(vtoc);
29438488aeb5Staylor 
29448488aeb5Staylor 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2945c6ef114fSmmusante 		    "try using fdisk(1M) and then provide a specific slice"));
29468488aeb5Staylor 		return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
29478488aeb5Staylor 	}
29488488aeb5Staylor 
29498488aeb5Staylor 	(void) close(fd);
29508488aeb5Staylor 	efi_free(vtoc);
29518488aeb5Staylor 	return (0);
29528488aeb5Staylor }
2953e7cbe64fSgw 
2954e7cbe64fSgw static boolean_t
2955e7cbe64fSgw supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf)
2956e7cbe64fSgw {
2957e7cbe64fSgw 	char *type;
2958e7cbe64fSgw 	nvlist_t **child;
2959e7cbe64fSgw 	uint_t children, c;
2960e7cbe64fSgw 
2961e7cbe64fSgw 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0);
2962e7cbe64fSgw 	if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 ||
2963e7cbe64fSgw 	    strcmp(type, VDEV_TYPE_FILE) == 0 ||
2964e7cbe64fSgw 	    strcmp(type, VDEV_TYPE_LOG) == 0 ||
2965e7cbe64fSgw 	    strcmp(type, VDEV_TYPE_MISSING) == 0) {
2966e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2967e7cbe64fSgw 		    "vdev type '%s' is not supported"), type);
2968e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf);
2969e7cbe64fSgw 		return (B_FALSE);
2970e7cbe64fSgw 	}
2971e7cbe64fSgw 	if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
2972e7cbe64fSgw 	    &child, &children) == 0) {
2973e7cbe64fSgw 		for (c = 0; c < children; c++) {
2974e7cbe64fSgw 			if (!supported_dump_vdev_type(hdl, child[c], errbuf))
2975e7cbe64fSgw 				return (B_FALSE);
2976e7cbe64fSgw 		}
2977e7cbe64fSgw 	}
2978e7cbe64fSgw 	return (B_TRUE);
2979e7cbe64fSgw }
2980e7cbe64fSgw 
2981e7cbe64fSgw /*
2982e7cbe64fSgw  * check if this zvol is allowable for use as a dump device; zero if
2983e7cbe64fSgw  * it is, > 0 if it isn't, < 0 if it isn't a zvol
2984e7cbe64fSgw  */
2985e7cbe64fSgw int
2986e7cbe64fSgw zvol_check_dump_config(char *arg)
2987e7cbe64fSgw {
2988e7cbe64fSgw 	zpool_handle_t *zhp = NULL;
2989e7cbe64fSgw 	nvlist_t *config, *nvroot;
2990e7cbe64fSgw 	char *p, *volname;
2991e7cbe64fSgw 	nvlist_t **top;
2992e7cbe64fSgw 	uint_t toplevels;
2993e7cbe64fSgw 	libzfs_handle_t *hdl;
2994e7cbe64fSgw 	char errbuf[1024];
2995e7cbe64fSgw 	char poolname[ZPOOL_MAXNAMELEN];
2996e7cbe64fSgw 	int pathlen = strlen(ZVOL_FULL_DEV_DIR);
2997e7cbe64fSgw 	int ret = 1;
2998e7cbe64fSgw 
2999e7cbe64fSgw 	if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) {
3000e7cbe64fSgw 		return (-1);
3001e7cbe64fSgw 	}
3002e7cbe64fSgw 
3003e7cbe64fSgw 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3004e7cbe64fSgw 	    "dump is not supported on device '%s'"), arg);
3005e7cbe64fSgw 
3006e7cbe64fSgw 	if ((hdl = libzfs_init()) == NULL)
3007e7cbe64fSgw 		return (1);
3008e7cbe64fSgw 	libzfs_print_on_error(hdl, B_TRUE);
3009e7cbe64fSgw 
3010e7cbe64fSgw 	volname = arg + pathlen;
3011e7cbe64fSgw 
3012e7cbe64fSgw 	/* check the configuration of the pool */
3013e7cbe64fSgw 	if ((p = strchr(volname, '/')) == NULL) {
3014e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3015e7cbe64fSgw 		    "malformed dataset name"));
3016e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
3017e7cbe64fSgw 		return (1);
3018e7cbe64fSgw 	} else if (p - volname >= ZFS_MAXNAMELEN) {
3019e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3020e7cbe64fSgw 		    "dataset name is too long"));
3021e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf);
3022e7cbe64fSgw 		return (1);
3023e7cbe64fSgw 	} else {
3024e7cbe64fSgw 		(void) strncpy(poolname, volname, p - volname);
3025e7cbe64fSgw 		poolname[p - volname] = '\0';
3026e7cbe64fSgw 	}
3027e7cbe64fSgw 
3028e7cbe64fSgw 	if ((zhp = zpool_open(hdl, poolname)) == NULL) {
3029e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3030e7cbe64fSgw 		    "could not open pool '%s'"), poolname);
3031e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
3032e7cbe64fSgw 		goto out;
3033e7cbe64fSgw 	}
3034e7cbe64fSgw 	config = zpool_get_config(zhp, NULL);
3035e7cbe64fSgw 	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
3036e7cbe64fSgw 	    &nvroot) != 0) {
3037e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3038e7cbe64fSgw 		    "could not obtain vdev configuration for  '%s'"), poolname);
3039e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf);
3040e7cbe64fSgw 		goto out;
3041e7cbe64fSgw 	}
3042e7cbe64fSgw 
3043e7cbe64fSgw 	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
3044e7cbe64fSgw 	    &top, &toplevels) == 0);
3045e7cbe64fSgw 	if (toplevels != 1) {
3046e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3047e7cbe64fSgw 		    "'%s' has multiple top level vdevs"), poolname);
3048e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf);
3049e7cbe64fSgw 		goto out;
3050e7cbe64fSgw 	}
3051e7cbe64fSgw 
3052e7cbe64fSgw 	if (!supported_dump_vdev_type(hdl, top[0], errbuf)) {
3053e7cbe64fSgw 		goto out;
3054e7cbe64fSgw 	}
3055e7cbe64fSgw 	ret = 0;
3056e7cbe64fSgw 
3057e7cbe64fSgw out:
3058e7cbe64fSgw 	if (zhp)
3059e7cbe64fSgw 		zpool_close(zhp);
3060e7cbe64fSgw 	libzfs_fini(hdl);
3061e7cbe64fSgw 	return (ret);
3062e7cbe64fSgw }
3063