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 /*
2339c23413Seschrock  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28fa9e4066Sahrens 
29f3861e1aSahl #include <alloca.h>
30fa9e4066Sahrens #include <assert.h>
31fa9e4066Sahrens #include <ctype.h>
32fa9e4066Sahrens #include <errno.h>
33fa9e4066Sahrens #include <devid.h>
34f3861e1aSahl #include <dirent.h>
35fa9e4066Sahrens #include <fcntl.h>
36fa9e4066Sahrens #include <libintl.h>
37fa9e4066Sahrens #include <stdio.h>
38fa9e4066Sahrens #include <stdlib.h>
39f3861e1aSahl #include <strings.h>
40fa9e4066Sahrens #include <unistd.h>
418488aeb5Staylor #include <sys/efi_partition.h>
428488aeb5Staylor #include <sys/vtoc.h>
43fa9e4066Sahrens #include <sys/zfs_ioctl.h>
44ea8dc4b6Seschrock #include <sys/zio.h>
4506eeb2adSek110237 #include <strings.h>
46fa9e4066Sahrens 
47fa9e4066Sahrens #include "zfs_namecheck.h"
48b1b8ab34Slling #include "zfs_prop.h"
49fa9e4066Sahrens #include "libzfs_impl.h"
50fa9e4066Sahrens 
51fa9e4066Sahrens /*
52fa9e4066Sahrens  * Validate the given pool name, optionally putting an extended error message in
53fa9e4066Sahrens  * 'buf'.
54fa9e4066Sahrens  */
5599653d4eSeschrock static boolean_t
5699653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool)
57fa9e4066Sahrens {
58fa9e4066Sahrens 	namecheck_err_t why;
59fa9e4066Sahrens 	char what;
60b468a217Seschrock 	int ret;
61fa9e4066Sahrens 
62b468a217Seschrock 	ret = pool_namecheck(pool, &why, &what);
63b468a217Seschrock 
64b468a217Seschrock 	/*
65b468a217Seschrock 	 * The rules for reserved pool names were extended at a later point.
66b468a217Seschrock 	 * But we need to support users with existing pools that may now be
67b468a217Seschrock 	 * invalid.  So we only check for this expanded set of names during a
68b468a217Seschrock 	 * create (or import), and only in userland.
69b468a217Seschrock 	 */
70b468a217Seschrock 	if (ret == 0 && !isopen &&
71b468a217Seschrock 	    (strncmp(pool, "mirror", 6) == 0 ||
72b468a217Seschrock 	    strncmp(pool, "raidz", 5) == 0 ||
738654d025Sperrin 	    strncmp(pool, "spare", 5) == 0 ||
748654d025Sperrin 	    strcmp(pool, "log") == 0)) {
7599653d4eSeschrock 		zfs_error_aux(hdl,
7699653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "name is reserved"));
7799653d4eSeschrock 		return (B_FALSE);
78b468a217Seschrock 	}
79b468a217Seschrock 
80b468a217Seschrock 
81b468a217Seschrock 	if (ret != 0) {
8299653d4eSeschrock 		if (hdl != NULL) {
83fa9e4066Sahrens 			switch (why) {
84b81d61a6Slling 			case NAME_ERR_TOOLONG:
8599653d4eSeschrock 				zfs_error_aux(hdl,
86b81d61a6Slling 				    dgettext(TEXT_DOMAIN, "name is too long"));
87b81d61a6Slling 				break;
88b81d61a6Slling 
89fa9e4066Sahrens 			case NAME_ERR_INVALCHAR:
9099653d4eSeschrock 				zfs_error_aux(hdl,
91fa9e4066Sahrens 				    dgettext(TEXT_DOMAIN, "invalid character "
92fa9e4066Sahrens 				    "'%c' in pool name"), what);
93fa9e4066Sahrens 				break;
94fa9e4066Sahrens 
95fa9e4066Sahrens 			case NAME_ERR_NOLETTER:
9699653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
9799653d4eSeschrock 				    "name must begin with a letter"));
98fa9e4066Sahrens 				break;
99fa9e4066Sahrens 
100fa9e4066Sahrens 			case NAME_ERR_RESERVED:
10199653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
10299653d4eSeschrock 				    "name is reserved"));
103fa9e4066Sahrens 				break;
104fa9e4066Sahrens 
105fa9e4066Sahrens 			case NAME_ERR_DISKLIKE:
10699653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
10799653d4eSeschrock 				    "pool name is reserved"));
108fa9e4066Sahrens 				break;
1095ad82045Snd150628 
1105ad82045Snd150628 			case NAME_ERR_LEADING_SLASH:
1115ad82045Snd150628 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1125ad82045Snd150628 				    "leading slash in name"));
1135ad82045Snd150628 				break;
1145ad82045Snd150628 
1155ad82045Snd150628 			case NAME_ERR_EMPTY_COMPONENT:
1165ad82045Snd150628 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1175ad82045Snd150628 				    "empty component in name"));
1185ad82045Snd150628 				break;
1195ad82045Snd150628 
1205ad82045Snd150628 			case NAME_ERR_TRAILING_SLASH:
1215ad82045Snd150628 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1225ad82045Snd150628 				    "trailing slash in name"));
1235ad82045Snd150628 				break;
1245ad82045Snd150628 
1255ad82045Snd150628 			case NAME_ERR_MULTIPLE_AT:
1265ad82045Snd150628 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1275ad82045Snd150628 				    "multiple '@' delimiters in name"));
1285ad82045Snd150628 				break;
1295ad82045Snd150628 
130fa9e4066Sahrens 			}
131fa9e4066Sahrens 		}
13299653d4eSeschrock 		return (B_FALSE);
133fa9e4066Sahrens 	}
134fa9e4066Sahrens 
13599653d4eSeschrock 	return (B_TRUE);
136fa9e4066Sahrens }
137fa9e4066Sahrens 
138b1b8ab34Slling static int
139b1b8ab34Slling zpool_get_all_props(zpool_handle_t *zhp)
140b1b8ab34Slling {
141b1b8ab34Slling 	zfs_cmd_t zc = { 0 };
142b1b8ab34Slling 	libzfs_handle_t *hdl = zhp->zpool_hdl;
143b1b8ab34Slling 
144b1b8ab34Slling 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
145b1b8ab34Slling 
146b1b8ab34Slling 	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
147b1b8ab34Slling 		return (-1);
148b1b8ab34Slling 
149b1b8ab34Slling 	while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) {
150b1b8ab34Slling 		if (errno == ENOMEM) {
151b1b8ab34Slling 			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
152b1b8ab34Slling 				zcmd_free_nvlists(&zc);
153b1b8ab34Slling 				return (-1);
154b1b8ab34Slling 			}
155b1b8ab34Slling 		} else {
156b1b8ab34Slling 			zcmd_free_nvlists(&zc);
157b1b8ab34Slling 			return (-1);
158b1b8ab34Slling 		}
159b1b8ab34Slling 	}
160b1b8ab34Slling 
161b1b8ab34Slling 	if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) {
162b1b8ab34Slling 		zcmd_free_nvlists(&zc);
163b1b8ab34Slling 		return (-1);
164b1b8ab34Slling 	}
165b1b8ab34Slling 
166b1b8ab34Slling 	zcmd_free_nvlists(&zc);
167b1b8ab34Slling 
168b1b8ab34Slling 	return (0);
169b1b8ab34Slling }
170b1b8ab34Slling 
171fa9e4066Sahrens /*
172fa9e4066Sahrens  * Open a handle to the given pool, even if the pool is currently in the FAULTED
173fa9e4066Sahrens  * state.
174fa9e4066Sahrens  */
175fa9e4066Sahrens zpool_handle_t *
17699653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool)
177fa9e4066Sahrens {
178fa9e4066Sahrens 	zpool_handle_t *zhp;
17994de1d4cSeschrock 	boolean_t missing;
180fa9e4066Sahrens 
181fa9e4066Sahrens 	/*
182fa9e4066Sahrens 	 * Make sure the pool name is valid.
183fa9e4066Sahrens 	 */
18499653d4eSeschrock 	if (!zpool_name_valid(hdl, B_TRUE, pool)) {
185ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_INVALIDNAME,
18699653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"),
18799653d4eSeschrock 		    pool);
188fa9e4066Sahrens 		return (NULL);
189fa9e4066Sahrens 	}
190fa9e4066Sahrens 
19199653d4eSeschrock 	if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
19299653d4eSeschrock 		return (NULL);
193fa9e4066Sahrens 
19499653d4eSeschrock 	zhp->zpool_hdl = hdl;
195fa9e4066Sahrens 	(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
196fa9e4066Sahrens 
19794de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0) {
19894de1d4cSeschrock 		zpool_close(zhp);
19994de1d4cSeschrock 		return (NULL);
20094de1d4cSeschrock 	}
20194de1d4cSeschrock 
20294de1d4cSeschrock 	if (missing) {
20399653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
20499653d4eSeschrock 		    "no such pool"));
205ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_NOENT,
20699653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"),
20799653d4eSeschrock 		    pool);
20894de1d4cSeschrock 		zpool_close(zhp);
209fa9e4066Sahrens 		return (NULL);
210fa9e4066Sahrens 	}
211fa9e4066Sahrens 
212fa9e4066Sahrens 	return (zhp);
213fa9e4066Sahrens }
214fa9e4066Sahrens 
215fa9e4066Sahrens /*
216fa9e4066Sahrens  * Like the above, but silent on error.  Used when iterating over pools (because
217fa9e4066Sahrens  * the configuration cache may be out of date).
218fa9e4066Sahrens  */
21994de1d4cSeschrock int
22094de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret)
221fa9e4066Sahrens {
222fa9e4066Sahrens 	zpool_handle_t *zhp;
22394de1d4cSeschrock 	boolean_t missing;
224fa9e4066Sahrens 
22594de1d4cSeschrock 	if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
22694de1d4cSeschrock 		return (-1);
227fa9e4066Sahrens 
22899653d4eSeschrock 	zhp->zpool_hdl = hdl;
229fa9e4066Sahrens 	(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
230fa9e4066Sahrens 
23194de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0) {
23294de1d4cSeschrock 		zpool_close(zhp);
23394de1d4cSeschrock 		return (-1);
234fa9e4066Sahrens 	}
235fa9e4066Sahrens 
23694de1d4cSeschrock 	if (missing) {
23794de1d4cSeschrock 		zpool_close(zhp);
23894de1d4cSeschrock 		*ret = NULL;
23994de1d4cSeschrock 		return (0);
24094de1d4cSeschrock 	}
24194de1d4cSeschrock 
24294de1d4cSeschrock 	*ret = zhp;
24394de1d4cSeschrock 	return (0);
244fa9e4066Sahrens }
245fa9e4066Sahrens 
246fa9e4066Sahrens /*
247fa9e4066Sahrens  * Similar to zpool_open_canfail(), but refuses to open pools in the faulted
248fa9e4066Sahrens  * state.
249fa9e4066Sahrens  */
250fa9e4066Sahrens zpool_handle_t *
25199653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool)
252fa9e4066Sahrens {
253fa9e4066Sahrens 	zpool_handle_t *zhp;
254fa9e4066Sahrens 
25599653d4eSeschrock 	if ((zhp = zpool_open_canfail(hdl, pool)) == NULL)
256fa9e4066Sahrens 		return (NULL);
257fa9e4066Sahrens 
258fa9e4066Sahrens 	if (zhp->zpool_state == POOL_STATE_UNAVAIL) {
259ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL,
26099653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name);
261fa9e4066Sahrens 		zpool_close(zhp);
262fa9e4066Sahrens 		return (NULL);
263fa9e4066Sahrens 	}
264fa9e4066Sahrens 
265fa9e4066Sahrens 	return (zhp);
266fa9e4066Sahrens }
267fa9e4066Sahrens 
268fa9e4066Sahrens /*
269fa9e4066Sahrens  * Close the handle.  Simply frees the memory associated with the handle.
270fa9e4066Sahrens  */
271fa9e4066Sahrens void
272fa9e4066Sahrens zpool_close(zpool_handle_t *zhp)
273fa9e4066Sahrens {
274fa9e4066Sahrens 	if (zhp->zpool_config)
275fa9e4066Sahrens 		nvlist_free(zhp->zpool_config);
276088e9d47Seschrock 	if (zhp->zpool_old_config)
277088e9d47Seschrock 		nvlist_free(zhp->zpool_old_config);
278b1b8ab34Slling 	if (zhp->zpool_props)
279b1b8ab34Slling 		nvlist_free(zhp->zpool_props);
280fa9e4066Sahrens 	free(zhp);
281fa9e4066Sahrens }
282fa9e4066Sahrens 
283fa9e4066Sahrens /*
284fa9e4066Sahrens  * Return the name of the pool.
285fa9e4066Sahrens  */
286fa9e4066Sahrens const char *
287fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp)
288fa9e4066Sahrens {
289fa9e4066Sahrens 	return (zhp->zpool_name);
290fa9e4066Sahrens }
291fa9e4066Sahrens 
292fa9e4066Sahrens /*
293fa9e4066Sahrens  * Return the GUID of the pool.
294fa9e4066Sahrens  */
295fa9e4066Sahrens uint64_t
296fa9e4066Sahrens zpool_get_guid(zpool_handle_t *zhp)
297fa9e4066Sahrens {
298fa9e4066Sahrens 	uint64_t guid;
299fa9e4066Sahrens 
300fa9e4066Sahrens 	verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_POOL_GUID,
301fa9e4066Sahrens 	    &guid) == 0);
302fa9e4066Sahrens 	return (guid);
303fa9e4066Sahrens }
304fa9e4066Sahrens 
305fa9e4066Sahrens /*
30699653d4eSeschrock  * Return the version of the pool.
30799653d4eSeschrock  */
30899653d4eSeschrock uint64_t
30999653d4eSeschrock zpool_get_version(zpool_handle_t *zhp)
31099653d4eSeschrock {
31199653d4eSeschrock 	uint64_t version;
31299653d4eSeschrock 
31399653d4eSeschrock 	verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_VERSION,
31499653d4eSeschrock 	    &version) == 0);
31599653d4eSeschrock 
31699653d4eSeschrock 	return (version);
31799653d4eSeschrock }
31899653d4eSeschrock 
31999653d4eSeschrock /*
320fa9e4066Sahrens  * Return the amount of space currently consumed by the pool.
321fa9e4066Sahrens  */
322fa9e4066Sahrens uint64_t
323fa9e4066Sahrens zpool_get_space_used(zpool_handle_t *zhp)
324fa9e4066Sahrens {
325fa9e4066Sahrens 	nvlist_t *nvroot;
326fa9e4066Sahrens 	vdev_stat_t *vs;
327fa9e4066Sahrens 	uint_t vsc;
328fa9e4066Sahrens 
329fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
330fa9e4066Sahrens 	    &nvroot) == 0);
331fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
332fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
333fa9e4066Sahrens 
334fa9e4066Sahrens 	return (vs->vs_alloc);
335fa9e4066Sahrens }
336fa9e4066Sahrens 
337fa9e4066Sahrens /*
338fa9e4066Sahrens  * Return the total space in the pool.
339fa9e4066Sahrens  */
340fa9e4066Sahrens uint64_t
341fa9e4066Sahrens zpool_get_space_total(zpool_handle_t *zhp)
342fa9e4066Sahrens {
343fa9e4066Sahrens 	nvlist_t *nvroot;
344fa9e4066Sahrens 	vdev_stat_t *vs;
345fa9e4066Sahrens 	uint_t vsc;
346fa9e4066Sahrens 
347fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
348fa9e4066Sahrens 	    &nvroot) == 0);
349fa9e4066Sahrens 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS,
350fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
351fa9e4066Sahrens 
352fa9e4066Sahrens 	return (vs->vs_space);
353fa9e4066Sahrens }
354fa9e4066Sahrens 
355fa9e4066Sahrens /*
356fa9e4066Sahrens  * Return the alternate root for this pool, if any.
357fa9e4066Sahrens  */
358fa9e4066Sahrens int
359fa9e4066Sahrens zpool_get_root(zpool_handle_t *zhp, char *buf, size_t buflen)
360fa9e4066Sahrens {
361fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
362fa9e4066Sahrens 
363fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
36499653d4eSeschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 ||
365e9dbad6fSeschrock 	    zc.zc_value[0] == '\0')
366fa9e4066Sahrens 		return (-1);
367fa9e4066Sahrens 
368e9dbad6fSeschrock 	(void) strlcpy(buf, zc.zc_value, buflen);
369fa9e4066Sahrens 
370fa9e4066Sahrens 	return (0);
371fa9e4066Sahrens }
372fa9e4066Sahrens 
373fa9e4066Sahrens /*
374fa9e4066Sahrens  * Return the state of the pool (ACTIVE or UNAVAILABLE)
375fa9e4066Sahrens  */
376fa9e4066Sahrens int
377fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp)
378fa9e4066Sahrens {
379fa9e4066Sahrens 	return (zhp->zpool_state);
380fa9e4066Sahrens }
381fa9e4066Sahrens 
382fa9e4066Sahrens /*
383fa9e4066Sahrens  * Create the named pool, using the provided vdev list.  It is assumed
384fa9e4066Sahrens  * that the consumer has already validated the contents of the nvlist, so we
385fa9e4066Sahrens  * don't have to worry about error semantics.
386fa9e4066Sahrens  */
387fa9e4066Sahrens int
38899653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
38999653d4eSeschrock     const char *altroot)
390fa9e4066Sahrens {
391fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
39299653d4eSeschrock 	char msg[1024];
393fa9e4066Sahrens 
39499653d4eSeschrock 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
39599653d4eSeschrock 	    "cannot create '%s'"), pool);
39699653d4eSeschrock 
39799653d4eSeschrock 	if (!zpool_name_valid(hdl, B_FALSE, pool))
39899653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
39999653d4eSeschrock 
40099653d4eSeschrock 	if (altroot != NULL && altroot[0] != '/')
401ece3d9b3Slling 		return (zfs_error_fmt(hdl, EZFS_BADPATH,
40299653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "bad alternate root '%s'"), altroot));
40399653d4eSeschrock 
404e9dbad6fSeschrock 	if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0)
405fa9e4066Sahrens 		return (-1);
40699653d4eSeschrock 
407fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
408fa9e4066Sahrens 
409fa9e4066Sahrens 	if (altroot != NULL)
410e9dbad6fSeschrock 		(void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value));
411fa9e4066Sahrens 
412ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc) != 0) {
413e9dbad6fSeschrock 		zcmd_free_nvlists(&zc);
41499653d4eSeschrock 
415fa9e4066Sahrens 		switch (errno) {
416fa9e4066Sahrens 		case EBUSY:
417fa9e4066Sahrens 			/*
418fa9e4066Sahrens 			 * This can happen if the user has specified the same
419fa9e4066Sahrens 			 * device multiple times.  We can't reliably detect this
420fa9e4066Sahrens 			 * until we try to add it and see we already have a
421fa9e4066Sahrens 			 * label.
422fa9e4066Sahrens 			 */
42399653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
42499653d4eSeschrock 			    "one or more vdevs refer to the same device"));
42599653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
426fa9e4066Sahrens 
427fa9e4066Sahrens 		case EOVERFLOW:
428fa9e4066Sahrens 			/*
42999653d4eSeschrock 			 * This occurs when one of the devices is below
430fa9e4066Sahrens 			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
431fa9e4066Sahrens 			 * device was the problem device since there's no
432fa9e4066Sahrens 			 * reliable way to determine device size from userland.
433fa9e4066Sahrens 			 */
434fa9e4066Sahrens 			{
435fa9e4066Sahrens 				char buf[64];
436fa9e4066Sahrens 
437fa9e4066Sahrens 				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
438fa9e4066Sahrens 
43999653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
44099653d4eSeschrock 				    "one or more devices is less than the "
44199653d4eSeschrock 				    "minimum size (%s)"), buf);
442fa9e4066Sahrens 			}
44399653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
444fa9e4066Sahrens 
445fa9e4066Sahrens 		case ENOSPC:
44699653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
44799653d4eSeschrock 			    "one or more devices is out of space"));
44899653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
449fa9e4066Sahrens 
450fa9e4066Sahrens 		default:
45199653d4eSeschrock 			return (zpool_standard_error(hdl, errno, msg));
452fa9e4066Sahrens 		}
453fa9e4066Sahrens 	}
454e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
455fa9e4066Sahrens 
456fa9e4066Sahrens 	/*
457fa9e4066Sahrens 	 * If this is an alternate root pool, then we automatically set the
458e9dbad6fSeschrock 	 * mountpoint of the root dataset to be '/'.
459fa9e4066Sahrens 	 */
460fa9e4066Sahrens 	if (altroot != NULL) {
461fa9e4066Sahrens 		zfs_handle_t *zhp;
462fa9e4066Sahrens 
46399653d4eSeschrock 		verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_ANY)) != NULL);
464e9dbad6fSeschrock 		verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
465e9dbad6fSeschrock 		    "/") == 0);
466fa9e4066Sahrens 
467fa9e4066Sahrens 		zfs_close(zhp);
468fa9e4066Sahrens 	}
469fa9e4066Sahrens 
470fa9e4066Sahrens 	return (0);
471fa9e4066Sahrens }
472fa9e4066Sahrens 
473fa9e4066Sahrens /*
474fa9e4066Sahrens  * Destroy the given pool.  It is up to the caller to ensure that there are no
475fa9e4066Sahrens  * datasets left in the pool.
476fa9e4066Sahrens  */
477fa9e4066Sahrens int
478fa9e4066Sahrens zpool_destroy(zpool_handle_t *zhp)
479fa9e4066Sahrens {
480fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
481fa9e4066Sahrens 	zfs_handle_t *zfp = NULL;
48299653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
48399653d4eSeschrock 	char msg[1024];
484fa9e4066Sahrens 
485fa9e4066Sahrens 	if (zhp->zpool_state == POOL_STATE_ACTIVE &&
48699653d4eSeschrock 	    (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name,
48799653d4eSeschrock 	    ZFS_TYPE_FILESYSTEM)) == NULL)
488fa9e4066Sahrens 		return (-1);
489fa9e4066Sahrens 
4905ad82045Snd150628 	if (zpool_remove_zvol_links(zhp) != 0)
491fa9e4066Sahrens 		return (-1);
492fa9e4066Sahrens 
493fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
494fa9e4066Sahrens 
495ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
49699653d4eSeschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
49799653d4eSeschrock 		    "cannot destroy '%s'"), zhp->zpool_name);
498fa9e4066Sahrens 
49999653d4eSeschrock 		if (errno == EROFS) {
50099653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
50199653d4eSeschrock 			    "one or more devices is read only"));
50299653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
50399653d4eSeschrock 		} else {
50499653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, msg);
505fa9e4066Sahrens 		}
506fa9e4066Sahrens 
507fa9e4066Sahrens 		if (zfp)
508fa9e4066Sahrens 			zfs_close(zfp);
509fa9e4066Sahrens 		return (-1);
510fa9e4066Sahrens 	}
511fa9e4066Sahrens 
512fa9e4066Sahrens 	if (zfp) {
513fa9e4066Sahrens 		remove_mountpoint(zfp);
514fa9e4066Sahrens 		zfs_close(zfp);
515fa9e4066Sahrens 	}
516fa9e4066Sahrens 
517fa9e4066Sahrens 	return (0);
518fa9e4066Sahrens }
519fa9e4066Sahrens 
520fa9e4066Sahrens /*
521fa9e4066Sahrens  * Add the given vdevs to the pool.  The caller must have already performed the
522fa9e4066Sahrens  * necessary verification to ensure that the vdev specification is well-formed.
523fa9e4066Sahrens  */
524fa9e4066Sahrens int
525fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
526fa9e4066Sahrens {
527e9dbad6fSeschrock 	zfs_cmd_t zc = { 0 };
52899653d4eSeschrock 	int ret;
52999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
53099653d4eSeschrock 	char msg[1024];
53199653d4eSeschrock 	nvlist_t **spares;
53299653d4eSeschrock 	uint_t nspares;
53399653d4eSeschrock 
53499653d4eSeschrock 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
53599653d4eSeschrock 	    "cannot add to '%s'"), zhp->zpool_name);
53699653d4eSeschrock 
537e7437265Sahrens 	if (zpool_get_version(zhp) < SPA_VERSION_SPARES &&
53899653d4eSeschrock 	    nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
53999653d4eSeschrock 	    &spares, &nspares) == 0) {
54099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
54199653d4eSeschrock 		    "upgraded to add hot spares"));
54299653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
54399653d4eSeschrock 	}
544fa9e4066Sahrens 
545e9dbad6fSeschrock 	if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0)
54699653d4eSeschrock 		return (-1);
547fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
548fa9e4066Sahrens 
549ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) {
550fa9e4066Sahrens 		switch (errno) {
551fa9e4066Sahrens 		case EBUSY:
552fa9e4066Sahrens 			/*
553fa9e4066Sahrens 			 * This can happen if the user has specified the same
554fa9e4066Sahrens 			 * device multiple times.  We can't reliably detect this
555fa9e4066Sahrens 			 * until we try to add it and see we already have a
556fa9e4066Sahrens 			 * label.
557fa9e4066Sahrens 			 */
55899653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
55999653d4eSeschrock 			    "one or more vdevs refer to the same device"));
56099653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
561fa9e4066Sahrens 			break;
562fa9e4066Sahrens 
563fa9e4066Sahrens 		case EOVERFLOW:
564fa9e4066Sahrens 			/*
565fa9e4066Sahrens 			 * This occurrs when one of the devices is below
566fa9e4066Sahrens 			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
567fa9e4066Sahrens 			 * device was the problem device since there's no
568fa9e4066Sahrens 			 * reliable way to determine device size from userland.
569fa9e4066Sahrens 			 */
570fa9e4066Sahrens 			{
571fa9e4066Sahrens 				char buf[64];
572fa9e4066Sahrens 
573fa9e4066Sahrens 				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
574fa9e4066Sahrens 
57599653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
57699653d4eSeschrock 				    "device is less than the minimum "
57799653d4eSeschrock 				    "size (%s)"), buf);
578fa9e4066Sahrens 			}
57999653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
58099653d4eSeschrock 			break;
58199653d4eSeschrock 
58299653d4eSeschrock 		case ENOTSUP:
58399653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5848654d025Sperrin 			    "pool must be upgraded to add these vdevs"));
58599653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADVERSION, msg);
586fa9e4066Sahrens 			break;
587fa9e4066Sahrens 
588b1b8ab34Slling 		case EDOM:
589b1b8ab34Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5908654d025Sperrin 			    "root pool can not have multiple vdevs"
5918654d025Sperrin 			    " or separate logs"));
592b1b8ab34Slling 			(void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg);
593b1b8ab34Slling 			break;
594b1b8ab34Slling 
595fa9e4066Sahrens 		default:
59699653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, msg);
597fa9e4066Sahrens 		}
598fa9e4066Sahrens 
59999653d4eSeschrock 		ret = -1;
60099653d4eSeschrock 	} else {
60199653d4eSeschrock 		ret = 0;
602fa9e4066Sahrens 	}
603fa9e4066Sahrens 
604e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
605fa9e4066Sahrens 
60699653d4eSeschrock 	return (ret);
607fa9e4066Sahrens }
608fa9e4066Sahrens 
609fa9e4066Sahrens /*
610fa9e4066Sahrens  * Exports the pool from the system.  The caller must ensure that there are no
611fa9e4066Sahrens  * mounted datasets in the pool.
612fa9e4066Sahrens  */
613fa9e4066Sahrens int
614fa9e4066Sahrens zpool_export(zpool_handle_t *zhp)
615fa9e4066Sahrens {
616fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
617fa9e4066Sahrens 
618fa9e4066Sahrens 	if (zpool_remove_zvol_links(zhp) != 0)
619fa9e4066Sahrens 		return (-1);
620fa9e4066Sahrens 
621fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
622fa9e4066Sahrens 
623ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0)
624ece3d9b3Slling 		return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
62599653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot export '%s'"),
62699653d4eSeschrock 		    zhp->zpool_name));
627fa9e4066Sahrens 	return (0);
628fa9e4066Sahrens }
629fa9e4066Sahrens 
630fa9e4066Sahrens /*
631fa9e4066Sahrens  * Import the given pool using the known configuration.  The configuration
632fa9e4066Sahrens  * should have come from zpool_find_import().  The 'newname' and 'altroot'
633fa9e4066Sahrens  * parameters control whether the pool is imported with a different name or with
634fa9e4066Sahrens  * an alternate root, respectively.
635fa9e4066Sahrens  */
636fa9e4066Sahrens int
63799653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
63899653d4eSeschrock     const char *altroot)
639fa9e4066Sahrens {
640e9dbad6fSeschrock 	zfs_cmd_t zc = { 0 };
641fa9e4066Sahrens 	char *thename;
642fa9e4066Sahrens 	char *origname;
643fa9e4066Sahrens 	int ret;
644fa9e4066Sahrens 
645fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
646fa9e4066Sahrens 	    &origname) == 0);
647fa9e4066Sahrens 
648fa9e4066Sahrens 	if (newname != NULL) {
64999653d4eSeschrock 		if (!zpool_name_valid(hdl, B_FALSE, newname))
650ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_INVALIDNAME,
65199653d4eSeschrock 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
65299653d4eSeschrock 			    newname));
653fa9e4066Sahrens 		thename = (char *)newname;
654fa9e4066Sahrens 	} else {
655fa9e4066Sahrens 		thename = origname;
656fa9e4066Sahrens 	}
657fa9e4066Sahrens 
65899653d4eSeschrock 	if (altroot != NULL && altroot[0] != '/')
659ece3d9b3Slling 		return (zfs_error_fmt(hdl, EZFS_BADPATH,
66099653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "bad alternate root '%s'"),
66199653d4eSeschrock 		    altroot));
662fa9e4066Sahrens 
663fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name));
664fa9e4066Sahrens 
665fa9e4066Sahrens 	if (altroot != NULL)
666e9dbad6fSeschrock 		(void) strlcpy(zc.zc_value, altroot, sizeof (zc.zc_value));
667fa9e4066Sahrens 	else
668e9dbad6fSeschrock 		zc.zc_value[0] = '\0';
669fa9e4066Sahrens 
670fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
671ea8dc4b6Seschrock 	    &zc.zc_guid) == 0);
672fa9e4066Sahrens 
673e9dbad6fSeschrock 	if (zcmd_write_src_nvlist(hdl, &zc, config, NULL) != 0)
67499653d4eSeschrock 		return (-1);
675fa9e4066Sahrens 
676fa9e4066Sahrens 	ret = 0;
677ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) {
678fa9e4066Sahrens 		char desc[1024];
679fa9e4066Sahrens 		if (newname == NULL)
680fa9e4066Sahrens 			(void) snprintf(desc, sizeof (desc),
681fa9e4066Sahrens 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
682fa9e4066Sahrens 			    thename);
683fa9e4066Sahrens 		else
684fa9e4066Sahrens 			(void) snprintf(desc, sizeof (desc),
685fa9e4066Sahrens 			    dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"),
686fa9e4066Sahrens 			    origname, thename);
687fa9e4066Sahrens 
688fa9e4066Sahrens 		switch (errno) {
689ea8dc4b6Seschrock 		case ENOTSUP:
690ea8dc4b6Seschrock 			/*
691ea8dc4b6Seschrock 			 * Unsupported version.
692ea8dc4b6Seschrock 			 */
69399653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADVERSION, desc);
694ea8dc4b6Seschrock 			break;
695ea8dc4b6Seschrock 
696b5989ec7Seschrock 		case EINVAL:
697b5989ec7Seschrock 			(void) zfs_error(hdl, EZFS_INVALCONFIG, desc);
698b5989ec7Seschrock 			break;
699b5989ec7Seschrock 
700fa9e4066Sahrens 		default:
70199653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, desc);
702fa9e4066Sahrens 		}
703fa9e4066Sahrens 
704fa9e4066Sahrens 		ret = -1;
705fa9e4066Sahrens 	} else {
706fa9e4066Sahrens 		zpool_handle_t *zhp;
707ecd6cf80Smarks 
708fa9e4066Sahrens 		/*
709fa9e4066Sahrens 		 * This should never fail, but play it safe anyway.
710fa9e4066Sahrens 		 */
71194de1d4cSeschrock 		if (zpool_open_silent(hdl, thename, &zhp) != 0) {
71294de1d4cSeschrock 			ret = -1;
71394de1d4cSeschrock 		} else if (zhp != NULL) {
714fa9e4066Sahrens 			ret = zpool_create_zvol_links(zhp);
715fa9e4066Sahrens 			zpool_close(zhp);
716fa9e4066Sahrens 		}
717ecd6cf80Smarks 
718fa9e4066Sahrens 	}
719fa9e4066Sahrens 
720ecd6cf80Smarks 
721e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
722fa9e4066Sahrens 	return (ret);
723fa9e4066Sahrens }
724fa9e4066Sahrens 
725fa9e4066Sahrens /*
726fa9e4066Sahrens  * Scrub the pool.
727fa9e4066Sahrens  */
728fa9e4066Sahrens int
729fa9e4066Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type)
730fa9e4066Sahrens {
731fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
732fa9e4066Sahrens 	char msg[1024];
73399653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
734fa9e4066Sahrens 
735fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
736fa9e4066Sahrens 	zc.zc_cookie = type;
737fa9e4066Sahrens 
738ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0)
739fa9e4066Sahrens 		return (0);
740fa9e4066Sahrens 
741fa9e4066Sahrens 	(void) snprintf(msg, sizeof (msg),
742fa9e4066Sahrens 	    dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name);
743fa9e4066Sahrens 
74499653d4eSeschrock 	if (errno == EBUSY)
74599653d4eSeschrock 		return (zfs_error(hdl, EZFS_RESILVERING, msg));
74699653d4eSeschrock 	else
74799653d4eSeschrock 		return (zpool_standard_error(hdl, errno, msg));
748fa9e4066Sahrens }
749fa9e4066Sahrens 
750a43d325bSek110237 /*
751a43d325bSek110237  * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL
752a43d325bSek110237  * spare; but FALSE if its an INUSE spare.
753a43d325bSek110237  */
75499653d4eSeschrock static nvlist_t *
75599653d4eSeschrock vdev_to_nvlist_iter(nvlist_t *nv, const char *search, uint64_t guid,
756a43d325bSek110237     boolean_t *avail_spare)
757ea8dc4b6Seschrock {
758ea8dc4b6Seschrock 	uint_t c, children;
759ea8dc4b6Seschrock 	nvlist_t **child;
76099653d4eSeschrock 	uint64_t theguid, present;
761ea8dc4b6Seschrock 	char *path;
762ea8dc4b6Seschrock 	uint64_t wholedisk = 0;
76399653d4eSeschrock 	nvlist_t *ret;
764ea8dc4b6Seschrock 
76599653d4eSeschrock 	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &theguid) == 0);
766ea8dc4b6Seschrock 
767ea8dc4b6Seschrock 	if (search == NULL &&
768ea8dc4b6Seschrock 	    nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &present) == 0) {
769ea8dc4b6Seschrock 		/*
770ea8dc4b6Seschrock 		 * If the device has never been present since import, the only
771ea8dc4b6Seschrock 		 * reliable way to match the vdev is by GUID.
772ea8dc4b6Seschrock 		 */
77399653d4eSeschrock 		if (theguid == guid)
77499653d4eSeschrock 			return (nv);
775ea8dc4b6Seschrock 	} else if (search != NULL &&
776ea8dc4b6Seschrock 	    nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
777ea8dc4b6Seschrock 		(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
778ea8dc4b6Seschrock 		    &wholedisk);
779ea8dc4b6Seschrock 		if (wholedisk) {
780ea8dc4b6Seschrock 			/*
781ea8dc4b6Seschrock 			 * For whole disks, the internal path has 's0', but the
782ea8dc4b6Seschrock 			 * path passed in by the user doesn't.
783ea8dc4b6Seschrock 			 */
784ea8dc4b6Seschrock 			if (strlen(search) == strlen(path) - 2 &&
785ea8dc4b6Seschrock 			    strncmp(search, path, strlen(search)) == 0)
78699653d4eSeschrock 				return (nv);
787ea8dc4b6Seschrock 		} else if (strcmp(search, path) == 0) {
78899653d4eSeschrock 			return (nv);
789ea8dc4b6Seschrock 		}
790ea8dc4b6Seschrock 	}
791ea8dc4b6Seschrock 
792ea8dc4b6Seschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
793ea8dc4b6Seschrock 	    &child, &children) != 0)
79499653d4eSeschrock 		return (NULL);
795ea8dc4b6Seschrock 
796ea8dc4b6Seschrock 	for (c = 0; c < children; c++)
79799653d4eSeschrock 		if ((ret = vdev_to_nvlist_iter(child[c], search, guid,
798a43d325bSek110237 		    avail_spare)) != NULL)
799ea8dc4b6Seschrock 			return (ret);
800ea8dc4b6Seschrock 
80199653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
80299653d4eSeschrock 	    &child, &children) == 0) {
80399653d4eSeschrock 		for (c = 0; c < children; c++) {
80499653d4eSeschrock 			if ((ret = vdev_to_nvlist_iter(child[c], search, guid,
805a43d325bSek110237 			    avail_spare)) != NULL) {
806a43d325bSek110237 				*avail_spare = B_TRUE;
80799653d4eSeschrock 				return (ret);
80899653d4eSeschrock 			}
80999653d4eSeschrock 		}
810ea8dc4b6Seschrock 	}
811ea8dc4b6Seschrock 
81299653d4eSeschrock 	return (NULL);
81399653d4eSeschrock }
81499653d4eSeschrock 
81599653d4eSeschrock nvlist_t *
816a43d325bSek110237 zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare)
817ea8dc4b6Seschrock {
818ea8dc4b6Seschrock 	char buf[MAXPATHLEN];
819ea8dc4b6Seschrock 	const char *search;
820ea8dc4b6Seschrock 	char *end;
821ea8dc4b6Seschrock 	nvlist_t *nvroot;
822ea8dc4b6Seschrock 	uint64_t guid;
823ea8dc4b6Seschrock 
8240917b783Seschrock 	guid = strtoull(path, &end, 10);
825ea8dc4b6Seschrock 	if (guid != 0 && *end == '\0') {
826ea8dc4b6Seschrock 		search = NULL;
827ea8dc4b6Seschrock 	} else if (path[0] != '/') {
828ea8dc4b6Seschrock 		(void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path);
829ea8dc4b6Seschrock 		search = buf;
830ea8dc4b6Seschrock 	} else {
831ea8dc4b6Seschrock 		search = path;
832ea8dc4b6Seschrock 	}
833ea8dc4b6Seschrock 
834ea8dc4b6Seschrock 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
835ea8dc4b6Seschrock 	    &nvroot) == 0);
836ea8dc4b6Seschrock 
837a43d325bSek110237 	*avail_spare = B_FALSE;
838a43d325bSek110237 	return (vdev_to_nvlist_iter(nvroot, search, guid, avail_spare));
839a43d325bSek110237 }
840a43d325bSek110237 
841a43d325bSek110237 /*
842a43d325bSek110237  * Returns TRUE if the given guid corresponds to a spare (INUSE or not).
843a43d325bSek110237  */
844a43d325bSek110237 static boolean_t
845a43d325bSek110237 is_spare(zpool_handle_t *zhp, uint64_t guid)
846a43d325bSek110237 {
847a43d325bSek110237 	uint64_t spare_guid;
848a43d325bSek110237 	nvlist_t *nvroot;
849a43d325bSek110237 	nvlist_t **spares;
850a43d325bSek110237 	uint_t nspares;
851a43d325bSek110237 	int i;
852a43d325bSek110237 
853a43d325bSek110237 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
854a43d325bSek110237 	    &nvroot) == 0);
855a43d325bSek110237 	if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
856a43d325bSek110237 	    &spares, &nspares) == 0) {
857a43d325bSek110237 		for (i = 0; i < nspares; i++) {
858a43d325bSek110237 			verify(nvlist_lookup_uint64(spares[i],
859a43d325bSek110237 			    ZPOOL_CONFIG_GUID, &spare_guid) == 0);
860a43d325bSek110237 			if (guid == spare_guid)
861a43d325bSek110237 				return (B_TRUE);
862a43d325bSek110237 		}
863a43d325bSek110237 	}
864a43d325bSek110237 
865a43d325bSek110237 	return (B_FALSE);
866ea8dc4b6Seschrock }
867ea8dc4b6Seschrock 
868fa9e4066Sahrens /*
8693d7072f8Seschrock  * Bring the specified vdev online.   The 'flags' parameter is a set of the
8703d7072f8Seschrock  * ZFS_ONLINE_* flags.
871fa9e4066Sahrens  */
872fa9e4066Sahrens int
8733d7072f8Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
8743d7072f8Seschrock     vdev_state_t *newstate)
875fa9e4066Sahrens {
876fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
877fa9e4066Sahrens 	char msg[1024];
87899653d4eSeschrock 	nvlist_t *tgt;
879a43d325bSek110237 	boolean_t avail_spare;
88099653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
881fa9e4066Sahrens 
882fa9e4066Sahrens 	(void) snprintf(msg, sizeof (msg),
883ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot online %s"), path);
884ea8dc4b6Seschrock 
885ea8dc4b6Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
886a43d325bSek110237 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL)
88799653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
888ea8dc4b6Seschrock 
88999653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
89099653d4eSeschrock 
891a43d325bSek110237 	if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE)
892a43d325bSek110237 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
893a43d325bSek110237 
8943d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_ONLINE;
8953d7072f8Seschrock 	zc.zc_obj = flags;
896fa9e4066Sahrens 
8973d7072f8Seschrock 
898ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0)
89999653d4eSeschrock 		return (zpool_standard_error(hdl, errno, msg));
9003d7072f8Seschrock 
9013d7072f8Seschrock 	*newstate = zc.zc_cookie;
9023d7072f8Seschrock 	return (0);
903fa9e4066Sahrens }
904fa9e4066Sahrens 
905fa9e4066Sahrens /*
906fa9e4066Sahrens  * Take the specified vdev offline
907fa9e4066Sahrens  */
908fa9e4066Sahrens int
9093d7072f8Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp)
910fa9e4066Sahrens {
911fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
912fa9e4066Sahrens 	char msg[1024];
91399653d4eSeschrock 	nvlist_t *tgt;
914a43d325bSek110237 	boolean_t avail_spare;
91599653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
916fa9e4066Sahrens 
917ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
918ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot offline %s"), path);
919ea8dc4b6Seschrock 
920fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
921a43d325bSek110237 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == NULL)
92299653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
92399653d4eSeschrock 
92499653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
925fa9e4066Sahrens 
926a43d325bSek110237 	if (avail_spare || is_spare(zhp, zc.zc_guid) == B_TRUE)
927a43d325bSek110237 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
928a43d325bSek110237 
9293d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_OFFLINE;
9303d7072f8Seschrock 	zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0;
931441d80aaSlling 
932ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
933fa9e4066Sahrens 		return (0);
934fa9e4066Sahrens 
935fa9e4066Sahrens 	switch (errno) {
936fa9e4066Sahrens 	case EBUSY:
93799653d4eSeschrock 
938fa9e4066Sahrens 		/*
939fa9e4066Sahrens 		 * There are no other replicas of this device.
940fa9e4066Sahrens 		 */
94199653d4eSeschrock 		return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
942fa9e4066Sahrens 
943fa9e4066Sahrens 	default:
94499653d4eSeschrock 		return (zpool_standard_error(hdl, errno, msg));
945fa9e4066Sahrens 	}
94699653d4eSeschrock }
94799653d4eSeschrock 
94899653d4eSeschrock /*
9493d7072f8Seschrock  * Mark the given vdev faulted.
9503d7072f8Seschrock  */
9513d7072f8Seschrock int
9523d7072f8Seschrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid)
9533d7072f8Seschrock {
9543d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
9553d7072f8Seschrock 	char msg[1024];
9563d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
9573d7072f8Seschrock 
9583d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
9593d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid);
9603d7072f8Seschrock 
9613d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
9623d7072f8Seschrock 	zc.zc_guid = guid;
9633d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_FAULTED;
9643d7072f8Seschrock 
9653d7072f8Seschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
9663d7072f8Seschrock 		return (0);
9673d7072f8Seschrock 
9683d7072f8Seschrock 	switch (errno) {
9693d7072f8Seschrock 	case EBUSY:
9703d7072f8Seschrock 
9713d7072f8Seschrock 		/*
9723d7072f8Seschrock 		 * There are no other replicas of this device.
9733d7072f8Seschrock 		 */
9743d7072f8Seschrock 		return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
9753d7072f8Seschrock 
9763d7072f8Seschrock 	default:
9773d7072f8Seschrock 		return (zpool_standard_error(hdl, errno, msg));
9783d7072f8Seschrock 	}
9793d7072f8Seschrock 
9803d7072f8Seschrock }
9813d7072f8Seschrock 
9823d7072f8Seschrock /*
9833d7072f8Seschrock  * Mark the given vdev degraded.
9843d7072f8Seschrock  */
9853d7072f8Seschrock int
9863d7072f8Seschrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid)
9873d7072f8Seschrock {
9883d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
9893d7072f8Seschrock 	char msg[1024];
9903d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
9913d7072f8Seschrock 
9923d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
9933d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid);
9943d7072f8Seschrock 
9953d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
9963d7072f8Seschrock 	zc.zc_guid = guid;
9973d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_DEGRADED;
9983d7072f8Seschrock 
9993d7072f8Seschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
10003d7072f8Seschrock 		return (0);
10013d7072f8Seschrock 
10023d7072f8Seschrock 	return (zpool_standard_error(hdl, errno, msg));
10033d7072f8Seschrock }
10043d7072f8Seschrock 
10053d7072f8Seschrock /*
100699653d4eSeschrock  * Returns TRUE if the given nvlist is a vdev that was originally swapped in as
100799653d4eSeschrock  * a hot spare.
100899653d4eSeschrock  */
100999653d4eSeschrock static boolean_t
101099653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which)
101199653d4eSeschrock {
101299653d4eSeschrock 	nvlist_t **child;
101399653d4eSeschrock 	uint_t c, children;
101499653d4eSeschrock 	char *type;
101599653d4eSeschrock 
101699653d4eSeschrock 	if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child,
101799653d4eSeschrock 	    &children) == 0) {
101899653d4eSeschrock 		verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE,
101999653d4eSeschrock 		    &type) == 0);
102099653d4eSeschrock 
102199653d4eSeschrock 		if (strcmp(type, VDEV_TYPE_SPARE) == 0 &&
102299653d4eSeschrock 		    children == 2 && child[which] == tgt)
102399653d4eSeschrock 			return (B_TRUE);
102499653d4eSeschrock 
102599653d4eSeschrock 		for (c = 0; c < children; c++)
102699653d4eSeschrock 			if (is_replacing_spare(child[c], tgt, which))
102799653d4eSeschrock 				return (B_TRUE);
102899653d4eSeschrock 	}
102999653d4eSeschrock 
103099653d4eSeschrock 	return (B_FALSE);
1031fa9e4066Sahrens }
1032fa9e4066Sahrens 
1033fa9e4066Sahrens /*
1034fa9e4066Sahrens  * Attach new_disk (fully described by nvroot) to old_disk.
10358654d025Sperrin  * If 'replacing' is specified, the new disk will replace the old one.
1036fa9e4066Sahrens  */
1037fa9e4066Sahrens int
1038fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp,
1039fa9e4066Sahrens     const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing)
1040fa9e4066Sahrens {
1041fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1042fa9e4066Sahrens 	char msg[1024];
1043fa9e4066Sahrens 	int ret;
104499653d4eSeschrock 	nvlist_t *tgt;
1045a43d325bSek110237 	boolean_t avail_spare;
10468654d025Sperrin 	uint64_t val, is_log;
104799653d4eSeschrock 	char *path;
104899653d4eSeschrock 	nvlist_t **child;
104999653d4eSeschrock 	uint_t children;
105099653d4eSeschrock 	nvlist_t *config_root;
105199653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1052fa9e4066Sahrens 
1053ea8dc4b6Seschrock 	if (replacing)
1054ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
1055ea8dc4b6Seschrock 		    "cannot replace %s with %s"), old_disk, new_disk);
1056ea8dc4b6Seschrock 	else
1057ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
1058ea8dc4b6Seschrock 		    "cannot attach %s to %s"), new_disk, old_disk);
1059ea8dc4b6Seschrock 
1060fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1061a43d325bSek110237 	if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare)) == 0)
106299653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
106399653d4eSeschrock 
1064a43d325bSek110237 	if (avail_spare)
106599653d4eSeschrock 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
106699653d4eSeschrock 
106799653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
1068fa9e4066Sahrens 	zc.zc_cookie = replacing;
1069fa9e4066Sahrens 
107099653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
107199653d4eSeschrock 	    &child, &children) != 0 || children != 1) {
107299653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
107399653d4eSeschrock 		    "new device must be a single disk"));
107499653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALCONFIG, msg));
107599653d4eSeschrock 	}
107699653d4eSeschrock 
107799653d4eSeschrock 	verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
107899653d4eSeschrock 	    ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);
107999653d4eSeschrock 
108099653d4eSeschrock 	/*
108199653d4eSeschrock 	 * If the target is a hot spare that has been swapped in, we can only
108299653d4eSeschrock 	 * replace it with another hot spare.
108399653d4eSeschrock 	 */
108499653d4eSeschrock 	if (replacing &&
108599653d4eSeschrock 	    nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
108699653d4eSeschrock 	    nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
1087a43d325bSek110237 	    (zpool_find_vdev(zhp, path, &avail_spare) == NULL ||
1088a43d325bSek110237 	    !avail_spare) && is_replacing_spare(config_root, tgt, 1)) {
108999653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
109099653d4eSeschrock 		    "can only be replaced by another hot spare"));
109199653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTARGET, msg));
109299653d4eSeschrock 	}
109399653d4eSeschrock 
109499653d4eSeschrock 	/*
109599653d4eSeschrock 	 * If we are attempting to replace a spare, it canot be applied to an
109699653d4eSeschrock 	 * already spared device.
109799653d4eSeschrock 	 */
109899653d4eSeschrock 	if (replacing &&
109999653d4eSeschrock 	    nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
1100a43d325bSek110237 	    zpool_find_vdev(zhp, path, &avail_spare) != NULL && avail_spare &&
110199653d4eSeschrock 	    is_replacing_spare(config_root, tgt, 0)) {
110299653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
110399653d4eSeschrock 		    "device has already been replaced with a spare"));
110499653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTARGET, msg));
110599653d4eSeschrock 	}
110699653d4eSeschrock 
1107e9dbad6fSeschrock 	if (zcmd_write_src_nvlist(hdl, &zc, nvroot, NULL) != 0)
110899653d4eSeschrock 		return (-1);
1109fa9e4066Sahrens 
1110ecd6cf80Smarks 	ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc);
1111fa9e4066Sahrens 
1112e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
1113fa9e4066Sahrens 
1114fa9e4066Sahrens 	if (ret == 0)
1115fa9e4066Sahrens 		return (0);
1116fa9e4066Sahrens 
1117fa9e4066Sahrens 	switch (errno) {
1118fa9e4066Sahrens 	case ENOTSUP:
1119fa9e4066Sahrens 		/*
1120fa9e4066Sahrens 		 * Can't attach to or replace this type of vdev.
1121fa9e4066Sahrens 		 */
11228654d025Sperrin 		if (replacing) {
11238654d025Sperrin 			is_log = B_FALSE;
11248654d025Sperrin 			(void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_LOG,
11258654d025Sperrin 			    &is_log);
11268654d025Sperrin 			if (is_log)
11278654d025Sperrin 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
11288654d025Sperrin 				    "cannot replace a log with a spare"));
11298654d025Sperrin 			else
113099653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
113199653d4eSeschrock 				    "cannot replace a replacing device"));
11328654d025Sperrin 		} else {
113399653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
113499653d4eSeschrock 			    "can only attach to mirrors and top-level "
113599653d4eSeschrock 			    "disks"));
11368654d025Sperrin 		}
113799653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADTARGET, msg);
1138fa9e4066Sahrens 		break;
1139fa9e4066Sahrens 
1140fa9e4066Sahrens 	case EINVAL:
1141fa9e4066Sahrens 		/*
1142fa9e4066Sahrens 		 * The new device must be a single disk.
1143fa9e4066Sahrens 		 */
114499653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
114599653d4eSeschrock 		    "new device must be a single disk"));
114699653d4eSeschrock 		(void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
1147fa9e4066Sahrens 		break;
1148fa9e4066Sahrens 
1149fa9e4066Sahrens 	case EBUSY:
115099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"),
115199653d4eSeschrock 		    new_disk);
115299653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
1153fa9e4066Sahrens 		break;
1154fa9e4066Sahrens 
1155fa9e4066Sahrens 	case EOVERFLOW:
1156fa9e4066Sahrens 		/*
1157fa9e4066Sahrens 		 * The new device is too small.
1158fa9e4066Sahrens 		 */
115999653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
116099653d4eSeschrock 		    "device is too small"));
116199653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
1162fa9e4066Sahrens 		break;
1163fa9e4066Sahrens 
1164fa9e4066Sahrens 	case EDOM:
1165fa9e4066Sahrens 		/*
1166fa9e4066Sahrens 		 * The new device has a different alignment requirement.
1167fa9e4066Sahrens 		 */
116899653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
116999653d4eSeschrock 		    "devices have different sector alignment"));
117099653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
1171fa9e4066Sahrens 		break;
1172fa9e4066Sahrens 
1173fa9e4066Sahrens 	case ENAMETOOLONG:
1174fa9e4066Sahrens 		/*
1175fa9e4066Sahrens 		 * The resulting top-level vdev spec won't fit in the label.
1176fa9e4066Sahrens 		 */
117799653d4eSeschrock 		(void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg);
1178fa9e4066Sahrens 		break;
1179fa9e4066Sahrens 
1180fa9e4066Sahrens 	default:
118199653d4eSeschrock 		(void) zpool_standard_error(hdl, errno, msg);
1182fa9e4066Sahrens 	}
1183fa9e4066Sahrens 
118499653d4eSeschrock 	return (-1);
1185fa9e4066Sahrens }
1186fa9e4066Sahrens 
1187fa9e4066Sahrens /*
1188fa9e4066Sahrens  * Detach the specified device.
1189fa9e4066Sahrens  */
1190fa9e4066Sahrens int
1191fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
1192fa9e4066Sahrens {
1193fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1194fa9e4066Sahrens 	char msg[1024];
119599653d4eSeschrock 	nvlist_t *tgt;
1196a43d325bSek110237 	boolean_t avail_spare;
119799653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1198fa9e4066Sahrens 
1199fa9e4066Sahrens 	(void) snprintf(msg, sizeof (msg),
1200ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot detach %s"), path);
1201ea8dc4b6Seschrock 
1202ea8dc4b6Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1203a43d325bSek110237 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0)
120499653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
1205ea8dc4b6Seschrock 
1206a43d325bSek110237 	if (avail_spare)
120799653d4eSeschrock 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
120899653d4eSeschrock 
120999653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
121099653d4eSeschrock 
1211ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0)
1212ea8dc4b6Seschrock 		return (0);
1213fa9e4066Sahrens 
1214fa9e4066Sahrens 	switch (errno) {
1215fa9e4066Sahrens 
1216fa9e4066Sahrens 	case ENOTSUP:
1217fa9e4066Sahrens 		/*
1218fa9e4066Sahrens 		 * Can't detach from this type of vdev.
1219fa9e4066Sahrens 		 */
122099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only "
122199653d4eSeschrock 		    "applicable to mirror and replacing vdevs"));
122299653d4eSeschrock 		(void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg);
1223fa9e4066Sahrens 		break;
1224fa9e4066Sahrens 
1225fa9e4066Sahrens 	case EBUSY:
1226fa9e4066Sahrens 		/*
1227fa9e4066Sahrens 		 * There are no other replicas of this device.
1228fa9e4066Sahrens 		 */
122999653d4eSeschrock 		(void) zfs_error(hdl, EZFS_NOREPLICAS, msg);
1230fa9e4066Sahrens 		break;
1231fa9e4066Sahrens 
1232fa9e4066Sahrens 	default:
123399653d4eSeschrock 		(void) zpool_standard_error(hdl, errno, msg);
1234fa9e4066Sahrens 	}
1235fa9e4066Sahrens 
123699653d4eSeschrock 	return (-1);
123799653d4eSeschrock }
123899653d4eSeschrock 
123999653d4eSeschrock /*
124099653d4eSeschrock  * Remove the given device.  Currently, this is supported only for hot spares.
124199653d4eSeschrock  */
124299653d4eSeschrock int
124399653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
124499653d4eSeschrock {
124599653d4eSeschrock 	zfs_cmd_t zc = { 0 };
124699653d4eSeschrock 	char msg[1024];
124799653d4eSeschrock 	nvlist_t *tgt;
1248a43d325bSek110237 	boolean_t avail_spare;
124999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
125099653d4eSeschrock 
125199653d4eSeschrock 	(void) snprintf(msg, sizeof (msg),
125299653d4eSeschrock 	    dgettext(TEXT_DOMAIN, "cannot remove %s"), path);
125399653d4eSeschrock 
125499653d4eSeschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1255a43d325bSek110237 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0)
125699653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
125799653d4eSeschrock 
1258a43d325bSek110237 	if (!avail_spare) {
125999653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
126039c23413Seschrock 		    "only inactive hot spares can be removed"));
126199653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
126299653d4eSeschrock 	}
126399653d4eSeschrock 
126499653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
126599653d4eSeschrock 
1266ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
126799653d4eSeschrock 		return (0);
126899653d4eSeschrock 
126999653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
1270fa9e4066Sahrens }
1271fa9e4066Sahrens 
1272ea8dc4b6Seschrock /*
1273ea8dc4b6Seschrock  * Clear the errors for the pool, or the particular device if specified.
1274ea8dc4b6Seschrock  */
1275ea8dc4b6Seschrock int
1276ea8dc4b6Seschrock zpool_clear(zpool_handle_t *zhp, const char *path)
1277ea8dc4b6Seschrock {
1278ea8dc4b6Seschrock 	zfs_cmd_t zc = { 0 };
1279ea8dc4b6Seschrock 	char msg[1024];
128099653d4eSeschrock 	nvlist_t *tgt;
1281a43d325bSek110237 	boolean_t avail_spare;
128299653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1283ea8dc4b6Seschrock 
1284ea8dc4b6Seschrock 	if (path)
1285ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg),
1286ea8dc4b6Seschrock 		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
1287e9dbad6fSeschrock 		    path);
1288ea8dc4b6Seschrock 	else
1289ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg),
1290ea8dc4b6Seschrock 		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
1291ea8dc4b6Seschrock 		    zhp->zpool_name);
1292ea8dc4b6Seschrock 
1293ea8dc4b6Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
129499653d4eSeschrock 	if (path) {
1295a43d325bSek110237 		if ((tgt = zpool_find_vdev(zhp, path, &avail_spare)) == 0)
129699653d4eSeschrock 			return (zfs_error(hdl, EZFS_NODEVICE, msg));
129799653d4eSeschrock 
1298a43d325bSek110237 		if (avail_spare)
129999653d4eSeschrock 			return (zfs_error(hdl, EZFS_ISSPARE, msg));
130099653d4eSeschrock 
130199653d4eSeschrock 		verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
130299653d4eSeschrock 		    &zc.zc_guid) == 0);
1303ea8dc4b6Seschrock 	}
1304ea8dc4b6Seschrock 
1305ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0)
1306ea8dc4b6Seschrock 		return (0);
1307ea8dc4b6Seschrock 
130899653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
1309ea8dc4b6Seschrock }
1310ea8dc4b6Seschrock 
1311fa9e4066Sahrens /*
13123d7072f8Seschrock  * Similar to zpool_clear(), but takes a GUID (used by fmd).
13133d7072f8Seschrock  */
13143d7072f8Seschrock int
13153d7072f8Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid)
13163d7072f8Seschrock {
13173d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
13183d7072f8Seschrock 	char msg[1024];
13193d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
13203d7072f8Seschrock 
13213d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
13223d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"),
13233d7072f8Seschrock 	    guid);
13243d7072f8Seschrock 
13253d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
13263d7072f8Seschrock 	zc.zc_guid = guid;
13273d7072f8Seschrock 
13283d7072f8Seschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0)
13293d7072f8Seschrock 		return (0);
13303d7072f8Seschrock 
13313d7072f8Seschrock 	return (zpool_standard_error(hdl, errno, msg));
13323d7072f8Seschrock }
13333d7072f8Seschrock 
13343d7072f8Seschrock /*
1335f3861e1aSahl  * Iterate over all zvols in a given pool by walking the /dev/zvol/dsk/<pool>
1336f3861e1aSahl  * hierarchy.
1337fa9e4066Sahrens  */
1338f3861e1aSahl int
1339f3861e1aSahl zpool_iter_zvol(zpool_handle_t *zhp, int (*cb)(const char *, void *),
1340f3861e1aSahl     void *data)
1341f3861e1aSahl {
1342f3861e1aSahl 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1343f3861e1aSahl 	char (*paths)[MAXPATHLEN];
1344f3861e1aSahl 	size_t size = 4;
1345f3861e1aSahl 	int curr, fd, base, ret = 0;
1346f3861e1aSahl 	DIR *dirp;
1347f3861e1aSahl 	struct dirent *dp;
1348f3861e1aSahl 	struct stat st;
1349f3861e1aSahl 
1350f3861e1aSahl 	if ((base = open("/dev/zvol/dsk", O_RDONLY)) < 0)
1351f3861e1aSahl 		return (errno == ENOENT ? 0 : -1);
1352f3861e1aSahl 
1353f3861e1aSahl 	if (fstatat(base, zhp->zpool_name, &st, 0) != 0) {
1354f3861e1aSahl 		int err = errno;
1355f3861e1aSahl 		(void) close(base);
1356f3861e1aSahl 		return (err == ENOENT ? 0 : -1);
1357fa9e4066Sahrens 	}
1358fa9e4066Sahrens 
1359f3861e1aSahl 	/*
1360f3861e1aSahl 	 * Oddly this wasn't a directory -- ignore that failure since we
1361f3861e1aSahl 	 * know there are no links lower in the (non-existant) hierarchy.
1362f3861e1aSahl 	 */
1363f3861e1aSahl 	if (!S_ISDIR(st.st_mode)) {
1364f3861e1aSahl 		(void) close(base);
1365f3861e1aSahl 		return (0);
1366f3861e1aSahl 	}
1367f3861e1aSahl 
1368f3861e1aSahl 	if ((paths = zfs_alloc(hdl, size * sizeof (paths[0]))) == NULL) {
1369f3861e1aSahl 		(void) close(base);
1370f3861e1aSahl 		return (-1);
1371f3861e1aSahl 	}
1372f3861e1aSahl 
1373f3861e1aSahl 	(void) strlcpy(paths[0], zhp->zpool_name, sizeof (paths[0]));
1374f3861e1aSahl 	curr = 0;
1375f3861e1aSahl 
1376f3861e1aSahl 	while (curr >= 0) {
1377f3861e1aSahl 		if (fstatat(base, paths[curr], &st, AT_SYMLINK_NOFOLLOW) != 0)
1378f3861e1aSahl 			goto err;
1379f3861e1aSahl 
1380f3861e1aSahl 		if (S_ISDIR(st.st_mode)) {
1381f3861e1aSahl 			if ((fd = openat(base, paths[curr], O_RDONLY)) < 0)
1382f3861e1aSahl 				goto err;
1383f3861e1aSahl 
1384f3861e1aSahl 			if ((dirp = fdopendir(fd)) == NULL) {
1385f3861e1aSahl 				(void) close(fd);
1386f3861e1aSahl 				goto err;
1387f3861e1aSahl 			}
1388f3861e1aSahl 
1389f3861e1aSahl 			while ((dp = readdir(dirp)) != NULL) {
1390f3861e1aSahl 				if (dp->d_name[0] == '.')
1391f3861e1aSahl 					continue;
1392f3861e1aSahl 
1393f3861e1aSahl 				if (curr + 1 == size) {
1394f3861e1aSahl 					paths = zfs_realloc(hdl, paths,
1395f3861e1aSahl 					    size * sizeof (paths[0]),
1396f3861e1aSahl 					    size * 2 * sizeof (paths[0]));
1397f3861e1aSahl 					if (paths == NULL) {
1398f3861e1aSahl 						(void) closedir(dirp);
1399f3861e1aSahl 						(void) close(fd);
1400f3861e1aSahl 						goto err;
1401f3861e1aSahl 					}
1402f3861e1aSahl 
1403f3861e1aSahl 					size *= 2;
1404f3861e1aSahl 				}
1405f3861e1aSahl 
1406f3861e1aSahl 				(void) strlcpy(paths[curr + 1], paths[curr],
1407f3861e1aSahl 				    sizeof (paths[curr + 1]));
1408f3861e1aSahl 				(void) strlcat(paths[curr], "/",
1409f3861e1aSahl 				    sizeof (paths[curr]));
1410f3861e1aSahl 				(void) strlcat(paths[curr], dp->d_name,
1411f3861e1aSahl 				    sizeof (paths[curr]));
1412f3861e1aSahl 				curr++;
1413f3861e1aSahl 			}
1414f3861e1aSahl 
1415f3861e1aSahl 			(void) closedir(dirp);
1416f3861e1aSahl 
1417f3861e1aSahl 		} else {
1418f3861e1aSahl 			if ((ret = cb(paths[curr], data)) != 0)
1419f3861e1aSahl 				break;
1420f3861e1aSahl 		}
1421f3861e1aSahl 
1422f3861e1aSahl 		curr--;
1423f3861e1aSahl 	}
1424f3861e1aSahl 
1425f3861e1aSahl 	free(paths);
1426f3861e1aSahl 	(void) close(base);
1427f3861e1aSahl 
1428f3861e1aSahl 	return (ret);
1429f3861e1aSahl 
1430f3861e1aSahl err:
1431f3861e1aSahl 	free(paths);
1432f3861e1aSahl 	(void) close(base);
1433f3861e1aSahl 	return (-1);
1434f3861e1aSahl }
1435f3861e1aSahl 
1436f3861e1aSahl typedef struct zvol_cb {
1437f3861e1aSahl 	zpool_handle_t *zcb_pool;
1438f3861e1aSahl 	boolean_t zcb_create;
1439f3861e1aSahl } zvol_cb_t;
1440f3861e1aSahl 
1441f3861e1aSahl /*ARGSUSED*/
1442f3861e1aSahl static int
1443f3861e1aSahl do_zvol_create(zfs_handle_t *zhp, void *data)
1444f3861e1aSahl {
14453aefe2c7Sahrens 	int ret = 0;
1446f3861e1aSahl 
14473aefe2c7Sahrens 	if (ZFS_IS_VOLUME(zhp)) {
1448f3861e1aSahl 		(void) zvol_create_link(zhp->zfs_hdl, zhp->zfs_name);
14493aefe2c7Sahrens 		ret = zfs_iter_snapshots(zhp, do_zvol_create, NULL);
14503aefe2c7Sahrens 	}
1451f3861e1aSahl 
14523aefe2c7Sahrens 	if (ret == 0)
14533aefe2c7Sahrens 		ret = zfs_iter_filesystems(zhp, do_zvol_create, NULL);
1454fa9e4066Sahrens 
1455fa9e4066Sahrens 	zfs_close(zhp);
1456f3861e1aSahl 
1457fa9e4066Sahrens 	return (ret);
1458fa9e4066Sahrens }
1459fa9e4066Sahrens 
1460fa9e4066Sahrens /*
1461fa9e4066Sahrens  * Iterate over all zvols in the pool and make any necessary minor nodes.
1462fa9e4066Sahrens  */
1463fa9e4066Sahrens int
1464fa9e4066Sahrens zpool_create_zvol_links(zpool_handle_t *zhp)
1465fa9e4066Sahrens {
1466fa9e4066Sahrens 	zfs_handle_t *zfp;
1467fa9e4066Sahrens 	int ret;
1468fa9e4066Sahrens 
1469fa9e4066Sahrens 	/*
1470fa9e4066Sahrens 	 * If the pool is unavailable, just return success.
1471fa9e4066Sahrens 	 */
147299653d4eSeschrock 	if ((zfp = make_dataset_handle(zhp->zpool_hdl,
147399653d4eSeschrock 	    zhp->zpool_name)) == NULL)
1474fa9e4066Sahrens 		return (0);
1475fa9e4066Sahrens 
14763aefe2c7Sahrens 	ret = zfs_iter_filesystems(zfp, do_zvol_create, NULL);
1477fa9e4066Sahrens 
1478fa9e4066Sahrens 	zfs_close(zfp);
1479fa9e4066Sahrens 	return (ret);
1480fa9e4066Sahrens }
1481fa9e4066Sahrens 
1482f3861e1aSahl static int
1483f3861e1aSahl do_zvol_remove(const char *dataset, void *data)
1484f3861e1aSahl {
1485f3861e1aSahl 	zpool_handle_t *zhp = data;
1486f3861e1aSahl 
1487f3861e1aSahl 	return (zvol_remove_link(zhp->zpool_hdl, dataset));
1488f3861e1aSahl }
1489f3861e1aSahl 
1490fa9e4066Sahrens /*
1491f3861e1aSahl  * Iterate over all zvols in the pool and remove any minor nodes.  We iterate
1492f3861e1aSahl  * by examining the /dev links so that a corrupted pool doesn't impede this
1493f3861e1aSahl  * operation.
1494fa9e4066Sahrens  */
1495fa9e4066Sahrens int
1496fa9e4066Sahrens zpool_remove_zvol_links(zpool_handle_t *zhp)
1497fa9e4066Sahrens {
1498f3861e1aSahl 	return (zpool_iter_zvol(zhp, do_zvol_remove, zhp));
1499fa9e4066Sahrens }
1500c67d9675Seschrock 
1501c67d9675Seschrock /*
1502c67d9675Seschrock  * Convert from a devid string to a path.
1503c67d9675Seschrock  */
1504c67d9675Seschrock static char *
1505c67d9675Seschrock devid_to_path(char *devid_str)
1506c67d9675Seschrock {
1507c67d9675Seschrock 	ddi_devid_t devid;
1508c67d9675Seschrock 	char *minor;
1509c67d9675Seschrock 	char *path;
1510c67d9675Seschrock 	devid_nmlist_t *list = NULL;
1511c67d9675Seschrock 	int ret;
1512c67d9675Seschrock 
1513c67d9675Seschrock 	if (devid_str_decode(devid_str, &devid, &minor) != 0)
1514c67d9675Seschrock 		return (NULL);
1515c67d9675Seschrock 
1516c67d9675Seschrock 	ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list);
1517c67d9675Seschrock 
1518c67d9675Seschrock 	devid_str_free(minor);
1519c67d9675Seschrock 	devid_free(devid);
1520c67d9675Seschrock 
1521c67d9675Seschrock 	if (ret != 0)
1522c67d9675Seschrock 		return (NULL);
1523c67d9675Seschrock 
152499653d4eSeschrock 	if ((path = strdup(list[0].devname)) == NULL)
152599653d4eSeschrock 		return (NULL);
152699653d4eSeschrock 
1527c67d9675Seschrock 	devid_free_nmlist(list);
1528c67d9675Seschrock 
1529c67d9675Seschrock 	return (path);
1530c67d9675Seschrock }
1531c67d9675Seschrock 
1532c67d9675Seschrock /*
1533c67d9675Seschrock  * Convert from a path to a devid string.
1534c67d9675Seschrock  */
1535c67d9675Seschrock static char *
1536c67d9675Seschrock path_to_devid(const char *path)
1537c67d9675Seschrock {
1538c67d9675Seschrock 	int fd;
1539c67d9675Seschrock 	ddi_devid_t devid;
1540c67d9675Seschrock 	char *minor, *ret;
1541c67d9675Seschrock 
1542c67d9675Seschrock 	if ((fd = open(path, O_RDONLY)) < 0)
1543c67d9675Seschrock 		return (NULL);
1544c67d9675Seschrock 
1545c67d9675Seschrock 	minor = NULL;
1546c67d9675Seschrock 	ret = NULL;
1547c67d9675Seschrock 	if (devid_get(fd, &devid) == 0) {
1548c67d9675Seschrock 		if (devid_get_minor_name(fd, &minor) == 0)
1549c67d9675Seschrock 			ret = devid_str_encode(devid, minor);
1550c67d9675Seschrock 		if (minor != NULL)
1551c67d9675Seschrock 			devid_str_free(minor);
1552c67d9675Seschrock 		devid_free(devid);
1553c67d9675Seschrock 	}
1554c67d9675Seschrock 	(void) close(fd);
1555c67d9675Seschrock 
1556c67d9675Seschrock 	return (ret);
1557c67d9675Seschrock }
1558c67d9675Seschrock 
1559c67d9675Seschrock /*
1560c67d9675Seschrock  * Issue the necessary ioctl() to update the stored path value for the vdev.  We
1561c67d9675Seschrock  * ignore any failure here, since a common case is for an unprivileged user to
1562c67d9675Seschrock  * type 'zpool status', and we'll display the correct information anyway.
1563c67d9675Seschrock  */
1564c67d9675Seschrock static void
1565c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
1566c67d9675Seschrock {
1567c67d9675Seschrock 	zfs_cmd_t zc = { 0 };
1568c67d9675Seschrock 
1569c67d9675Seschrock 	(void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1570e9dbad6fSeschrock 	(void) strncpy(zc.zc_value, path, sizeof (zc.zc_value));
1571c67d9675Seschrock 	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1572ea8dc4b6Seschrock 	    &zc.zc_guid) == 0);
1573c67d9675Seschrock 
157499653d4eSeschrock 	(void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc);
1575c67d9675Seschrock }
1576c67d9675Seschrock 
1577c67d9675Seschrock /*
1578c67d9675Seschrock  * Given a vdev, return the name to display in iostat.  If the vdev has a path,
1579c67d9675Seschrock  * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type.
1580c67d9675Seschrock  * We also check if this is a whole disk, in which case we strip off the
1581c67d9675Seschrock  * trailing 's0' slice name.
1582c67d9675Seschrock  *
1583c67d9675Seschrock  * This routine is also responsible for identifying when disks have been
1584c67d9675Seschrock  * reconfigured in a new location.  The kernel will have opened the device by
1585c67d9675Seschrock  * devid, but the path will still refer to the old location.  To catch this, we
1586c67d9675Seschrock  * first do a path -> devid translation (which is fast for the common case).  If
1587c67d9675Seschrock  * the devid matches, we're done.  If not, we do a reverse devid -> path
1588c67d9675Seschrock  * translation and issue the appropriate ioctl() to update the path of the vdev.
1589c67d9675Seschrock  * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any
1590c67d9675Seschrock  * of these checks.
1591c67d9675Seschrock  */
1592c67d9675Seschrock char *
159399653d4eSeschrock zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv)
1594c67d9675Seschrock {
1595c67d9675Seschrock 	char *path, *devid;
1596ea8dc4b6Seschrock 	uint64_t value;
1597ea8dc4b6Seschrock 	char buf[64];
15983d7072f8Seschrock 	vdev_stat_t *vs;
15993d7072f8Seschrock 	uint_t vsc;
1600c67d9675Seschrock 
1601ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1602ea8dc4b6Seschrock 	    &value) == 0) {
1603ea8dc4b6Seschrock 		verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
1604ea8dc4b6Seschrock 		    &value) == 0);
16055ad82045Snd150628 		(void) snprintf(buf, sizeof (buf), "%llu",
16065ad82045Snd150628 		    (u_longlong_t)value);
1607ea8dc4b6Seschrock 		path = buf;
1608ea8dc4b6Seschrock 	} else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
1609c67d9675Seschrock 
16103d7072f8Seschrock 		/*
16113d7072f8Seschrock 		 * If the device is dead (faulted, offline, etc) then don't
16123d7072f8Seschrock 		 * bother opening it.  Otherwise we may be forcing the user to
16133d7072f8Seschrock 		 * open a misbehaving device, which can have undesirable
16143d7072f8Seschrock 		 * effects.
16153d7072f8Seschrock 		 */
16163d7072f8Seschrock 		if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
16173d7072f8Seschrock 		    (uint64_t **)&vs, &vsc) != 0 ||
16183d7072f8Seschrock 		    vs->vs_state >= VDEV_STATE_DEGRADED) &&
16193d7072f8Seschrock 		    zhp != NULL &&
1620c67d9675Seschrock 		    nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) {
1621c67d9675Seschrock 			/*
1622c67d9675Seschrock 			 * Determine if the current path is correct.
1623c67d9675Seschrock 			 */
1624c67d9675Seschrock 			char *newdevid = path_to_devid(path);
1625c67d9675Seschrock 
1626c67d9675Seschrock 			if (newdevid == NULL ||
1627c67d9675Seschrock 			    strcmp(devid, newdevid) != 0) {
1628c67d9675Seschrock 				char *newpath;
1629c67d9675Seschrock 
1630c67d9675Seschrock 				if ((newpath = devid_to_path(devid)) != NULL) {
1631c67d9675Seschrock 					/*
1632c67d9675Seschrock 					 * Update the path appropriately.
1633c67d9675Seschrock 					 */
1634c67d9675Seschrock 					set_path(zhp, nv, newpath);
163599653d4eSeschrock 					if (nvlist_add_string(nv,
163699653d4eSeschrock 					    ZPOOL_CONFIG_PATH, newpath) == 0)
1637c67d9675Seschrock 						verify(nvlist_lookup_string(nv,
163899653d4eSeschrock 						    ZPOOL_CONFIG_PATH,
163999653d4eSeschrock 						    &path) == 0);
164099653d4eSeschrock 					free(newpath);
164199653d4eSeschrock 				}
1642c67d9675Seschrock 			}
1643c67d9675Seschrock 
1644c67d9675Seschrock 			if (newdevid)
1645c67d9675Seschrock 				devid_str_free(newdevid);
1646c67d9675Seschrock 		}
1647c67d9675Seschrock 
1648c67d9675Seschrock 		if (strncmp(path, "/dev/dsk/", 9) == 0)
1649c67d9675Seschrock 			path += 9;
1650c67d9675Seschrock 
1651c67d9675Seschrock 		if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
1652ea8dc4b6Seschrock 		    &value) == 0 && value) {
165399653d4eSeschrock 			char *tmp = zfs_strdup(hdl, path);
165499653d4eSeschrock 			if (tmp == NULL)
165599653d4eSeschrock 				return (NULL);
1656c67d9675Seschrock 			tmp[strlen(path) - 2] = '\0';
1657c67d9675Seschrock 			return (tmp);
1658c67d9675Seschrock 		}
1659c67d9675Seschrock 	} else {
1660c67d9675Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
166199653d4eSeschrock 
166299653d4eSeschrock 		/*
166399653d4eSeschrock 		 * If it's a raidz device, we need to stick in the parity level.
166499653d4eSeschrock 		 */
166599653d4eSeschrock 		if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) {
166699653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
166799653d4eSeschrock 			    &value) == 0);
166899653d4eSeschrock 			(void) snprintf(buf, sizeof (buf), "%s%llu", path,
16695ad82045Snd150628 			    (u_longlong_t)value);
167099653d4eSeschrock 			path = buf;
167199653d4eSeschrock 		}
1672c67d9675Seschrock 	}
1673c67d9675Seschrock 
167499653d4eSeschrock 	return (zfs_strdup(hdl, path));
1675c67d9675Seschrock }
1676ea8dc4b6Seschrock 
1677ea8dc4b6Seschrock static int
1678ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b)
1679ea8dc4b6Seschrock {
1680ea8dc4b6Seschrock 	return (memcmp(a, b, sizeof (zbookmark_t)));
1681ea8dc4b6Seschrock }
1682ea8dc4b6Seschrock 
1683ea8dc4b6Seschrock /*
1684ea8dc4b6Seschrock  * Retrieve the persistent error log, uniquify the members, and return to the
1685ea8dc4b6Seschrock  * caller.
1686ea8dc4b6Seschrock  */
1687ea8dc4b6Seschrock int
168855434c77Sek110237 zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
1689ea8dc4b6Seschrock {
1690ea8dc4b6Seschrock 	zfs_cmd_t zc = { 0 };
1691ea8dc4b6Seschrock 	uint64_t count;
1692e9dbad6fSeschrock 	zbookmark_t *zb = NULL;
169355434c77Sek110237 	int i;
1694ea8dc4b6Seschrock 
1695ea8dc4b6Seschrock 	/*
1696ea8dc4b6Seschrock 	 * Retrieve the raw error list from the kernel.  If the number of errors
1697ea8dc4b6Seschrock 	 * has increased, allocate more space and continue until we get the
1698ea8dc4b6Seschrock 	 * entire list.
1699ea8dc4b6Seschrock 	 */
1700ea8dc4b6Seschrock 	verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT,
1701ea8dc4b6Seschrock 	    &count) == 0);
170275519f38Sek110237 	if (count == 0)
170375519f38Sek110237 		return (0);
1704e9dbad6fSeschrock 	if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
17055ad82045Snd150628 	    count * sizeof (zbookmark_t))) == (uintptr_t)NULL)
170699653d4eSeschrock 		return (-1);
1707e9dbad6fSeschrock 	zc.zc_nvlist_dst_size = count;
1708ea8dc4b6Seschrock 	(void) strcpy(zc.zc_name, zhp->zpool_name);
1709ea8dc4b6Seschrock 	for (;;) {
171099653d4eSeschrock 		if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG,
171199653d4eSeschrock 		    &zc) != 0) {
1712e9dbad6fSeschrock 			free((void *)(uintptr_t)zc.zc_nvlist_dst);
171399653d4eSeschrock 			if (errno == ENOMEM) {
1714bf561db0Svb160487 				count = zc.zc_nvlist_dst_size;
1715e9dbad6fSeschrock 				if ((zc.zc_nvlist_dst = (uintptr_t)
1716bf561db0Svb160487 				    zfs_alloc(zhp->zpool_hdl, count *
1717bf561db0Svb160487 				    sizeof (zbookmark_t))) == (uintptr_t)NULL)
171899653d4eSeschrock 					return (-1);
1719ea8dc4b6Seschrock 			} else {
1720ea8dc4b6Seschrock 				return (-1);
1721ea8dc4b6Seschrock 			}
1722ea8dc4b6Seschrock 		} else {
1723ea8dc4b6Seschrock 			break;
1724ea8dc4b6Seschrock 		}
1725ea8dc4b6Seschrock 	}
1726ea8dc4b6Seschrock 
1727ea8dc4b6Seschrock 	/*
1728ea8dc4b6Seschrock 	 * Sort the resulting bookmarks.  This is a little confusing due to the
1729ea8dc4b6Seschrock 	 * implementation of ZFS_IOC_ERROR_LOG.  The bookmarks are copied last
1730e9dbad6fSeschrock 	 * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks
1731ea8dc4b6Seschrock 	 * _not_ copied as part of the process.  So we point the start of our
1732ea8dc4b6Seschrock 	 * array appropriate and decrement the total number of elements.
1733ea8dc4b6Seschrock 	 */
1734e9dbad6fSeschrock 	zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) +
1735e9dbad6fSeschrock 	    zc.zc_nvlist_dst_size;
1736e9dbad6fSeschrock 	count -= zc.zc_nvlist_dst_size;
1737ea8dc4b6Seschrock 
1738ea8dc4b6Seschrock 	qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare);
1739ea8dc4b6Seschrock 
174055434c77Sek110237 	verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0);
174155434c77Sek110237 
1742ea8dc4b6Seschrock 	/*
174355434c77Sek110237 	 * Fill in the nverrlistp with nvlist's of dataset and object numbers.
1744ea8dc4b6Seschrock 	 */
1745ea8dc4b6Seschrock 	for (i = 0; i < count; i++) {
1746ea8dc4b6Seschrock 		nvlist_t *nv;
1747ea8dc4b6Seschrock 
1748c0a81264Sek110237 		/* ignoring zb_blkid and zb_level for now */
1749c0a81264Sek110237 		if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset &&
1750c0a81264Sek110237 		    zb[i-1].zb_object == zb[i].zb_object)
1751ea8dc4b6Seschrock 			continue;
1752ea8dc4b6Seschrock 
175355434c77Sek110237 		if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0)
1754e9dbad6fSeschrock 			goto nomem;
175555434c77Sek110237 		if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET,
175655434c77Sek110237 		    zb[i].zb_objset) != 0) {
175755434c77Sek110237 			nvlist_free(nv);
1758e9dbad6fSeschrock 			goto nomem;
1759e9dbad6fSeschrock 		}
176055434c77Sek110237 		if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT,
176155434c77Sek110237 		    zb[i].zb_object) != 0) {
176255434c77Sek110237 			nvlist_free(nv);
176399653d4eSeschrock 			goto nomem;
1764ea8dc4b6Seschrock 		}
176555434c77Sek110237 		if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) {
176655434c77Sek110237 			nvlist_free(nv);
1767e9dbad6fSeschrock 			goto nomem;
1768e9dbad6fSeschrock 		}
176955434c77Sek110237 		nvlist_free(nv);
1770e9dbad6fSeschrock 	}
1771e9dbad6fSeschrock 
17723ccfa83cSahrens 	free((void *)(uintptr_t)zc.zc_nvlist_dst);
1773ea8dc4b6Seschrock 	return (0);
177499653d4eSeschrock 
177599653d4eSeschrock nomem:
1776e9dbad6fSeschrock 	free((void *)(uintptr_t)zc.zc_nvlist_dst);
177799653d4eSeschrock 	return (no_memory(zhp->zpool_hdl));
1778ea8dc4b6Seschrock }
1779eaca9bbdSeschrock 
1780eaca9bbdSeschrock /*
1781eaca9bbdSeschrock  * Upgrade a ZFS pool to the latest on-disk version.
1782eaca9bbdSeschrock  */
1783eaca9bbdSeschrock int
1784eaca9bbdSeschrock zpool_upgrade(zpool_handle_t *zhp)
1785eaca9bbdSeschrock {
1786eaca9bbdSeschrock 	zfs_cmd_t zc = { 0 };
178799653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1788eaca9bbdSeschrock 
1789eaca9bbdSeschrock 	(void) strcpy(zc.zc_name, zhp->zpool_name);
1790ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0)
1791ece3d9b3Slling 		return (zpool_standard_error_fmt(hdl, errno,
179299653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"),
179399653d4eSeschrock 		    zhp->zpool_name));
1794eaca9bbdSeschrock 	return (0);
1795eaca9bbdSeschrock }
179606eeb2adSek110237 
179706eeb2adSek110237 void
1798*2a6b87f0Sek110237 zpool_set_history_str(const char *subcommand, int argc, char **argv,
1799*2a6b87f0Sek110237     char *history_str)
180006eeb2adSek110237 {
180106eeb2adSek110237 	int i;
180206eeb2adSek110237 
1803*2a6b87f0Sek110237 	(void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN);
1804*2a6b87f0Sek110237 	for (i = 1; i < argc; i++) {
1805*2a6b87f0Sek110237 		if (strlen(history_str) + 1 + strlen(argv[i]) >
1806*2a6b87f0Sek110237 		    HIS_MAX_RECORD_LEN)
1807*2a6b87f0Sek110237 			break;
1808*2a6b87f0Sek110237 		(void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN);
1809*2a6b87f0Sek110237 		(void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN);
1810*2a6b87f0Sek110237 	}
1811*2a6b87f0Sek110237 }
1812*2a6b87f0Sek110237 
1813*2a6b87f0Sek110237 /*
1814*2a6b87f0Sek110237  * Stage command history for logging.
1815*2a6b87f0Sek110237  */
1816*2a6b87f0Sek110237 int
1817*2a6b87f0Sek110237 zpool_stage_history(libzfs_handle_t *hdl, const char *history_str)
1818*2a6b87f0Sek110237 {
1819*2a6b87f0Sek110237 	if (history_str == NULL)
1820*2a6b87f0Sek110237 		return (EINVAL);
1821*2a6b87f0Sek110237 
1822*2a6b87f0Sek110237 	if (strlen(history_str) > HIS_MAX_RECORD_LEN)
1823*2a6b87f0Sek110237 		return (EINVAL);
1824*2a6b87f0Sek110237 
1825228975ccSek110237 	if (hdl->libzfs_log_str != NULL)
1826ecd6cf80Smarks 		free(hdl->libzfs_log_str);
1827ecd6cf80Smarks 
1828*2a6b87f0Sek110237 	if ((hdl->libzfs_log_str = strdup(history_str)) == NULL)
1829*2a6b87f0Sek110237 		return (no_memory(hdl));
1830ecd6cf80Smarks 
1831*2a6b87f0Sek110237 	return (0);
183206eeb2adSek110237 }
183306eeb2adSek110237 
183406eeb2adSek110237 /*
183506eeb2adSek110237  * Perform ioctl to get some command history of a pool.
183606eeb2adSek110237  *
183706eeb2adSek110237  * 'buf' is the buffer to fill up to 'len' bytes.  'off' is the
183806eeb2adSek110237  * logical offset of the history buffer to start reading from.
183906eeb2adSek110237  *
184006eeb2adSek110237  * Upon return, 'off' is the next logical offset to read from and
184106eeb2adSek110237  * 'len' is the actual amount of bytes read into 'buf'.
184206eeb2adSek110237  */
184306eeb2adSek110237 static int
184406eeb2adSek110237 get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len)
184506eeb2adSek110237 {
184606eeb2adSek110237 	zfs_cmd_t zc = { 0 };
184706eeb2adSek110237 	libzfs_handle_t *hdl = zhp->zpool_hdl;
184806eeb2adSek110237 
184906eeb2adSek110237 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
185006eeb2adSek110237 
185106eeb2adSek110237 	zc.zc_history = (uint64_t)(uintptr_t)buf;
185206eeb2adSek110237 	zc.zc_history_len = *len;
185306eeb2adSek110237 	zc.zc_history_offset = *off;
185406eeb2adSek110237 
185506eeb2adSek110237 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) {
185606eeb2adSek110237 		switch (errno) {
185706eeb2adSek110237 		case EPERM:
1858ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_PERM,
1859ece3d9b3Slling 			    dgettext(TEXT_DOMAIN,
186006eeb2adSek110237 			    "cannot show history for pool '%s'"),
186106eeb2adSek110237 			    zhp->zpool_name));
186206eeb2adSek110237 		case ENOENT:
1863ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_NOHISTORY,
186406eeb2adSek110237 			    dgettext(TEXT_DOMAIN, "cannot get history for pool "
186506eeb2adSek110237 			    "'%s'"), zhp->zpool_name));
1866d7306b64Sek110237 		case ENOTSUP:
1867d7306b64Sek110237 			return (zfs_error_fmt(hdl, EZFS_BADVERSION,
1868d7306b64Sek110237 			    dgettext(TEXT_DOMAIN, "cannot get history for pool "
1869d7306b64Sek110237 			    "'%s', pool must be upgraded"), zhp->zpool_name));
187006eeb2adSek110237 		default:
1871ece3d9b3Slling 			return (zpool_standard_error_fmt(hdl, errno,
187206eeb2adSek110237 			    dgettext(TEXT_DOMAIN,
187306eeb2adSek110237 			    "cannot get history for '%s'"), zhp->zpool_name));
187406eeb2adSek110237 		}
187506eeb2adSek110237 	}
187606eeb2adSek110237 
187706eeb2adSek110237 	*len = zc.zc_history_len;
187806eeb2adSek110237 	*off = zc.zc_history_offset;
187906eeb2adSek110237 
188006eeb2adSek110237 	return (0);
188106eeb2adSek110237 }
188206eeb2adSek110237 
188306eeb2adSek110237 /*
188406eeb2adSek110237  * Process the buffer of nvlists, unpacking and storing each nvlist record
188506eeb2adSek110237  * into 'records'.  'leftover' is set to the number of bytes that weren't
188606eeb2adSek110237  * processed as there wasn't a complete record.
188706eeb2adSek110237  */
188806eeb2adSek110237 static int
188906eeb2adSek110237 zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
189006eeb2adSek110237     nvlist_t ***records, uint_t *numrecords)
189106eeb2adSek110237 {
189206eeb2adSek110237 	uint64_t reclen;
189306eeb2adSek110237 	nvlist_t *nv;
189406eeb2adSek110237 	int i;
189506eeb2adSek110237 
189606eeb2adSek110237 	while (bytes_read > sizeof (reclen)) {
189706eeb2adSek110237 
189806eeb2adSek110237 		/* get length of packed record (stored as little endian) */
189906eeb2adSek110237 		for (i = 0, reclen = 0; i < sizeof (reclen); i++)
190006eeb2adSek110237 			reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i);
190106eeb2adSek110237 
190206eeb2adSek110237 		if (bytes_read < sizeof (reclen) + reclen)
190306eeb2adSek110237 			break;
190406eeb2adSek110237 
190506eeb2adSek110237 		/* unpack record */
190606eeb2adSek110237 		if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0)
190706eeb2adSek110237 			return (ENOMEM);
190806eeb2adSek110237 		bytes_read -= sizeof (reclen) + reclen;
190906eeb2adSek110237 		buf += sizeof (reclen) + reclen;
191006eeb2adSek110237 
191106eeb2adSek110237 		/* add record to nvlist array */
191206eeb2adSek110237 		(*numrecords)++;
191306eeb2adSek110237 		if (ISP2(*numrecords + 1)) {
191406eeb2adSek110237 			*records = realloc(*records,
191506eeb2adSek110237 			    *numrecords * 2 * sizeof (nvlist_t *));
191606eeb2adSek110237 		}
191706eeb2adSek110237 		(*records)[*numrecords - 1] = nv;
191806eeb2adSek110237 	}
191906eeb2adSek110237 
192006eeb2adSek110237 	*leftover = bytes_read;
192106eeb2adSek110237 	return (0);
192206eeb2adSek110237 }
192306eeb2adSek110237 
192406eeb2adSek110237 #define	HIS_BUF_LEN	(128*1024)
192506eeb2adSek110237 
192606eeb2adSek110237 /*
192706eeb2adSek110237  * Retrieve the command history of a pool.
192806eeb2adSek110237  */
192906eeb2adSek110237 int
193006eeb2adSek110237 zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
193106eeb2adSek110237 {
193206eeb2adSek110237 	char buf[HIS_BUF_LEN];
193306eeb2adSek110237 	uint64_t off = 0;
193406eeb2adSek110237 	nvlist_t **records = NULL;
193506eeb2adSek110237 	uint_t numrecords = 0;
193606eeb2adSek110237 	int err, i;
193706eeb2adSek110237 
193806eeb2adSek110237 	do {
193906eeb2adSek110237 		uint64_t bytes_read = sizeof (buf);
194006eeb2adSek110237 		uint64_t leftover;
194106eeb2adSek110237 
194206eeb2adSek110237 		if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
194306eeb2adSek110237 			break;
194406eeb2adSek110237 
194506eeb2adSek110237 		/* if nothing else was read in, we're at EOF, just return */
194606eeb2adSek110237 		if (!bytes_read)
194706eeb2adSek110237 			break;
194806eeb2adSek110237 
194906eeb2adSek110237 		if ((err = zpool_history_unpack(buf, bytes_read,
195006eeb2adSek110237 		    &leftover, &records, &numrecords)) != 0)
195106eeb2adSek110237 			break;
195206eeb2adSek110237 		off -= leftover;
195306eeb2adSek110237 
195406eeb2adSek110237 		/* CONSTCOND */
195506eeb2adSek110237 	} while (1);
195606eeb2adSek110237 
195706eeb2adSek110237 	if (!err) {
195806eeb2adSek110237 		verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0);
195906eeb2adSek110237 		verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD,
196006eeb2adSek110237 		    records, numrecords) == 0);
196106eeb2adSek110237 	}
196206eeb2adSek110237 	for (i = 0; i < numrecords; i++)
196306eeb2adSek110237 		nvlist_free(records[i]);
196406eeb2adSek110237 	free(records);
196506eeb2adSek110237 
196606eeb2adSek110237 	return (err);
196706eeb2adSek110237 }
196855434c77Sek110237 
196955434c77Sek110237 void
197055434c77Sek110237 zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
197155434c77Sek110237     char *pathname, size_t len)
197255434c77Sek110237 {
197355434c77Sek110237 	zfs_cmd_t zc = { 0 };
197455434c77Sek110237 	boolean_t mounted = B_FALSE;
197555434c77Sek110237 	char *mntpnt = NULL;
197655434c77Sek110237 	char dsname[MAXNAMELEN];
197755434c77Sek110237 
197855434c77Sek110237 	if (dsobj == 0) {
197955434c77Sek110237 		/* special case for the MOS */
198055434c77Sek110237 		(void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj);
198155434c77Sek110237 		return;
198255434c77Sek110237 	}
198355434c77Sek110237 
198455434c77Sek110237 	/* get the dataset's name */
198555434c77Sek110237 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
198655434c77Sek110237 	zc.zc_obj = dsobj;
198755434c77Sek110237 	if (ioctl(zhp->zpool_hdl->libzfs_fd,
198855434c77Sek110237 	    ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) {
198955434c77Sek110237 		/* just write out a path of two object numbers */
199055434c77Sek110237 		(void) snprintf(pathname, len, "<0x%llx>:<0x%llx>",
199155434c77Sek110237 		    dsobj, obj);
199255434c77Sek110237 		return;
199355434c77Sek110237 	}
199455434c77Sek110237 	(void) strlcpy(dsname, zc.zc_value, sizeof (dsname));
199555434c77Sek110237 
199655434c77Sek110237 	/* find out if the dataset is mounted */
199755434c77Sek110237 	mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt);
199855434c77Sek110237 
199955434c77Sek110237 	/* get the corrupted object's path */
200055434c77Sek110237 	(void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
200155434c77Sek110237 	zc.zc_obj = obj;
200255434c77Sek110237 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH,
200355434c77Sek110237 	    &zc) == 0) {
200455434c77Sek110237 		if (mounted) {
200555434c77Sek110237 			(void) snprintf(pathname, len, "%s%s", mntpnt,
200655434c77Sek110237 			    zc.zc_value);
200755434c77Sek110237 		} else {
200855434c77Sek110237 			(void) snprintf(pathname, len, "%s:%s",
200955434c77Sek110237 			    dsname, zc.zc_value);
201055434c77Sek110237 		}
201155434c77Sek110237 	} else {
201255434c77Sek110237 		(void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj);
201355434c77Sek110237 	}
201455434c77Sek110237 	free(mntpnt);
201555434c77Sek110237 }
2016b1b8ab34Slling 
20178488aeb5Staylor #define	RDISK_ROOT	"/dev/rdsk"
20188488aeb5Staylor #define	BACKUP_SLICE	"s2"
20198488aeb5Staylor /*
20208488aeb5Staylor  * Don't start the slice at the default block of 34; many storage
20218488aeb5Staylor  * devices will use a stripe width of 128k, so start there instead.
20228488aeb5Staylor  */
20238488aeb5Staylor #define	NEW_START_BLOCK	256
20248488aeb5Staylor 
20258488aeb5Staylor /*
20268488aeb5Staylor  * determine where a partition starts on a disk in the current
20278488aeb5Staylor  * configuration
20288488aeb5Staylor  */
20298488aeb5Staylor static diskaddr_t
20308488aeb5Staylor find_start_block(nvlist_t *config)
20318488aeb5Staylor {
20328488aeb5Staylor 	nvlist_t **child;
20338488aeb5Staylor 	uint_t c, children;
20348488aeb5Staylor 	char *path;
20358488aeb5Staylor 	diskaddr_t sb = MAXOFFSET_T;
20368488aeb5Staylor 	int fd;
20378488aeb5Staylor 	char diskname[MAXPATHLEN];
20388488aeb5Staylor 	uint64_t wholedisk;
20398488aeb5Staylor 
20408488aeb5Staylor 	if (nvlist_lookup_nvlist_array(config,
20418488aeb5Staylor 	    ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) {
20428488aeb5Staylor 		if (nvlist_lookup_uint64(config,
20438488aeb5Staylor 		    ZPOOL_CONFIG_WHOLE_DISK,
20448488aeb5Staylor 		    &wholedisk) != 0 || !wholedisk) {
20458488aeb5Staylor 			return (MAXOFFSET_T);
20468488aeb5Staylor 		}
20478488aeb5Staylor 		if (nvlist_lookup_string(config,
20488488aeb5Staylor 		    ZPOOL_CONFIG_PATH, &path) != 0) {
20498488aeb5Staylor 			return (MAXOFFSET_T);
20508488aeb5Staylor 		}
20518488aeb5Staylor 
20528488aeb5Staylor 		(void) snprintf(diskname, sizeof (diskname), "%s%s",
20538488aeb5Staylor 		    RDISK_ROOT, strrchr(path, '/'));
20548488aeb5Staylor 		if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) {
20558488aeb5Staylor 			struct dk_gpt *vtoc;
20568488aeb5Staylor 			if (efi_alloc_and_read(fd, &vtoc) >= 0) {
20578488aeb5Staylor 				sb = vtoc->efi_parts[0].p_start;
20588488aeb5Staylor 				efi_free(vtoc);
20598488aeb5Staylor 			}
20608488aeb5Staylor 			(void) close(fd);
20618488aeb5Staylor 		}
20628488aeb5Staylor 		return (sb);
20638488aeb5Staylor 	}
20648488aeb5Staylor 
20658488aeb5Staylor 	for (c = 0; c < children; c++) {
20668488aeb5Staylor 		sb = find_start_block(child[c]);
20678488aeb5Staylor 		if (sb != MAXOFFSET_T) {
20688488aeb5Staylor 			return (sb);
20698488aeb5Staylor 		}
20708488aeb5Staylor 	}
20718488aeb5Staylor 	return (MAXOFFSET_T);
20728488aeb5Staylor }
20738488aeb5Staylor 
20748488aeb5Staylor /*
20758488aeb5Staylor  * Label an individual disk.  The name provided is the short name,
20768488aeb5Staylor  * stripped of any leading /dev path.
20778488aeb5Staylor  */
20788488aeb5Staylor int
20798488aeb5Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name)
20808488aeb5Staylor {
20818488aeb5Staylor 	char path[MAXPATHLEN];
20828488aeb5Staylor 	struct dk_gpt *vtoc;
20838488aeb5Staylor 	int fd;
20848488aeb5Staylor 	size_t resv = EFI_MIN_RESV_SIZE;
20858488aeb5Staylor 	uint64_t slice_size;
20868488aeb5Staylor 	diskaddr_t start_block;
20878488aeb5Staylor 	char errbuf[1024];
20888488aeb5Staylor 
20898488aeb5Staylor 	if (zhp) {
20908488aeb5Staylor 		nvlist_t *nvroot;
20918488aeb5Staylor 
20928488aeb5Staylor 		verify(nvlist_lookup_nvlist(zhp->zpool_config,
20938488aeb5Staylor 		    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
20948488aeb5Staylor 
20958488aeb5Staylor 		if (zhp->zpool_start_block == 0)
20968488aeb5Staylor 			start_block = find_start_block(nvroot);
20978488aeb5Staylor 		else
20988488aeb5Staylor 			start_block = zhp->zpool_start_block;
20998488aeb5Staylor 		zhp->zpool_start_block = start_block;
21008488aeb5Staylor 	} else {
21018488aeb5Staylor 		/* new pool */
21028488aeb5Staylor 		start_block = NEW_START_BLOCK;
21038488aeb5Staylor 	}
21048488aeb5Staylor 
21058488aeb5Staylor 	(void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name,
21068488aeb5Staylor 	    BACKUP_SLICE);
21078488aeb5Staylor 
21088488aeb5Staylor 	if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) {
21098488aeb5Staylor 		/*
21108488aeb5Staylor 		 * This shouldn't happen.  We've long since verified that this
21118488aeb5Staylor 		 * is a valid device.
21128488aeb5Staylor 		 */
21138488aeb5Staylor 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
21148488aeb5Staylor 		    "label '%s': unable to open device"), name);
21158488aeb5Staylor 		return (zfs_error(hdl, EZFS_OPENFAILED, errbuf));
21168488aeb5Staylor 	}
21178488aeb5Staylor 
21188488aeb5Staylor 	if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) {
21198488aeb5Staylor 		/*
21208488aeb5Staylor 		 * The only way this can fail is if we run out of memory, or we
21218488aeb5Staylor 		 * were unable to read the disk's capacity
21228488aeb5Staylor 		 */
21238488aeb5Staylor 		if (errno == ENOMEM)
21248488aeb5Staylor 			(void) no_memory(hdl);
21258488aeb5Staylor 
21268488aeb5Staylor 		(void) close(fd);
21278488aeb5Staylor 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
21288488aeb5Staylor 		    "label '%s': unable to read disk capacity"), name);
21298488aeb5Staylor 
21308488aeb5Staylor 		return (zfs_error(hdl, EZFS_NOCAP, errbuf));
21318488aeb5Staylor 	}
21328488aeb5Staylor 
21338488aeb5Staylor 	slice_size = vtoc->efi_last_u_lba + 1;
21348488aeb5Staylor 	slice_size -= EFI_MIN_RESV_SIZE;
21358488aeb5Staylor 	if (start_block == MAXOFFSET_T)
21368488aeb5Staylor 		start_block = NEW_START_BLOCK;
21378488aeb5Staylor 	slice_size -= start_block;
21388488aeb5Staylor 
21398488aeb5Staylor 	vtoc->efi_parts[0].p_start = start_block;
21408488aeb5Staylor 	vtoc->efi_parts[0].p_size = slice_size;
21418488aeb5Staylor 
21428488aeb5Staylor 	/*
21438488aeb5Staylor 	 * Why we use V_USR: V_BACKUP confuses users, and is considered
21448488aeb5Staylor 	 * disposable by some EFI utilities (since EFI doesn't have a backup
21458488aeb5Staylor 	 * slice).  V_UNASSIGNED is supposed to be used only for zero size
21468488aeb5Staylor 	 * partitions, and efi_write() will fail if we use it.  V_ROOT, V_BOOT,
21478488aeb5Staylor 	 * etc. were all pretty specific.  V_USR is as close to reality as we
21488488aeb5Staylor 	 * can get, in the absence of V_OTHER.
21498488aeb5Staylor 	 */
21508488aeb5Staylor 	vtoc->efi_parts[0].p_tag = V_USR;
21518488aeb5Staylor 	(void) strcpy(vtoc->efi_parts[0].p_name, "zfs");
21528488aeb5Staylor 
21538488aeb5Staylor 	vtoc->efi_parts[8].p_start = slice_size + start_block;
21548488aeb5Staylor 	vtoc->efi_parts[8].p_size = resv;
21558488aeb5Staylor 	vtoc->efi_parts[8].p_tag = V_RESERVED;
21568488aeb5Staylor 
21578488aeb5Staylor 	if (efi_write(fd, vtoc) != 0) {
21588488aeb5Staylor 		/*
21598488aeb5Staylor 		 * Some block drivers (like pcata) may not support EFI
21608488aeb5Staylor 		 * GPT labels.  Print out a helpful error message dir-
21618488aeb5Staylor 		 * ecting the user to manually label the disk and give
21628488aeb5Staylor 		 * a specific slice.
21638488aeb5Staylor 		 */
21648488aeb5Staylor 		(void) close(fd);
21658488aeb5Staylor 		efi_free(vtoc);
21668488aeb5Staylor 
21678488aeb5Staylor 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
21688488aeb5Staylor 		    "cannot label '%s': try using fdisk(1M) and then "
21698488aeb5Staylor 		    "provide a specific slice"), name);
21708488aeb5Staylor 		return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
21718488aeb5Staylor 	}
21728488aeb5Staylor 
21738488aeb5Staylor 	(void) close(fd);
21748488aeb5Staylor 	efi_free(vtoc);
21758488aeb5Staylor 	return (0);
21768488aeb5Staylor }
21778488aeb5Staylor 
2178b1b8ab34Slling int
2179b1b8ab34Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
2180b1b8ab34Slling {
2181b1b8ab34Slling 	zfs_cmd_t zc = { 0 };
2182b1b8ab34Slling 	int ret = -1;
2183b1b8ab34Slling 	char errbuf[1024];
2184b1b8ab34Slling 	nvlist_t *nvl = NULL;
2185b1b8ab34Slling 	nvlist_t *realprops;
2186b1b8ab34Slling 
2187b1b8ab34Slling 	(void) snprintf(errbuf, sizeof (errbuf),
2188b1b8ab34Slling 	    dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
2189b1b8ab34Slling 	    zhp->zpool_name);
2190b1b8ab34Slling 
2191e7437265Sahrens 	if (zpool_get_version(zhp) < SPA_VERSION_BOOTFS) {
2192b1b8ab34Slling 		zfs_error_aux(zhp->zpool_hdl,
2193b1b8ab34Slling 		    dgettext(TEXT_DOMAIN, "pool must be "
2194b1b8ab34Slling 		    "upgraded to support pool properties"));
2195b1b8ab34Slling 		return (zfs_error(zhp->zpool_hdl, EZFS_BADVERSION, errbuf));
2196b1b8ab34Slling 	}
2197b1b8ab34Slling 
2198b1b8ab34Slling 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp))
2199b1b8ab34Slling 		return (zfs_error(zhp->zpool_hdl, EZFS_POOLPROPS, errbuf));
2200b1b8ab34Slling 
2201b1b8ab34Slling 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
2202b1b8ab34Slling 	    nvlist_add_string(nvl, propname, propval) != 0) {
2203b1b8ab34Slling 		return (no_memory(zhp->zpool_hdl));
2204b1b8ab34Slling 	}
2205b1b8ab34Slling 
2206b1b8ab34Slling 	if ((realprops = zfs_validate_properties(zhp->zpool_hdl, ZFS_TYPE_POOL,
2207b1b8ab34Slling 	    zhp->zpool_name, nvl, 0, NULL, errbuf)) == NULL) {
2208b1b8ab34Slling 		nvlist_free(nvl);
2209b1b8ab34Slling 		return (-1);
2210b1b8ab34Slling 	}
2211b1b8ab34Slling 
2212b1b8ab34Slling 	nvlist_free(nvl);
2213b1b8ab34Slling 	nvl = realprops;
2214b1b8ab34Slling 
2215b1b8ab34Slling 	/*
2216b1b8ab34Slling 	 * Execute the corresponding ioctl() to set this property.
2217b1b8ab34Slling 	 */
2218b1b8ab34Slling 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2219b1b8ab34Slling 
2220b1b8ab34Slling 	if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl, NULL) != 0)
2221b1b8ab34Slling 		return (-1);
2222b1b8ab34Slling 
2223ecd6cf80Smarks 	ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc);
2224b1b8ab34Slling 	zcmd_free_nvlists(&zc);
2225b1b8ab34Slling 
2226b1b8ab34Slling 	if (ret)
2227b1b8ab34Slling 		(void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf);
2228b1b8ab34Slling 
2229b1b8ab34Slling 	return (ret);
2230b1b8ab34Slling }
2231b1b8ab34Slling 
22323d7072f8Seschrock uint64_t
22333d7072f8Seschrock zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop)
22343d7072f8Seschrock {
22353d7072f8Seschrock 	uint64_t value;
22363d7072f8Seschrock 	nvlist_t *nvp;
22373d7072f8Seschrock 
2238e7437265Sahrens 	if (zpool_get_version(zhp) < SPA_VERSION_BOOTFS)
22393d7072f8Seschrock 		return (0);
22403d7072f8Seschrock 
22413d7072f8Seschrock 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp))
22423d7072f8Seschrock 		return (zpool_prop_default_numeric(prop));
22433d7072f8Seschrock 
22443d7072f8Seschrock 	switch (prop) {
22453d7072f8Seschrock 	case ZPOOL_PROP_AUTOREPLACE:
22463d7072f8Seschrock 		if (nvlist_lookup_nvlist(zhp->zpool_props,
22473d7072f8Seschrock 		    zpool_prop_to_name(prop), &nvp) != 0) {
22483d7072f8Seschrock 			value = zpool_prop_default_numeric(prop);
22493d7072f8Seschrock 		} else {
22503d7072f8Seschrock 			VERIFY(nvlist_lookup_uint64(nvp, ZFS_PROP_VALUE,
22513d7072f8Seschrock 			    &value) == 0);
22523d7072f8Seschrock 		}
22533d7072f8Seschrock 		return (value);
22543d7072f8Seschrock 		break;
22553d7072f8Seschrock 
22563d7072f8Seschrock 	default:
22573d7072f8Seschrock 		assert(0);
22583d7072f8Seschrock 	}
22593d7072f8Seschrock 
22603d7072f8Seschrock 	return (0);
22613d7072f8Seschrock }
22623d7072f8Seschrock 
2263b1b8ab34Slling int
2264b1b8ab34Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *propbuf,
2265b1b8ab34Slling     size_t proplen, zfs_source_t *srctype)
2266b1b8ab34Slling {
2267b1b8ab34Slling 	uint64_t value;
2268b1b8ab34Slling 	char msg[1024], *strvalue;
2269b1b8ab34Slling 	nvlist_t *nvp;
2270b1b8ab34Slling 	zfs_source_t src = ZFS_SRC_NONE;
2271b1b8ab34Slling 
2272b1b8ab34Slling 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
2273b1b8ab34Slling 	    "cannot get property '%s'"), zpool_prop_to_name(prop));
2274b1b8ab34Slling 
2275e7437265Sahrens 	if (zpool_get_version(zhp) < SPA_VERSION_BOOTFS) {
2276b1b8ab34Slling 		zfs_error_aux(zhp->zpool_hdl,
2277b1b8ab34Slling 		    dgettext(TEXT_DOMAIN, "pool must be "
2278b1b8ab34Slling 		    "upgraded to support pool properties"));
2279b1b8ab34Slling 		return (zfs_error(zhp->zpool_hdl, EZFS_BADVERSION, msg));
2280b1b8ab34Slling 	}
2281b1b8ab34Slling 
22823d7072f8Seschrock 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) &&
22833d7072f8Seschrock 	    prop != ZPOOL_PROP_NAME)
2284b1b8ab34Slling 		return (zfs_error(zhp->zpool_hdl, EZFS_POOLPROPS, msg));
2285b1b8ab34Slling 
2286b1b8ab34Slling 	switch (prop) {
22873d7072f8Seschrock 	case ZPOOL_PROP_NAME:
2288b1b8ab34Slling 		(void) strlcpy(propbuf, zhp->zpool_name, proplen);
2289b1b8ab34Slling 		break;
2290b1b8ab34Slling 
22913d7072f8Seschrock 	case ZPOOL_PROP_BOOTFS:
2292b1b8ab34Slling 		if (nvlist_lookup_nvlist(zhp->zpool_props,
2293b1b8ab34Slling 		    zpool_prop_to_name(prop), &nvp) != 0) {
2294b1b8ab34Slling 			strvalue = (char *)zfs_prop_default_string(prop);
2295b1b8ab34Slling 			if (strvalue == NULL)
2296b1b8ab34Slling 				strvalue = "-";
2297b1b8ab34Slling 			src = ZFS_SRC_DEFAULT;
2298b1b8ab34Slling 		} else {
2299b1b8ab34Slling 			VERIFY(nvlist_lookup_uint64(nvp,
2300b1b8ab34Slling 			    ZFS_PROP_SOURCE, &value) == 0);
2301b1b8ab34Slling 			src = value;
2302b1b8ab34Slling 			VERIFY(nvlist_lookup_string(nvp, ZFS_PROP_VALUE,
2303b1b8ab34Slling 			    &strvalue) == 0);
2304b1b8ab34Slling 			if (strlen(strvalue) >= proplen)
2305b1b8ab34Slling 				return (-1);
2306b1b8ab34Slling 		}
23073d7072f8Seschrock 		(void) strlcpy(propbuf, strvalue, proplen);
23083d7072f8Seschrock 		break;
23093d7072f8Seschrock 
2310ecd6cf80Smarks 	case ZPOOL_PROP_DELEGATION:
23113d7072f8Seschrock 	case ZPOOL_PROP_AUTOREPLACE:
23123d7072f8Seschrock 		if (nvlist_lookup_nvlist(zhp->zpool_props,
23133d7072f8Seschrock 		    zpool_prop_to_name(prop), &nvp) != 0) {
23143d7072f8Seschrock 			value = zpool_prop_default_numeric(prop);
23153d7072f8Seschrock 			src = ZFS_SRC_DEFAULT;
23163d7072f8Seschrock 		} else {
23173d7072f8Seschrock 			VERIFY(nvlist_lookup_uint64(nvp,
23183d7072f8Seschrock 			    ZFS_PROP_SOURCE, &value) == 0);
23193d7072f8Seschrock 			src = value;
23203d7072f8Seschrock 			VERIFY(nvlist_lookup_uint64(nvp, ZFS_PROP_VALUE,
23213d7072f8Seschrock 			    &value) == 0);
23223d7072f8Seschrock 		}
23233d7072f8Seschrock 		(void) strlcpy(propbuf, value ? "on" : "off", proplen);
2324b1b8ab34Slling 		break;
2325b1b8ab34Slling 
2326b1b8ab34Slling 	default:
2327b1b8ab34Slling 		return (-1);
2328b1b8ab34Slling 	}
2329b1b8ab34Slling 	if (srctype)
2330b1b8ab34Slling 		*srctype = src;
2331b1b8ab34Slling 	return (0);
2332b1b8ab34Slling }
2333b1b8ab34Slling 
2334b1b8ab34Slling int
2335b1b8ab34Slling zpool_get_proplist(libzfs_handle_t *hdl, char *fields, zpool_proplist_t **listp)
2336b1b8ab34Slling {
2337b1b8ab34Slling 	return (zfs_get_proplist_common(hdl, fields, listp, ZFS_TYPE_POOL));
2338b1b8ab34Slling }
2339b1b8ab34Slling 
2340b1b8ab34Slling 
2341b1b8ab34Slling int
2342b1b8ab34Slling zpool_expand_proplist(zpool_handle_t *zhp, zpool_proplist_t **plp)
2343b1b8ab34Slling {
2344b1b8ab34Slling 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2345b1b8ab34Slling 	zpool_proplist_t *entry;
2346b1b8ab34Slling 	char buf[ZFS_MAXPROPLEN];
2347b1b8ab34Slling 
2348b1b8ab34Slling 	if (zfs_expand_proplist_common(hdl, plp, ZFS_TYPE_POOL) != 0)
2349b1b8ab34Slling 		return (-1);
2350b1b8ab34Slling 
2351b1b8ab34Slling 	for (entry = *plp; entry != NULL; entry = entry->pl_next) {
2352b1b8ab34Slling 
2353b1b8ab34Slling 		if (entry->pl_fixed)
2354b1b8ab34Slling 			continue;
2355b1b8ab34Slling 
2356b1b8ab34Slling 		if (entry->pl_prop != ZFS_PROP_INVAL &&
2357b1b8ab34Slling 		    zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf),
2358b1b8ab34Slling 		    NULL) == 0) {
2359b1b8ab34Slling 			if (strlen(buf) > entry->pl_width)
2360b1b8ab34Slling 				entry->pl_width = strlen(buf);
2361b1b8ab34Slling 		}
2362b1b8ab34Slling 	}
2363b1b8ab34Slling 
2364b1b8ab34Slling 	return (0);
2365b1b8ab34Slling }
2366